WordPress как API: подход API-First в WordPress

Все мы знаем, что WordPress – это CMS, однако в данной статье мы покажем вам, как использовать WordPress в качестве API для контента. Фронтэнд – в сторону, он нам не потребуется; нам нужны будут только конечные точки URL, которые возвращает JSON. Эту статью нельзя назвать всесторонним применением данного подхода, однако она дает неплохую пищу для размышлений. Если вы хотите разработать систему наподобие представленной, обязательно обратите внимание на WP REST API – достаточно стабильный проект с хорошими перспективами развития.

Меня недавно попросили выбрать и применить систему CMS для цифрового агентства, которая позволила бы управлять многочисленными сайтами в одной сборке. По многим причинам я решил, что главный кандидат – это WordPress. Система является бесплатной с открытым кодом, обладает масштабным сообществом пользователей, она проста в использовании, а также обладает возможностью мультисайтов. Это успешный и зрелый проект. Однако у меня были свои условия.

Использование WordPress обычным путем означает выполнение установки, создание темы (или модификация существующей), а также принятие того, что любая последующая настройка будет иметь свое место в экосистеме, созданной CMS – а эта экосистема включает в себя языки программирования, технологии (PHP, MySQL), плагины, темы, действия, фильтры и многое другое.

Я всегда рассматривал контент как «сердце» веб-сайта. Натура и креативный концепт (а не CMS) каждого отдельного проекта диктуют то, какая среда и какие технологии будут лучшим образом отвечать цели — доставке контента.

Я не хочу ограничивать свой технологический выбор одним PHP только потому, что WordPress основан на этом языке; я хочу, чтобы разработчики могли выбирать технологию, которая будет целесообразной для создания независимых, автономных веб-сайтов, а не только плагинов и тем WordPress.

Создаем уровень посредника

В решении API-first промежуточный уровень, который находится между сайтом и CMS, позволит освободить WordPress от работы с фронтэндом и «запрограммировать» систему только на управление и доставку контента.

Такой уровень «посредника» способен «говорить» на универсальном языке (я предпочитаю JSON), который могут понять разные платформы.

Схема будет примерно такая:

middleman

Адаптация WordPress

В обычном WordPress-мире все происходит следующим образом: люди получают доступ к сайту через дружественное к пользователям доменное имя, контент передается из базы данных, тема форматирует и выводит его в виде HTML-страницы. Та страница обычно имеет визуальный интерфейс для просмотра записей и страниц пользователями, контент на ней фильтруется при помощи рубрик, меток и других таксономий.

Наш API-First WordPress не будет иметь ничего из этого. Единственный ввод, который мы получим от пользователей – это URL, в котором будут находиться запросы; их мы будем парсить, чтобы извлечь тип данных, формат, а также фильтры.

Создаем плагин

Есть хорошие и плохие способы изменения функциональности в WordPress. Говоря простым языком, смешивание с основной кодовой базой – плохой подход; вместо этого мы создадим отдельный плагин.

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

Давайте заложим фундамент для нашего плагина:

class API {
  public function __construct() {
    add_action('template_redirect', array($this, 'hijackRequests'), -100);
  }

  public function hijackRequests() {
    $entries = get_posts($_GET['filter']);

    $this->writeJsonResponse($entries);
  }

  protected function writeJsonResponse($message, $status = 200) {
    header('content-type: application/json; charset=utf-8', true, $status);
    echo(json_encode($message) . "\n");
    exit;
  }
}

new API();

Это хорошая практика – обертывать плагин в construct, чтобы избежать загрязнения глобального пространства имен в результате добавления «болтающихся» функций, которые могут привести к потенциальным конфликтам имен.

Затем мы регистрируем функцию при помощи действия template_redirect, которое срабатывает после того, как начнется программа инициализации, и перед тем, как WordPress примет решение, какой шаблон использовать для представления страницы.

Затем мы вызываем функцию get_posts(), которая принимает массив фильтров в качестве своего аргумента и возвращает массив соответствующих записей (название функции может ввести в заблуждение; она может возвращать как записи, так и страницы).

После сохранения плагина и его активации достаточно перейти по адресу: http://your-WP/index.php?filter[post_type]=post&filter[posts_per_page]=1, чтобы получить JSON-представление вашей последней записи. Прекрасно!

Мультиплексирование запросов

На данный момент у нас есть очень базовый API, который позволяет нам получать записи из WordPress на основе набора фильтров, которых может вполне хватить для простого проекта. Однако что произойдет, если нам нужно будет получить многочисленные наборы данных, чтобы обработать разные элементы страницы? Отправлять многочисленные HTTP-запросы – не самый разумный выход.

