Як завантажується ядро ​​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. Цим ми й займемося.




Порядок завантаження (теорія)

Зрозуміти логіку завантаження не так складно, як здається на перший погляд. Для цього давайте поглянемо на цю, таку улюблену мною картинку:

Порядок завантаження ядра 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() .
  • Логіку роботи файлу Ієрархія шаблону .

Дивіться також картинку про те, як працює запит WordPress:

Як працюють функції запитів у WordPress




Завантажити запит 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() , робить наступні дії по порядку:

  1. Викликає WP::init() .

    Цей метод визначає поточного користувача для звичайних (не REST) ​​запитів. див. wp_get_current_user() .

    Пізніше (якщо це REST запит), на хуку аутентифікації rest_authentication_errors авторизований користувач буде обнулений при неправильному коді nonce. Дивіться:

  2. Викликає WP::parse_request() .

    Цей метод визначає параметри поточного запиту $wp->query_vars .

  3. Запуск 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 (логіка обробки запитів для звичайних сторінок тут закінчується).

    1. Встановлюється константа define( 'REST_REQUEST', true ).
    2. Запускається сервер REST rest_get_server() .

      При запуску спрацьовує хук rest_api_init . На ньому до наявного сервера додаються свої маршрути.

    3. Обробляється запит REST WP_REST_Server::serve_request( $route ) .

      При обробці запиту перевіряється доступність поточного маршруту, маршрут обробляється, повертається відповідь сервера REST у вигляді об’єкта WP_REST_Response .

      При обробці запиту спрацьовують наступні корисні хуки (у вказаному порядку):

    4. Робота 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() і дві функції похідні від неї:




Цікава картинка про те, як завантажується WordPress

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *