Как импортировать JSON в WordPress

Дата публикации:Апрель 29, 2015

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

Что такое JSON

Если вы не знакомы с JSON (аббревиатура от JavaScript Object Notation), просто примите к сведению, что это стандартный формат для представления данных, и, что более важно, для такого представления данных, которое понимают многочисленные устройства, языки и протоколы. Допустим, к примеру, что вы знакомы с человеком, у которого много характеристик. Объект JSON этого человека выглядел бы следующим образом:

{
  "first-name": "Tomaz",
  "last-name": "Zaman",
  "age": 32,
  "address": {
    "country": "Slovenia"
  },
  "hobbies": [
    "skydiving",
    "movies"
  ]
}

Во многих отношениях JSON является преемником XML; прежде всего потому, что он проще и быстрее для записи и чтения.

Никаких плагинов не требуется

К сожалению, без плагина WP-REST-API система WordPress не может хорошо обработать данные JSON (если вообще может). Все это по той простой причине, что тип отправляемых данных для форм — x-www-form-urlencoded; это означает, что когда вы публикуете что-то через POST (к примеру, отправляете новую статью), данные экранируются и затем кодируются в URL. Это стандартное поведение HTML-форм, однако, поскольку мы рассматриваем импортирование данных в этой статье, у нас нет никаких форм, только данные.

Однако нам нужен некоторый URL, который мы будем вызывать из нашего внешнего сервиса, чтобы импортировать данные, верно? Хорошо, давайте будем использовать то, что WordPress в данный момент нам может предложить: wp_ajax. Поскольку это внутренняя служба, она не знает, где находится ajax endpoint (вызываемый URL), поэтому нам нужно вручную прописать URL с соответствующим действием. Обычно выглядит такой URL следующим образом: http://example.com/wp-admin/admin-ajax.php?action=your_import_action_name.

Если касаться руководств, то я всегда считаю, что лучше всего продемонстрировать реальный пример, поэтому я покажу вам, как импортировать разработчиков нашего произвольного приложения (основанного на Ruby on Rails) в WordPress в виде произвольного типа записей (который мы назовем developer).

Регистрируем хуки

Чтобы сделать более мощным WordPress AJAX, мы создадим два хука/действия, которые будут инициировать функцию импорта (весь код помещайте в functions.php или в любой другой файл, который идет с вашей темой/плагином).

add_action( 'wp_ajax_import_developer', 'import_developer' );
add_action( 'wp_ajax_nopriv_import_developer', 'import_developer' );

Теперь нам надо определить функцию, с которой будут сцепляться наши действия:

function import_developer() {

  $developer_data = json_decode( file_get_contents( 'php://input' ) );

  if ( compare_keys() ) {
    insert_or_update( $developer_data );
  }

  wp_die();

}

Важные участки функции:

  • Строка 3: скрипт считывает тело запроса, декодирует формат и связывает его с $developer_data
  • Строка 5: выполняется проверка безопасности (об этом позже)
  • Строка 6: данные передаются в другую функцию, которая либо создают новую запись разработчика, либо обновляет уже существующую
  • Строка 9: убеждаемся в том, что после того как мы импортируем разработчика, обработка закончится.

Самый важный участок здесь – это импорт разработчика, поэтому давайте рассмотрим его далее.

Добавление или обновление записи

Перед тем, как мы пойдем дальше, давайте посмотрим на то, как выглядит наше представление JSON для разработчика (как именно наше произвольное приложение передает данные в WordPress):

{
    "id": "1",
    "full_name": "Tomaz Zaman",
    "bio": "Codeable founder",
    "tags": [
        "CSS",
        "HTML",
        "PHP",
        "WordPress"
    ]
}

В конце импорта full_name превратится в заголовок записи, bio станет контентом записи, а tags превратится, очевидно, в метки.

Чтобы определить, какое из двух действий выполнить, нам нужно проверить, существует ли запись, и для этого мы используем произвольное поле developer_id в нашем произвольном типе записей. Помимо него я буду также использовать еще одно произвольное поле, в котором будет храниться весь JSON в своем базовом виде. Возможно, это будет не слишком полезным для вас, однако мы будем использовать некоторые из этих данных просто для их вывода (в качестве превью); таким образом, мы можем сделать это в нашей теме, не требуя дополнительных полей, если какие-то атрибуты никогда не меняются в WordPress. Я назову это произвольное поле json. Вы можете использовать гораздо больше произвольный полей, если вам это требуется.

