Безголовый WordPress: взлеты и падения создания несвязанного WordPress
Опубликовано: 2022-03-10WordPress прошел долгий путь от своего начала как простой инструмент для написания блогов. Спустя долгие 15 лет она стала выбором CMS номер один как для разработчиков, так и для тех, кто не является разработчиком. В настоящее время WordPress поддерживает примерно 30% из 10 миллионов лучших сайтов в Интернете.
С тех пор, как REST API был включен в ядро WordPress, разработчики могут экспериментировать и использовать его независимо друг от друга, т. е. писать интерфейсную часть с помощью фреймворков или библиотек JavaScript. В Infinum мы использовали (и до сих пор) используем WordPress «классическим» способом: PHP как для интерфейса, так и для сервера. Через некоторое время мы захотели попробовать развязанный подход. В этой статье я поделюсь обзором того, чего мы хотели достичь и с чем столкнулись, пытаясь реализовать наши цели.
Есть несколько типов проектов, которые могут извлечь выгоду из этого подхода. Например, простые презентационные сайты или сайты, использующие WordPress в качестве бэкенда, являются основными кандидатами на использование развязанного подхода.
К счастью, в последние годы индустрия стала уделять больше внимания производительности. Тем не менее, будучи простым в использовании инклюзивным и универсальным программным обеспечением, WordPress поставляется с множеством опций, которые не обязательно используются в каждом проекте. В результате может пострадать производительность сайта.
Рекомендуемая литература : Как использовать тепловые карты для отслеживания кликов на вашем сайте WordPress
Если долгое время отклика веб-сайта не дает вам спать по ночам, это руководство для вас. Я расскажу об основах создания несвязанного WordPress и некоторых извлеченных уроках, в том числе:
- Значение «несвязанного WordPress»
- Работа с WordPress REST API по умолчанию
- Повышение производительности с помощью развязанного подхода JSON
- Вопросы безопасности
Итак, что же такое несвязанный WordPress?
Когда дело доходит до того, как программируется WordPress, одно можно сказать наверняка: он не следует шаблону проектирования Model- View -Controller (MVC), знакомому многим разработчикам. Из-за своей истории и того, что она является своего рода ответвлением старой платформы для ведения блогов под названием «b2» (подробнее здесь), она в значительной степени написана процедурным способом (с использованием кода, основанного на функциях). Разработчики ядра WordPress использовали систему хуков, которые позволяли другим разработчикам изменять или расширять определенные функции.
Это комплексная система с рабочим интерфейсом администратора; он управляет подключением к базе данных и имеет множество полезных API-интерфейсов, которые обрабатывают аутентификацию пользователей, маршрутизацию и многое другое.
Но благодаря REST API вы можете разделить серверную часть WordPress как своего рода модель и контроллер, связанные вместе, которые обрабатывают данные и взаимодействие с базой данных, и использовать REST API Controller для взаимодействия с отдельным уровнем представления с использованием различных конечных точек API. В дополнение к разделению MVC мы можем (по соображениям безопасности или повышения скорости) разместить JS-приложение на отдельном сервере, как показано на схеме ниже:
Преимущества использования развязанного подхода
Одна из причин, по которой вы можете захотеть использовать этот подход, — обеспечить разделение задач. Фронтенд и бэкэнд взаимодействуют через конечные точки; каждый из них может находиться на своем отдельном сервере, который можно оптимизировать специально для каждой соответствующей задачи, т. е. отдельно запускать приложение PHP и запускать приложение Node.js.
Отделив ваш интерфейс от бэкэнда, вам будет проще переделывать его в будущем, не меняя CMS. Кроме того, разработчикам внешнего интерфейса нужно заботиться только о том, что делать с данными, которые им предоставляет серверная часть. Это позволяет им проявлять творческий подход и использовать современные библиотеки, такие как ReactJS, Vue или Angular, для разработки высокодинамичных веб-приложений. Например, при использовании вышеупомянутых библиотек проще создать прогрессивное веб-приложение.
Еще одно преимущество отражается в безопасности сайта. Использование веб-сайта через серверную часть становится более сложным, поскольку оно в значительной степени скрыто от общественности.
Рекомендуемая литература : Безопасность WordPress как процесс
Недостатки использования развязанного подхода
Во-первых, наличие несвязанного WordPress означает поддержку двух отдельных экземпляров:
- WordPress для серверной части;
- Отдельное внешнее приложение, включая своевременные обновления безопасности.
Во-вторых, у некоторых интерфейсных библиотек более крутая кривая обучения. Изучение нового языка займет либо много времени (если вы привыкли только к HTML и CSS для создания шаблонов), либо потребуется привлечение к проекту дополнительных экспертов по JavaScript.
В-третьих, отделяя интерфейс, вы теряете мощь WYSIWYG-редактора, а кнопка «Live Preview» в WordPress тоже не работает.
Работа с REST API WordPress
Прежде чем мы углубимся в код, еще пара слов о WordPress REST API. Полная мощь REST API в WordPress появилась в версии 4.7 от 6 декабря 2016 года.
Что позволяет WordPress REST API, так это удаленно взаимодействовать с вашей установкой WordPress, отправляя и получая объекты JSON.
Настройка проекта
Поскольку он поставляется вместе с последней установкой WordPress, мы будем работать над темой Twenty Seventeen. Я работаю над Variing Vagrant Vagrants и создал тестовый сайт с URL-адресом https://dev.wordpress.test/
. Этот URL будет использоваться на протяжении всей статьи. Мы также будем импортировать сообщения из репозитория Wordpress.org Theme Review Teams, чтобы у нас были некоторые тестовые данные для работы. Но сначала мы познакомимся с конечными точками по умолчанию, а затем создадим собственную пользовательскую конечную точку.
Доступ к конечной точке REST по умолчанию
Как уже упоминалось, WordPress поставляется с несколькими встроенными конечными точками, которые вы можете изучить, перейдя по маршруту /wp-json/
:
https://dev.wordpress.test/wp-json/
Либо поместив этот URL-адрес непосредственно в браузер, либо добавив его в приложение почтальона, вы получите ответ JSON от WordPress REST API, который выглядит примерно так:
{ "name": "Test dev site", "description": "Just another WordPress site", "url": "https://dev.wordpress.test", "home": "https://dev.wordpress.test", "gmt_offset": "0", "timezone_string": "", "namespaces": [ "oembed/1.0", "wp/v2" ], "authentication": [], "routes": { "/": { "namespace": "", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/" } }, "/oembed/1.0": { "namespace": "oembed/1.0", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "namespace": { "required": false, "default": "oembed/1.0" }, "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/oembed/1.0" } }, ... "wp/v2": { ...
Таким образом, чтобы получить все сообщения на нашем сайте с помощью REST, нам нужно перейти по https://dev.wordpress.test/wp-json/wp/v2/posts
. Обратите внимание, что wp/v2/
помечает зарезервированные основные конечные точки, такие как сообщения, страницы, медиа, таксономии, категории и т. д.
Итак, как нам добавить пользовательскую конечную точку?
Создайте пользовательскую конечную точку REST
Допустим, мы хотим добавить новую конечную точку или дополнительное поле к существующей конечной точке. Есть несколько способов сделать это. Во-первых, это можно сделать автоматически при создании пользовательского типа записи. Например, мы хотим создать конечную точку документации. Давайте создадим небольшой тестовый плагин. Создайте папку test-documentation в папке wp-content/plugins и добавьте файл document.php , который выглядит следующим образом:
<?php /** * Test plugin * * @since 1.0.0 * @package test_plugin * * @wordpress-plugin * Plugin Name: Test Documentation Plugin * Plugin URI: * Description: The test plugin that adds rest functionality * Version: 1.0.0 * Author: Infinum <[email protected]> * Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: test-plugin */ namespace Test_Plugin; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } /** * Class that holds all the necessary functionality for the * documentation custom post type * * @since 1.0.0 */ class Documentation { /** * The custom post type slug * * @var string * * @since 1.0.0 */ const PLUGIN_NAME = 'documentation-plugin'; /** * The custom post type slug * * @var string * * @since 1.0.0 */ const POST_TYPE_SLUG = 'documentation'; /** * The custom taxonomy type slug * * @var string * * @since 1.0.0 */ const TAXONOMY_SLUG = 'documentation-category'; /** * Register custom post type * * @since 1.0.0 */ public function register_post_type() { $args = array( 'label' => esc_html( 'Documentation', 'test-plugin' ), 'public' => true, 'menu_position' => 47, 'menu_icon' => 'dashicons-book', 'supports' => array( 'title', 'editor', 'revisions', 'thumbnail' ), 'has_archive' => false, 'show_in_rest' => true, 'publicly_queryable' => false, ); register_post_type( self::POST_TYPE_SLUG, $args ); } /** * Register custom tag taxonomy * * @since 1.0.0 */ public function register_taxonomy() { $args = array( 'hierarchical' => false, 'label' => esc_html( 'Documentation tags', 'test-plugin' ), 'show_ui' => true, 'show_admin_column' => true, 'update_count_callback' => '_update_post_term_count', 'show_in_rest' => true, 'query_var' => true, ); register_taxonomy( self::TAXONOMY_SLUG, [ self::POST_TYPE_SLUG ], $args ); } } $documentation = new Documentation(); add_action( 'init', [ $documentation, 'register_post_type' ] ); add_action( 'init', [ $documentation, 'register_taxonomy' ] );
Зарегистрировав новый тип записи и таксономию, а также установив для аргумента show_in_rest
значение true
, WordPress автоматически создал маршрут REST в пространстве имен /wp/v2/
. Теперь у вас есть https://dev.wordpress.test/wp-json/wp/v2/documentation
и https://dev.wordpress.test/wp-json/wp/v2/documentation-category
конечные точки. Если мы добавим запись в нашу недавно созданную пользовательскую запись документации, идущую по https://dev.wordpress.test/?post_type=documentation
, она даст нам ответ, который выглядит следующим образом:
[ { "id": 4, "date": "2018-06-11T19:48:51", "date_gmt": "2018-06-11T19:48:51", "guid": { "rendered": "https://dev.wordpress.test/?post_type=documentation&p=4" }, "modified": "2018-06-11T19:48:51", "modified_gmt": "2018-06-11T19:48:51", "slug": "test-documentation", "status": "publish", "type": "documentation", "link": "https://dev.wordpress.test/documentation/test-documentation/", "title": { "rendered": "Test documentation" }, "content": { "rendered": "
Это часть документации
\п", "защищено": ложь }, "избранное_медиа": 0, "шаблон": "", "категория документации": [ 2 ], "_ссылки": { "себя": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4" } ], "коллекция": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation" } ], "о": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/types/documentation" } ], "история версий": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4/revisions" } ], "ВП: вложение": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/media?parent=4" } ], "ВП: срок": [ { "таксономия": "категория документации", «встраиваемый»: правда, "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation-category?post=4" } ], "любопытство": [ { "имя": "вп", "href": "https://api.w.org/{rel}", "шаблон": правда } ] } } ]
Это отличная отправная точка для нашего одностраничного приложения. Другой способ добавить пользовательскую конечную точку — подключиться к rest_api_init
и создать конечную точку самостоятельно. Давайте добавим маршрут custom-documentation
, который немного отличается от того, который мы зарегистрировали. Все еще работая в том же плагине, мы можем добавить:
/** * Create a custom endpoint * * @since 1.0.0 */ public function create_custom_documentation_endpoint() { register_rest_route( self::PLUGIN_NAME . '/v1', '/custom-documentation', array( 'methods' => 'GET', 'callback' => [ $this, 'get_custom_documentation' ], ) ); } /** * Create a callback for the custom documentation endpoint * * @return string JSON that indicates success/failure of the update, * or JSON that indicates an error occurred. * @since 1.0.0 */ public function get_custom_documentation() { /* Some permission checks can be added here. */ // Return only documentation name and tag name. $doc_args = array( 'post_type' => self::POST_TYPE_SLUG, 'post_status' => 'publish', 'perm' => 'readable' ); $query = new \WP_Query( $doc_args ); $response = []; $counter = 0; // The Loop if ( $query->have_posts() ) { while ( $query->have_posts() ) { $query->the_post(); $post_id = get_the_ID(); $post_tags = get_the_terms( $post_id, self::TAXONOMY_SLUG ); $response[ $counter ]['title'] = get_the_title(); foreach ( $post_tags as $tags_key => $tags_value ) { $response[ $counter ]['tags'][] = $tags_value->name; } $counter++; } } else { $response = esc_html__( 'There are no posts.', 'documentation-plugin' ); } /* Restore original Post Data */ wp_reset_postdata(); return rest_ensure_response( $response ); }
И подключите метод create_custom_documentation_endpoint()
к rest_api_init
, например:
add_action( 'rest_api_init', [ $documentation, 'create_custom_documentation_endpoint' ] );
Это добавит пользовательский маршрут в https://dev.wordpress.test/wp-json/documentation-plugin/v1/custom-documentation
с обратным вызовом, возвращающим ответ для этого маршрута.
[{ "title": "Another test documentation", "tags": ["Another tag"] }, { "title": "Test documentation", "tags": ["REST API", "test tag"] }]
Есть много других вещей, которые вы можете делать с REST API (более подробную информацию вы можете найти в руководстве по REST API).
Как обойти длительное время отклика при использовании REST API по умолчанию
Для тех, кто пытался создать несвязанный сайт WordPress, это не новость — REST API работает медленно.
Моя команда и я впервые столкнулись со странным отставанием REST API от WordPress на клиентском сайте (не разделенном), где мы использовали настраиваемые конечные точки для получения списка местоположений на карте Google вместе с другой метаинформацией, созданной с помощью Advanced Custom Fields Pro . плагин. Выяснилось, что время первого байта (TTFB) — который используется как показатель отзывчивости веб-сервера или другого сетевого ресурса — заняло более 3 секунд.
После небольшого исследования мы поняли, что вызовы REST API по умолчанию на самом деле очень медленные, особенно когда мы «загрузили» сайт дополнительными плагинами. Итак, мы провели небольшой тест. Мы установили несколько популярных плагинов и получили интересные результаты. Приложение postman дало время загрузки 1,97 с для размера ответа 41,9 КБ. Время загрузки Chrome составило 1,25 с (TTFB — 1,25 с, контент был загружен за 3,96 мс). Просто для получения простого списка сообщений. Никакой таксономии, никаких пользовательских данных, никаких дополнительных метаполей.
Почему это случилось?
Оказывается, доступ к REST API в WordPress по умолчанию загрузит все ядро WordPress для обслуживания конечных точек, даже если оно не используется. Кроме того, чем больше плагинов вы добавляете, тем хуже становится. Контроллер REST по умолчанию WP_REST_Controller
— это действительно большой класс, который делает гораздо больше, чем необходимо при создании простой веб-страницы. Он обрабатывает регистрацию маршрутов, проверку разрешений, создание и удаление элементов и так далее.
Есть два распространенных решения этой проблемы:
- Перехватывать загрузку плагинов и предотвращать загрузку их всех, когда вам нужно обработать простой ответ REST;
- Загрузите только самый минимум WordPress и сохраните данные во временном файле, из которого мы затем извлекаем данные с помощью пользовательской страницы.
Повышение производительности с помощью подхода с развязкой JSON
Когда вы работаете с простыми презентационными сайтами, вам не нужны все функции, которые предлагает вам REST API. Конечно, здесь важно хорошее планирование. Вы действительно не хотите создавать свой сайт без REST API, а затем через несколько лет сказать, что хотели бы подключиться к своему сайту или, возможно, создать мобильное приложение, которое должно использовать функциональность REST API. Ты?
По этой причине мы использовали две функции WordPress, которые могут помочь вам при выводе простых данных JSON:
- Transients API для кэширования,
- Загрузка минимально необходимого WordPress с помощью константы
SHORTINIT
.
Создание простой конечной точки несвязанных страниц
Давайте создадим небольшой плагин, который продемонстрирует эффект, о котором мы говорим. Во-первых, добавьте файл wp-config-simple.php в свой плагин json-transient
, который выглядит следующим образом:
<?php /** * Create simple wp configuration for the routes * * @since 1.0.0 * @package json-transient */ define( 'SHORTINIT', true ); $parse_uri = explode( 'wp-content', $_SERVER['SCRIPT_FILENAME'] ); require_once filter_var( $parse_uri[0] . 'wp-load.php', FILTER_SANITIZE_STRING );
define( 'SHORTINIT', true );
предотвратит загрузку большинства основных файлов WordPress, как видно из файла wp-settings.php .
Нам по-прежнему могут понадобиться некоторые функции WordPress, поэтому мы можем запросить файл (например, wp-load.php ) вручную. Поскольку wp-load.php находится в корне нашей установки WordPress, мы получим его, получив путь к нашему файлу, используя $_SERVER['SCRIPT_FILENAME']
, а затем взорвав эту строку с помощью строки wp-content
. Это вернет массив с двумя значениями:
- Корень нашей установки;
- Остальной путь к файлу (который нас не интересует).
Имейте в виду, что мы используем установку WordPress по умолчанию, а не модифицированную, как, например, в шаблоне Bedrock, который разделяет WordPress на другую файловую организацию.
Наконец, для безопасности нам потребуется файл wp-load.php с небольшой очисткой.
В наш файл init.php мы добавим следующее:
* Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: json-transient */ namespace Json_Transient; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } class Init { /** * Get the array of allowed types to do operations on. * * @return array * * @since 1.0.0 */ public function get_allowed_post_types() { return array( 'post', 'page' ); } /** * Check if post type is allowed to be save in transient. * * @param string $post_type Get post type. * @return boolean * * @since 1.0.0 */ public function is_post_type_allowed_to_save( $post_type = null ) { if( ! $post_type ) { return false; } $allowed_types = $this->get_allowed_post_types(); if ( in_array( $post_type, $allowed_types, true ) ) { return true; } return false; } /** * Get Page cache name for transient by post slug and type. * * @param string $post_slug Page Slug to save. * @param string $post_type Page Type to save. * @return string * * @since 1.0.0 */ public function get_page_cache_name_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $post_slug = str_replace( '__trashed', '', $post_slug ); return 'jt_data_' . $post_type . '_' . $post_slug; } /** * Get full post data by post slug and type. * * @param string $post_slug Page Slug to do Query by. * @param string $post_type Page Type to do Query by. * @return array * * @since 1.0.0 */ public function get_page_data_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $page_output = ''; $args = array( 'name' => $post_slug, 'post_type' => $post_type, 'posts_per_page' => 1, 'no_found_rows' => true ); $the_query = new \WP_Query( $args ); if ( $the_query->have_posts() ) { while ( $the_query->have_posts() ) { $the_query->the_post(); $page_output = $the_query->post; } wp_reset_postdata(); } return $page_output; } /** * Return Page in JSON format * * @param string $post_slug Page Slug. * @param string $post_type Page Type. * @return json * * @since 1.0.0 */ public function get_json_page( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } return wp_json_encode( $this->get_page_data_by_slug( $post_slug, $post_type ) ); } /** * Update Page to transient for caching on action hooks save_post. * * @param int $post_id Saved Post ID provided by action hook. * * @since 1.0.0 */ public function update_page_transient( $post_id ) { $post_status = get_post_status( $post_id ); $post = get_post( $post_id ); $post_slug = $post->post_name; $post_type = $post->post_type; $cache_name = $this->get_page_cache_name_by_slug( $post_slug, $post_type ); if( ! $cache_name ) { return false; } if( $post_status === 'auto-draft' || $post_status === 'inherit' ) { return false; } else if( $post_status === 'trash' ) { delete_transient( $cache_name ); } else { if( $this->is_post_type_allowed_to_save( $post_type ) ) { $cache = $this->get_json_page( $post_slug, $post_type ); set_transient( $cache_name, $cache, 0 ); } } } } $init = new Init(); add_action( 'save_post', [ $init, 'update_page_transient' ] );
Вспомогательные методы в приведенном выше коде позволят нам немного кэшировать:
-
get_allowed_post_types()
Этот метод позволяет типам сообщений знать, что мы хотим включить отображение в нашей пользовательской «конечной точке». Вы можете расширить это, и в плагине мы фактически сделали этот метод фильтруемым, так что вы можете просто использовать фильтр для добавления дополнительных элементов. -
is_post_type_allowed_to_save()
Этот метод просто проверяет, находится ли тип записи, из которого мы пытаемся получить данные, в разрешенный массив, указанный предыдущим методом. -
get_page_cache_name_by_slug()
Этот метод вернет имя переходного процесса, из которого будут извлечены данные. -
get_page_data_by_slug()
Этот метод — это метод, который будет выполнятьWP_Query
для сообщения через его слаг и тип сообщения и возвращать содержимое массива сообщений, которое мы преобразуем с помощью JSON, используя методget_json_page()
. -
update_page_transient()
Это будет запущено наsave_post
и перезапишет переходный процесс в базе данных данными JSON нашего сообщения. Этот последний метод известен как «метод кэширования ключей».
Давайте объясним переходные процессы более подробно.
API переходов
Transients API используется для хранения данных в таблице параметров вашей базы данных WordPress в течение определенного периода времени. Это постоянный объектный кеш, означающий, что вы сохраняете какой-то объект, например, результаты больших и медленных запросов или полные страницы, которые могут сохраняться при загрузке страниц. Он похож на обычный кеш объектов WordPress, но, в отличие от WP_Cache
, переходные процессы будут сохранять данные при загрузке страницы, где WP_Cache
(хранящий данные в памяти) будет хранить данные только на время запроса.
Это хранилище ключей и значений, что означает, что мы можем легко и быстро извлекать нужные данные, подобно тому, как это делают in-memory caching systems
такие как Memcached или Redis. Разница в том, что вам обычно нужно устанавливать их отдельно на сервер (что может быть проблемой на общих серверах), тогда как переходные процессы встроены в WordPress.
Как указано на его странице Кодекса, переходные процессы по своей природе ускоряются за счет кэширующих плагинов. Так как они могут хранить переходные процессы в памяти, а не в базе данных. Общее правило заключается в том, что вы не должны предполагать, что переходный процесс всегда присутствует в базе данных, поэтому рекомендуется проверять его существование перед его извлечением.
$transient_name = get_transient( 'transient_name' ); if ( $transient_name === false ) { set_transient( 'transient_name', $transient_data, $transient_expiry ); }
Вы можете использовать его без истечения срока действия (как мы это делаем), и именно поэтому мы внедрили своего рода «очистку кеша» при последующем сохранении. В дополнение ко всем замечательным функциям, которые они предоставляют, они могут хранить до 4 ГБ данных, но мы не рекомендуем хранить что-либо настолько большое в одном поле базы данных.
Рекомендуемая литература : Будьте бдительны: функции PHP и WordPress, которые могут сделать ваш сайт небезопасным
Окончательная конечная точка: тестирование и проверка
Последняя часть головоломки, которая нам нужна, — это «конечная точка». Я использую здесь термин «конечная точка», хотя это не конечная точка, поскольку мы напрямую вызываем определенный файл для получения наших результатов. Итак, мы можем создать файл test.php , который выглядит так:
get_page_cache_name_by_slug( $post_slug, $post_type ) ); // Return error on false. if ( $cache === false ) { wp_send_json( 'Error, the page does not exist or it is not cached correctly. Please try rebuilding cache and try again!' ); } // Decode json for output. wp_send_json( json_decode( $cache ) );
Если мы перейдем на https://dev.wordpress.test/wp-content/plugins/json-transient/test.php
, мы увидим это сообщение:
Ошибка, слаг страницы или тип отсутствует!
Итак, нам нужно указать тип сообщения и слаг сообщения. Теперь, когда мы перейдем к https://dev.wordpress.test/wp-content/plugins/json-transient/test.php?slug=hello-world&type=post
, мы увидим:
Ошибка, страница не существует или неправильно кешируется. Пожалуйста, попробуйте восстановить кэш и повторите попытку!
О, подождите! Сначала нам нужно пересохранить наши страницы и сообщения. Поэтому, когда вы начинаете, это может быть легко. Но если у вас уже есть более 100 страниц или постов, это может оказаться непростой задачей. Вот почему мы реализовали способ очистки переходных процессов в плагине Decoupled JSON Content и перестроили их в пакетном режиме.
Но продолжайте и повторно сохраните сообщение Hello World , а затем снова откройте ссылку. Теперь у вас должно получиться что-то вроде этого:
{ "ID": 1, "post_author": "1", "post_date": "2018-06-26 18:28:57", "post_date_gmt": "2018-06-26 18:28:57", "post_content": "Welcome to WordPress. This is your first post. Edit or delete it, then start writing!", "post_title": "Hello world!", "post_excerpt": "", "post_status": "publish", "comment_status": "open", "ping_status": "open", "post_password": "", "post_name": "hello-world", "to_ping": "", "pinged": "", "post_modified": "2018-06-30 08:34:52", "post_modified_gmt": "2018-06-30 08:34:52", "post_content_filtered": "", "post_parent": 0, "guid": "http:\/\/dev.wordpress.test\/?p=1", "menu_order": 0, "post_type": "post", "post_mime_type": "", "comment_count": "1", "filter": "raw" }
Вот и все. Плагин, который мы сделали, имеет еще несколько дополнительных функций, которые вы можете использовать, но в двух словах, это то, как вы можете получать данные JSON из вашего WordPress, что намного быстрее, чем с помощью REST API.
До и после: улучшенное время отклика
Мы проводили тестирование в Chrome, где можно было увидеть общее время отклика и TTFB отдельно. Мы протестировали время отклика десять раз подряд: сначала без плагинов, а затем с добавленными плагинами. Кроме того, мы протестировали ответ для списка сообщений и для одного сообщения.
Результаты теста представлены в таблицах ниже:
Как видите, разница кардинальная.
Вопросы безопасности
Есть несколько предостережений, на которые вам нужно обратить внимание. Прежде всего, мы вручную загружаем основные файлы WordPress, что в мире WordPress является большим запретом. Почему? Что ж, помимо того факта, что получение основных файлов вручную может быть сложным (особенно если вы используете нестандартные установки, такие как Bedrock), это может создать некоторые проблемы с безопасностью.
Если вы решите использовать метод, описанный в этой статье, убедитесь, что вы знаете, как повысить безопасность своего сервера.
Сначала добавьте заголовки HTML, как в файле test.php :
header( 'Access-Control-Allow-Origin: your-front-end-app.url' ); header( 'Content-Type: application/json' );
Первый заголовок — это способ обойти меру безопасности CORS, чтобы только ваше внешнее приложение могло извлекать содержимое при переходе к указанному файлу.
Во-вторых, отключите обход каталогов вашего приложения. Вы можете сделать это, изменив настройки nginx
или добавив Options -Indexes
в свой файл .htaccess , если вы используете сервер Apache.
Добавление проверки токена в ответ также является хорошей мерой, которая может предотвратить нежелательный доступ. На самом деле мы работаем над тем, чтобы изменить наш плагин Decoupled JSON, чтобы мы могли включать эти меры безопасности по умолчанию.
Проверка заголовка авторизации, отправленного внешним приложением, может выглядеть так:
if ( ! isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) { return; } $auth_header = $_SERVER['HTTP_AUTHORIZATION'];
Затем вы можете проверить, предоставлен ли конкретный токен (секрет, который используется только интерфейсными и внутренними приложениями) и правильный.
Заключение
REST API великолепен, потому что его можно использовать для создания полноценных приложений — создания, извлечения, обновления и удаления данных. Недостатком его использования является его скорость.
Очевидно, что создание приложения отличается от создания классического веб-сайта. Вам, вероятно, не понадобятся все плагины, которые мы установили. Но если вам просто нужны данные для презентационных целей, кэширование данных и предоставление их в пользовательском файле кажется идеальным решением на данный момент при работе с несвязанными сайтами.
Вы можете подумать, что создание собственного плагина для ускорения времени отклика веб-сайта — это излишество, но мы живем в мире, в котором каждая секунда на счету. Всем известно, что если сайт работает медленно, пользователи его покинут. Существует множество исследований, демонстрирующих связь между производительностью веб-сайта и показателями конверсии. Но если вам все же нужно убедить, Google наказывает медленные сайты.
Метод, описанный в этой статье, решает проблему скорости, с которой сталкивается WordPress REST API, и даст вам дополнительный импульс при работе над отдельным проектом WordPress. Поскольку мы находимся в бесконечном стремлении выжать последнюю миллисекунду из каждого запроса и ответа, мы планируем еще больше оптимизировать плагин. А пока, пожалуйста, поделитесь своими идеями по ускорению несвязанного WordPress!