Использование XML-RPC API Wordpress

Категория: WordPress

WordPress предоставляет XML-RPC API для взаимодействия с данными WordPress (постами, пользователями, категориями, тегами и прочими таксономиями). Однако, функционал API из коробки даже не позволяет получить список постов из определенной категории - фильтр по категории просто отсутствует. Я, признаться, ожидал найти некий метод, который обеспечит возможности фильтрации постов подобно WP_Query, но нет..

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

Внимание!

Для корректной работы XML-RPC API WordPress нужны PHP расширения php7.0-xml и php7.0-xmlrpc! При установке, соответственно, указывайте свою версию PHP.

Выполнение XML-RPC запроса

Для работы с WordPress API вы можете использовать curl, file_get_contents() + stream_context_create() или wordpress-xmlrpc-client. Я приведу примеры с использованием cURL и file_get_contents().

Все запросы к API нужно отправлять на URL:

http://your-wordpress.site/xmlrpc.php

Отправить запрос с помощью cURL

function do_api_request_via_curl($url, $xmlRequest)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: text/xml']);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);

    $error = curl_error($ch);$data = xmlrpc_decode($xmlResponse);
    if ($error) {
        die('Error: ' . $error);
    }

    $response = curl_exec($ch);

    return $response;
}

Отправить запрос с помощью file_get_contents

function do_api_request_via_fgc($url, $xmlRequest)
{
    $options = [
        'http' => [
            'method' => 'POST',
            'header' => 'Content-Type: text/xml',
            'content' => $xmlRequest
        ]
    ];

    $context = stream_context_create($options);
    $result = file_get_contents($url, false, $context);

    return $result;
}

Пример получения постов

Для формирования XML-RPC запроса и декодирования ответа я использовал стандартную библиотеку php5-xmlrpc (или php7.0-xmlrpc для PHP7):

sudo apt-get install php5-xmlrpc
XMLReader

Чтобы не ставить дополнительный PHP модуль xmlrpc, можно обойтись классом XMLReader для декодирования ответа API.

Пример формирования данных запроса к WordPress API для получения списка постов:

$xmlRequest = xmlrpc_encode_request('wp.getPosts', [1, 'WP_USER', 'WP_USER_PASSWORD', [
    'post_status' => 'publish',
    'post_type' => 'post',
    'number' => 2,
    's' => urlencode("приложени")
], ['post_title']]);

Отправляем запрос:

$xmlResponse = do_api_request_via_curl('YOUR_WP_URL', $xmlRequest);
Роль пользователя

Через API пользователь будет получать только посты, на которые у него есть права редактирования. Поэтому для получения всех постов, используйте учетку пользователя с ролью "Редактор" или выше.

И декодируем ответ:

$data = xmlrpc_decode($xmlResponse);

Расширение WordPress API

Приведу пример расширения WordPress API методом my.wpQuery, который принимает параметры в стандартном формате WP_Query. Добавление нового метода API в лучших традициях WordPress происходит в 2 этапа:

  1. Регистрируем метод и его обработчик;
  2. Пишем сам обработчик запроса.

Регистрируем API метод

add_filter('xmlrpc_methods', function($methods) {
    $methods['my.wpQuery'] = 'xmlrpc_method_my_wp_query';
    return $methods;
});

Обработчик API метода

function xmlrpc_method_my_wp_query($args) {
    /** @var wp_xmlrpc_server $wp_xmlrpc_server */
    global $wp_xmlrpc_server;
    $wp_xmlrpc_server->escape($args);
$data = xmlrpc_decode($xmlResponse);
    if (count($args) < 3) {
        $error = new IXR_Error(400, __('Insufficient arguments passed to this XML-RPC method.'));
        return $error;
    }

    $args = array_pad($args, 5, []);
    list($blog_id, $username, $password, $query_args, $fields) = $args;

    if (!$user = $wp_xmlrpc_server->login($username, $password)) {
        return $wp_xmlrpc_server->error;
    }

    do_action('xmlrpc_call', 'mm.wpQuery');

    $posts = wp_get_recent_posts($query_args);

    $result = [];
    foreach ($posts as $post) {
        if (!current_user_can('edit_post', $post['ID'])) {
            continue;
        }

        $result[] = !empty($fields) ? array_intersect_key($post, array_flip($fields)) : $post;
    }

    return $result;
}

Пример выполнения запроса my.wpQuery:

$xmlRequest = xmlrpc_encode_request('my.wpQuery', [1, 'WP_USER', 'WP_USER_PASSWORD', [
    'category_name' => 'reviews',
    'numberposts' => 2
], ['ID', 'post_title']]);

$xmlResponse = do_api_request_via_fgc($wpUrl, $xmlRequest);

$data = xmlrpc_decode($xmlResponse);

Используем функцию wp_get_recent_posts(), поскольку она, в отличие, от get_posts() возвращает посты как ассоциативные массивы вместо объектов WP_Post. Это позволяет без лишних движений извлечь только нужные поля постов, ну и API должен вернуть посты как ассоциативные массивы.

$posts = wp_get_recent_posts($query_args);

Ф-цию array_intersect_key() используем для выбора только необходимых полей, поскольку метод $wp_xmlrpc_server->_prepare_post(), который извлекает указанные поля для API метода wp.getPosts, есть protected и мы не можем его использовать в нашем API (разве что расширить класс wp_xmlrpc_server).

Пример использования API метода: https://gist.github.com/Sorbing/266b41c8fab37d9d5fd67f8ebccbd0cb

#wordpress api, #wordpress xml-rpc api, #extend wordpress api