Внутри WordPress Действия и фильтры

Когда WordPress 1.2 выкатили еще в 2004 году, новая архитектура плагина была введена, что в настоящее время обычно называют действия и фильтры, крючки, и Plugin API.

WordPress Actions and Filters

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

Дальнейшее чтение на SmashingMag:

Предупреждение

Это подробный пошаговое пошаговое походе некоторых из 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 довольно проста и может быть представлена на следующей диаграмме:

WordPress filter structure
Структура данных $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 .

A custom pretty print of the $wp_filter global vs. a var_dump
Обычай довольно-печать $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

Великолепный Журнал

Великолепный, сокрушительный, разящий (см. перевод smashing) независимый журнал о веб-разработке. Основан в 2006 году в Германии. Имеет няшный дизайн и кучу крутых авторов, которых читают 2 млн человек в месяц.

Добавить комментарий

%d такие блоггеры, как: