@@ -0,0 +1,146 @@ | |||
# Плагин WordPress для интеграции с Редакцией | |||
Написан в 2017 году. | |||
Есть некоторые отступления от PSR. Но у WP свои стандарты кодирования, плюс тогда мой внутренний перфекционист, местами, желал странного. Сейчас, разумеется, автоформат — маст хэв! | |||
Имеется видеоролик (3 минуты), о том, как сей плагин предполагалось использовать: | |||
https://youtu.be/qjWFutZEUlM | |||
Если, вдруг, возникнет вопрос "Что еще за Редакция?" то про нее (12 минут) тут: | |||
https://youtu.be/Dn0X1Mhjg6c | |||
--- | |||
### Дальше оригинальное Readme плагина: | |||
--- | |||
Данное решение позволяет подключить к Редакции наполняемый сайт, | |||
построенный на базе популярной CMS WordPress. Для этого Вам | |||
не понадобится изучать наш API и в абсолютном большинстве случаев | |||
не потребуется программирование. | |||
Системные требования: | |||
- WordPress 4.7.3+ | |||
- PHP 5.4+ (gd, curl, json, mbstring) | |||
Устанавливается плагин через панель управления WordPress: | |||
`Плагины > Добавить новый > Загрузить плагин` | |||
Папка `/wp-content/plugins/chiefred/logs` должна быть доступна для записи. | |||
После активации плагина в меню Настройки появится подпункт | |||
`API ChiefRed.com`, где нужно задать параметры взаимодействия с Редакцией, | |||
получить данные для настройки самой Редакции для работы с Вашим сайтом, | |||
а также можно отрегулировать отображение на сайте загружаемых из | |||
Редакции материалов. | |||
## Настройки сайта для взаимодействия с редакцией | |||
- ID этого cайта в Редакции – берется в первой колонке таблицы | |||
подраздела «Сайты» роли Администратора в Редакции. | |||
- IP-адрес сервера API и Порт API (Редакции) – указаны в подразделе | |||
«Обзор состояния системы» роли Администратора в Редакции – инфоблок | |||
«Реквизиты API Редакции». | |||
- Секрет синхронизации – последовательность случайных символов, | |||
длиной до 64 знаков. Допускаются только латинские маленькие и | |||
большие буквы, а также цифры. | |||
## Реквизиты данного сайта для настройки редакции | |||
Важно после сохранения Секрета в плагине в точности скопировать его в | |||
настройки Вашего сайта в самой Редакции. Кроме него в реквизитах сайта | |||
в Редакции нужно указать: | |||
- Домен | |||
- IP-адрес сервера сайта; | |||
- Скрипт канонического URL статьи; | |||
- Скрипт сброса флага задержки. | |||
Все это можно узнать на странице настроек плагина. | |||
## Синхронизация | |||
После сохранения всех настроек в плагине и Редакции все будет готово к | |||
выкладке статей из Редакции на Ваш сайт. Этот процесс осуществляется | |||
автоматически, по мере отправки статей на публикацию Менеджером | |||
предметной области. | |||
Если же Вы выкладываете материалы на сайт повторно (переносите или | |||
восстанавливаете сайт с нуля, уже имея в Редакции готовые статьи), то | |||
начало процесса синхронизации можно ускорить с помощью утилиты | |||
«Выполнить синхронизацию», доступной в нижней части страницы настроек | |||
плагина. | |||
Там же можно просмотреть «Журнал последней синхронизации» и отменить | |||
очередную внеплановую синхронизацию. | |||
Плановая синхронизация осуществляется каждые четыре часа. | |||
> ВАЖНО! Для систематического осуществления процесса синхронизации | |||
> необходимо обеспечить регулярный запуск скрипта wp-cron.php, | |||
> отвечающего в WordPress за периодические задачи. На молодых сайтах | |||
> с низкой посещаемостью для этого необходимо использовать системный | |||
> планировщик хостинга. На эту тему существует множество материалов, | |||
> найти которые можно в Google, например, по запросу: | |||
> «WordPress запуск по crontab». | |||
## Отображение статей на сайте | |||
Получив статью из Редакции, плагин создает обычную статическую | |||
страницу (page). WordPress (как и Редакция) поддерживает иерархическую | |||
структуру материалов. Так что размещаемые на сайте статьи органично | |||
вписываются в структуру данных WordPress. Дополнительные данные из | |||
Редакции, необходимые для работы плагина, размещаются в скрытых | |||
мета-полях статьи. Например, там хранятся, и выводятся плагином на | |||
странице статьи, мета-поля keywords и description (полезные для SEO). | |||
Плагин «из коробки» настроен отображать статьи в расширенном формате: | |||
со ссылкой на родительскую статью, подписями авторов, шлейфом анонсов | |||
дочерних статей и формой сбора возражений читателей. Но все эти | |||
дополнительные компоненты статьи можно отключить в настройках плагина. | |||
Для более тонкой настройки вывода статьи можно отредактировать файлы, | |||
отвечающие за ее отображение: | |||
- `/wp-content/plugins/chiefred/views/article.php` – шаблон вывода; | |||
- `/wp-content/plugins/chiefred/res/chiefred.css` – таблицы стилей; | |||
- `/wp-content/plugins/chiefred/res/chiefred.js` – скрипты формы | |||
сбора возражений читателей. | |||
Правда, вместо них Вы найдете: `article.default.php`, `chiefred.default.css` | |||
и `chiefred.default.js` – это входящие в поставку плагина | |||
стандартные (default) файлы, которые нужно скопировать, соответственно, | |||
в `article.php`, `chiefred.css` и `chiefred.js`, в которые и следует вносить | |||
изменения. | |||
Плагин также добавляет визуальный редактор поля «Отрывок» в редакторе | |||
статей WordPress, где размещается Анонс статьи. | |||
## Отображение иллюстраций на сайте | |||
WordPress, как и Редакция, поддерживает несколько форматов миниатюр | |||
иллюстраций, создаваемых в процессе синхронизации. В настройках плагина | |||
можно указать, какой формат иллюстрации Вы хотите вставлять в статью: | |||
одну из миниатюр или полный. | |||
Также здесь можно задать присваиваемый тегу иллюстрации класс и | |||
настроить обертывание иллюстраций ссылкой на полноформатное изображение. | |||
> ВАЖНО! В теле статьи хранится тег картинки с минимальным набором | |||
> атрибутов: идентификатор, класс и ссылка на миниатюру выбранного | |||
> формата. Остальные атрибуты и обертывание ссылкой добавляются | |||
> динамически, в момент вывода статьи читателю. Это сделано для | |||
> сохранения возможности изменить формат вывода иллюстраций, если Вы | |||
> решите пересмотреть дизайн своего сайта. То есть, простым изменением | |||
> настроек плагина можно менять вывод сразу всех иллюстраций во всех | |||
> статьях, при условии что в теле статьи в тегах картинок были | |||
> сохранены их идентификаторы. | |||
> | |||
> Не удаляйте и не меняйте атрибут «id» картинок в статьях! | |||
@@ -0,0 +1,103 @@ | |||
<?php | |||
/** | |||
* @package ChiefRedCom | |||
* @version 1.0 | |||
*/ | |||
/* | |||
Plugin Name: API v1 ChiefRed.com | |||
Description: Подключение к API v1 сервиса наполнения сайтов статьями <a href="https://chiefred.com">ChiefRed.com</a> | |||
Version: 1.0 | |||
Author: ChiefRed.com | |||
Author URI: https://ChiefRed.com/ | |||
*/ | |||
if ( ! defined( 'ABSPATH' ) ) exit; | |||
define( 'CHIEFRED_VERSION', '1.0' ); | |||
define( 'CHIEFRED_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); | |||
define( 'CHIEFRED_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); | |||
define( 'CHIEFRED_LOCAL_DEBUG', getenv('DEV_LOCAL') ); | |||
define( 'CHIEFRED_LOCAL_BASE', 'https://chiefred.dev' ); | |||
define('CHIEFRED_LL_OFF', 0); | |||
define('CHIEFRED_LL_ERROR', 1); | |||
define('CHIEFRED_LL_WARNING', 2); | |||
define('CHIEFRED_LL_INFO', 3); | |||
define('CHIEFRED_LL_DEBUG', 4); | |||
define('CHIEFRED_LOG_LEVEL', CHIEFRED_LL_INFO); | |||
if(CHIEFRED_LOG_LEVEL > CHIEFRED_LL_OFF) { | |||
define('CHIEFRED_LOG_FILE', fopen(CHIEFRED_PLUGIN_DIR.'/logs/chiefred.log', 'a+')); | |||
} | |||
define( 'CHIEFRED_MEDIUM_IMG_WIDTH_LIMIT', 400 ); | |||
define( 'CHIEFRED_SMALL_IMG_WIDTH_LIMIT', 200 ); | |||
register_activation_hook(__FILE__, 'chiefred_plugin_activation'); | |||
function chiefred_plugin_activation() | |||
{ | |||
add_option('chiefred_site_id', '', '', 'no'); | |||
add_option('chiefred_api_ip', '', '', 'no'); | |||
add_option('chiefred_api_port', '', '', 'no'); | |||
add_option('chiefred_sync_lock', '0', '', 'no'); | |||
add_option('chiefred_article_parent_link', '1', '', 'yes'); | |||
add_option('chiefred_article_creators', '1', '', 'yes'); | |||
add_option('chiefred_article_childrens', '1', '', 'yes'); | |||
add_option('chiefred_article_was_useful', '1', '', 'yes'); | |||
add_option('chiefred_illustration_size', 'medium', '', 'yes'); | |||
add_option('chiefred_illustration_class', '', '', 'yes'); | |||
add_option('chiefred_illustration_link', '1', '', 'yes'); | |||
add_option('chiefred_illustration_link_class', 'photo', '', 'yes'); | |||
add_option('chiefred_illustration_link_rel', 'lightbox', '', 'yes'); | |||
add_option('chiefred_illustration_link_target', '_blank', '', 'yes'); | |||
if (! wp_next_scheduled ( 'chiefred_every4hours_synchronize' )) { | |||
wp_schedule_event(time(), 'every4hours', 'chiefred_every4hours_synchronize'); | |||
} | |||
} | |||
register_deactivation_hook(__FILE__, 'chiefred_plugin_deactivation'); | |||
function chiefred_plugin_deactivation() | |||
{ | |||
wp_clear_scheduled_hook('chiefred_synchronize'); | |||
wp_clear_scheduled_hook('chiefred_every4hours_synchronize'); | |||
} | |||
require_once( CHIEFRED_PLUGIN_DIR . 'class.chiefred.php' ); | |||
add_action( 'init', array( 'ChiefRed', 'init' ) ); | |||
if ( is_admin() ) { | |||
require_once( CHIEFRED_PLUGIN_DIR . 'class.chiefred-admin.php' ); | |||
add_action( 'init', array( 'ChiefRed_Admin', 'init' ) ); | |||
} | |||
function chiefred_log_e($msg=null, $var=null) | |||
{ | |||
if (CHIEFRED_LOG_LEVEL >= CHIEFRED_LL_ERROR) chiefred_logger('ERROR', $msg, $var); | |||
} | |||
function chiefred_log_w($msg=null, $var=null) | |||
{ | |||
if (CHIEFRED_LOG_LEVEL >= CHIEFRED_LL_WARNING) chiefred_logger('WARNING', $msg, $var); | |||
} | |||
function chiefred_log_i($msg=null, $var=null) | |||
{ | |||
if (CHIEFRED_LOG_LEVEL >= CHIEFRED_LL_INFO) chiefred_logger('INFO', $msg, $var); | |||
} | |||
function chiefred_log_d($msg=null, $var=null) | |||
{ | |||
if (CHIEFRED_LOG_LEVEL >= CHIEFRED_LL_DEBUG) chiefred_logger('DEBUG', $msg, $var); | |||
} | |||
function chiefred_logger($level='debug', $msg=null, $var=null) | |||
{ | |||
if (CHIEFRED_LOG_FILE && $msg) { | |||
if ($var !== null) $msg .= ': '.var_export($var, true); | |||
$level = str_pad("[{$level}]", 9, ' '); | |||
fwrite(CHIEFRED_LOG_FILE, date( 'Y-m-d H:i:s', current_time( 'timestamp', 0 ) )." {$level} {$msg}\n"); | |||
} | |||
} |
@@ -0,0 +1,192 @@ | |||
<?php | |||
if ( ! defined( 'ABSPATH' ) ) exit; | |||
class ChiefRed_Admin { | |||
private static $initiated = false; | |||
public static function init() | |||
{ | |||
if ( ! self::$initiated ) { | |||
self::init_hooks(); | |||
} | |||
if (isset($_POST['chiefred_action'])) { | |||
if ( function_exists('current_user_can') && !current_user_can('manage_options') ) exit('CANT'); | |||
if ( | |||
! isset( $_POST['chiefred_token'] ) | |||
|| ! wp_verify_nonce( $_POST['chiefred_token'], 'wp_rest' ) | |||
) { | |||
exit('CSRF'); | |||
} else { | |||
switch ($_POST['chiefred_action']) { | |||
case 'synchronize': | |||
wp_clear_scheduled_hook('chiefred_synchronize'); | |||
if (false !== wp_schedule_single_event( time(), 'chiefred_synchronize' )) { | |||
exit('ok'); | |||
} else { | |||
exit('notOk'); | |||
} | |||
case 'clear_synchronize': | |||
wp_clear_scheduled_hook('chiefred_synchronize'); | |||
exit('ok'); | |||
case 'save': | |||
update_option('chiefred_site_id', absint($_POST['site_id'])); | |||
if (filter_var(trim($_POST['api_ip']), FILTER_VALIDATE_IP)) { | |||
update_option('chiefred_api_ip', trim($_POST['api_ip'])); | |||
} | |||
update_option('chiefred_api_port', absint($_POST['api_port'])); | |||
update_option('chiefred_api_secret', preg_replace('/[^a-zA-Z0-9]+/', '', $_POST['api_secret'])); | |||
update_option('chiefred_article_parent_link', absint($_POST['article_parent_link'])); | |||
update_option('chiefred_article_creators', absint($_POST['article_creators'])); | |||
update_option('chiefred_article_childrens', absint($_POST['article_childrens'])); | |||
update_option('chiefred_article_was_useful', absint($_POST['article_was_useful'])); | |||
if (in_array($_POST['illustration_size'], ['thumbnail', 'medium', 'medium_large', 'full'])) { | |||
update_option('chiefred_illustration_size', $_POST['illustration_size']); | |||
} | |||
update_option('chiefred_illustration_class', sanitize_html_class($_POST['illustration_class'])); | |||
update_option('chiefred_illustration_link', absint($_POST['illustration_link'])); | |||
update_option('chiefred_illustration_link_class', sanitize_html_class($_POST['illustration_link_class'])); | |||
update_option('chiefred_illustration_link_rel', sanitize_html_class($_POST['illustration_link_rel'])); | |||
update_option('chiefred_illustration_link_target', sanitize_html_class($_POST['illustration_link_target'])); | |||
exit('<script type="text/javascript">window.location = window.location.href;</script>'); | |||
} | |||
} | |||
} | |||
} | |||
public static function init_hooks() | |||
{ | |||
self::$initiated = true; | |||
add_filter( 'plugin_action_links', [__CLASS__, 'options_link'], 2, 2); | |||
add_action( 'admin_menu', [__CLASS__, 'admin_menu'], 5 ); | |||
add_action( 'admin_enqueue_scripts', [__CLASS__, 'load_resources'] ); | |||
add_action( 'wp_ajax_display_synchronize_log', [__CLASS__, 'display_synchronize_log'] ); | |||
add_action( 'add_meta_boxes', [__CLASS__, 'switch_boxes'] ); | |||
add_post_type_support( 'page', 'excerpt' ); | |||
} | |||
public static function admin_menu() | |||
{ | |||
add_options_page( | |||
'Настройки плагина API ChiefRed.com', | |||
'API ChiefRed.com', | |||
'manage_options', | |||
'chiefred', | |||
array( __CLASS__, 'display_options_page' ) | |||
); | |||
} | |||
public static function options_link($actions, $file) | |||
{ | |||
if (false !== strpos($file, 'chiefred')) { | |||
$add['options'] = '<a href="options-general.php?page=chiefred">Настройки</a>'; | |||
$actions = $add + $actions; | |||
} | |||
return $actions; | |||
} | |||
public static function load_resources() | |||
{ | |||
wp_register_style( 'chiefred_options.css', CHIEFRED_PLUGIN_URL . 'res/chiefred_options.css', array(), CHIEFRED_VERSION ); | |||
wp_enqueue_style( 'chiefred_options.css' ); | |||
wp_register_script( 'chiefred_options.js', CHIEFRED_PLUGIN_URL . 'res/chiefred_options.js', array('jquery'), CHIEFRED_VERSION ); | |||
wp_enqueue_script( 'chiefred_options.js' ); | |||
wp_register_script( 'jquery.mask.min.js', CHIEFRED_PLUGIN_URL . 'res/jquery.mask.min.js', array('jquery'), CHIEFRED_VERSION ); | |||
wp_enqueue_script( 'jquery.mask.min.js' ); | |||
} | |||
public static function display_options_page() | |||
{ | |||
$options['site_id'] = get_option('chiefred_site_id'); | |||
$options['api_ip'] = get_option('chiefred_api_ip'); | |||
$options['api_port'] = get_option('chiefred_api_port'); | |||
$options['api_secret'] = get_option('chiefred_api_secret'); | |||
$options['article_parent_link'] = get_option('chiefred_article_parent_link'); | |||
$options['article_creators'] = get_option('chiefred_article_creators'); | |||
$options['article_childrens'] = get_option('chiefred_article_childrens'); | |||
$options['article_was_useful'] = get_option('chiefred_article_was_useful'); | |||
$options['illustration_size'] = get_option('chiefred_illustration_size'); | |||
$options['illustration_class'] = get_option('chiefred_illustration_class'); | |||
$options['illustration_link'] = get_option('chiefred_illustration_link'); | |||
$options['illustration_link_class'] = get_option('chiefred_illustration_link_class'); | |||
$options['illustration_link_rel'] = get_option('chiefred_illustration_link_rel'); | |||
$options['illustration_link_target'] = get_option('chiefred_illustration_link_target'); | |||
foreach (ChiefRed::get_image_sizes() as $size_name => $size) { | |||
switch ($size_name) { | |||
case 'thumbnail': | |||
$options['image_sizes']['thumbnail'] = ['nname'=>'Малый', 'width'=>$size['width']]; | |||
break; | |||
case 'medium': | |||
$options['image_sizes']['medium'] = ['nname'=>'Средний', 'width'=>$size['width']]; | |||
break; | |||
case 'medium_large': | |||
$options['image_sizes']['medium_large'] = ['nname'=>'Крупный', 'width'=>$size['width']]; | |||
break; | |||
} | |||
} | |||
$options['image_sizes']['full'] = ['nname'=>'Полный', 'width'=>800]; | |||
ChiefRed::view( 'options', $options ); | |||
} | |||
public static function display_synchronize_log() | |||
{ | |||
header('Content-Type: text/plain; charset=utf-8'); | |||
echo htmlspecialchars(file_get_contents( CHIEFRED_PLUGIN_DIR . '/logs/chiefred.log' )); | |||
wp_die(); | |||
} | |||
public static function switch_boxes() | |||
{ | |||
if ( ! post_type_supports( $GLOBALS['post']->post_type, 'excerpt' ) ) | |||
{ | |||
return; | |||
} | |||
remove_meta_box( | |||
'postexcerpt', | |||
'', | |||
'normal' | |||
); | |||
add_meta_box( | |||
'postexcerpt2', | |||
__('Excerpt'), | |||
array(__CLASS__, 'show'), | |||
null, | |||
'normal', | |||
'core' | |||
); | |||
} | |||
public static function show( $post ) | |||
{ | |||
?> | |||
<label class="screen-reader-text" for="excerpt"><?php | |||
_e( 'Excerpt' ) | |||
?></label> | |||
<?php | |||
wp_editor( | |||
self::unescape($post->post_excerpt), | |||
'excerpt', | |||
array( | |||
'editor_height' => 500, | |||
'media_buttons' => FALSE, | |||
'teeny' => TRUE, | |||
'tinymce' => TRUE | |||
) | |||
); | |||
} | |||
public static function unescape( $str ) | |||
{ | |||
return str_replace( | |||
array ( '<', '>', '"', '&', ' ', '&nbsp;' ), | |||
array ( '<', '>', '"', '&', ' ', ' ' ), | |||
$str | |||
); | |||
} | |||
} |
@@ -0,0 +1,820 @@ | |||
<?php | |||
if ( ! defined( 'ABSPATH' ) ) exit; | |||
class ChiefRed { | |||
private static $initiated = false; | |||
public static function init() | |||
{ | |||
if(!session_id()) { | |||
session_start(); | |||
$_SESSION['starttime'] = (!isset($_SESSION['starttime'])) ? time() : $_SESSION['starttime']; | |||
} | |||
if ( ! self::$initiated ) { | |||
self::init_hooks(); | |||
} | |||
} | |||
private static function init_hooks() | |||
{ | |||
self::$initiated = true; | |||
add_action( 'rest_api_init', | |||
function () { | |||
register_rest_route( 'chiefred', '/sync(.*)', | |||
array( | |||
'methods' => 'GET', | |||
'callback' => array( 'ChiefRed', 'sync' ), | |||
) | |||
); | |||
register_rest_route( 'chiefred', '/canonical(.*)', | |||
array( | |||
'methods' => 'GET', | |||
'callback' => array( 'ChiefRed', 'canonical' ), | |||
) | |||
); | |||
register_rest_route( 'chiefred', '/was_useful(.*)', | |||
array( | |||
'methods' => 'POST', | |||
'callback' => array( 'ChiefRed', 'was_useful' ), | |||
) | |||
); | |||
} | |||
); | |||
add_filter( 'cron_schedules', [__CLASS__, 'add_every4hours_schedule'] ); | |||
add_action( 'chiefred_synchronize', [__CLASS__, 'synchronize'] ); | |||
add_action( 'chiefred_every4hours_synchronize', [__CLASS__, 'synchronize'] ); | |||
add_action( 'wp_enqueue_scripts', [__CLASS__, 'load_resources'] ); | |||
add_action( 'wp_head', [__CLASS__, 'add_article_headers'] ); | |||
add_filter( 'the_content', [__CLASS__, 'add_article_components'] ); | |||
} | |||
public static function add_every4hours_schedule( $schedules ) { | |||
$schedules['every4hours'] = array( | |||
'interval' => 14400, | |||
'display' => __('Every 4 hours') | |||
); | |||
return $schedules; | |||
} | |||
public static function load_resources() | |||
{ | |||
$post = get_post(); | |||
if ($post) { | |||
$article_id = get_post_meta($post->ID, '_chiefred_id', true); | |||
if ( $post && 'page' == $post->post_type && $article_id ) { | |||
$css_file = (file_exists(CHIEFRED_PLUGIN_DIR.'res/chiefred.css')) ? CHIEFRED_PLUGIN_URL.'res/chiefred.css' : CHIEFRED_PLUGIN_URL.'res/chiefred.default.css'; | |||
wp_register_style( 'chiefred.css', $css_file, array(), CHIEFRED_VERSION ); | |||
wp_enqueue_style( 'chiefred.css'); | |||
$js_file = (file_exists(CHIEFRED_PLUGIN_DIR.'res/chiefred.js')) ? CHIEFRED_PLUGIN_URL.'res/chiefred.js' : CHIEFRED_PLUGIN_URL.'res/chiefred.default.js'; | |||
wp_register_script( 'chiefred.js', $js_file, array('jquery'), CHIEFRED_VERSION ); | |||
wp_enqueue_script( 'chiefred.js' ); | |||
} | |||
} | |||
} | |||
public static function add_article_headers() | |||
{ | |||
$post = get_post(); | |||
if ($post) { | |||
$keywords = esc_attr(get_post_meta($post->ID, '_chiefred_keyword', true)); | |||
$description = esc_attr(get_post_meta($post->ID, '_chiefred_description', true)); | |||
if ( $post && 'page' == $post->post_type && $keywords ) { | |||
echo "<meta name=\"keywords\" content=\"{$keywords}\" />\n"; | |||
} | |||
if ( $post && 'page' == $post->post_type && $description ) { | |||
echo "<meta name=\"description\" content=\"{$description}\" />\n"; | |||
} | |||
} | |||
} | |||
public static function add_article_components($content) | |||
{ | |||
$illustration_size = get_option('chiefred_illustration_size', 'medium'); | |||
$illustration_class = get_option('chiefred_illustration_class'); | |||
$illustration_link = get_option('chiefred_illustration_link'); | |||
$illustration_link_class = get_option('chiefred_illustration_link_class'); | |||
$illustration_link_rel = get_option('chiefred_illustration_link_rel'); | |||
$illustration_link_target = get_option('chiefred_illustration_link_target'); | |||
$dom = new DOMDocument('1.0', 'UTF-8'); | |||
libxml_use_internal_errors(true); | |||
$post = get_post(); | |||
$article = (object)[]; | |||
$article->id = get_post_meta($post->ID, '_chiefred_id', true); | |||
if ( $post && 'page' == $post->post_type && $article->id ) { | |||
if ( get_option('chiefred_article_parent_link') && $post->post_parent ) { | |||
$article->parent = (object)[]; | |||
$article->parent->href = wp_get_canonical_url($post->post_parent); | |||
$article->parent->title = get_the_title($post->post_parent); | |||
} | |||
if ( get_option('chiefred_article_creators') ) { | |||
$article->creators = []; | |||
$creators = json_decode(get_post_meta($post->ID, '_chiefred_creators', true)); | |||
if(isset($creators->author)) { | |||
$article->creators[(is_array($creators->author)?$creators->author[0]:$creators->author)] = 'автор'; //обратная совместимость со старым форматом с массивом | |||
} | |||
if(isset($creators->editor)) { | |||
$article->creators[(is_array($creators->editor)?$creators->editor[0]:$creators->editor)] = 'редактор'; //обратная совместимость со старым форматом с массивом | |||
} | |||
if(isset($creators->illustrators)) foreach($creators->illustrators as $creator) { | |||
$article->creators[$creator] = (isset($article->creators[$creator]))?($article->creators[$creator].', иллюстрации'):'иллюстрации'; | |||
} | |||
} | |||
$article->content = $content; | |||
$iquery = new WP_Query( "post_type=attachment&post_status=inherit&post_mime_type=image/jpeg&meta_key=_chiefred_article_id&meta_value={$article->id}" ); | |||
foreach ($iquery->posts as $i) { | |||
$attachment_image = wp_get_attachment_image_src($i->ID, $illustration_size); | |||
$src = $attachment_image[0]; | |||
$href = wp_get_attachment_image_src($i->ID, 'full')[0]; | |||
$illustration_id = get_post_meta($i->ID, '_chiefred_id', true); | |||
$illustration_alt = get_post_meta($i->ID, '_chiefred_alt', true); | |||
$illustration_title = get_post_meta($i->ID, '_chiefred_title', true); | |||
$attrs = ['class'=>$illustration_class, 'src'=>$src, 'alt'=>$illustration_alt, 'title'=>$illustration_title, 'width'=>$attachment_image[1], 'height'=>$attachment_image[2]]; | |||
$link_attrs = ($illustration_link) ? ['class'=>$illustration_link_class, 'href'=>$href, 'rel'=>$illustration_link_rel, 'target'=>$illustration_link_target] : null; | |||
if (false !== $dom->loadHTML('<?xml encoding="UTF-8"><div id="chiefred-wrapper">'.$article->content.'</div>')) { | |||
$dom = self::update_img($dom, 'chiefred_img_'.$illustration_id, $attrs, $link_attrs); | |||
$article->content = self::DOMinnerHTML($dom->getElementById('chiefred-wrapper')); | |||
} | |||
} | |||
if ( get_option('chiefred_article_childrens') ) { | |||
$article->childrens = []; | |||
$cquery = new WP_Query( "post_type=page&post_status=publish&post_parent={$post->ID}&orderby=meta_value_num&order=ASC&meta_key=_chiefred_order&posts_per_page=-1" ); | |||
foreach ($cquery->posts as $c) { | |||
$child = (object)[]; | |||
$child->article_id = get_post_meta($c->ID, '_chiefred_id', true); | |||
$child->href = wp_get_canonical_url($c); | |||
$child->title = $c->post_title; | |||
$child->excerpt = $c->post_excerpt; | |||
$iquery = new WP_Query( "post_type=attachment&post_status=inherit&post_mime_type=image/jpeg&meta_key=_chiefred_article_id&meta_value={$child->article_id}" ); | |||
foreach ($iquery->posts as $i) { | |||
$attachment_image = wp_get_attachment_image_src($i->ID, $illustration_size); | |||
$src = $attachment_image[0]; | |||
$href = wp_get_attachment_image_src($i->ID, 'full')[0]; | |||
$illustration_id = get_post_meta($i->ID, '_chiefred_id', true); | |||
$illustration_alt = get_post_meta($i->ID, '_chiefred_alt', true); | |||
$illustration_title = get_post_meta($i->ID, '_chiefred_title', true); | |||
$attrs = ['class'=>$illustration_class, 'src'=>$src, 'alt'=>$illustration_alt, 'title'=>$illustration_title, 'width'=>$attachment_image[1], 'height'=>$attachment_image[2]]; | |||
$link_attrs = ($illustration_link) ? ['class'=>$illustration_link_class, 'href'=>$href, 'rel'=>$illustration_link_rel, 'target'=>$illustration_link_target] : null; | |||
if (false !== $dom->loadHTML('<?xml encoding="UTF-8"><div id="chiefred-wrapper">'.$child->excerpt.'</div>')) { | |||
$dom = self::update_img($dom, 'chiefred_img_'.$illustration_id, $attrs, $link_attrs); | |||
$child->excerpt = self::DOMinnerHTML($dom->getElementById('chiefred-wrapper')); | |||
} | |||
} | |||
$article->childrens[] = $child; | |||
} | |||
} | |||
if ( get_option('chiefred_article_was_useful') ) { | |||
$article->was_useful = true; | |||
} | |||
return ChiefRed::view( 'article', compact('article'), true ); | |||
} else { | |||
return $content; | |||
} | |||
} | |||
public static function was_useful(WP_REST_Request $request) | |||
{ | |||
$ret = ["code"=>200, "message"=>"ok"]; | |||
$post = $request->get_body_params(); | |||
if ( | |||
! isset( $post['chiefred_token'] ) | |||
|| ! wp_verify_nonce( $post['chiefred_token'], 'wp_rest' ) | |||
) { | |||
exit('CSRF'); | |||
} else { | |||
$api_port = get_option('chiefred_api_port'); | |||
$sync_base = (CHIEFRED_LOCAL_DEBUG) ? CHIEFRED_LOCAL_BASE.":{$api_port}/sync/v1" : "https://chiefred.com:{$api_port}/sync/v1"; | |||
$site_id = get_option('chiefred_site_id'); | |||
$sync_secret = get_option('chiefred_api_secret'); | |||
if (!$api_port || !$site_id || !$sync_secret) { | |||
return $ret; | |||
} | |||
$scrollpath = intval($post['scrollpath']); | |||
$objection = (object)[ | |||
'article_id' => intval($post['article_id']), | |||
'is_error' => ('error' == $post['type']) ? 1 : 0, | |||
'message' => sanitize_text_field($post['message']), | |||
]; | |||
if($scrollpath == 0) return $ret; | |||
if(time() - $_SESSION['starttime'] < 30) return $ret; | |||
if(mb_strlen($objection->message) < 10) return $ret; | |||
if(mb_strpos($objection->message, 'http://') !== false) return $ret; | |||
if(mb_strpos($objection->message, 'https://') !== false) return $ret; | |||
if(mb_strpos($objection->message, 'www.') !== false) return $ret; | |||
$data = json_encode($objection); | |||
$challenge = md5(uniqid()); | |||
$sign = md5($challenge . $data . $sync_secret); | |||
$ch = curl_init(); | |||
curl_setopt($ch, CURLOPT_URL, "{$sync_base}/objection/{$challenge}/{$site_id}/{$sign}"); | |||
curl_setopt($ch, CURLOPT_POST, 1); | |||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data); | |||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |||
if (CHIEFRED_LOCAL_DEBUG) { | |||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); | |||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); | |||
} | |||
$raw_resp = curl_exec($ch); | |||
curl_close ($ch); | |||
return $ret; | |||
} | |||
} | |||
public static function sync(WP_REST_Request $request) | |||
{ | |||
$get = $request->get_query_params(); | |||
$challenge = preg_replace('[^a-zA-Z0-9]', '', (isset($get['challenge']))?$get['challenge']: ''); | |||
if ($challenge) { | |||
if ($_SERVER['REMOTE_ADDR'] == get_option('chiefred_api_ip')) { | |||
wp_schedule_single_event( time(), 'chiefred_synchronize' ); | |||
return ["code"=>200, "message"=>"ok", "data"=>null, "sign"=>md5($challenge . get_option('chiefred_api_secret'))]; | |||
} else { | |||
return ["code"=>401, "message"=>"Wrong Request IP", "data"=>null, "sign"=>null]; | |||
} | |||
} else { | |||
return ["code"=>400, "message"=>"Wrong Request Format", "data"=>null, "sign"=>null]; | |||
} | |||
} | |||
public static function canonical(WP_REST_Request $request) | |||
{ | |||
$get = $request->get_query_params(); | |||
$challenge = preg_replace('[^a-zA-Z0-9]', '', (isset($get['challenge']))?$get['challenge']: ''); | |||
$article_id = intval((isset($_GET['article_id']))?$_GET['article_id']:0); | |||
if ($challenge && $article_id) { | |||
if ($_SERVER['REMOTE_ADDR'] == get_option('chiefred_api_ip')) { | |||
$query = new WP_Query( "post_type=page&post_status=publish&meta_key=_chiefred_id&meta_value={$article_id}&posts_per_page=1" ); | |||
if ($query->have_posts()) { | |||
$query->the_post(); | |||
$canonical = wp_get_canonical_url(); | |||
wp_reset_postdata(); | |||
$data = json_encode($canonical); | |||
return ["code"=>200, "message"=>"ok", "data"=>$data, "sign"=>md5($challenge . $data . get_option('chiefred_api_secret'))]; | |||
} else { | |||
return ["code"=>404, "message"=>"Article Not Found", "data"=>null, "sign"=>null]; | |||
} | |||
} else { | |||
return ["code"=>401, "message"=>"Wrong Request IP", "data"=>null, "sign"=>null]; | |||
} | |||
} else { | |||
return ["code"=>400, "message"=>"Wrong Request Format", "data"=>null, "sign"=>null]; | |||
} | |||
} | |||
public static function synchronize() | |||
{ | |||
$sync_lock = intval(get_option('chiefred_sync_lock', 0)); | |||
if ($sync_lock+600 > time()) { | |||
chiefred_log_i('Сеанс синхронизации перенесен на 5 минут в связи с блокировкой, установленной другим сенасом'); | |||
wp_schedule_single_event( time()+300, 'chiefred_synchronize' ); | |||
return; | |||
} | |||
update_option('chiefred_sync_lock', time()); | |||
file_put_contents( CHIEFRED_PLUGIN_DIR . '/logs/chiefred.log', '' ); | |||
$api_port = get_option('chiefred_api_port'); | |||
$sync_base = (CHIEFRED_LOCAL_DEBUG) ? CHIEFRED_LOCAL_BASE.":{$api_port}/sync/v1" : "https://chiefred.com:{$api_port}/sync/v1"; | |||
$site_id = get_option('chiefred_site_id'); | |||
$sync_secret = get_option('chiefred_api_secret'); | |||
$illustration_size = get_option('chiefred_illustration_size', 'medium'); | |||
$illustration_class = get_option('chiefred_illustration_class'); | |||
if (!$api_port || !$site_id || !$sync_secret) { | |||
chiefred_log_e('СИНХРОНИЗАЦИЯ НЕВОЗМОЖНА: Необходимо произвести настройку плагина для взаимодействия с Редакцией'); | |||
return; | |||
} | |||
$dom = new DOMDocument('1.0', 'UTF-8'); | |||
libxml_use_internal_errors(true); | |||
chiefred_log_i('Начало процесса синхронизации'); | |||
$max_query = new WP_Query( array( 'post_type' => 'page', 'post_status' => 'publish', 'orderby'=>'meta_value_num', 'order'=>'DESC','meta_key'=>'_chiefred_id','posts_per_page'=>1) ); | |||
if ($max_query->have_posts()) { | |||
$max_query->the_post(); | |||
$post_id = get_the_ID(); | |||
$max_id = get_post_meta( $post_id, '_chiefred_id', true ); | |||
wp_reset_postdata(); | |||
} else { | |||
$max_id = 0; | |||
} | |||
$max_query = new WP_Query( array( 'post_type' => 'page', 'post_status' => 'publish', 'orderby'=>'meta_value_num', 'order'=>'DESC','meta_key'=>'_chiefred_sync_at','posts_per_page'=>1) ); | |||
if ($max_query->have_posts()) { | |||
$max_query->the_post(); | |||
$post_id = get_the_ID(); | |||
$sync_at = get_post_meta( $post_id, '_chiefred_sync_at', true ); | |||
wp_reset_postdata(); | |||
} else { | |||
$sync_at = 0; | |||
} | |||
chiefred_log_i("Запрашиваем обновления статей с параметрами: \$max_id={$max_id}, \$sync_at={$sync_at}"); | |||
$challenge = md5(uniqid()); | |||
$raw_resp = self::file_get_contents_curl("{$sync_base}/articles/{$challenge}/{$site_id}/{$max_id}/{$sync_at}"); | |||
//chiefred_log_d("raw_resp", $raw_resp); | |||
$resp = json_decode($raw_resp); | |||
if($resp && $resp->code==200){ | |||
chiefred_log_i("Получен ответ Редакции с кодом 200 (ок)"); | |||
$data = json_encode($resp->data); | |||
if (md5($challenge . $data . $sync_secret) == $resp->sign) { | |||
chiefred_log_i("Подпись данных верна"); | |||
$articles_ids = $resp->data; | |||
$articles_update_count = 0; | |||
foreach ($articles_ids as $article_id) { | |||
$articles_update_count++; | |||
if ($articles_update_count > 2) { | |||
chiefred_log_i("Есть еще статьи, требующие обновления, но в текущем сеансе достигнута квота по статьям."); | |||
if (false !== wp_schedule_single_event( time()+300, 'chiefred_synchronize' )) { | |||
chiefred_log_i("Поэтому, ставим еще одно задание по синхронизации через 5 минут"); | |||
} | |||
break; | |||
} | |||
chiefred_log_i("Нужно обновить статью с id={$article_id}"); | |||
$challenge = md5(uniqid()); | |||
$raw_resp = self::file_get_contents_curl("{$sync_base}/article/{$challenge}/{$site_id}/{$article_id}"); | |||
$resp = json_decode($raw_resp); | |||
//chiefred_log_d("resp", $resp); | |||
if($resp && $resp->code==200){ | |||
chiefred_log_i("Получен ответ Редакции с кодом 200 (ок)"); | |||
$data = json_encode($resp->data); | |||
if (md5($challenge . $data . $sync_secret) == $resp->sign) { | |||
chiefred_log_i("Подпись данных верна"); | |||
$article = $resp->data; | |||
$article->creators = json_encode($article->creators); | |||
$query = new WP_Query( "post_type=page&post_status=publish&meta_key=_chiefred_id&meta_value={$article->id}" ); | |||
if ($query->have_posts()) { | |||
chiefred_log_i("На сайте обнаружена статья с id={$article_id} - обновим ее"); | |||
$query->the_post(); | |||
$the_post = array(); | |||
$the_post['ID'] = get_the_ID(); | |||
$the_post['post_title'] = $article->title; | |||
$the_post['post_excerpt'] = str_replace('<img data-id', '<img id', $article->short); | |||
$the_post['post_content'] = str_replace('<img data-id', '<img id', $article->full); | |||
remove_action( 'post_updated', 'wp_save_post_revision' ); | |||
if (wp_update_post( $the_post )) { | |||
chiefred_log_i("Статья успешно обновлена"); | |||
} | |||
add_action( 'post_updated', 'wp_save_post_revision' ); | |||
chiefred_log_d("the_post", $the_post); | |||
update_post_meta($the_post['ID'], '_chiefred_parent_id', $article->parent_id); | |||
update_post_meta($the_post['ID'], '_chiefred_order', $article->order); | |||
update_post_meta($the_post['ID'], '_chiefred_keyword', $article->keyword); | |||
update_post_meta($the_post['ID'], '_chiefred_description', $article->description); | |||
update_post_meta($the_post['ID'], '_chiefred_creators', $article->creators); | |||
update_post_meta($the_post['ID'], '_chiefred_sync_at', $article->sync_at); | |||
chiefred_log_d("the_post_metas", get_post_meta($the_post['ID'])); | |||
wp_reset_postdata(); | |||
} else { | |||
chiefred_log_i("На сайте нет статьи с id={$article_id} - добавляем"); | |||
$the_post = array(); | |||
if ($article->parent_id>0) { | |||
chiefred_log_i("Полученная статья является дочерней \$parent_id={$article->parent_id} - ищем родительскую на сайте"); | |||
$query = new WP_Query( "post_type=page&post_status=publish&meta_key=_chiefred_id&meta_value={$article->parent_id}" ); | |||
if ($query->have_posts()) { | |||
$query->the_post(); | |||
$the_post['post_parent'] = get_the_ID(); | |||
$the_post['menu_order'] = $article->order; | |||
wp_reset_postdata(); | |||
chiefred_log_i("Родительская статья обнаружена - устанавливаем связь"); | |||
} | |||
} | |||
$the_post['post_author'] = 1; | |||
$the_post['post_type'] = 'page'; | |||
$the_post['post_status'] = 'publish'; | |||
$the_post['post_title'] = $article->title; | |||
$the_post['post_excerpt'] = str_replace('<img data-id="', '<img id="chiefred_img_', $article->short); | |||
$the_post['post_content'] = str_replace('<img data-id="', '<img id="chiefred_img_', $article->full); | |||
$the_post['post_name'] = $article->keyword; | |||
chiefred_log_d("the_post", $the_post); | |||
$post_id = wp_insert_post($the_post, false); | |||
if ($post_id) { | |||
chiefred_log_i("Статья успешно добавлена"); | |||
} | |||
add_post_meta($post_id, '_chiefred_id', $article->id, true); | |||
add_post_meta($post_id, '_chiefred_parent_id', $article->parent_id, true); | |||
add_post_meta($post_id, '_chiefred_order', $article->order, true); | |||
add_post_meta($post_id, '_chiefred_keyword', $article->keyword, true); | |||
add_post_meta($post_id, '_chiefred_description', $article->description, true); | |||
add_post_meta($post_id, '_chiefred_creators', wp_slash($article->creators), true); | |||
add_post_meta($post_id, '_chiefred_sync_at', $article->sync_at, true); | |||
chiefred_log_d("the_post_metas", get_post_meta($post_id)); | |||
wp_reset_postdata(); | |||
} | |||
} else { | |||
chiefred_log_w("Проверка подписи провалена"); | |||
} | |||
} else { | |||
if (!$resp) { | |||
chiefred_log_w("Сервер {$sync_base} не ответил на запрос"); | |||
} else { | |||
chiefred_log_w("Сервер вернул ошибку - code:{$resp->code}, message:{$resp->message}"); | |||
} | |||
} | |||
} | |||
} else { | |||
chiefred_log_w("Проверка подписи провалена"); | |||
} | |||
} else { | |||
if (!$resp) { | |||
chiefred_log_w("Сервер {$sync_base} не ответил на запрос"); | |||
} else { | |||
chiefred_log_w("Сервер вернул ошибку - code:{$resp->code}, message:{$resp->message}"); | |||
} | |||
} | |||
///// Иллюстрации ///// | |||
$max_query = new WP_Query( array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => 'image/jpeg', 'orderby'=>'meta_value_num', 'order'=>'DESC','meta_key'=>'_chiefred_id','posts_per_page'=>1) ); | |||
if ($max_query->have_posts()) { | |||
$max_query->the_post(); | |||
$post_id = get_the_ID(); | |||
$max_id = get_post_meta( $post_id, '_chiefred_id', true ); | |||
wp_reset_postdata(); | |||
} else { | |||
$max_id = 0; | |||
} | |||
$max_query = new WP_Query( array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => 'image/jpeg', 'orderby'=>'meta_value_num', 'order'=>'DESC','meta_key'=>'_chiefred_sync_at','posts_per_page'=>1) ); | |||
if ($max_query->have_posts()) { | |||
$max_query->the_post(); | |||
$post_id = get_the_ID(); | |||
$sync_at = get_post_meta( $post_id, '_chiefred_sync_at', true ); | |||
wp_reset_postdata(); | |||
} else { | |||
$sync_at = 0; | |||
} | |||
chiefred_log_i("Запрашиваем обновления иллюстраций с параметрами: \$max_id={$max_id}, \$sync_at={$sync_at}"); | |||
$challenge = md5(uniqid()); | |||
$raw_resp = self::file_get_contents_curl("{$sync_base}/illustrations/{$challenge}/{$site_id}/{$max_id}/{$sync_at}"); | |||
$resp = json_decode($raw_resp); | |||
//chiefred_log_d("resp", $resp); | |||
if($resp && $resp->code==200){ | |||
chiefred_log_i("Получен ответ Редакции с кодом 200 (ок)"); | |||
$data = json_encode($resp->data); | |||
if (md5($challenge . $data . $sync_secret) == $resp->sign) { | |||
chiefred_log_i("Подпись данных верна"); | |||
$illustrations_ids = $resp->data; | |||
$illustrations_update_count = 0; | |||
foreach ($illustrations_ids as $illustration_id) { | |||
$illustrations_update_count++; | |||
if ($illustrations_update_count > 16) { | |||
chiefred_log_i("Есть еще иллюстрации, требующие обновления, но в текущем сеансе достигнута квота по иллюстрациям."); | |||
if (false !== wp_schedule_single_event( time()+300, 'chiefred_synchronize' )) { | |||
chiefred_log_i("Поэтому, ставим еще одно задание по синхронизации через 5 минут"); | |||
} | |||
break; | |||
} | |||
chiefred_log_i("Нужно обновить иллюстрацию с id={$illustration_id}"); | |||
$challenge = md5(uniqid()); | |||
$raw_resp = self::file_get_contents_curl("{$sync_base}/illustration/{$challenge}/{$site_id}/{$illustration_id}"); | |||
$resp = json_decode($raw_resp); | |||
//chiefred_log_d("resp", $resp); | |||
if($resp && $resp->code==200){ | |||
chiefred_log_i("Получен ответ Редакции с кодом 200 (ок)"); | |||
$data = json_encode($resp->data); | |||
if (md5($challenge . $data . $sync_secret) == $resp->sign) { | |||
chiefred_log_i("Подпись данных верна"); | |||
$illustration = $resp->data; | |||
$query = new WP_Query( "post_type=attachment&post_status=inherit&post_mime_type=image/jpeg&meta_key=_chiefred_id&meta_value={$illustration->id}" ); | |||
if ($query->have_posts()) { | |||
chiefred_log_i("На сайте обнаружена иллюстрация с id={$article_id} - заменяем ее"); | |||
$query->the_post(); | |||
$attachment_id = get_the_ID(); | |||
wp_reset_postdata(); | |||
wp_delete_attachment( $attachment_id, true ); | |||
} | |||
$query = new WP_Query( "post_type=page&post_status=publish&meta_key=_chiefred_id&meta_value={$illustration->article_id}" ); | |||
if ($query->have_posts()) { | |||
$query->the_post(); | |||
$the_post = get_post(get_the_ID(), OBJECT); | |||
wp_reset_postdata(); | |||
chiefred_log_i("На сайте найдена статья, к которой относится иллюстрация"); | |||
$upload_dir = wp_upload_dir(); | |||
$upload_path = str_replace( '/', DIRECTORY_SEPARATOR, $upload_dir['path'] ) . DIRECTORY_SEPARATOR; | |||
$img = $illustration->image; | |||
$img = str_replace('data:image/jpeg;base64,', '', $img); | |||
$img = str_replace(' ', '+', $img); | |||
$img_decoded = base64_decode($img); | |||
$filename = $illustration->id . '.jpeg'; | |||
$hashed_filename = md5( $filename . microtime() ) . '_' . $filename; | |||
$image_upload = file_put_contents( $upload_path . $hashed_filename, $img_decoded ); | |||
if( !function_exists( 'wp_handle_sideload' ) ) { | |||
require_once( ABSPATH . 'wp-admin/includes/file.php' ); | |||
} | |||
if( !function_exists( 'wp_get_current_user' ) ) { | |||
require_once( ABSPATH . 'wp-includes/pluggable.php' ); | |||
} | |||
$file = array(); | |||
$file['error'] = ''; | |||
$file['tmp_name'] = $upload_path . $hashed_filename; | |||
$file['name'] = $hashed_filename; | |||
$file['type'] = 'image/jpeg'; | |||
$file['size'] = filesize( $upload_path . $hashed_filename ); | |||
$file_return = wp_handle_sideload( $file, array( 'test_form' => false ) ); | |||
$filename = $file_return['file']; | |||
$attachment = array( | |||
'post_author' => 1, | |||
'post_mime_type' => $file_return['type'], | |||
'post_title' => $illustration->name, | |||
'post_content' => $illustration->title, | |||
'post_status' => 'inherit', | |||
'guid' => $upload_dir['url'] . '/' . basename($filename) | |||
); | |||
chiefred_log_i("Иллюстрация сохранена в файл: {$attachment['guid']}"); | |||
$attach_id = wp_insert_attachment( $attachment, $filename, $the_post->ID ); | |||
require_once(ABSPATH . 'wp-admin/includes/image.php'); | |||
$attach_data = wp_generate_attachment_metadata( $attach_id, $filename ); | |||
wp_update_attachment_metadata( $attach_id, $attach_data ); | |||
add_post_meta($attach_id, '_chiefred_id', $illustration->id, true); | |||
add_post_meta($attach_id, '_chiefred_article_id', $illustration->article_id, true); | |||
add_post_meta($attach_id, '_chiefred_sync_at', $illustration->sync_at, true); | |||
add_post_meta($attach_id, '_chiefred_alt', $illustration->name, true); | |||
add_post_meta($attach_id, '_chiefred_title', $illustration->title, true); | |||
chiefred_log_d("\$attach_id={$attach_id}"); | |||
$t = $illustration; | |||
$t->image = '<truncated>'; | |||
chiefred_log_d("\$illustration", $illustration); | |||
$image = imagecreatefromstring($img_decoded); | |||
@$iSize = getimagesizefromstring($img_decoded); | |||
if ($image && $iSize) { | |||
foreach ($attach_data['sizes'] as $size_name => $size) { | |||
if (CHIEFRED_SMALL_IMG_WIDTH_LIMIT > $size['width']) { | |||
$k = max($size['width'] / 120, $size['height'] / 90); | |||
$newwidth = $iSize[0] * $illustration->preview_s_z * $k; | |||
$newheight = $iSize[1] * $illustration->preview_s_z * $k; | |||
$resized = imagecreatetruecolor($newwidth, $newheight); | |||
$dest = imagecreatetruecolor($size['width'], $size['height']); | |||
imagecopyresampled($resized, $image, 0, 0, 0, 0, $newwidth, $newheight, $iSize[0], $iSize[1]); | |||
imagecopy($dest, $resized, 0, 0, -1*$illustration->preview_s_x*$k, -1*$illustration->preview_s_y*$k, $size['width'], $size['height']); | |||
imagedestroy($resized); | |||
ob_start(); | |||
imagejpeg($dest, "{$upload_dir['path']}/{$size['file']}"); | |||
ob_end_clean(); | |||
imagedestroy($dest); | |||
} elseif(CHIEFRED_MEDIUM_IMG_WIDTH_LIMIT > $size['width']) { | |||
$k = max($size['width'] / 240, $size['height'] / 180); | |||
$newwidth = $iSize[0] * $illustration->preview_m_z * $k; | |||
$newheight = $iSize[1] * $illustration->preview_m_z * $k; | |||
$resized = imagecreatetruecolor($newwidth, $newheight); | |||
$dest = imagecreatetruecolor($size['width'], $size['height']); | |||
imagecopyresampled($resized, $image, 0, 0, 0, 0, $newwidth, $newheight, $iSize[0], $iSize[1]); | |||
imagecopy($dest, $resized, 0, 0, -1*$illustration->preview_m_x*$k, -1*$illustration->preview_m_y*$k, $size['width'], $size['height']); | |||
imagedestroy($resized); | |||
ob_start(); | |||
imagejpeg($dest, "{$upload_dir['path']}/{$size['file']}"); | |||
ob_end_clean(); | |||
imagedestroy($dest); | |||
} | |||
} | |||
imagedestroy($image); | |||
$iSize = null; | |||
} | |||
$src = wp_get_attachment_image_src($attach_id, $illustration_size)[0]; | |||
chiefred_log_d("img \$illustration_class:{$illustration_class} \$illustration_size:{$illustration_size} \$src:{$src}"); | |||
$attrs = ['class'=>$illustration_class, 'src'=>$src]; | |||
if (false !== $dom->loadHTML('<?xml encoding="UTF-8"><div id="chiefred-wrapper">'.$the_post->post_excerpt.'</div>')) { | |||
$dom = self::update_img($dom, 'chiefred_img_'.$illustration->id, $attrs); | |||
$the_post->post_excerpt = self::DOMinnerHTML($dom->getElementById('chiefred-wrapper')); | |||
} | |||
if (false !== $dom->loadHTML('<?xml encoding="UTF-8"><div id="chiefred-wrapper">'.$the_post->post_content.'</div>')) { | |||
$dom = self::update_img($dom, 'chiefred_img_'.$illustration->id, $attrs); | |||
$the_post->post_content = self::DOMinnerHTML($dom->getElementById('chiefred-wrapper')); | |||
} | |||
remove_action( 'post_updated', 'wp_save_post_revision' ); | |||
if (wp_update_post( $the_post )) { | |||
chiefred_log_i("Страница иллюстрации успешно обновлена"); | |||
} else { | |||
chiefred_log_w("Страницу иллюстрации обновить НЕ УДАЛОСЬ"); | |||
} | |||
add_action( 'post_updated', 'wp_save_post_revision' ); | |||
} else { | |||
chiefred_log_i("Иллюстрации без привязки к статье нам не нужны - загрузим потом"); | |||
continue; | |||
} | |||
} else { | |||
chiefred_log_w("Проверка подписи провалена"); | |||
} | |||
} else { | |||
if (!$resp) { | |||
chiefred_log_w("Сервер {$sync_base} не ответил на запрос"); | |||
} else { | |||
chiefred_log_w("Сервер вернул ошибку - code:{$resp->code}, message:{$resp->message}"); | |||
} | |||
} | |||
} | |||
} else { | |||
chiefred_log_w("Проверка подписи провалена"); | |||
} | |||
} else { | |||
if (!$resp) { | |||
chiefred_log_w("Сервер {$sync_base} не ответил на запрос"); | |||
} else { | |||
chiefred_log_w("Сервер вернул ошибку - code:{$resp->code}, message:{$resp->message}"); | |||
} | |||
} | |||
chiefred_log_i('Процесс синхронизации завершен'); | |||
update_option('chiefred_sync_lock', 0); | |||
} | |||
// [ UTILS ] ///////////////////////////////////////////////////////////////////////////////////////////////////// | |||
public static function update_img(DOMDocument $dom, $id=null, $attrs=[], $link_attrs=null) | |||
{ | |||
foreach ($dom->getElementsByTagName('img') as $item) { | |||
if ($item->getAttribute('id') == $id) { | |||
foreach ($attrs as $attr => $val) { | |||
if ($val) { | |||
$item->setAttribute($attr, $val); | |||
} else { | |||
$item->removeAttribute($attr); | |||
} | |||
} | |||
if (null !== $link_attrs && 'a' != $item->parentNode->tagName) { | |||
$link = $dom->createElement('a'); | |||
foreach ($link_attrs as $attr => $val) { | |||
if ($val) { | |||
$link->setAttribute($attr, $val); | |||
} else { | |||
$link->removeAttribute($attr); | |||
} | |||
} | |||
$item->parentNode->replaceChild($link, $item); | |||
$link->appendChild($item); | |||
} | |||
} | |||
} | |||
return $dom; | |||
} | |||
public static function get_image_sizes( $size = '' ) | |||
{ | |||
global $_wp_additional_image_sizes; | |||
$sizes = array(); | |||
$get_intermediate_image_sizes = get_intermediate_image_sizes(); | |||
foreach( $get_intermediate_image_sizes as $_size ) { | |||
if ( in_array( $_size, array( 'thumbnail', 'medium', 'medium_large', 'large' ) ) ) { | |||
$sizes[ $_size ]['width'] = get_option( $_size . '_size_w' ); | |||
$sizes[ $_size ]['height'] = get_option( $_size . '_size_h' ); | |||
$sizes[ $_size ]['crop'] = (bool) get_option( $_size . '_crop' ); | |||
} elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) { | |||
$sizes[ $_size ] = array( | |||
'width' => $_wp_additional_image_sizes[ $_size ]['width'], | |||
'height' => $_wp_additional_image_sizes[ $_size ]['height'], | |||
'crop' => $_wp_additional_image_sizes[ $_size ]['crop'] | |||
); | |||
} | |||
} | |||
if ( $size ) { | |||
if( isset( $sizes[ $size ] ) ) { | |||
return $sizes[ $size ]; | |||
} else { | |||
return false; | |||
} | |||
} | |||
return $sizes; | |||
} | |||
public static function DOMinnerHTML(DOMNode $element) | |||
{ | |||
$innerHTML = ""; | |||
$children = $element->childNodes; | |||
foreach ($children as $child) | |||
{ | |||
$innerHTML .= $element->ownerDocument->saveHTML($child); | |||
} | |||
return $innerHTML; | |||
} | |||
public static function view( $name, array $args = array(), $as_string=false ) | |||
{ | |||
foreach ( $args AS $key => $val ) { | |||
$$key = $val; | |||
} | |||
if (file_exists(CHIEFRED_PLUGIN_DIR."views/{$name}.php")) { | |||
$file = CHIEFRED_PLUGIN_DIR."views/{$name}.php"; | |||
} elseif(file_exists(CHIEFRED_PLUGIN_DIR."views/{$name}.default.php")) { | |||
$file = CHIEFRED_PLUGIN_DIR."views/{$name}.default.php"; | |||
} else { | |||
return 'ChiefRedERROR: View ($name) not found'; | |||
} | |||
if($as_string) { | |||
ob_start(); | |||
} | |||
include( $file ); | |||
if($as_string) { | |||
return ob_get_clean(); | |||
} | |||
} | |||
public static function file_get_contents_curl($url) | |||
{ | |||
$ch = curl_init(); | |||
curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE); | |||
curl_setopt($ch, CURLOPT_HEADER, 0); | |||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |||
curl_setopt($ch, CURLOPT_URL, $url); | |||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); | |||
if (CHIEFRED_LOCAL_DEBUG) { | |||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); | |||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); | |||
} | |||
$data = curl_exec($ch); | |||
curl_close($ch); | |||
return $data; | |||
} | |||
} |
@@ -0,0 +1,137 @@ | |||
/** | |||
* Файл chiefred.default.css - стандартный набор стилей для отображения статьи, | |||
* загруженной по API ChiefRed.com | |||
* | |||
* НЕ РЕДАКТИРУЙТЕ ЭТОТ ФАЙЛ!!! | |||
* | |||
* При последующих обновлениях плагина он будет замещаться и все Ваши изменения пропадут. | |||
* Создайте новый файл с именем chiefred.css в той же папке, скопируйте в него содержимое | |||
* этого файла и там уже вносите свои правки. | |||
* | |||
*/ | |||
.chiefred-article-parent span::before { | |||
content: "\2190 "; | |||
color: #007acc; | |||
display: inline-block; | |||
width: 10px; | |||
height: 10px; | |||
margin-right: 10px; | |||
} | |||
.chiefred-article-creators { | |||
font-size: 13px; | |||
color: #3fa55e; | |||
margin: 20px 0; | |||
cursor: default; | |||
} | |||
.chiefred-article-creators span { | |||
font-style: italic; | |||
margin: 0 2px; | |||
} | |||
.chiefred-article-creators span::after { | |||
content: ", "; | |||
} | |||
.chiefred-article-creators span:last-child::after { | |||
content: ""; | |||
} | |||
.chiefred-article-content p, | |||
.chiefred-article-child p | |||
{ | |||
text-align: justify; | |||
text-indent: 2em; | |||
font-size: 1em; | |||
line-height: 1.7em; | |||
padding-bottom: 11px; | |||
margin: 0; | |||
} | |||
.chiefred-article-content .photo, | |||
.chiefred-article-child .photo | |||
{ | |||
margin: 5px 25px 5px 0; | |||
float: left; | |||
cursor: zoom-in; | |||
} | |||
.chiefred-article-child-readmore { | |||
overflow: hidden; | |||
margin: 0 0 40px; | |||
} | |||
.chiefred-article-child-readmore a:hover { | |||
background: #107eb5; | |||
} | |||
.chiefred-article-child-readmore a { | |||
float: right; | |||
display: block; | |||
background: #1494d5; | |||
color: #fff; | |||
text-decoration: none; | |||
text-transform: uppercase; | |||
font-weight: bold; | |||
padding: 7px 28px; | |||
border-radius: 4px; | |||
} | |||
#chiefred-was-usefull { | |||
border-top: 1px solid #ccc; | |||
overflow: hidden; | |||
padding: 30px 0; | |||
} | |||
#chiefred-wu-is { | |||
width: 473px; | |||
overflow: hidden; | |||
margin: 0 auto; | |||
} | |||
#chiefred-wu-caption { | |||
font-size: 16px; | |||
font-weight: bold; | |||
float: left; | |||
} | |||
#chiefred-wu-buttons { | |||
float: left; | |||
margin-top: 24px; | |||
} | |||
.chiefred-btn { | |||
border: 1px solid #ccc !important; | |||
border-radius: 3px !important; | |||
min-width: 100px !important; | |||
padding: 7px !important; | |||
outline: none !important; | |||
background: #fff !important; | |||
color: #3E4156 !important; | |||
font-size: 14px !important; | |||
cursor: pointer !important; | |||
margin-right: 30px !important; | |||
} | |||
.chiefred-btn:hover { | |||
background: #ccc !important; | |||
} | |||
#chiefred-pwu-yes, #chiefred-pwu-no, #chiefred-pwu-error { | |||
width: 473px; | |||
margin: 30px auto; | |||
} | |||
#chiefred-was-usefull textarea { | |||
width: 100%; | |||
height: 100px; | |||
padding: 10px 20px; | |||
max-width: 100%; | |||
outline-color: #ffd27d; | |||
} | |||
.chiefred-wu-limit { | |||
font-size: 12px; | |||
} | |||
.chiefred-wu-limit .chiefred-btn { | |||
float: right !important; | |||
margin: 5px 0 !important; | |||
background: #428bca !important; | |||
color: #fff !important; | |||
border-color: #357ebd !important; | |||
} |
@@ -0,0 +1,113 @@ | |||
/** | |||
* Файл chiefred.default.js - стандартный Java-скрипт для отображения статьи, | |||
* загруженной по API ChiefRed.com | |||
* | |||
* НЕ РЕДАКТИРУЙТЕ ЭТОТ ФАЙЛ!!! | |||
* | |||
* При последующих обновлениях плагина он будет замещаться и все Ваши изменения пропадут. | |||
* Создайте новый файл с именем chiefred.js в той же папке, скопируйте в него содержимое | |||
* этого файла и там уже вносите свои правки. | |||
* | |||
*/ | |||
var chiefred_scrollpath = 0; | |||
jQuery( document ).scroll(function() | |||
{ | |||
chiefred_scrollpath++; | |||
}); | |||
jQuery( document ).ready(function() | |||
{ | |||
var chiefred_wu_submit = function(e) | |||
{ | |||
var wu_type = (e.target.id == 'chiefred-swu-no') ? 'useless' : 'error'; | |||
var message = (wu_type == 'useless') ? jQuery('#chiefred-twu-no').val() : jQuery('#chiefred-twu-error').val(); | |||
jQuery.ajax({ | |||
type: "POST", | |||
url: jQuery('#chiefred-was-usefull').data('href'), | |||
data: { | |||
article_id: jQuery('#chiefred-was-usefull').data('article-id'), | |||
type: wu_type, | |||
message: message, | |||
scrollpath: chiefred_scrollpath, | |||
chiefred_token: jQuery('#chiefred-was-usefull').data('nonce') | |||
}, | |||
beforeSend: function (xhr) { | |||
xhr.setRequestHeader('X-WP-Nonce', jQuery('#chiefred-was-usefull').data('nonce')); | |||
}, | |||
success: function(data) | |||
{ | |||
console.log('chiefred-was-usefull: ok'); | |||
}, | |||
error: function(data) | |||
{ | |||
console.log('error:', data); | |||
}, | |||
}); | |||
jQuery('#chiefred-was-usefull').html('<div id="chiefred-wu-is thanks">Спасибо!</div>'); | |||
} | |||
jQuery('#chiefred-pwu-yes').hide(); | |||
jQuery('#chiefred-bwu-yes').click(function() | |||
{ | |||
jQuery('#chiefred-bwu-yes').addClass('active'); | |||
jQuery('#chiefred-pwu-yes').show(); | |||
jQuery('#chiefred-bwu-no').removeClass('active'); | |||
jQuery('#chiefred-pwu-no').hide(); | |||
jQuery('#chiefred-bwu-error').removeClass('active'); | |||
jQuery('#chiefred-pwu-error').hide(); | |||
}); | |||
var chiefred_ta_lim = 1000; | |||
jQuery('#chiefred-pwu-no').hide(); | |||
jQuery('#chiefred-bwu-no').click(function() | |||
{ | |||
jQuery('#chiefred-bwu-yes').removeClass('active'); | |||
jQuery('#chiefred-pwu-yes').hide(); | |||
jQuery('#chiefred-bwu-no').addClass('active'); | |||
jQuery('#chiefred-pwu-no').show(); | |||
jQuery('#chiefred-twu-no').focus(); | |||
jQuery('#chiefred-bwu-error').removeClass('active'); | |||
jQuery('#chiefred-pwu-error').hide(); | |||
}); | |||
jQuery('#chiefred-swu-no').click(chiefred_wu_submit); | |||
var chiefred_twu_no_updated = function() | |||
{ | |||
cur = chiefred_ta_lim - jQuery('#chiefred-twu-no').val().length; | |||
if (cur < 0) { | |||
jQuery('#chiefred-twu-no').val(jQuery('#chiefred-twu-no').val().substr(0, chiefred_ta_lim)); | |||
cur = 0; | |||
} | |||
jQuery('#chiefred-lwu-no').html(cur); | |||
} | |||
chiefred_twu_no_updated(); | |||
jQuery('#chiefred-twu-no').keyup(chiefred_twu_no_updated); | |||
jQuery('#chiefred-twu-no').change(chiefred_twu_no_updated); | |||
jQuery('#chiefred-pwu-error').hide(); | |||
jQuery('#chiefred-bwu-error').click(function() | |||
{ | |||
jQuery('#chiefred-bwu-yes').removeClass('active'); | |||
jQuery('#chiefred-pwu-yes').hide(); | |||
jQuery('#chiefred-bwu-no').removeClass('active'); | |||
jQuery('#chiefred-pwu-no').hide(); | |||
jQuery('#chiefred-bwu-error').addClass('active'); | |||
jQuery('#chiefred-pwu-error').show(); | |||
jQuery('#chiefred-twu-error').focus(); | |||
}); | |||
jQuery('#chiefred-swu-error').click(chiefred_wu_submit); | |||
var chiefred_twu_error_updated = function() | |||
{ | |||
cur = chiefred_ta_lim - jQuery('#chiefred-twu-error').val().length; | |||
if (cur < 0) { | |||
jQuery('#chiefred-twu-error').val(jQuery('#chiefred-twu-error').val().substr(0, chiefred_ta_lim)); | |||
cur = 0; | |||
} | |||
jQuery('#chiefred-lwu-error').html(cur); | |||
} | |||
chiefred_twu_error_updated(); | |||
jQuery('#chiefred-twu-error').keyup(chiefred_twu_error_updated); | |||
jQuery('#chiefred-twu-error').change(chiefred_twu_error_updated); | |||
}); |
@@ -0,0 +1,46 @@ | |||
.chiefred-options { | |||
display: block; | |||
margin: 1em 0; | |||
width: 100%; | |||
max-width: 630px; | |||
} | |||
.chiefred-options th { | |||
display: inline-block; | |||
width: 250px; | |||
text-align: left; | |||
} | |||
.chiefred-options .devider { | |||
display: inline-block; | |||
width: 10px; | |||
} | |||
.chiefred-options .option { | |||
display: inline-block; | |||
width: 360px; | |||
text-align: left; | |||
} | |||
.chiefred-options input, | |||
.chiefred-options select { | |||
width: 360px; | |||
} | |||
.chiefred-options .error { | |||
border: 1px solid red; | |||
} | |||
#options-changed { | |||
display:inline-block; | |||
margin: 6px 12px; | |||
} | |||
#TB_window { | |||
width: 90% !important; | |||
margin-left: -45% !important; | |||
} | |||
#TB_ajaxContent { | |||
width: auto !important; | |||
} |
@@ -0,0 +1,162 @@ | |||
jQuery( document ).ready( function () | |||
{ | |||
jQuery('#options-changed').hide(); | |||
jQuery('#site_id').mask("09999") | |||
.blur(function() | |||
{ | |||
if( jQuery(this).val().match(/^\d+$/gm) ) { | |||
jQuery(this).removeClass('error'); | |||
} else { | |||
jQuery(this).addClass('error'); | |||
} | |||
}); | |||
jQuery('#api_ip').mask("099.099.099.099") | |||
.blur(function() | |||
{ | |||
if( jQuery(this).val().match(/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/gm) ) { | |||
jQuery(this).removeClass('error'); | |||
} else { | |||
jQuery(this).addClass('error'); | |||
} | |||
}); | |||
jQuery('#api_port').mask("99999") | |||
.blur(function() | |||
{ | |||
if( jQuery(this).val().match(/^\d{5}$/gm) ) { | |||
jQuery(this).removeClass('error'); | |||
} else { | |||
jQuery(this).addClass('error'); | |||
} | |||
}); | |||
jQuery('#api_secret').mask("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", {translation: {'Z': {pattern: /[a-zA-Z0-9]/, optional: true}}}) | |||
.blur(function() | |||
{ | |||
if( '' !== jQuery(this).val() ) { | |||
jQuery(this).removeClass('error'); | |||
} else { | |||
jQuery(this).addClass('error'); | |||
} | |||
}); | |||
jQuery('#chiefred-options input, #chiefred-options select').trigger( "blur" ); | |||
jQuery("#site_ip,#sync_script_url,#canonical_script_url").click(function() | |||
{ | |||
jQuery(this).select(); | |||
}); | |||
jQuery('#chiefred-options #site_id, #chiefred-options #api_ip , #chiefred-options #api_port, #chiefred-options #api_secret').change(function() | |||
{ | |||
jQuery('.utils').hide(); | |||
jQuery('#options-changed').show(); | |||
}); | |||
jQuery('.chiefred-options-cancel-btn').click(function() | |||
{ | |||
location.reload(); | |||
}); | |||
jQuery('.chiefred-options-save-btn').click(function() | |||
{ | |||
jQuery('#chiefred-options').submit(); | |||
}); | |||
jQuery('.chiefred-synchronize-log-btn').click(function() | |||
{ | |||
jQuery.ajax({ | |||
type: "POST", | |||
url: ajaxurl, | |||
data: { | |||
action: 'display_synchronize_log', | |||
}, | |||
success: function(data) | |||
{ | |||
jQuery('#TB_ajaxWindowTitle').text('Журнал последней синхронизации'); | |||
jQuery('#TB_ajaxContent').html('<pre class="synchronize_log">' + data + '</pre>'); | |||
}, | |||
error: function(data) | |||
{ | |||
console.log('error:', data); | |||
}, | |||
}); | |||
}); | |||
setInterval( | |||
function() | |||
{ | |||
if(jQuery('pre.synchronize_log').is(":visible")) { | |||
jQuery.ajax({ | |||
type: "POST", | |||
url: ajaxurl, | |||
data: { | |||
action: 'display_synchronize_log', | |||
}, | |||
success: function(data) | |||
{ | |||
jQuery('pre.synchronize_log').html(data); | |||
}, | |||
error: function(data) | |||
{ | |||
console.log('error:', data); | |||
}, | |||
}); | |||
} | |||
} | |||
, 3000 | |||
); | |||
jQuery('.chiefred-synchronize-btn').click(function() | |||
{ | |||
jQuery.ajax({ | |||
type: "POST", | |||
url: location.href, | |||
data: { | |||
chiefred_action: 'synchronize', | |||
chiefred_token: jQuery('#chiefred_token').val() | |||
}, | |||
beforeSend: function (xhr) { | |||
xhr.setRequestHeader('X-WP-Nonce', jQuery('#chiefred_token').val()); | |||
}, | |||
success: function(data) | |||
{ | |||
if('ok'==data){ | |||
alert('Внеплановая синхронизация успешно инициирована'); | |||
} else { | |||
alert('Не удалось инициировать синхронизацию'); | |||
} | |||
}, | |||
error: function(data) | |||
{ | |||
console.log('error:', data); | |||
}, | |||
}); | |||
}); | |||
jQuery('.chiefred-clear-synchronize-btn').click(function() | |||
{ | |||
jQuery.ajax({ | |||
type: "POST", | |||
url: location.href, | |||
data: { | |||
chiefred_action: 'clear_synchronize', | |||
chiefred_token: jQuery('#chiefred_token').val() | |||
}, | |||
beforeSend: function (xhr) { | |||
xhr.setRequestHeader('X-WP-Nonce', jQuery('#chiefred_token').val()); | |||
}, | |||
success: function(data) | |||
{ | |||
if('ok'==data){ | |||
alert('Внеплановая синхронизация успешно отменена'); | |||
} else { | |||
alert('Не удалось отменить внеплановую синхронизацию'); | |||
} | |||
}, | |||
error: function(data) | |||
{ | |||
console.log('error:', data); | |||
}, | |||
}); | |||
}); | |||
}); |
@@ -0,0 +1,18 @@ | |||
// jQuery Mask Plugin v1.14.10 | |||
// github.com/igorescobar/jQuery-Mask-Plugin | |||
var $jscomp={scope:{},findInternal:function(a,f,c){a instanceof String&&(a=String(a));for(var l=a.length,g=0;g<l;g++){var b=a[g];if(f.call(c,b,g,a))return{i:g,v:b}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(a,f,c){if(c.get||c.set)throw new TypeError("ES3 does not support getters and setters.");a!=Array.prototype&&a!=Object.prototype&&(a[f]=c.value)}; | |||
$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(a,f,c,l){if(f){c=$jscomp.global;a=a.split(".");for(l=0;l<a.length-1;l++){var g=a[l];g in c||(c[g]={});c=c[g]}a=a[a.length-1];l=c[a];f=f(l);f!=l&&null!=f&&$jscomp.defineProperty(c,a,{configurable:!0,writable:!0,value:f})}}; | |||
$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(a,c){return $jscomp.findInternal(this,a,c).v}},"es6-impl","es3"); | |||
(function(a,f,c){"function"===typeof define&&define.amd?define(["jquery"],a):"object"===typeof exports?module.exports=a(require("jquery")):a(f||c)})(function(a){var f=function(b,h,e){var d={invalid:[],getCaret:function(){try{var a,n=0,h=b.get(0),e=document.selection,k=h.selectionStart;if(e&&-1===navigator.appVersion.indexOf("MSIE 10"))a=e.createRange(),a.moveStart("character",-d.val().length),n=a.text.length;else if(k||"0"===k)n=k;return n}catch(A){}},setCaret:function(a){try{if(b.is(":focus")){var p, | |||
d=b.get(0);d.setSelectionRange?d.setSelectionRange(a,a):(p=d.createTextRange(),p.collapse(!0),p.moveEnd("character",a),p.moveStart("character",a),p.select())}}catch(z){}},events:function(){b.on("keydown.mask",function(a){b.data("mask-keycode",a.keyCode||a.which);b.data("mask-previus-value",b.val())}).on(a.jMaskGlobals.useInput?"input.mask":"keyup.mask",d.behaviour).on("paste.mask drop.mask",function(){setTimeout(function(){b.keydown().keyup()},100)}).on("change.mask",function(){b.data("changed",!0)}).on("blur.mask", | |||
function(){c===d.val()||b.data("changed")||b.trigger("change");b.data("changed",!1)}).on("blur.mask",function(){c=d.val()}).on("focus.mask",function(b){!0===e.selectOnFocus&&a(b.target).select()}).on("focusout.mask",function(){e.clearIfNotMatch&&!g.test(d.val())&&d.val("")})},getRegexMask:function(){for(var a=[],b,d,e,k,c=0;c<h.length;c++)(b=m.translation[h.charAt(c)])?(d=b.pattern.toString().replace(/.{1}$|^.{1}/g,""),e=b.optional,(b=b.recursive)?(a.push(h.charAt(c)),k={digit:h.charAt(c),pattern:d}): | |||
a.push(e||b?d+"?":d)):a.push(h.charAt(c).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"));a=a.join("");k&&(a=a.replace(new RegExp("("+k.digit+"(.*"+k.digit+")?)"),"($1)?").replace(new RegExp(k.digit,"g"),k.pattern));return new RegExp(a)},destroyEvents:function(){b.off("input keydown keyup paste drop blur focusout ".split(" ").join(".mask "))},val:function(a){var d=b.is("input")?"val":"text";if(0<arguments.length){if(b[d]()!==a)b[d](a);d=b}else d=b[d]();return d},calculateCaretPosition:function(a,d){var h= | |||
d.length,e=b.data("mask-previus-value")||"",k=e.length;8===b.data("mask-keycode")&&e!==d?a-=d.slice(0,a).length-e.slice(0,a).length:e!==d&&(a=a>=k?h:a+(d.slice(0,a).length-e.slice(0,a).length));return a},behaviour:function(e){e=e||window.event;d.invalid=[];var h=b.data("mask-keycode");if(-1===a.inArray(h,m.byPassKeys)){var h=d.getMasked(),c=d.getCaret();setTimeout(function(a,b){d.setCaret(d.calculateCaretPosition(a,b))},10,c,h);d.val(h);d.setCaret(c);return d.callbacks(e)}},getMasked:function(a,b){var c= | |||
[],p=void 0===b?d.val():b+"",k=0,g=h.length,f=0,l=p.length,n=1,v="push",w=-1,r,u;e.reverse?(v="unshift",n=-1,r=0,k=g-1,f=l-1,u=function(){return-1<k&&-1<f}):(r=g-1,u=function(){return k<g&&f<l});for(var y;u();){var x=h.charAt(k),t=p.charAt(f),q=m.translation[x];if(q)t.match(q.pattern)?(c[v](t),q.recursive&&(-1===w?w=k:k===r&&(k=w-n),r===w&&(k-=n)),k+=n):t===y?y=void 0:q.optional?(k+=n,f-=n):q.fallback?(c[v](q.fallback),k+=n,f-=n):d.invalid.push({p:f,v:t,e:q.pattern}),f+=n;else{if(!a)c[v](x);t===x? | |||
f+=n:y=x;k+=n}}p=h.charAt(r);g!==l+1||m.translation[p]||c.push(p);return c.join("")},callbacks:function(a){var f=d.val(),p=f!==c,g=[f,a,b,e],k=function(a,b,d){"function"===typeof e[a]&&b&&e[a].apply(this,d)};k("onChange",!0===p,g);k("onKeyPress",!0===p,g);k("onComplete",f.length===h.length,g);k("onInvalid",0<d.invalid.length,[f,a,b,d.invalid,e])}};b=a(b);var m=this,c=d.val(),g;h="function"===typeof h?h(d.val(),void 0,b,e):h;m.mask=h;m.options=e;m.remove=function(){var a=d.getCaret();d.destroyEvents(); | |||
d.val(m.getCleanVal());d.setCaret(a);return b};m.getCleanVal=function(){return d.getMasked(!0)};m.getMaskedVal=function(a){return d.getMasked(!1,a)};m.init=function(c){c=c||!1;e=e||{};m.clearIfNotMatch=a.jMaskGlobals.clearIfNotMatch;m.byPassKeys=a.jMaskGlobals.byPassKeys;m.translation=a.extend({},a.jMaskGlobals.translation,e.translation);m=a.extend(!0,{},m,e);g=d.getRegexMask();if(c)d.events(),d.val(d.getMasked());else{e.placeholder&&b.attr("placeholder",e.placeholder);b.data("mask")&&b.attr("autocomplete", | |||
"off");c=0;for(var f=!0;c<h.length;c++){var l=m.translation[h.charAt(c)];if(l&&l.recursive){f=!1;break}}f&&b.attr("maxlength",h.length);d.destroyEvents();d.events();c=d.getCaret();d.val(d.getMasked());d.setCaret(c)}};m.init(!b.is("input"))};a.maskWatchers={};var c=function(){var b=a(this),c={},e=b.attr("data-mask");b.attr("data-mask-reverse")&&(c.reverse=!0);b.attr("data-mask-clearifnotmatch")&&(c.clearIfNotMatch=!0);"true"===b.attr("data-mask-selectonfocus")&&(c.selectOnFocus=!0);if(l(b,e,c))return b.data("mask", | |||
new f(this,e,c))},l=function(b,c,e){e=e||{};var d=a(b).data("mask"),h=JSON.stringify;b=a(b).val()||a(b).text();try{return"function"===typeof c&&(c=c(b)),"object"!==typeof d||h(d.options)!==h(e)||d.mask!==c}catch(u){}},g=function(a){var b=document.createElement("div"),c;a="on"+a;c=a in b;c||(b.setAttribute(a,"return;"),c="function"===typeof b[a]);return c};a.fn.mask=function(b,c){c=c||{};var e=this.selector,d=a.jMaskGlobals,h=d.watchInterval,d=c.watchInputs||d.watchInputs,g=function(){if(l(this,b, | |||
c))return a(this).data("mask",new f(this,b,c))};a(this).each(g);e&&""!==e&&d&&(clearInterval(a.maskWatchers[e]),a.maskWatchers[e]=setInterval(function(){a(document).find(e).each(g)},h));return this};a.fn.masked=function(a){return this.data("mask").getMaskedVal(a)};a.fn.unmask=function(){clearInterval(a.maskWatchers[this.selector]);delete a.maskWatchers[this.selector];return this.each(function(){var b=a(this).data("mask");b&&b.remove().removeData("mask")})};a.fn.cleanVal=function(){return this.data("mask").getCleanVal()}; | |||
a.applyDataMask=function(b){b=b||a.jMaskGlobals.maskElements;(b instanceof a?b:a(b)).filter(a.jMaskGlobals.dataMaskAttr).each(c)};g={maskElements:"input,td,span,div",dataMaskAttr:"*[data-mask]",dataMask:!0,watchInterval:300,watchInputs:!0,useInput:!/Chrome\/[2-4][0-9]|SamsungBrowser/.test(window.navigator.userAgent)&&g("input"),watchDataMask:!1,byPassKeys:[9,16,17,18,36,37,38,39,40,91],translation:{0:{pattern:/\d/},9:{pattern:/\d/,optional:!0},"#":{pattern:/\d/,recursive:!0},A:{pattern:/[a-zA-Z0-9]/}, | |||
S:{pattern:/[a-zA-Z]/}}};a.jMaskGlobals=a.jMaskGlobals||{};g=a.jMaskGlobals=a.extend(!0,{},g,a.jMaskGlobals);g.dataMask&&a.applyDataMask();setInterval(function(){a.jMaskGlobals.watchDataMask&&a.applyDataMask()},g.watchInterval)},window.jQuery,window.Zepto); |
@@ -0,0 +1,69 @@ | |||
<?php | |||
/** | |||
* Файл article.default.php - стандартный шаблон вывода статьи, | |||
* загруженной по API ChiefRed.com | |||
* | |||
* НЕ РЕДАКТИРУЙТЕ ЭТОТ ФАЙЛ!!! | |||
* | |||
* При последующих обновлениях плагина он будет замещаться и все Ваши изменения пропадут. | |||
* Создайте новый файл с именем article.php в той же папке, скопируйте в него содержимое | |||
* этого файла и там уже вносите свои правки. | |||
* | |||
*/ | |||
if ( ! defined( 'ABSPATH' ) ) exit; | |||
if(isset($article->parent)) { ?> | |||
<div class="chiefred-article-parent"> | |||
<span></span> | |||
<a href="<?php echo esc_url($article->parent->href); ?>"><?php echo sanitize_text_field($article->parent->title); ?></a> | |||
</div> | |||
<?php } ?> | |||
<?php if(isset($article->creators)) { ?> | |||
<div class="chiefred-article-creators"> | |||
Материал подготовили: | |||
<?php foreach($article->creators as $name => $parts) { ?> | |||
<span title="<?php echo esc_attr($parts); ?>"><?php echo sanitize_text_field($name); ?></span> | |||
<?php } ?> | |||
</div> | |||
<?php } ?> | |||
<div class="chiefred-article-content"> | |||
<?php echo wp_kses_post($article->content); ?> | |||
</div> | |||
<?php if(isset($article->childrens)) { ?> | |||
<?php foreach($article->childrens as $child) { ?> | |||
<div class="chiefred-article-child"> | |||
<a href="<?php echo esc_url($child->href); ?>"><h2><?php echo sanitize_text_field($child->title); ?></h2></a> | |||
<?php echo wp_kses_post($child->excerpt); ?> | |||
<div class="chiefred-article-child-readmore"> | |||
<a href="<?php echo esc_url($child->href); ?>">Подробнее</a> | |||
</div> | |||
</div> | |||
<?php } ?> | |||
<?php } ?> | |||
<?php if(isset($article->was_useful)) { ?> | |||
<div id="chiefred-was-usefull" data-href="<?php echo esc_url( get_rest_url('', 'chiefred/was_useful') ); ?>" data-article-id="<?php echo absint($article->id); ?>" data-nonce="<?php echo esc_attr(wp_create_nonce('wp_rest')); ?>"> | |||
<div id="chiefred-wu-is"> | |||
<div id="chiefred-wu-caption">Была ли наша статья полезной для Вас?</div> | |||
<div id="chiefred-wu-buttons"> | |||
<input type="button" id="chiefred-bwu-yes" class="chiefred-btn" value="Да" /> | |||
<input type="button" id="chiefred-bwu-no" class="chiefred-btn" value="Нет" /> | |||
<input type="button" id="chiefred-bwu-error" class="chiefred-btn" value="Ошибка" /> | |||
</div> | |||
</div> | |||
<div id="chiefred-pwu-yes"><div>Спасибо!</div></div> | |||
<div id="chiefred-pwu-no"> | |||
<textarea id="chiefred-twu-no" placeholder="На какой вопрос Вы не смогли найти ответ?"></textarea> | |||
<div class="chiefred-wu-limit">Доступно <span id="chiefred-lwu-no"></span> символов <input type="button" id="chiefred-swu-no" class="chiefred-btn" value="Отправить" /></div> | |||
</div> | |||
<div id="chiefred-pwu-error"> | |||
<textarea id="chiefred-twu-error" placeholder="Пожалуйста, скопируйте сюда содержащий ошибку текст и поясните ее суть."></textarea> | |||
<div class="chiefred-wu-limit">Доступно <span id="chiefred-lwu-error"></span> символов <input type="button" id="chiefred-swu-error" class="chiefred-btn" value="Отправить" /></div> | |||
</div> | |||
</div> | |||
<?php } ?> |
@@ -0,0 +1,190 @@ | |||
<?php if ( ! defined( 'ABSPATH' ) ) exit; ?> | |||
<h1>Настройки взаимодействия с API v1 ChiefRed.com</h1> | |||
<form id="chiefred-options" action="" method="POST"> | |||
<input type="hidden" name="chiefred_action" value="save"> | |||
<?php wp_nonce_field( 'wp_rest', 'chiefred_token' ); ?> | |||
<h2 style="margin: 2em 0 1em 0;">Настройки сайта для взаимодействия с Редакцией</h2> | |||
<table cellspacing="0" class="chiefred-options"> | |||
<tr> | |||
<th>ID этого cайта в Редакции</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<span class="site-id"><input id="site_id" name="site_id" type="text" value="<?php echo esc_attr( $site_id ); ?>" class="regular-text code" placeholder="номер"></span> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>IP-адрес сервера API</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<span class="api-ip"><input id="api_ip" name="api_ip" type="text" value="<?php echo esc_attr( $api_ip ); ?>" class="regular-text code" placeholder="IPv4-адрес"></span> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>Порт API (Редакции)</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<span class="api-port"><input id="api_port" name="api_port" type="text" value="<?php echo esc_attr( $api_port ); ?>" class="regular-text code" placeholder="5 цифр"></span> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>Секрет синхронизации</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<span class="api-secret"><input id="api_secret" name="api_secret" type="text" value="<?php echo esc_attr( $api_secret ); ?>" class="regular-text code" placeholder="до 64 знаков: a-zA-Z0-9"></span> | |||
</td> | |||
</tr> | |||
</table> | |||
<h2 style="margin: 2em 0 1em 0;">Реквизиты данного сайта для настройки Редакции</h2> | |||
<table cellspacing="0" class="chiefred-options"> | |||
<tr> | |||
<th>IP-адрес сервера этого cайта</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<span class="site-id"><input id="site_ip" name="site_ip" type="text" value="<?php echo esc_attr( $_SERVER['SERVER_ADDR'] ); ?>" class="regular-text code" readonly="readonly"></span> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>Скрипт канонического URL статьи</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<span class="canonical_script_url"><input id="canonical_script_url" name="canonical_script_url" type="text" value="<?php echo esc_url( get_rest_url('', 'chiefred/canonical') ); ?>" class="regular-text code" readonly="readonly"></span> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>Скрипт сброса флага задержки</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<span class="site-id"><input id="sync_script_url" name="sync_script_url" type="text" value="<?php echo esc_url( get_rest_url('', 'chiefred/sync') ); ?>" class="regular-text code" readonly="readonly"></span> | |||
</td> | |||
</tr> | |||
</table> | |||
<h2 style="margin: 2em 0 1em 0;">Параметры отображения статей</h2> | |||
<table cellspacing="0" class="chiefred-options"> | |||
<tr> | |||
<th>Ссылка на статью-родителя</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<select name="article_parent_link"> | |||
<option value="0"<?php echo (0 == $article_parent_link)?' selected':'' ?>>Не добавлять</option> | |||
<option value="1"<?php echo (1 == $article_parent_link)?' selected':'' ?>>Добавить</option> | |||
</select> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>Подписи авторов</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<select name="article_creators"> | |||
<option value="0"<?php echo (0 == $article_creators)?' selected':'' ?>>Не добавлять</option> | |||
<option value="1"<?php echo (1 == $article_creators)?' selected':'' ?>>Добавить</option> | |||
</select> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>Анонсы дочерних статей</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<select name="article_childrens"> | |||
<option value="0"<?php echo (0 == $article_childrens)?' selected':'' ?>>Не добавлять</option> | |||
<option value="1"<?php echo (1 == $article_childrens)?' selected':'' ?>>Добавить</option> | |||
</select> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>Форма «Была ли статья полезна?»</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<select name="article_was_useful"> | |||
<option value="0"<?php echo (0 == $article_was_useful)?' selected':'' ?>>Не добавлять</option> | |||
<option value="1"<?php echo (1 == $article_was_useful)?' selected':'' ?>>Добавить</option> | |||
</select> | |||
</td> | |||
</tr> | |||
</table> | |||
<h2 style="margin: 2em 0 1em 0;">Параметры отображения иллюстраций</h2> | |||
<table cellspacing="0" class="chiefred-options"> | |||
<tr> | |||
<th>Размер иллюстраций в тексте</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<select name="illustration_size"> | |||
<?php | |||
foreach ($image_sizes as $size_name => $size) { | |||
if ($size['width'] <= 800) echo '<option value="' . esc_attr($size_name) . '"' . (($size_name == $illustration_size)?' selected':'') . '>' . esc_attr($size['nname']) . ' (ширина ' . absint($size['width']) . ' пикселей)</option>'; | |||
} | |||
?> | |||
</select> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>CLASS тега IMG иллюстрации</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<input id="illustration_class" name="illustration_class" type="text" value="<?php echo sanitize_html_class( $illustration_class ); ?>" /> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>Ссылка на полный размер</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<select name="illustration_link"> | |||
<option value="0"<?php echo (0 == $illustration_link)?' selected':'' ?>>Не добавлять</option> | |||
<option value="1"<?php echo (1 == $illustration_link)?' selected':'' ?>>Добавить</option> | |||
</select> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>CLASS тега A ссылки</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<input id="illustration_link_class" name="illustration_link_class" type="text" value="<?php echo sanitize_html_class( $illustration_link_class ); ?>" /> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>REL тега A ссылки</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<input id="illustration_link_rel" name="illustration_link_rel" type="text" value="<?php echo sanitize_html_class( $illustration_link_rel ); ?>" /> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th>TARGET тега A ссылки</th> | |||
<td class="devider" /> | |||
<td class="option"> | |||
<input id="illustration_link_target" name="illustration_link_target" type="text" value="<?php echo sanitize_html_class( $illustration_link_target ); ?>" /> | |||
</td> | |||
</tr> | |||
</table> | |||
<input class="button button-primary chiefred-options-save-btn" value="Сохранить изменения" type="button"> | |||
<b id="options-changed">Настройки были изменены!</b> | |||
<div class="utils"> | |||
<h1 style="margin: 2em 0 1em 0;">Утилиты</h1> | |||
<?php if ($site_id && $api_ip && $api_port && $api_secret) { ?> | |||
<input class="button chiefred-synchronize-btn" value="Выполнить синхронизацию" type="button" title="Инициировать внеплановый сеанс синхронизации сайта с Редакцией. Не следует вызывать чаще чем один раз в 5 минут. Редакция может отклонить слишком частые запросы."> | |||
<input class="button chiefred-clear-synchronize-btn" value="Остановить синхронизацию" type="button" title="Отменить следующую инициированную внеплановую синхронизацию (сеансы могут назначаться сами, с интервалом в 5 минут, если в Редакции еще остался готовый, но неопубликованный контент). Не влияет на плановую синхронизацию, выполняемую каждые 4 часа."> | |||
<?php } ?> | |||
<a class="button thickbox chiefred-synchronize-log-btn" href="#TB_inline?width=600&height=650&inlineId=chiefred-synchronize-log">Журнал последней синхронизации</a> | |||
</div> | |||
</form> | |||
<?php add_thickbox(); ?> | |||
<div id="chiefred-synchronize-log" style="display:none;"> | |||
<p>Загрузка...</p> | |||
</div> |