Когда WordPress 1.2 выкатили еще в 2004 году, новая архитектура плагина была введена, что в настоящее время обычно называют действия и фильтры, крючки, и Plugin API.
Ядро WordPress было тщательно посыпать действиями и фильтрами, что внешний код (в виде тем и плагинов) может подключиться, вводя новые функциональные возможности в стандартный поток. WordPress Plugin API обеспечивает аккуратный интерфейс для работы с действиями и фильтрами. Эта статья собирает понимание внутренней работы, элегантность и красоту Plugin API. Это поможет WordPress плагин и тема разработчики получить более глубокое понимание того, что происходит за кулисами, почему некоторые вещи будут работать, а другие не будут, и где искать, когда они неожиданно этого не делают.
Дальнейшее чтение на SmashingMag:
- Использование ролей пользователей в WordPress
- Как стать лучшим профессионалом WordPress
- Полезные инструменты WordPress, темы и плагины
- Написание эффективной документации для конечных пользователей WordPress
Предупреждение
Это подробный пошаговое пошаговое походе некоторых из WordPress ‘основной исходный код. Чтобы получить максимальную погоду, понимание и удовольствие от него, вам понадобятся базовые знания о функциях PHP и WordPress, а также исходный код для WordPress 3 «(который можно просматривать в Интернете)и мужество копаться в и получить ваши руки грязные.
API-на-амплуа
Функции, которые чаще всего используют разработчики тематичек и плагинов:
Эти функции хорошо известны, хорошо документированы, и широко используется в изобилии в большинстве тем и плагинов. Страница Codex Plugin API содержит некоторые основные примеры крючков WordPress в действии. Исходный код Plugin API сделал себя как дома в /wp-includes/plugin.php
файле. Не стесняйтесь, чтобы открыть его в вашем любимом текстовом редакторе или просмотреть его в Интернете, чтобы следовать вместе.
API довольно компактный, около 350 строк кода (остальные комментарии). Он предоставляет 22 функции, 14 из которых работают непосредственно с действиями и фильтрами, в то время как остальные являются функциями помощника и утилиты, которые относятся к разрешению пути плагина, активации и деактивации.
Plugin API становится доступным на самых ранних стадиях процесса загрузки WordPress, и самое раннее действие можно подключить в muplugins_loaded
это, который выстрелил в конце концов«должны использовать»и сетевые плагины включены — довольно бесполезно, если ваш плагин не является ни один из них. plugins_loaded
Действие снимается сразу же после включения всех действительных файлов плагинов в область. Наконец, after_setup_theme
снимается после включения активного functions.php
шаблона.
Ссылка на действия и ссылка на фильтр содержат описания для многих действий и фильтров, доступных во время типичных сценариев запросов.
$wp фильтр
Plugin API предоставляет функции, которые действуют на $wp_filter
глобальном, который представляет собой простой ассоциативный массив с определенной структурой. Все функции действия и фильтрации считываются и пишутся в этот глобально общий ассоциативный массив, что делает API полностью отделенным от основного кода WordPress. Вы можете включить файл Plugin API plugin.php
в любой другой проект или структуру PHP и использовать все функции действия и фильтрации ( / , do
, , ) без apply
add
remove
has
current
каких-либо изменений. В самом деле, почти неизменным файл поставляется с BackPress, коллекция автономных библиотек, которые выросли из WordPress. Секрет этого заключается в высокой гибкости API и простоте его концепции.
$wp_filter
Глобальный начинается в WordPress как неопределенная переменная, полностью лишена каких-либо данных. Данные записываются ему после того, как действие или фильтр добавляется add_action()
через или add_filter()
. Итак, это будет нашей отправной точкой. Эти две функции имеют идентичный прототип с точки зрения функциональных аргументов:
function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1)
Эта функция определена на линии 65. Это очень просто. Обратите внимание, как он true
возвращается, независимо от того, что происходит внутри. add_action()
Функция (на линии 331) вызывает add_filter()
функцию без каких-либо изменений. Это означает, что $wp_filter
не проводится различия между фильтрами и действиями при их очереди. Структура данных $wp_filter
довольно проста и может быть представлена на следующей диаграмме:
Массив «функции» (т.е. массив, содержащий функцию обратного вызова и количество аргументов, которые он принимает) идентифицируется _wp_filter_build_unique_id()
функцией помощника(строка 750), которая возвращает уникальную idx
для обратного вызова, заказанный «приоритетом» и прикрепляемый к «тегу» (который — это название фильтра или действия). Это приводит к списку действий с уникальными обратными вызовами, которые будут вызываться только один раз, независимо от того, сколько раз добавляется один и тот же обратный вызов (уникальный идентификатор обеспечивает это).
Приходите получить некоторые действия!
Действия обычно отключаются через do_action()
функцию, которая имеет следующий прототип:
function do_action($tag, $arg = ’, ...)
Определение функции находится на линии 359, вы более чем приветствуется, чтобы прочитать биты кода там и вернуться к шагзают объяснение.
Прежде всего, $wp_actions
глобальный отслеживает, как время того, что конкретное действие было вызвано. Это простой ассоциативный массив, с тегом действия или именем в качестве его ключей. did_action()
Функция(строка 423) возвращает количество раз, когда действие было вызвано доступом к этому $wp_actions
массиву. Далее all
действие запускается _wp_call_all_hook()
функцией. Эта функция просто тянет на все зарегистрированные или добавленные крючки в $wp_filter[‘all’]
массиве с call_user_func_array()
помощью функции PHP (мы рассмотрим большое применение действия немного all
позже). За этим следует простое «проверка и возврат, если действия не существует».
Далее вы заметите, что тег действия выталкивается в глобальный $wp_current_filter
массив. current_filter()
Функция(строка 306) возвращает последнее значение, хранящееся в этом глобальном массиве. Действия и фильтрация обратных вызовов могут тянуть на больше действий и фильтров, ссылаясь на другие обратные вызовы, в результате чего длинные цепочки. Можно проследить цепь крючков, загнав в глобальный $wp_current_filter
массив во время выполнения обратного вызова. Тем не менее, эти цепи, как правило, не получают больше, чем несколько ссылок, если вы не сделаете этого:
add_action( 'my_action', 'my_function' );
add_action( 'my_action_2', 'my_function_2' );
add_action( 'my_action_3', 'my_function_3' );
add_action( 'my_action_4', 'my_function_4' );
function my_function() { do_action( 'my_action_2'); }
function my_function_2() { do_action( 'my_action_3'); }
function my_function_3() { do_action( 'my_action_4'); }
function my_function_4() { var_dump( $GLOBALS['wp_current_filter']); }
do_action( 'my_action' );
/* array(4) {
[0]=> string(9) "my_action"
[1]=> string(11) "my_action_2"
[2]=> string(11) "my_action_3"
[3]=> string(11) "my_action_4"
} */
Зачем кому-то это делать? Предыдущий является наглядным примером, однако рассмотреть следующий кусок кода с участием, get_{$meta_type}_metadata
где я хочу, чтобы увеличить конкретный ключ:
add_filter( 'get_post_metadata', 'augment_post_meta_by_key', 999, 4 );
function augment_post_meta_by_key( $null, $object_id, $meta_key, $single ) {
if ( $meta_key != 'my_key' ) return $null; /* Ignore everything else */
/* Get the value */
$value = get_post_meta( $object_id, 'my_key', true );
if ( $value == '12345' ) return '54321'; /* Simple augmentation of a meta value */
}
Видите ловушку? Правильно, это бесконечный цикл. Фильтр будет отключаться внутри, augment_post_meta_by_key
потому что мы делаем больше мета-запросов. Так что $current_filter
цепь будет довольно длинной, если вы посмотрите на нее. Решение мгновелось бы удалить фильтр, прежде чем получить значение и повторно добавить его впоследствии.
Вернуться в русло: посмотрите на линию 386. Все аргументы обратного вызова собраны в локальную $args
переменную, с func_get_arg()
помощью PHP. Если вам интересно о необычном // array(&this)
бизнесе вокруг линии 387, проверьте билет #17111.
Сразу после того, как будут рассмотрены аргументы обратного вызова, $wp_filter
глобальный имеет свои данные для текущего тега, отсортированного по приоритету. При добавлении в теги действия и фильтры $wp_filter
создаются приоритетные массивы, содержащие обратные вызовы, и в несортированный порядок. Другими словами, добавление четырех действий с приоритетами 10, 1, 15, 3 приведет к тому, что тег, содержащий приоритеты 10, 1, 15, 3 в точно таком же порядке; таким образом, требуется сортировка по приоритету. Сортировка осуществляется ksort()
простым, и глобальный $merged_filters
массив отслеживает, сортируются приоритеты тега или нет. Использование ksort()
показывает, что приоритеты могут быть строки и отрицательные цифры,что является совершенно действительным, и что никакие действия обратный вызов никогда не гарантируется для запуска в первую очередь. При добавлении действия или фильтра эта строка кода unset( $merged_filters[$tag] );
гарантирует, что приоритеты отсортированы, даже если они были отсортированы один раз.
Далее, каждый $wp_filter[$tag]
обратный call_user_func_array()
вызов вызывается функцией, а второй аргумент (т.е. массив аргументов для вызова действий с) усечен до числа принятых аргументов ( $accepted_args
).
Наконец, текущее действие получает от » $wp_current_filter
Фильтры
apply_filters()
Функция(строка 134) проходит практически тот же процесс, что и do_action()
функция, с некоторыми незначительными различиями в реализации кода и существенным отличием в том, что apply_filters()
функция возвращает значение.
Если вы читали исходный код, вы, возможно, заметили, что has_action()
сейчас обернуты has_filter()
вокруг; что remove_action()
и remove_all_actions()
обернуты вокруг remove_filter()
remove_all_filters()
и; и add_action()
что обернуты вокруг add_filter()
…
Итак, почему Ботер!?
Хотя оба будут называть ваши функции таким же образом, и вы на самом деле может — но никогда не должны! — применить add_action()
к спискам фильтров и наоборот, или использовать apply_filters()
вместо или даже вместо , do_action()
do_action()
apply_filters()
сохраняя их функционально и семантически отдельные является абсолютно критическим. Как Сэмюэл Вуд говорит в «Действия и фильтры не одно и то же«:
Фильтры фильтруют вещи. Действия не делают. И это критически важно, когда вы пишете фильтр. Функция фильтра никогда, никогда не должна иметь неожиданных побочных эффектов.
ref-array
Краткое примечание о do_action_ref_array()
(линия 197) и apply_filters_ref_array()
(линия 448). Эти функции содержат тот же код, что и их ref_array
не-аналоги, и они принимают массив аргументов, а не список аргументов:
do_action( 'my_action', 'a string', array( 1, 2, 3 ), false, 2 );
$my_action_arguments = array(
'a string',
array( 1, 2, 3 ),
false,
2
);
do_action_ref_array( 'my_action', $my_action_arguments );
Они ведут себя одинаково. Версия массива удобна для использования, когда ваши аргументы наращиваются в массиве, потому что вам не придется распаковывать его.
Отладки
Сброс
Чистая установка WordPress будет содержать около 200 действий и фильтров и в два раза больше зарегистрированных обратных вызовов, когда wp
действие срабатывает. Вы, вероятно, бросили глобальный $wp_filter
массив в начале этой статьи, чтобы увидеть его структуру, и, возможно, заметил, что интерпретация его довольно трудно из-за огромного объема данных и var_dump
презентации. Теперь, когда вы знакомы со $wp_filter
структурой, массив может быть обычай довольно-печатных с чем-то более или менее просто, как следующее:
echo '<ul>;
/* Each [tag] */
foreach ( $GLOBALS['wp_filter'] as $tag => $priority_sets ) {
echo '<li><strong> . $tag . '</strong><ul>;
/* Each [priority] */
foreach ( $priority_sets as $priority => $idxs ) {
echo '<li> . $priority . '<ul>;
/* Each [callback] */
foreach ( $idxs as $idx => $callback ) {
if ( gettype($callback['function']) == 'object' ) $function = '{ closure }';
else if ( is_array( $callback['function'] ) ) {
$function = print_r( $callback['function'][0], true );
$function .= ':: '.print_r( $callback['function'][1], true );
}
else $function = $callback['function'];
echo '<li> . $function . '<i>(' . $callback['accepted_args'] . ' arguments)</i></li>;
}
echo '</ul></li>;
}
echo '</ul></li>;
}
echo '</ul>;
Результатом является более компактный и дружелюбный отчет. Конечно, при отладке, вы, вероятно, знаете, что вы ищете, так что не будет необходимости сбрасывать все $wp_filter
.
Обычай довольно-печать $wp_filter
глобального (слева) по сравнению с var_dump
(справа).
Отслеживание через «все» Крюк
Помните all
крючок(линия 140)? Он сравнивает сярвые каждый раз, когда apply_filters()
do_action()
вызывается или функция. Это означает, что отслеживание выполнения фильтров и действий возможно и весьма полезно для отладки.
/* Hook to the 'all' action */
add_action( 'all', 'backtrace_filters_and_actions');
function backtrace_filters_and_actions() {
/* The arguments are not truncated, so we get everything */
$arguments = func_get_args();
$tag = array_shift( $arguments ); /* Shift the tag */
/* Get the hook type by backtracing */
$backtrace = debug_backtrace();
$hook_type = $backtrace[3]['function'];
echo "<pre>";
echo "<i>$hook_type</i> <b>$tag</b>n";
foreach ( $arguments as $argument )
echo "tt" . htmlentities(var_export( $argument, true )) . "n";
echo "n";
echo "</pre>";
}
Маленький фрагмент кода может быть улучшен путем добавления временных меток для профилирования, наряду с $wp_filter
демпингом, чтобы показать больше информации о том, что было названо, и многое другое более полезное.
Заключительные мысли
WordPress развивалась много с ранних версий, и это один из лучших примеров того, как написать CMS в PHP и других программ и сценариев языков. Основная архитектура WordPress стала очень надежной, и разработчики программного обеспечения могли многому научиться на исходном коде платформы. Внутренняя работа, элегантность и красота действий wordPress и фильтры дал мне (и, надеюсь, вы тоже) огромное понимание, вдохновение и мотивация, чтобы продолжать копать.
Дополнительные ресурсы
Не останавливайся! Ваше путешествие только началось. Проверьте эти:
- «WordPress Крючки базы данных«, Адам Браун обзор всех действий и фильтров, которые присутствуют в WordPress, с исходным кодом местах и многое другое.
- «Debug WordPress Крючки»,Андрей Савченко Более продвинутые крючком захоронения фрагментов для WordPress.
Источник: smashingmagazine.com