Ниже приведен код целиком (с разъяснением под ним):

function insert_or_update($developer_data) {

  if ( ! $developer_data)
    return false;

  $args = array(
    'meta_query' => array(
      array(
        'key'   => 'developer_id',
        'value' => $developer_data->id
      )
    ),
    'post_type'      => 'developer',
    'post_status'    => array('publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit'),
    'posts_per_page' => 1
  );

  $developer = get_posts( $args );

  $developer_id = '';

  if ( $developer )
    $developer_id = $developer[0]->ID;

  $developer_post = array(
    'ID'            => $developer_id,
    'post_title'    => $developer_data->full_name,
    'post_content'  => $developer_data->bio,
    'post_type'     => 'developer',
    'post_status'   => ( $developer ) ? $developer[0]->post_status : 'publish'
  );

  $developer_id = wp_insert_post( $developer_post );

  if ( $developer_id ) {
    update_post_meta( $developer_id, 'developer_id', $developer_data->id );

    update_post_meta( $developer_id, 'json', addslashes( file_get_contents( 'php://input' ) ) );

    wp_set_object_terms( $developer_id, $developer_data->tags, 'developer_tag' );
  }

  print_r( $developer_id );

}

Перед тем, как что-то сделать, мы проверяем, содержит ли $developer_data данные (строка 3), после чего готовим аргументы для нашего запроса, который либо вернет одну запись, либо не вернет ни одной (строки 6-18). Если он найдет существующую запись, то в таком случае он привяжет ее ID к переменной $developer_id (строка 23), что важно в WordPress. Когда мы используем wp_insert_post, он решает, создать новую запись или обновить уже существующую именно на основе того, существует ли ID или нет. В нашем случае мы должны предотвратить дубликаты, однако вы вполне можете изменить код по своему усмотрению.

После того, как запись будет создана/обновлена, нам нужно обновить наши произвольные поля (через update_post_meta). Как я уже говорил ранее, мы сохраняем сырые JSON данные в поле для удобства.

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

Последний шаг: чтобы наше внешнее приложение знало, что все прошло гладко, мы просто выводим ID записи в WordPress.

Что по поводу безопасности?

Поскольку мы соединяемся с WordPress извне, мы не можем использовать стандартные меры безопасности AJAX (wp_nonce), поэтому я решил воспользоваться произвольным решением. Скажу по правде, что я не придумывал его сам, я просто скопировал его с GitHub – то, что хорошо для них, хорошо и для нас.

Вот функция:

function compare_keys() {

  if ( ! isset( $_SERVER['HTTP_X_CODEABLE_SIGNATURE'] ) ) {
    throw new Exception( "HTTP header 'X-Codeable-Signature' is missing." );
  }

  list( $algo, $hash ) = explode( '=', $_SERVER['HTTP_X_CODEABLE_SIGNATURE'], 2 ) + array( '', '' );
  $raw_post = file_get_contents( 'php://input' );

  if ( $hash !== hash_hmac( $algo, $raw_post, CODEABLE_KEY ) ) {
    throw new Exception( 'Secret hash does not match.' );
  }

  return true;

}

Когда мы импортируем данные разработчика в WordPress, вместе с запросом передается специальный заголовок, который выглядит следующим образом: X-Codeable-Signature: sha1=246d2e58593645b1f261b1bbc867fe2a9fc1a682.

Если говорить простым языком, то эта сигнатура генерируется в теле запроса (нашего объекта разработчика JSON) и подписывается приватным ключом (определен в WordPress как CODEABLE_KEY и в нашем произвольном приложении), после чего эта сигнатура сравнивается с той же самой сигнатурой, сгенерированной в WordPress.

Заключение

Я понимаю, что это руководство может показаться сложным в техническом плане, однако истина в том, что JSON – широко используемый и поддерживаемый формат, к которому переходят многочисленные сервисы (да, Facebook тоже, и именно поэтому вы видите пустые поля, когда входите в систему – ваш браузер ждет JSON, который будет возвращен за кулисами) – таким образом, я призываю вас изучить JSON, поскольку это принесет вам определенную выгоду в будущем, особенно когда он станет частью ядра WordPress. А это рано или поздно случится.

Чтобы сэкономить ваше время, я подготовил вам код (упакованный в класс), расположенный на Gist.

Источник: codeable.io

Поделиться

Один комментарий

  1. Отлично большой + нужно описывать такие решения

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.