Пять проверенных методов, которые не использует ваш разработчик WordPress API

Опубликовано: 2022-03-11

Один из лучших способов повысить свой статус разработчика WordPress, по крайней мере, в глазах ваших клиентов, — это научиться пользоваться API. Вот типичный сценарий реализации WordPress API: ваш клиент просит вас добавить виджет на его сайт, например, виджет подписки на электронную почту. Вы берете какой-то код из их стороннего почтового сервиса — возможно, это тег скрипта или iframe — вставляете его на страницу и отвечаете своему клиенту: «Понятно!»

К сожалению, вы имеете дело с несколько более требовательным клиентом, и он замечает следующие недостатки:

  • Хотя виджет, как и остальная часть сайта, имеет шрифт без засечек, он не совсем правильный. Виджет использует Helvetica вместо пользовательского шрифта, который вы установили.
  • Форма подписки виджета запускает загрузку новой страницы, что может быть разрушительным, если разместить ее в середине статьи.
  • Виджету требуется дополнительное время для загрузки после остальной части страницы, что кажется неприятным и дешевым.
  • Клиент хотел бы, чтобы подписчики были помечены метаданными на основе поста, на который они подписались, а виджет не предлагает ничего отдаленно напоминающего этот функционал.
  • Клиента раздражает, что теперь ему придется управлять двумя инструментальными панелями (wp-admin и областью администрирования почтовой службы).

В этот момент может произойти одно из двух. Вы можете объявить эти элементы «хорошо иметь» и заверить своего клиента в достоинствах решения 80/20, или вы можете выполнить эти запросы. На своем личном опыте я обнаружил, что выполнение таких запросов, то есть демонстрация мастерства сторонних сервисов, — это надежный способ убедить клиента в том, что вы своего рода волшебник WordPress. Кроме того, это часто весело делать.

За последнее десятилетие я использовал WordPress в качестве платформы для использования API в сравнении с примерно 50 различными API. Одними из наиболее распространенных API были MailChimp, Google Analytics, Google Maps, CloudFlare и Bitbucket. Но что, если вам нужно сделать больше, что, если вам нужно индивидуальное решение?

Как разработать клиент WordPress API

В этой статье я собираюсь разработать общий API «почтовой службы», стараясь изо всех сил, чтобы все было как можно более агностическим. Однако я считаю разумным предположить, что мы имеем дело с JSON REST API. Вот некоторые справочные темы, которые могут помочь вам ознакомиться с техническими аспектами этой статьи:

  • Семейство HTTP-функций WordPress
  • JSON
  • ОТДЫХ

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

Скриншот панели управления Postman

Почтальон. Может быть, мой любимый инструмент разработки?

Однако, если вы совсем не знакомы с ними, все равно продолжайте читать. Техническая аудитория с некоторым опытом работы с WordPress получит максимальную отдачу от этой статьи, но я позабочусь о том, чтобы объяснить ценность каждого метода менее техническим способом. Нетехнический читатель оставит эту статью в состоянии оценить ROI каждого пункта до того, как спонсировать его, и оценить качество реализации после доставки.

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

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

Переходные процессы: когда их придержать, а когда свернуть

В моем вступительном абзаце я отметил, что клиенту было неприятно находиться в двух областях администрирования: wp-admin и приборной панели для их службы электронной почты. Хорошим способом решить эту проблему было бы предоставить им виджет панели инструментов в wp-admin для отображения дайджеста их недавней активности подписчиков.

Скриншот виджета панели управления wp-admin

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

Но опять же, это может потребовать нескольких HTTP-запросов к удаленному API (API, предоставляемому службой электронной почты), что приведет к длительной загрузке страницы. Решение этой проблемы производительности состоит в том, чтобы хранить вызовы API как переходные процессы. Эта статья Кодекса дает отличное объяснение, которое вам обязательно нужно прочитать, но я резюмирую его следующим образом:

  1. Получите данные из удаленного API.
  2. Сохраните его с помощью set_transient() со временем истечения срока действия по вашему выбору, основанному на вашем собственном суждении о производительности, ограничениях скорости и допустимой погрешности при отображении устаревших данных в этом конкретном приложении.
  3. Продолжайте свою бизнес-логику — обрабатывайте данные, возвращайте значение, в любом случае.
  4. Когда вам снова потребуются данные, например, при загрузке следующей страницы, проверьте их в временном кеше с помощью get_transient() , прежде чем сделать вывод, что вам нужно получить их из API.

