Java, UX, HTML, CSS, WEB-design

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

[ad_1]

  • Геннадий Ковшенин

  • 0 Комментарии

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

  • 11 минут чтения

  • WordPress, Техники (WP)

Краткое резюме ↬

Прошли те времена, когда разработчики WordPress, желая расширить функциональность, должны были изменять и взламывать исходный код ядра WordPress напрямую, что приводило к головным болям при обновлении и обмене модификациями.

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

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

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

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

  • Использование ролей пользователей в WordPress
  • Как стать лучшим профессионалом WordPress
  • Полезные инструменты, темы и плагины WordPress
  • Написание эффективной документации для конечных пользователей WordPress

Еще после прыжка! Продолжить чтение ниже ↓

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

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

API-интерфейс плагина

Наиболее часто разработчики тем и плагинов используют следующие функции:

  • add_action()
  • add_filter()
  • do_action()
  • apply_filters()

Эти функции хорошо известны, хорошо задокументированы и широко используются в большинстве тем и плагинов. На странице Codex Plugin API представлены некоторые базовые примеры хуков WordPress в действии. Исходный код Plugin API хорошо зарекомендовал себя в /wp-includes/plugin.php файл. Не стесняйтесь открывать его в своем любимом текстовом редакторе или просматривать в Интернете, чтобы следовать за ним.

API довольно компактный, всего около 350 строк кода (остальное — комментарии). Он предоставляет 22 функции, 14 из которых работают непосредственно с действиями и фильтрами, а остальные являются вспомогательными функциями и служебными функциями, которые относятся к разрешению, активации и деактивации путей плагинов.

API плагинов становится доступным на самых ранних этапах процесса загрузки WordPress, и самое раннее действие, к которому можно подключиться, это muplugins_loaded, который срабатывает после того, как включены все «обязательные» и сетевые плагины — довольно бесполезно, если ваш плагин не является ни тем, ни другим. То plugins_loaded действие запускается сразу после того, как все действительные файлы плагинов включены в область действия. Ну наконец то, after_setup_theme срабатывает, когда активный шаблон functions.php был включен.

Справочник по действиям и справочник по фильтрам содержат описания многих действий и фильтров, доступных в типичных сценариях запросов.

$wp_filter

Plugin API предоставляет функции, которые воздействуют на $wp_filter global, представляющий собой простой ассоциативный массив с определенной структурой. Все функции действий и фильтров считывают и записывают в этот глобально общий ассоциативный массив, что делает API полностью отделенным от основного кода WordPress. На самом деле вы можете включить API плагинов plugin.php файл в любом другом PHP-проекте или фреймворке и использовать все функции действий и фильтров (do/apply, add, remove, has, current) без каких-либо изменений. На самом деле почти неизмененный файл поставляется вместе с BackPress, набором автономных библиотек, выросших из WordPress. Секрет этого заключается в высокой гибкости API и простоте его концепции.

То $wp_filter global начинается в 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
Структура данных $wp_filter.

Массив «функций» (т. е. массив, содержащий обратный вызов функции и количество принимаемых им аргументов) идентифицируется _wp_filter_build_unique_id() (строка 750) вспомогательная функция, которая возвращает уникальный idx для обратного вызова, упорядоченного по «приоритету» и прикрепленного к «тегу» (имя фильтра или действия). Это приводит к списку действий с уникальными обратными вызовами, которые будут вызываться только один раз, независимо от того, сколько раз был добавлен один и тот же обратный вызов (уникальный идентификатор обеспечивает это).

Приходите получить некоторые действия!

Действия обычно запускаются через do_action() функция, которая имеет следующий прототип:

function do_action($tag, $arg = ’, ...)

Определение функции находится в строке 359, вы можете прочитать фрагменты кода и вернуться за пошаговым объяснением.

Прежде всего, $wp_actions global отслеживает, сколько раз было запущено конкретное действие. Это простой ассоциативный массив с тегом действия или именем в качестве ключей. То did_action() функция (строка 423) возвращает количество раз, когда действие было запущено при доступе к этому $wp_actions множество. Далее, all действие инициируется тем, _wp_call_all_hook() функция. Эта функция просто извлекает все зарегистрированные или добавленные хуки в $wp_filter[‘all’] массив с помощью PHP call_user_func_array() функция (мы рассмотрим отличное приложение 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 переменная, с помощью PHP func_get_arg(). Если вам интересно необычное // array(&this) бизнес по линии 387, проверьте билет № 17111.

Сразу после обработки аргументов обратного вызова $wp_filter global имеет данные для текущего тега, отсортированные по приоритету. Когда действия и фильтры добавляются к тегам в $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
Индивидуальный красивый принт $wp_filter глобальный (слева) по сравнению с var_dump (правильно).

Трассировка через хук all

Помните 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, с расположением исходного кода и многим другим.
  • «Отладка хуков WordPress», Андрей Савченко Более продвинутые сниппеты для сброса хуков для WordPress.
Сокрушительная редакция
(аль)



[ad_2]
Source: https://smashingmagazine.com

Заключение

Вы ознакомились с статьей — Внутренние действия и фильтры WordPress

Пожалуйста оцените статью, и напишите комментарий.

Похожие статьи

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

Ваш адрес email не будет опубликован.

Краткое описание по статье Внутренние действия и фильтры WordPress

Название: Внутренние действия и фильтры WordPress . Краткое описание: [ad_1] ⭐ Геннади . Дата публикации: 18.02.2022 . Автор: Алишер Валеев .

Для чего создан сайт Novosti-Nedeli.ru

Данный сайт посвящен новостям мира и мира технологий . Также тут вы найдете руководства по различным девайсам.

Сколько лет сайту?

Возраст составляет 3 года

Кнопка «Наверх»