WordPress: публикация постов с помощью XML-RPC с поддержкой таксономий

Владимир | | PHP, Web разработка, WordPress.

wordpress xml-rpc publish

WordPress на сегодняшний день является одой из самых популярных CMS и последнее время активно развивается. Но, к сожалению, это развитие не всегда получается гармоничным.

Одной из возможностей, которая почему-то по возможностям постоянно отстаёт от остальной части движка, является XML-RPC. На сегодняшний день этот протокол является основным средством удалённой публикации постов. И, при этом, он фактически бесполезен если вы используете произвольные типы записей (custom post types) и таксономии (custom taxonomies). Ни один XML-RPC метод публикации постов в WP 3.2.1 их не поддерживает.

Конечно, можно надеятся, что в будущих версиях ситуация изменится в лучшую сторону, но ничто не мешает добавить нужные методы прямо сейчас.

Рассмотрим небольшой пример.

Допустим, нам нужно публиковать посты произвольного типа через XML-RPC и связывать их с таксономиями. При этом, таксономии могут быть как иерархическими, так и плоскими.

Примечание. Подробнее о типах постов и таксономиях рассказано в статьях: WordPress: вывод записей произвольных типов (Custom Post Types) и Управление контентом в WordPress CMS: ситуация на сегодня и ближайшая перспектива.

Немного теории

В WordPress предусмотрен фильтр (xmlrpc_methods), позволяющий добавлять новые методы во встроенный XML-RPC сервер. Делается это следующим образом:

add_filter('xmlrpc_methods', 'add_xml_rpc_methods');

Во втором параметре фильтра указываем имя функции, которая создаст запись в глобальном массиве XML-RPC методов.

function add_xml_rpc_methods($methods) {
	$methods['my.my_method_name'] = 'my_method_name';
	return $methods;
}

function my_method_name($args) {
//обработка XML-RPC запроса и отправка ответа
}

Чтобы создать XML-RPC метод нужно добавить новый элемент в массив $methods. Ключ этого элемента является именем метода, а значение – именем функции, которая выполняет обработку XML-RPC запроса и формирует ответ.

Реализация: XML-RPC клиент

Начнём с кода, который отправляет XML-RPC запрос. В данном случае будем использовать библиотеку The Incutio XML-RPC Library (она же используется и в WordPress).

require_once ('IXR_Library.php');

$client = new IXR_Client('http://my_blog.com/xmlrpc.php');
$client->timeout = 60000;

$requestData[0] = 0; //id блога
$requestData[1] = 'admin'; //имя пользователя
$requestData[2] = 'pass'; //пароль

$post = array();

$post['post_title'] = 'New Post';
$post['post_excerpt'] = 'Short description';
$post['post_content'] = 'This story about ...';
$post['post_status'] = 'draft';
$post['post_type'] = 'my_custom_post_type'; //тип поста
$post['post_date'] = date('Y-m-d H:i:s');
$post['post_modified'] = date('Y-m-d H:i:s');

//формируем массив с терминами таксономий
$terms = array();
$terms['taxonomy_1'][] = (int)$term['term_id_1'];
$terms['taxonomy_1'][] = (int)$term['term_id_2'];
$terms['taxonomy_2'][] = (int)$term['term_id_3'];
$terms['taxonomy_3'][] = (int)$term['term_id_4'];

$post['tax_input'] = $terms;

$requestData[3] = $post;

if (!$client->query('my.publish_post', $requestData)) {
	echo 'Publish Post error: '.$client->getErrorMessage();
	return;
}

$publishedPost = $client->getResponse();

Прежде всего, создаём объект IXR_Client, конструктору которого передаём адрес скрипт, который выполняет обработку XML-RPC запросов (xmlrpc.php).

Затем формируем массив с данными для публикации поста. В первых трёх элементах указываем: id блога (на данный момент не используется), логин и пароль. В четвертом элементе – массив с данными нового поста.

Чтобы сократить количество кода на стороне XML-RPC сервера, названия полей этого массива должны совпадать с полями массива, который передаётся функции wp_insert_post. Кстати, большинство ключей элементов этого массива совпадает с именами полей таблицы posts базы данных.