Я считаю, что это полезная и жизнеспособная основа, но вы можете сделать еще один шаг, если на мгновение задумаетесь о глаголах REST. Из пяти наиболее распространенных методов (GET, POST, PATCH, PUT, DELETE) только один принадлежит вашему временному кешу. Угадаете, какой? Это ПОЛУЧИТЬ. В моих плагинах у меня почти всегда есть класс PHP, предназначенный для абстрагирования вызовов рассматриваемого удаленного API, и аргументом при создании экземпляра этого класса является метод HTTP. Если это не вызов GET, то я вообще не буду вызывать какой-либо уровень кэширования.

Кроме того, если это не вызов GET, то само собой разумеется, что я предпринимаю какие-то действия, чтобы каким-то образом изменить удаленные данные, возможно, путем добавления, редактирования или удаления подписчика электронной почты. Это может быть подходящее время, чтобы аннулировать существующий кеш для этого ресурса с помощью delete_transient() .

Чтобы вернуться к нашему примеру API подписки на электронную почту WordPress, вот как это будет работать на практике:

  • Виджет панели мониторинга для отображения последних подписчиков будет вызывать конечную точку API для /subscribers через запрос GET. Поскольку это запрос GET, он сохраняется в моем временном кеше.
  • Виджет боковой панели для подписки на список рассылки будет вызывать конечную точку API для /subscribers через запрос POST. Поскольку это запрос POST, он не только позволит избежать моего временного кеша, но и спровоцирует меня удалить соответствующую часть моего временного кеша, чтобы виджет панели инструментов отражал этого нового подписчика.
  • При именовании переходных процессов я часто упорядочиваю их, буквально называя их после URL-адреса удаленного API, который я вызываю. Это удобный способ определить правильный переходный процесс для удаления. Если это конечная точка, которая принимает аргументы, я объединяю их в строку и также добавляю к временному имени.

Как клиент или другой менее технический участник, вы должны специально запрашивать временное кэширование — или, по крайней мере, его обсуждение — каждый раз, когда приложение извлекает данные из удаленной службы. Вы должны ознакомиться с отличным плагином Query Monitor, чтобы получить представление о том, как работают переходные процессы. Это даст вам интерфейс для просмотра того, какие данные хранятся как временные, как часто и как долго.

Иногда переходные процессы недостаточно хороши

Некоторые премиальные услуги хостинга WordPress на самом деле не позволяют вам использовать переходные процессы в рабочей среде. У них есть работающий код, возможно, в виде плагина MU или какого-то другого скрипта, который перехватит вашу попытку использовать API переходов и вместо этого сохранит эту информацию через кеш объектов. Ярким примером этого является WP-Engine в его наиболее распространенной конфигурации.

Скриншот представления phpMyAdmin, описанного в заголовке

Тревожный вид в пользовательском интерфейсе phpMyAdmin: рабочий сайт полностью лишен переходных процессов? Вероятно, это означает, что работает кэширование объектов.

Если вы просто храните и извлекаете данные, вам на самом деле не нужно заботиться об этом, и вы можете даже не заметить, что это происходит. Все семейство функций *_transient() предоставит вам один и тот же конечный результат, просто отфильтрованный для использования объектного кеша вместо переходного кеша. Однако вы можете столкнуться с проблемами при попытке удалить переходные процессы. Вот почему.

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

Скриншот кнопок выбора

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

Даже если вы достаточно сообразительны, чтобы создать пространство имен для всех ваших временных ключей, чтобы у вас была некоторая надежда идентифицировать каждый из них для delete_transient() , в лучшем случае, вероятно, все еще используется необработанный SQL, которого я всегда стараюсь избегать в WordPress:

 <?php // Purge all the transients associated with our plugin. function purge() { global $wpdb; $prefix = esc_sql( $this -> get_transient_prefix() ); $options = $wpdb -> options; $t = esc_sql( "_transient_timeout_$prefix%" ); $sql = $wpdb -> prepare ( " SELECT option_name FROM $options WHERE option_name LIKE '%s' ", $t ); $transients = $wpdb -> get_col( $sql ); // For each transient... foreach( $transients as $transient ) { // Strip away the WordPress prefix in order to arrive at the transient key. $key = str_replace( '_transient_timeout_', '', $transient ); // Now that we have the key, use WordPress core to the delete the transient. delete_transient( $key ); } } ?>

Не удобно, не эффективно. Вместо этого в этой ситуации требуется кэширование объектов, потому что кэширование объектов дает нам удобный способ сгруппировать вместе кэшированные значения . Таким образом, когда вам нужно очистить все кешированные значения, связанные с вашим плагином, это простой однострочный вызов wp_cache_delete( $key, $group ) .