Возьмем в качестве примера страницу форума CSS-Tricks. Помимо некоторых метаданных, которые нам, вероятно, потребовались бы, есть как минимум три набора контента, которые можно получить от CMS: пункты в навигационной панели, свежие записи и подсказки.

Buckets

Мы можем определить наш собственный синтаксис для API, чтобы он автоматически поддерживал «контентные блоки» и возвращал их раздельно в виде JSON-массива.

Вместо того чтобы передавать фильтры как простой массив в URL, мы можем присоединить метку к каждому из них, чтобы указать, что они принадлежат к определенному блоку контента. Вернемся к нашему примеру выше. URL для мультиплексного запроса может иметь следующий вид:

?navigation:filter[category]=navigation
&latestPosts:filter[type]=post
&tips:filter[slug]=tips

Что вернет JSON-структуру:

{
  "navigation": [
    {
      "ID": 1
      (...)
    },
    {
      "ID": 2
      (...)
    }
  ],
  "latestPosts": [
    (...)
  ],
  "tips": [
    (...)
  ]
}

Это предоставит пользователям API легкий доступ к разным участкам контента без дополнительных усилий.

Функция hijackRequests может быть изменена для реализации этой возможности.

public function hijackRequests() {
  $usingBuckets = false;
  $buckets = array();
  $entries = array();

  foreach ($_GET as $variable => $value) {
    if (($separator = strpos($variable, ':')) !== false) {
      $usingBuckets = true;
      $bucket = substr($variable, 0, $separator);
      $filter = substr($variable, $separator + 1);
    } else {
      $bucket = 0;
      $filter = $variable;
    }

    $buckets[$bucket][$filter] = $value;
  }

  if ($usingBuckets) {
    foreach ($buckets as $name => $content) {
      $entries[$name] = get_posts($content['filter']);
    }
  } else {
    $entries = get_posts($buckets[0]['filter']);
  }

  $this->writeJsonResponse($entries);
}

Добавление галерей и произвольных полей

Наше JSON-представление записей основано на информации, возвращаемой get_posts(), однако есть некоторые элементы, которые были пропущены, но которые вы, возможно, хотите получить в своих фидах – к примеру, галереи изображений и произвольные поля. Мы можем прикрепить эту информацию самостоятельно к JSON-фиду с помощью функций get_post_galleries_images() и get_post_meta().

for ($i = 0, $numEntries = count($entries); $i < $numEntries; $i++) {
    $metaFields = get_post_meta($entries[$i]->ID);

  $galleriesImages = get_post_galleries_images($entries[$i]->ID);
  $entries[$i]->galleries = $galleriesImages;

  foreach ($metaFields as $field => $value) {
    // Discarding private meta fields (that begin with an underscore)
    if (strpos($field, '_') === 0) {
      continue;
    }

    if (is_array($value) && (count($value) == 1)) {
      $entries[$i]->$field = $value[0];
    } else {
      $entries[$i]->$field = $value;
    }
  }
}

Заключительные мысли

Решение, описанное в данной статье, просто показывает, как организовано обращение к API. Мы не стали касаться таких вещей, как аутентификация, типы запросов (POST, PUT, DELETE), многочисленные конечные точки для разных типов контента (пользователи, рубрики, параметры), управление версиями API, а также поддержка JSONP.

Это решение не планировалось для использования на рабочем сайте; оно было создано, чтобы продемонстрировать внутреннюю работу WordPress API, что, надеемся, вдохновит многих людей на создание своих решений, либо на расширение существующего, которое позволит реализовать собственные потребности.

По правде говоря, создание заказного API-решения вряд ли подойдет абсолютно всем пользователям. WP REST API – зрелый, стабильный проект, который в скором времени должен стать частью ядра WordPress. Его использование будет мудрым выбором.

Цель этой статьи – показать идею использования широко используемого, коммерчески оправданного, зрелого проекта, такого как WordPress, в качестве системы управления API. Т.е. мы отбрасываем большую часть WordPress, теряем преимущества таких вещей, как SEO-плагины и темы, но взамен получаем все плюсы системы, независимой от платформы.

Что вы думаете по этому поводу?

Источник: css-tricks.com

Блог про WordPress
Комментарии: 1
  1. Лев

    И какова скорость ответа такого API? Если прикрутить, к примеру… WPML + Woocommerce

Добавить комментарий

Получать новые комментарии по электронной почте.