Обратите внимание на параметр

$post['post_type'] = 'my_custom_post_type'; //тип поста

В нём указан тип поста, который мы хотим создать. Естественно, этот тип должен быть заранее создан.

Отдельно остановимся на таксономиях.

WordPress поддерживает таксономии 2-х типов: иерархические и плоские. Чтобы связать пост с терминами таксономий нужно перечислить их в элементе tax_input массива, который передаётся функции wp_insert_post. Например, так:

'tax_input' => array('taxonomy_1' => array('term', 'term2', 'term3'), 'taxonomy_2' => array('term1', 'term2'))

Здесь taxonomy_1, taxonomy_2 – имена таксономий, а term, term1 и т.д. – имена терминов.

Но здесь есть нюансы. Если публикуется «плоская» таксономия, то можно указать, либо имя термина, либо его id. При этом, id должен иметь тип int, если id сохранён в виде строки, то WordPress просто создаст новый термин. Для иерархических таксономий можно использовать только id термина (при этом нет ограничения на тип значения, оно будет автоматически приведено к типу int).

Т.е. универсальный вариант установки таксономий выглядит так:

$terms['taxonomy_1'][] = (int)$term['term_id_1'];
$terms['taxonomy_1'][] = (int)$term['term_id_2'];
$terms['taxonomy_2'][] = (int)$term['term_id_3'];
$terms['taxonomy_3'][] = (int)$term['term_id_4'];

Отправка запроса выполняется с помощью метода query, а прочитать результат можно используя getResponse.

XML-RPC сервер

На серверной стороне нужно зарегистрировать новый XML-RPC метод и написать функцию, которая будет обрабатывать запрос, и возвращать результат.

Примечание. Следующий код можно добавить в плагин или в файл functions.php темы.

add_filter('xmlrpc_methods', 'add_xml_rpc_methods' );

function add_xml_rpc_methods($methods) {
	$methods['my.publish_post'] = 'my_publish_post';
	return $methods;
}

function my_publish_post($args) {
	$blog_id = (int) $args[0];
	$username = $args[1];
	$password = $args[2];
	$post_data  = $args[3];

	if ( !get_option( 'enable_xmlrpc' ) ) {
		return new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) );
	}

	$user = wp_authenticate($username, $password);

	if (is_wp_error($user)) {
		return new IXR_Error(403, __('Bad login/pass combination.'));
	}

	wp_set_current_user( $user->ID );

	if ( !current_user_can( 'edit_private_posts' ) ) {
		return new IXR_Error( 401, __( 'Sorry, you cannot edit private posts.' ) );
	}

	if (!is_array($post_data)) {
		return new IXR_Error( 401, __( 'Sorry, no post data not found.' ) );
	}

	$id = wp_insert_post( $post_data );

	if ($id === 0) {
		return new IXR_Error( 401, __( 'Post save error.' ) );
	}

	$post = array();
	$post['id'] = $id;
	$post['permalink'] = get_permalink($id);

	return $post;
}

Здесь мы регистрируем XML-RPC метод my.publish_post и указываем, что при обращении к нему WordPress должен вызвать функцию my_publish_post.

Большая часть кода в этой функции совпадает с большинством обработчиков стандартных XML-RPC методов WP. Собственно он оттуда и скопирован 😉 . Этот код проверяет, разрешен ли XML-RPC для данного блога (строки 14-16, кстати, не забудьте его включить в админке на странице Settings -> Writing), аутентифицирует пользователя и проверяет, достаточно ли у него прав для публикации поста.

Сама публикация выполняется с помощью всего одной функции wp_insert_post (строка 34).

Клиенту возвращаем id созданного поста и постоянную ссылку на него (формируем с помощью функции get_permalink).

Заключение

Как видите, принцип достаточно простой. Любую встроенную функцию WP можно вызвать через XML-RPC протокол и использовать все возможности движка при удалённой публикации постов.

Если есть вопросы или замечания, пишите, постараюсь ответить.

Успехов!

Интересные ссылки

Закажите печать фотокниг тремя способами: онлайн, в офисе или вип

  • Alex

    А откуда термин «плоская таксономия»?

    • Если честно, не помню. И не уверен, что термин правильный, хотя есть термин «плоский список». Возможно, «не иерархическая таксономия» будет правильно 😉

  • «но ничто не мешает нужные методы прямо сейчас.»
    Видимо пропущено какое-то слово 🙂
    И спасибо за подробное описание!

  • Intertrey

    Владимир скажите пожалуйста, можно ли через xml-rpc как то передать в поле Set featured image «тумба маленькая картинки» собственно картинку(или url или саму картинку). Просто у меня есть тема шаблона, где картинки которые отображаются на главной странице, погружаются через  Set featured image вручную и как то не охото править к примеру 2000 постов патом, погружая её самую картинку ручками.

    • Да, конечно, можно. Но придется дорабатывать XML-RPC интерфейс. Подробно проблема обсуждается здесь.

  • Intertrey

    А через code-igniter и его встроенный xml-rpc клиент в последней версии,как то можно передать my_custom_post_type ?
    Обычные тэги передаются через mt_keywords и интересно узнать как таксономию передать…?)

    • Да можно, только удобнее использовать Incution XML-RPC. Вы передаете ей массив с данными и она генерирует правильный XML. Со встроенной библиотекой CI можно получить такой же XML, но придется возиться с типами данных.

      Пример передачи таксономии есть в этой статье.

  • Сергей

    Добрый день, а вы не подскажете, как быть когда надо отпарсить с помощью curl и потом создать новый пост через wp.newPost, у меня получилось через siple_dom_html вытащить тот текст что надо, но я как понял так не пойдет и надо юзать curl и xmlrpc, а с этим никогда не встречался, но понял принцип работы, а вот составить логику действий сейчас не получается.
    Вы не могли бы объяснить план действий парсинга контента curl в wordpress?

    • Если вы получили нужный текст (с помощью simple_dom_html), то этого достаточно чтобы использовать метод wp.newPost.

      Вообще
      я не совсем понимаю проблему. Если скрипт (который парсит контент)
      запускается на отдельном (от WP) сервере, то тогда использование xmlrpc
      имеет смысл. Если скрипт написан, например, как плагин к WP, то xmlrpc
      не нужен, т.к. можно просто создать пост с помощью функции
      wp_insert_post.

      curl используется только для получения содержимого указанной страницы и к парсингу отношения не имеет.

  • Левон

    У меня версия wordpress 3.5 В админке нету возмоности подключить эту функцию. Считается что оно подключено по умолчанию. Я установил программу Windows Live Writer но при подключении к серверу выдает ошибку. Произошла ошибка при попытке подключится к вашей службе блога по адресу http://ayasam.ru/xmlrpc.php «. Когда ввожу этот адрес в командную строку, получаю такой ответ «XML-RPC server accepts POST requests only.»
    Все другие варианты дают ошибку 404. мой сайт на WordPress 3.5 Искал в Инете инфу не нашел. Может кто сталкивался с этой проблемой?

    • XML-RPC у вас работает. Иначе вы бы не увидели сообщение «XML-RPC server accepts POST requests only». Т.е. проблема в Windows Live Writer или его настройках. Попробуйте использовать другой клиент.

  • CanaBeasT

    Все сделал, как описано в посте, но при попытке публикации, даже обычного поста выдает ошибку
    Publish Post error: XML-RPC services are disabled on this site. An admin user can enable them at домен/wp-admin/options-writing.php

    Хотя через metaWeblog.newPost обычные посты проходят.

    • Судя по описанию ошибки XML-RPC у вас отключен. Но начиная с версии 3.5 XML-RPC включен по-умолчанию. Поэтому проблема, скорее всего, в конфликте с плагинами или темой. Например, подобная проблема была с плагином NGG.

      В общем, отключайте все плагины, переключайте тему на стандартную и проверяйте работу XML-RPC.

  • CanaBeasT

    Вордпресс 3.51