Я бы резюмировал все это, сказав: вы не можете быть экспертом в использовании API, если вы еще не являетесь экспертом в управлении кешем для этих данных.

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

Удаленный API может помочь информировать вашу иерархию классов PHP

При размещении различных классов PHP для моего плагина я часто нахожу полезным имитировать способ определения конечных точек API — например, что общего у следующих конечных точек?

  • https://api.example-email-service.com/v1/subscribers.json
  • https://api.example-email-service.com/v1/lists.json
  • https://api.example-email-service.com/v1/campaigns.json

Все они возвращают collections , под которыми я подразумеваю результат запроса GET, возвращающий результаты от нуля до многих, где каждый результат является членом массива. Это может показаться довольно очевидным, но я считаю, что это полезная подсказка для следующей структуры классов в моем PHP-коде:

  • class.collection.php , абстрактный класс
  • class.subscribers.php расширяет абстрактный класс Collection .
  • class.lists.php расширяет абстрактный класс Collection .
  • class.campaigns.php расширяет абстрактный класс Collection .

Абстрактный класс будет принимать в качестве единственного аргумента массив параметров запроса: такие вещи, как нумерация страниц, столбец сортировки, порядок сортировки и поисковые фильтры. У него будут методы для общих задач, таких как вызов удаленного API, обработка ошибок и, возможно, преобразование результатов в HTML- <select> или jQueryUI AutoSuggest. Классы, которые создают экземпляр абстрактного класса, могут быть довольно короткими, возможно, делая немного больше, чем указывая строку для использования в URL-адресе конечной точки API *.json .

Скриншот игровой площадки Mailchimp API

Mailchimp публикует «игровую площадку» API для изолирования вызовов API и тому подобного. Он также действует как удобный способ просматривать всю иерархию данных их API, давая нам полезное представление о том, как мы могли бы структурировать нашу собственную иерархию классов.

Аналогично, что общего у следующих конечных точек?

  • https://api.example-email-service.com/v1/subscribers/104abyh4.json
  • https://api.example-email-service.com/v1/lists/837dy1h2.json
  • https://api.example-email-service.com/v1/campaigns/9i8udr43.json

Все они возвращают item , под которым я подразумеваю ровно одного конкретного уникального члена коллекции: такие вещи, как один конкретный подписчик электронной почты, один список адресов электронной почты или одна кампания по электронной почте. Поэтому мне нравится использовать следующую структуру в моем PHP-коде:

  • class.item.php , абстрактный класс
  • class.subscriber.php расширяет абстрактный класс Item .
  • class.list.php расширяет абстрактный класс Item .
  • class.campaign.php расширяет абстрактный класс Item .

Абстрактный класс будет принимать в качестве единственного аргумента строку, идентифицирующую конкретный запрашиваемый элемент. Опять же, создаваемые классы могут быть довольно короткими, возможно, делая немного больше, чем указывая строку для использования в */duy736td.json .

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

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

Идеальный вариант использования WP_Error

Мне стыдно признаться, что мне понадобилось на несколько лет больше, чем следовало бы, чтобы правильно начать использовать семейство функций WP_Error в моем коде. Я, как правило, просто кодировал свой путь, либо предполагая, что никогда не будет ошибок, о которых стоит заботиться программно, либо обрабатывая их в каждом конкретном случае. Работа с удаленными API прорезает этот менталитет, как лазерный луч, потому что представляет чрезвычайно удобный и мощный вариант использования WP_Error .

Вспомните ранее, что я упоминал, что у меня часто есть класс PHP, целью которого является выполнение HTTP-запросов к удаленному API. Когда вы отбрасываете весь шаблон, все манипуляции с данными, все второстепенные проблемы, этот класс действительно сводится к вызову wp_remote_request() , чтобы получить объект ответа HTTP от API. Удобно, что вместо этого wp_remote_request() вернет WP_Error , если вызов не будет выполнен по какой-либо причине, но что, если вызову удастся вернуть HTTP-ответ нежелательного типа?

Скриншот формы подписки

С технической точки зрения, вызов API работал , но не совсем без предостережений. Эти предостережения необходимо фиксировать и сообщать о них единым образом по всей кодовой базе.

Например, возможно, мы сделали вызов конечной точке /lists.json , но для этой конкретной учетной записи еще не настроены списки. Это вернет действительный ответ HTTP, но с кодом состояния 400. Хотя это не совсем фатальная ошибка сама по себе, с точки зрения некоторого внешнего кода, который хочет превратить этот вызов API в раскрывающееся меню, 400 может а также быть WSOD! Поэтому я считаю полезным выполнить дополнительный анализ результата wp_remote_request() , который в конце концов может вернуть WP_Error :

 <?php function call() { $response = wp_remote_request( $this -> url, $this -> args ); $code = wp_remote_retrieve_response_code( $response ); $first_digit = $code[0]; $good_responses = array( 2, 3 ); if( ! in_array( $first_digit, $good_responses ) { $body = wp_remote_retrieve_body( $response ); $out = new WP_Error( $code, $body ); } else { $out = $response; } return $out; } ?>

Этот шаблон может помочь упростить код, который вызывает наш вызывающий класс, потому что мы знаем, что можем безопасно полагаться на is_wp_error() , прежде чем продолжить наш вывод.

Как клиент, вы должны время от времени играть роль злонамеренного пользователя, сбитого с толку пользователя и нетерпеливого пользователя. Используйте приложение не по назначению. Делайте то, чего ваши разработчики не хотят, чтобы вы делали. Обратите внимание на то, что происходит. Получаете ли вы полезные сообщения об ошибках? Вы вообще получаете сообщения об ошибках? Если нет, возможно, стоит спонсировать работу над улучшением обработки ошибок.

Прекрасная отладочная мощь ob_get_clean()

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

Обычно удаленные HTTP-запросы являются наиболее трудоемкими частями загрузки данной страницы. По этой причине многие компоненты, управляемые API, выполняются либо через Ajax, либо через cron. Например, автоподсказка для поиска по списку подписчиков электронной почты, вероятно, должна пинговать удаленный источник данных по запросу при каждом нажатии клавиши, а не загружать все 100 000 подписчиков в DOM при загрузке страницы. Если это не вариант, возможно, большой запрос можно было бы синхронизировать с ночной задачей cron, чтобы результаты можно было получить с локального зеркала, а не с удаленного API.

Проблема с этим подходом в том, что его сложно отлаживать. Вместо того, чтобы просто включить WP_DEBUG и позволить сообщениям об ошибках появляться в окне вашего браузера, вы застреваете в сетевой консоли браузера или следите за файлом журнала во время выполнения задачи cron (надеюсь?). Я нахожу это неудобным.

Один из способов исправить эту ситуацию — сделать осторожные и стратегические вызовы error_log() . Но опять же, общая проблема с ведением журналов заключается в том, что в больших или загруженных приложениях журналы ошибок могут стать слишком большими или расти слишком быстро, чтобы их можно было использовать для мониторинга или синтаксического анализа. Следовательно, мы должны быть избирательны в отношении того, что мы регистрируем, уделяя этому столько же внимания, сколько и логике нашего приложения . Жаль, что вы потратили время на регистрацию какой-то экзотической пограничной ошибки, которая, кажется, возникает только периодически в какой-то нечастой задаче cron, только для того, чтобы понять, что истинная природа ошибки снова ускользнула от вас, потому что вы не смогли зарегистрировать какой-то конкретный элемент массива. скажем, оскорбительного значения.

Поэтому моя философия стала такой: я не всегда логирую, но когда делаю, то логирую все . Другими словами, после выявления особенно тревожной функции я регистрирую ее как можно более широкой сетью:

 <?php function debug( $bug ) { ob_start(); var_dump( $bug ); $out = ob_get_clean(); error_log( $out ); } ?>

Это равносильно тому, что var_dump() все значение ошибки в одну запись в файле журнала ошибок.

Скриншот файла журнала ошибок

Журнал ошибок стал слишком большим, чтобы его было удобно отлаживать.

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

Не совсем кликбейт, но сойдет

Пожалуйста, простите структуру списка этой статьи. Я не мог включить эти пункты в более унифицирующую тему статьи, потому что эти шаблоны очень общие: они применимы к любой конечной точке JSON REST и любому выводу WordPress .

Это шаблоны, которые я вижу снова и снова, независимо от того, что такое удаленный API или для чего мы его используем в WordPress. Я зашел так далеко, что собрал все эти виды принципов в шаблон плагина, который значительно ускоряет мою работу. Есть ли у вас схожие баллы, которые вы сохраняете за каждый проект? Пожалуйста, поделитесь ими, чтобы я мог украсть их и добавить в свой шаблон!

Связанный: Как подойти к современной разработке WordPress (часть 1)