Як завантажується ядро WordPress
При роботі з темами, плагінами та взагалі з будь-яким кодом WordPress, включаючи хакі у популярному файлі теми functions.php . Добре було б знати, у якій послідовності підключаються php файли движка, коли спрацьовують важливі хуки і які важливі константи визначені. У цій статті поговоримо про таку послідовність завантаження.
Приклади
Щоб було зрозуміліше, візьмемо просте завдання: нам потрібно підключити якийсь код до адмін-панелі WordPress і тільки там – код не повинен спрацьовувати у фронті або при AJAX запитах. Хтось скаже, що достатньо зробити перевірку за допомогою is_admin() , проте це не так, тому що is_admin() поверне true і за запитом AJAX у файл admin-ajax.php .
Або, наприклад, можна підключити якусь логіку на хук admin_init і потім довго дивуватися, а чому моя логіка працює і при запитах AJAX. Або чому вона заважає плагінам, які працюють з AJAX…
Або init . Наприклад, ви створили тип запису під час хука init і в самому файлі functions.php виконуєте перевірку, яка спирається на цей новий тип запису та очікуєте, що код буде працювати, але це не так, тому що прямий код у functions.php спрацьовує раніше ніж подія init …
Таких прикладів можна навести багато. Але щоб не помилятися, потрібно розібратися і зрозуміти послідовність завантаження ядра WordPress. Цим ми й займемося.
Порядок завантаження (теорія)
Зрозуміти логіку завантаження не так складно, як здається на перший погляд. Для цього давайте поглянемо на цю, таку улюблену мною картинку:
Існує 4 варіанти завантаження . Насправді їх трохи більше, але це є основними:
- Завантаження Фронтенду (теми).
- Завантажити запит REST.
- Завантаження Адмінки.
- Завантажити AJAX запит (admin-ajax.php).
У всіх випадках завантажується ядро WordPress – файл wp-load.php . Ядро завантажується завжди та скрізь!
Перш ніж переходити до кожного типу завантаження, потрібно розібратися, як завантажується саме ядро.
Завантаження ядра WordPress
Ядро WP завантажується за будь-якого запиту: фронт, аякс, адмінка, REST …
wp-load.php wp-config.php wp-settings.php // Функції завантаження (load): wp_debug_mode(), timer_start(), require_wp_db() ... // Функції констант: wp_initial_constants(), wp_cookie_constants() ... // Функції плагінів (хуки, активація): do_action(), plugin_dir_url(), register_activation_hook(). // Встановлюються константи: WP_START_TIMESTAMP, WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT, WP_DEBUG, SCRIPT_DEBUG, WP_CONTENT_DIR, WP_CACHE. // Стандартизуються змінні сервера: wp_fix_server_vars(). // Перевіряється режим розробки: wp_maintenance(). // Включається таймер (швидкість завантаження): timer_start(). // Включається режим дебаг: wp_debug_mode(). // Завантажується 'wp-content/advanced-cache.php' якщо він є та включено WP_CACHE. // База даних. $wpdb. require_wp_db(). // Завантажується 'wp-content/db.php' якщо є та створюється // з'єднання з БД і пов'язані змінні (префікс БД...). // Об'єктний кеш: 'wp-content/object-cache.php' якщо є, або 'wp-include/cache.php'. // Підключаються базові хуки (фільтри): default-filters.php. // Включається Multisite (якщо потрібно) // Завантажується 'wp-content/sunrise.php' якщо є (тільки для multisite). // register_shutdown_function( 'shutdown_action_hook' ) // SHORTINIT: зупинка завантаження, де є лише базове. if( SHORTINIT ) return false; // Підключаються функції локалізації. // Чи перевіряється чи встановлено WP: wp_not_installed(). // Підключається купа файлів із іншими функціями WordPress. // Підключається Must-use плагіни та спрацьовує подію: do_action( 'muplugins_loaded'); // Константи cookie, ssl: COOKIEPATH, COOKIE_DOMAIN // Загальні глобальні змінні: $pagenow, $is_apache, $is_nginx, $is_lynx // Глоб. змінні клієнта: $is_opera, $is_NS4, $is_safari, $is_chrome, $is_iphone, $is_IE, $is_edge // Підключаються активні плагіни. // Підключаються функції pluggable: pluggable.php. // Спрацьовує do_action( 'plugins_loaded'); // Примусове екранування значень $_POST, $_REQUEST ... див. wp_magic_quotes() . // Глобальні змінні: // $wp_the_query - new WP_Query() // $wp_query - $wp_the_query // $wp_rewrite - new WP_Rewrite() - константи, функції та правила ЧПУ. // $wp - new WP () - Запит WP (запускається пізніше). // $wp_widget_factory - new WP_Widget_Factory() // $wp_roles - new WP_Roles() // Поточна тема do_action( 'setup_theme'); // functions.php (child) - спочатку підключається functions.php дочірньої теми // functions.php (parent) - потім підключається functions.php основної теми // Файл перекладу WordPress: load_default_textdomain() do_action( 'after_setup_theme'); // перший хук доступний у темі // Встановлюється поточний користувач (створюється об'єкт). // Див. wp_get_current_user() // Користувач часто вже визначений після події 'plugins_loaded' плагінами. $wp->init(); // init подія. Коли середовище WP, плагіни та тема активовані, // Але екран ще нічого не виведено: do_action('init'); // Реєстрація віджетів: подія 'widget_init' // Перевірка статусу сайту для мультисайтового складання. // Сайт може бути видалений, неактивний, в архіві. ms_site_check() // Якщо сайт не пройшов перевірку, викликається drop файл і PHP переривається через die(). // Теж саме що init тільки після перевірки статусу. // До цього рядка робота PHP може не дійти. Наприклад, при REST запиті. do_action( 'wp_loaded');
Під час завантаження ядра завжди підключаються файл теми functions.php навіть у адмінці. Тобто. не важливо, чи потрібна нам тема чи ні, functions.php працює і тому його можна поставити в один ряд з плагінами… Зроблено так для зручності, щоб будь-який код можна було «сунути» в наш, тому й улюблений файл functions.php . Така поведінка не є логічною з точки зору програмування, але дуже зручною з точки зору розробки.
Ядро, як ми бачимо, знаходиться у файлі встановленні WordPress .
Після того, як знайдено файл конфігурації, він підключається. У ньому вказуються всі важливі константи, параметри підключення базі даних тощо. І потім підключається ядро-файл wp-settings.php .
Завантаження Фронт-енду (теми)
Будь-які Фронтенд запити надсилаються у файл index.php у кореневій папці домену. Це означає, що WordPress завантажується із темою. Для констатації цього факту в index.php визначається константа WP_USE_THEMES . Так наприклад, хук template-loader.php буде працювати тільки, якщо визначена ця константа.
Процес завантаження Фронту виглядає так:
index.php // визначається константа WP_USE_THEMES wp-blog-header.php // ЯДРО (описано вище) require_once dirname(__FILE__) . '/wp-load.php'; // Встановлення основного запиту WordPress. // Робить запит та визначає яка сторінка завантажується. // Див. https://wp-doc.com/function/wp wp(); // Див WP::main() // Підключення потрібного файлу шаблону теми 'template-loader.php' require_once ABSPATH. WPINC. '/template-loader.php';
- Докладніше про встановлення основного запиту та середовище WP читайте в описі функції wp() .
- Логіку роботи файлу Ієрархія шаблону .
Завантажити запит REST
REST запит на 90% обробляється як і запит для фронтенда. Його також починає обробляти файл index.php . Через правила перезапису (ЧПУ) встановлюється параметр запиту rest_route=маршрут
.
^wp-json/?$ => index.php?rest_route=/ ^wp-json/(.*)? => index.php?rest_route=/$matches[1]
Процес завантаження REST запиту виглядає так:
index.php // визначається константа WP_USE_THEMES wp-blog-header.php // ЯДРО (описано тут https://wp-doc.com/handbook/wordpress/loading#wpcore-load) require_once dirname(__FILE__) . '/wp-load.php'; // У процесі завантаження ядра створюється хук parse_request // який спрацьовує у функції `wp()` add_action( 'parse_request', 'rest_api_loaded'); // Встановлення основного запиту WordPress. // Робить запит та визначає яка сторінка завантажується. // У момент спрацьовування хука parse_request управління передається // Функції rest_api_loaded(), яка перериває PHP через die. // Див. https://wp-doc.com/function/wp wp(); // Див WP::main()
Пояснення до роботи wp() та хуку parse_request
Функція WP::main() , робить наступні дії по порядку:
- Викликає WP::init() .
Цей метод визначає поточного користувача для звичайних (не REST) запитів. див. wp_get_current_user() .
Пізніше (якщо це REST запит), на хуку аутентифікації rest_authentication_errors авторизований користувач буде обнулений при неправильному коді nonce. Дивіться:
- Викликає WP::parse_request() .
Цей метод визначає параметри поточного запиту $wp->query_vars .
- Запуск REST – rest_api_loaded() .
В кінці WP::parse_request() спрацьовує хук rest_api_loaded() :
add_action( 'parse_request', 'rest_api_loaded');
rest_api_loaded() перевіряє параметр запиту
$GLOBALS['wp']->query_vars['rest_route']
. Якщо це запит REST, то запускається логіка REST (логіка обробки запитів для звичайних сторінок тут закінчується).- Встановлюється константа
define( 'REST_REQUEST', true )
. - Запускається сервер REST rest_get_server() .
При запуску спрацьовує хук rest_api_init . На ньому до наявного сервера додаються свої маршрути.
- Обробляється запит REST WP_REST_Server::serve_request( $route ) .
При обробці запиту перевіряється доступність поточного маршруту, маршрут обробляється, повертається відповідь сервера REST у вигляді об’єкта WP_REST_Response .
При обробці запиту спрацьовують наступні корисні хуки (у вказаному порядку):
- Робота PHP переривається через die() .
- Встановлюється константа
Таким чином
За обробку запиту REST відповідає функція rest_api_loaded() .
REST запит виглядає так само як звичайний фронтенд запит. До моменту встановлення основного запиту WordPress функцією wp() . У ній як і в стандартному фронтенд запиті встановлюється поточний користувач. Але:
- Не встановлюються заголовки WP::send_headers() .
- НЕ відбувається основний запит WP::query_posts() .
- НЕ обробляється 404 сторінка WP::handle_404() .
- НЕ викликається файл template-loader.php , який визначає шаблон сторінки.
- НЕ працює хук редиректів template_redirect .
Заголовки REST відповіді ставить REST сервер, також він робить відповідний запит у БД або будь-що ще.
Завантаження Адмінки
Адмінка WordPress не пов’язана з «кореневим» файлом index.php . Все її завантаження починається з файлу wp-admin/admin.php .
Перше і головне, що там відбувається – це визначається константа WP_ADMIN , яка говорить всьому коду, який виконується потім, що ми знаходиться в адмінці.
wp-admin/admin.php // визначається константа WP_ADMIN define( 'WP_ADMIN', true ); // ЯДРО (описано вище) require_once dirname(dirname(__FILE__)) . '/wp-load.php'; // перевіряється необхідність Апгрейду WordPress // підключаються файли (додаткові функції) адмінки require_once ABSPATH. 'wp-admin/includes/admin.php'; // Перевіряє чи авторизований користувач, перед тим як допустити його на будь-яку сторінку // Якщо прав недостатньо, то користувач «відлетить» на сторінку авторизації auth_redirect(); // хук адмінки do_action( 'admin_init'); // встановлюється дані поточної сторінки set_current_screen(); // шапка require_once ABSPATH. 'wp-admin/admin-header.php'; // контент - тут логіка розгалужується і контент завантажується // або від плагіна // або ніякої (якщо це запит імпорту даних) // або рідні файли адмники, наприклад, wp-admin/options-general.php // підвал include ABSPATH. 'wp-admin/admin-footer.php';
Завантаження AJAX запиту
Надсилати AJAX запити прийнято до файлу wp-admin/admin-ajax.php , з нього і починається завантаження WordPress при AJAX запитах.
Давайте і тут розберемо порядок завантаження, потім трохи пояснень.
wp-admin/admin.php // визначається константа WP_ADMIN define( 'WP_ADMIN', true ); // ЯДРО (все, що є у ВП) (описано вище) require_once dirname(dirname(__FILE__)) . '/wp-load.php'; // Перевіряється наявність параметра запиту 'action' він має визначити для будь-якого AJAX запиту. if( empty( $_REQUEST['action'] ) ) die( '0' ); // підключаються файли (додаткові функції) адмінки require_once ABSPATH. 'wp-admin/includes/admin.php'; // підключаються обробники Ajax запитів ядра WordPress require_once ABSPATH. 'wp-admin/includes/ajax-actions.php'; // хук адмінки do_action( 'admin_init'); // перевірка та виправлення значень параметра action пов'язаних з ядром WordPress та додавання потрібного хука add_action( 'wp_ajax_' . $_GET['action'], 'wp_ajax_' . str_replace( '-', '_', $_GET['action'] ), 1 ); // Перевірка прав користувача та запуск потрібного хука do_action( 'wp_ajax_' . $_REQUEST['action'] ); // або do_action( 'wp_ajax_nopriv_' . $_REQUEST['action'] ); // Відповідь AJAX за замовчуванням die('0');
При AJAX запит також встановлюється константа WP_ADMIN . Це означає, що будь-який AJAX запит виглядає для ядра, як запит до адмінної частини, навіть якщо цей запит робиться з фронту… Це не завжди потрібно, але так прийнято в WordPress з причин стандартизації та зручності використання.
Далі завантажується ядро, у якому спрацьовують усі хуки. Тобто. підключаються та запускаються всі плагіни, спрацьовує код файлу functions.php , спрацьовує подію init
. Тобто. повністю завантажується та обробляється ядро WordPress.
Тепер, коли оброблено ядро, додатково підключаються всі PHP функції адмін-панелі (хоча часто вони не потрібні) і запускається один з AJAX хуків (залежить від авторизації): wp_ajax_(action)
або wp_ajax_nopriv_(action)
.
Запуск AJAX хука це останній етап – AJAX операція виконана і вона повинна перервати роботу PHP і вивести на екран будь-які дані – зазвичай це просто рядок, або рядок в json форматі.
До речі, для зручної json відповіді при AJAX запитах WP є спеціальна функція – wp_json_encode() і дві функції похідні від неї:
- wp_send_json_error() – для відповідей-помилок.
- wp_send_json_success() – для успішних відповідей.