WordPress как на ладони
Очень Удобный и Быстрый Хостинг для сайтов на WordPress. Пользуюсь сам и вам рекомендую!

Хуки в WordPress (фильтры и события)

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

Есть два типа хуков:

Фильтр (filter)
Изменяет значение переменной — получает значение и возвращает его (изменённое или нет).
Событие (action)
Запускает произвольный код — колбэк функция прикрепленный к хуку сработает в момент срабатывания хука в коде.

К хукам (фильтрам или событиям) прикрепляются PHP функции их еще называют коллбэками (callback), затем эти функции сработают в момент срабатывания хука. Такое поведение в программировании называется перехват.

В функцию прикрепленную к хуку могут передаваться параметры (дополнительные данные). На основе этих данных в функции можно создавать какую-либо логику. Читайте ниже.

Простой пример хука-события (action):

// создадим функцию для хука - события
function echo_1(){
	echo 'Hello';
}

// привяжем функцию к хуку
add_action( 'my_hook', 'echo_1' );

// создаем/используем/запускаем хук
do_action( 'my_hook' ); //> выведет на экран слово "Hello"

Пример с передачей параметра:

// создадим функции для событий
function echo_1( $data ){
	echo $data[0] .' '. $data[1] .'!';
}

// привяжем функции к хуку
add_action( 'my_hook', 'echo_1' );

// создаем/используем/запускаем хук
do_action( 'my_hook', [ 'Привет', ' мир' ] ); //> выведет "Привет мир!"

В программной части фильтры и события — это одно и тоже, т.е. в коде и то и другое работает одинаково, можно например заменить функцию add_filter() на add_action() — все будет работать! Разделение нужно, потому что это разные вещи по смыслу.

Список всех хуков WP смотрите на странице «Все хуки WordPress».

Всего в WordPress их около 2000. Некоторые важные хуки я описал и продолжаю описывать, они находятся тут.

Как работают Фильтры в WordPress

Для работы фильтра используются две функции:

  1. add_filter( hook_name, function, priority, args_num ) — добавляет/прикрепляет функцию к фильтру, которая будет вызвана в момент срабатывания фильтра. Такая функция называется «коллбэк-функция».

  2. apply_filters( hook_name, value, args... ) — создает хук-фильтр. Запускает прикрепленные к фильтру коллбэк-функцию.

На момент срабатывания хука в нём отработают только те коллбэки, которые уже были добавлены. Т.е. прикреплять коллбэк нужно до того как фильтр будет вызван с помощью apply_filters().

Пример

// коллбэк-функция
function my_filter_function( $str ){
	return 'Здравствуйте '. $str;
}

// Прикрепим коллбэк к фильтру.
add_filter( 'my_filter', 'my_filter_function' );

// Вызов фильтра
$name = apply_filters( 'my_filter', 'Владимир' );

echo $name; //> Здравствуйте Владимир

Еще пример

Допустим, у нас есть функция text(), которая возвращает текст. Нам нужно сделать так, чтобы этот текст можно было изменять за пределами этой функции. Для этого назовем наш фильтр my_filter_name и создадим хук:

function text( $text ){

	// удалим html теги из текста
	$text = strip_tags( $text );

	// возвращаем текст через фильтр.
	return apply_filters( 'my_filter_name', $text );
}

// коллбэк функция
function my_filter_function( $text ){

	// обрежем текст до 30 знаков
	return mb_substr( $text, 0, 30 ) .'...';
}

// Прикрепим функцию к фильтру
add_filter( 'my_filter_name', 'my_filter_function' );

// Вызываем text()
// функция удалит из текста html теги — это сделает она сама с помощью strip_tags().
// А дальше обрежет текст — это сделает наш фильтр

$text = 'Lorem <b>Ipsum</b> is simply dummy text of the printing and typesetting industry.';

echo text( $text );

// выведет:
// Lorem Ipsum is simply dummy te...

Фильтров в WordPress много и вы наверняка с ними встречались в темах и плагинах. Популярные из них: the_content, body_class, sanitize_user, comment_form.

Как работают События в WordPress

Для работы события используются две функции:

  1. add_action( hook_name, function, priority, args_num ) — добавляет/прикрепляет функции к событию, которое вызывается с помощью do_action(). Функция должна прикрепляться к событию до того, как событие произойдет. Нужно это, чтобы во время срабатывания события PHP функции уже были прикреплены к событию.

  2. do_action( hook_name, args... ) — это и есть событие. Запускает/вызывает добавленные к событию функции. Вызывается там, где должно сработать событие.

do_action() должна вызываться после add_action(), т.е. после того, как к событию добавлена функция, что логично...

Пример

Допустим, мы делаем тему и в каком-то месте темы нам нужно вызвать функцию, но мы заранее не знаем как функция будет называться. Т.е. пользователи сами будут добавлять функцию в это место.

Для этого в этом месте шаблона мы может вызвать не функцию а событие, назовем его my_action и затем прикрепить к этому событию функцию:

// создадим функцию для события
function my_action_function( $text ){
	echo 'Событие "my_action" сработало сейчас.';
}
// Прикрепим функцию к событию 'my_action'. Это можно сделать в другом файле
// главное до того как событие сработает.
add_action( 'my_action', 'my_action_function' );

// Вызов самого события. Вставляем эту строку в то место темы где нужно,
// чтобы сработала прикрепленная к нему функция
do_action( 'my_action' ); //> на месте этого кода будет выведена надпись:
						  // 'Событие "my_action" сработало сейчас.'

С событиями вы тоже встречались их много и одни из самых популярных это: wp_head, wp_footer.

Приоритет хука

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

Приоритет указывается в третьем параметре для функции которая прикрепляет функцию к хуку:

add_action( 'init', 'hook_callback1', 8 );
add_action( 'init', 'hook_callback2', 9 );

Функция с приоритетом 8 выполнится раньше функции с приоритетом 9. Если приоритет не указан, то он равен 10 — приоритет по умолчанию.

Если две функции прикреплены к одном хуку с одинаковым приоритетом, то они будут выполняться в порядке их прикрепления.

Рассмотрим как работают приоритеты на примере:

add_action( 'init', 'run_me_late', 11 );
add_action( 'init', 'run_me_early', 9 );
add_action( 'init', 'run_me_normal' );     // приоритет 10 по умолчанию
add_action( 'init', 'run_me_normal_two' ); // приоритет 10 по умолчанию

В момент срабатывания хука init функции выполняться в следующем порядке:

  1. run_me_early()
  2. run_me_normal()
  3. run_me_normal_two()
  4. run_me_late()
  • Как видно, чем больше число приоритета, тем позднее выполниться хук.

  • Если приоритет не указан, как в первом примере, то он равен 10.

Для фильтров приоритеты работают точно также.

Параметры хука

В прикрепляемую коллбэк-функцию могут передаваться какие-то данные - параметры. Их можно использовать в момент срабатывания хука, чтобы создать какую-то логику.

Например, когда WordPress сохраняет запись, запускается событие save_post. Этот хук может передать два параметра: ID записи и объект записи:

do_action( 'save_post', $post->ID, $post );

По умолчанию передается только первый параметр $post->ID:

add_action( 'save_post', 'my_save_post_callback' );

function my_save_post_callback( $post_id ) {
	// доступен один параметр
}

Однако можно указать что мы хотим получить 2 параметра. Для этого укажем четвертый параметр add_action():

add_action( 'save_post', 'my_save_post_callback', 10, 2 );

function my_save_post_callback( $post_id, $post ) {
	// доступны 2 параметра
}

Ограничение в один параметр по умолчанию сделано для быстродействия системы хуков.

Для фильтров все работает аналогично

При создании фильтра в него можно передать сколько угодно параметров через запятую:

$str = apply_filters( 'my_filter', $str, $data1, $data2 );

Теперь, при добавлении коллбэка. Мы можем использовать эти параметры. Для этого нужно указать количество передаваемых параметров:

add_filter( 'my_filter', 'my_filter_function', 10, 3 );

3 - количество параметров, которые получит функция my_filter_function() в момент вызова.

Функция фильтра будет выглядеть так:

function my_filter_function( $str, $data1, $data2 ){

	// Можем использовать $data1, $data2

	return $str;
}

Удаление хука

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

Для удаления функции привязанной к фильтру/событию, используется одна из функций:

Для справки. Это полностью одинаковые функции и обе они удаляют хук, а фильтр это или событие, в данном случае, значения не имеет. Так например, событии и фильтр мы можем удалить используя только функцию remove_filter() или только remove_action(). Но для понятности кода, все же лучше фильтры удалять с помощью remove_filter(), а события с помощью remove_action().

Для удаления хука нужно знать:

  1. Название хука, например wp_footer.
  2. Название прикрепленной функции, например my_action_function.
  3. Приоритет выполнения хука, если он был установлен при создании хука. Если при создании приоритет не был установлен, то он равен 10 и при удалении его указывать не обязательно.

    Если нужно удалить хук с приоритетом отличным от 10 и вы его не указали, то хук НЕ будет удален!

Пример удаления хука

Допустим где-то в плагине, к событию wp_footer прикреплена функция my_action_function, которая выводит текст в подвале темы:

add_action( 'wp_footer', 'my_action_function' );

function my_action_function( $text ){
	echo 'Это текст в подвале!';
}

В теме нам нужно удалить это событие, чтобы текст в подвале не выводился. Для этого в файле темы functions.php можно прописать такой код:

remove_action( 'wp_footer', 'my_action_function' );

Важный момент: удалять хук нужно после того как он добавлен, но еще не отработал.

Еще пример удаления хука

Демонстрация добавления и удаления хука:

// добавляем функцию к событию my_action
add_action( 'my_action', 'my_action_function' );

function my_action_function( $text ){
	echo 'Привет!';
}

// создаем событие
do_action( 'my_action' ); //> Привет!

// удаляем добавленное ранее событие
remove_action( 'my_action', 'my_action_function' );

// создаем событие еще раз
do_action( 'my_action' ); // ничего не выведет...

Удаление с учетом приоритета

Приоритет должен совпадать с тем который был задан при добавлении хука.

// если так добавлен
add_filter( 'my_filter', 'function_name', 99 );

// то так нужно удалять
remove_filter( 'my_filter', 'function_name', 99 );

Удаление хука статического метода класса

// так добавлен
add_filter( 'my_filter', [ 'My_Class', 'static_method_name' ], 15 );

// так нужно удалять
remove_filter( 'my_filter', [ 'My_Class', 'static_method_name' ], 15 );

Удаление хука не статического метода класса (если ЕСТЬ доступ к $this - экземпляру класса)

class A {

	function __construct(){
		add_action( 'my_action', [ $this, 'method_name' ], 15 );
	}

	function method_name(){
		echo 'Привет!';
	}
}

$class = new A(); // экземпляр

// для удаления нужно найти переменную в которую был сохранен
// экземпляр класса при создании, сейчас это $class
remove_action( 'my_action', [ $class, 'method_name' ], 15 );

Удаление хука не статического метода класса (если НЕТ доступа к $this - экземпляру класса)

Удалить хук для объекта класса к которому у нас нет доступа, стандартными функциями WP невозможно. Но сделать это можно, используя следующие кастомные функции:

GitHub

<?php

/**
 * Remove Class Action Without Access to Class Object
 *
 * @see remove_object_filter()
 */
function remove_object_action( string $hook_name, $static_callback, $priority = null ): bool {
	return remove_object_filter( $hook_name, $static_callback, $priority );
}

/**
 * Remove filters without access to class object (instance).
 *
 * To use remove_filter() function you need to have access to class instance,
 * or the filter should be added using static method as hook callback.
 * This function allows you to remove filters with callbacks you don't have access to.
 *
 * @param string       $hook_name          Filter name to remove.
 * @param string|array $static_callback    Hook callback where instance represented as class name.
 *                                         Eg: [ '\Space\My_Class', 'my_method' ] OR '\Space\My_Class' to remove all methods added to hook.
 * @param int|null     $priority           (optional) Priority of the filter. If not set all hooks with any priority will be removed.
 *
 * @return bool Whether the hook is removed.
 *
 * @requires WP 4.7+
 * @author   Kama (wp-kama.com)
 * @version  2.0
 */
function remove_object_filter( string $hook_name, $static_callback, $priority = null ): bool {
	if( is_string( $static_callback ) ){
		// '\Space\My_Class::my_method' or '\Space\My_Class'
		$static_callback = explode( '::', $static_callback ) + [ '', '' ];
	}

	$found = _find_hook_callback_instances( $hook_name, $static_callback, $priority );

	$res = 0;
	foreach( $found as $item ){
		$callback = [ $item['instance'], $item['method'] ];
		$res += (int) remove_filter( $hook_name, $callback, $item['priority'] );
	}

	return (bool) $res;
}

/**
 * Finds the instance of the object whose specified method is added for the specified hook.
 *
 * To use remove_filter() function you need to have access to class instance,
 * or the filter should be added using static method as hook callback.
 * This function allows you to find class instance that was used when the hook was added.
 *
 * @param string       $hook_name          Filter name.
 * @param string|array $static_callback    Hook callback where instance represented as class name.
 *                                         Eg: [ '\Space\My_Class', 'my_method' ]
 *                                         or [ '\Space\My_Class' ] to get all methods added for the hook.
 * @param int|null     $priority           (optional) Priority of the filter.
 *
 * @return array{ instance: object|string, method:string, priority:int }[]
 *
 * @author  Kama (wp-kama.com)
 * @version 1.1
 */
function _find_hook_callback_instances( string $hook_name, array $static_callback, $priority = null ): array {
	global $wp_filter;

	/** @var \WP_Hook $wp_hook WP hooks. */
	$wp_hook = $wp_filter[ $hook_name ] ?? null;

	if( empty( $wp_hook->callbacks ) ){
		return [];
	}

	$find_class_name = ltrim( $static_callback[0], '\\' ); //> \Space\My_Class >>> Space\My_Class
	$find_method_name = $static_callback[1] ?? '';

	$found = [];
	foreach( $wp_hook->callbacks as $the_priority => $hooks_data ){
		foreach( $hooks_data as $hook_data ){
			$real_callback = $hook_data['function'] ?? null;
			if( ! is_array( $real_callback ) ){
				continue;
			}

			[ $object, $the_method_name ] = $real_callback;
			$class_name = is_object( $object ) ? get_class( $object ) : $object;

			if(
				$class_name !== $find_class_name
				|| ( $find_method_name && $the_method_name !== $find_method_name )
				|| ( null !== $priority && $the_priority !== $priority )
			){
				continue;
			}

			$found[] = [
				'instance' => $object,
				'method' => $the_method_name,
				'priority' => $the_priority,
			];
		}
	}

	return $found;
}

Пример использования.

Допустим у нас есть такой класс:

namespace My\Space;

class MyClass {

	public function __construct() {
		add_action( 'some_action_hook', [ $this, 'my_method' ], 11 );
		add_filter( 'some_filter_hook', [ $this, 'my_method' ], 11 );
	}

	public function my_method() {
		die( 'my_method trigered: '. current_filter() );
	}
}

Мы инициализировали класс, в результате чего добавилось 2 хука:

new \My\Space\MyClass();

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

Рассмотрим все варианты как можно вызвать функцию, чтобы удалить хук:

remove_object_action( 'some_action_hook', [ 'My\Space\MyClass', 'my_method' ], 11 );
remove_object_action( 'some_action_hook', [ '\My\Space\MyClass', 'my_method' ], 11 );
remove_object_action( 'some_action_hook', [ '\\My\\Space\\MyClass', 'my_method' ], 11 );
remove_object_action( 'some_action_hook', [ \My\Space\MyClass::class, 'my_method' ], 11 );
remove_object_action( 'some_action_hook', '\My\Space\MyClass::my_method', 11 );
remove_object_action( 'some_action_hook', 'My\Space\MyClass::my_method', 11 );

// или аналогично для фильтров
remove_object_filter( 'some_filter_hook', [ 'My\Space\MyClass', 'my_method' ], 11 );
// etc...

Или если нужно удалить все хуки, независимо от приоритета, мы можем пропустить параметр $priority:

remove_object_action( 'some_action_hook', [ 'My\Space\MyClass', 'my_method' ] );

Удаление всех хуков, которые добавляет указанных класс

Этот пример показывает как удалить все добавленных хуки от определенного класса. Здесь не имеет значения какой метод класса добавлен к хуку, будут удалены все указанные хуки, указанного класса.

GitHub

<?php
/**
 * Remove current action or filter from plugin
 *
 * @param string $class_name Class name enqueueing the action.
 * @param null   $action_name Action name.
 */
function remove_plugin_action( $class_name, $action_name = null ) {
	global $wp_filter;

	if ( null === $action_name ) {
		$action_name = current_action();
	}

	/** @var WP_Hook $hooks WP hooks. */
	$hooks = $wp_filter[ $action_name ];

	$callbacks = $hooks->callbacks;

	foreach ( $callbacks as $priority => $actions ) {
		foreach ( $actions as $action ) {
			$function = $action['function'];
			if ( is_array( $function ) ) {
				$callback = $function[0];
				if (
					( is_object( $callback ) && get_class( $callback ) === $class_name ) ||
					( is_string( $callback ) && $callback === $class_name )
				) {
					remove_action( $action_name, $function, $priority );
				}
			}
		}
	}
}

// Example of usage.

/**
 * Enqueue Google maps scripts only on certain pages.
 */
function action_google_maps_script() {
	if ( ! ( is_page_template( 'templ-contact.php' ) ) ) {
		remove_plugin_action( 'PageSpeed_Optimization' );
	}
}

add_action( 'wp_enqueue_scripts', 'action_google_maps_script', 0 );

Удаление хука добавленного анонимной функцией (closure)

Удалить хук с замыканием не так просто, например такой код не сработает:

add_action( 'my_action', function(){  echo 'Привет!';  } );

remove_action( 'my_action', function(){  echo 'Привет!';  } ); // не работает!

Надежно удалить хук с использованием замыкания, можно только если замыкание создавалось в переменную и у нас есть доступ к этой переменной:

$my_func = function(){
	echo 'Привет!';
};

add_action( 'my_action', $my_func );

remove_action( 'my_action', $my_func ); // Работает!

НЕ надежный, но все же способ удалить хук с замыканием, когда у нас нет доступа к замыканию:

/**
 * Removes the hook when it has been added by a closure.
 * The accuracy of the function is not guaranteed - the first hook
 * that matches the priority and the number of hook arguments will be removed.
 *
 * @param string $name
 * @param int    $priority
 * @param int    $accepted_args
 */
function remove_closure_hook( $name, $priority = 10, $accepted_args = 1 ): bool {
	global $wp_filter;

	if( empty( $wp_filter[ $name ]->callbacks[ $priority ] ) ){
		return false;
	}

	$callbacks = & $wp_filter[ $name ]->callbacks[ $priority ];

	// Find our hook.
	// It is not always possible to identify it unambiguously, but
	// at least we know that it was created with a closure
	// and we know it's priority and number of parameters.
	foreach( $callbacks as $key => $hook ){

		if( ! ( $hook['function'] instanceof Closure ) ){
			continue;
		}

		if( $hook['accepted_args'] !== $accepted_args ){
			continue;
		}

		// remove
		unset( $callbacks[ $key ] );

		// first suitable only
		return true;
	}

	return false;
}

Пример использования:

add_action( 'my_action', function(){
	echo 'Привет!';
} );

do_action( 'my_action' ); // Привет!

remove_closure_hook( 'my_action', 10, 1 );

do_action( 'my_action' ); // (пусто)

Создание своего хука

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

Чтобы создать событие или фильтр в коде, к которому потом можно будет добавлять функции, используется функция

Синтаксис у этих функций такой:

do_action( $tag, $arg_a, $arg_b, ... );

apply_filters( $tag, $value, $arg_a, $arg_b, ... );
$tag(строка) (обязательный)
Название хука.
$value(строка/массив/число/объект/логический) (обязательный)
Значение, которое будет передаваться функции в её первом аргументе — значение, которое нужно отфильтровать.
$arg_a(строка/массив/число/объект/логический)
Значение аргумента.
$arg_b(строка/массив/число/объект/логический)
Значение еще одного аргумента.
Пример создания хука-события

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

Итак, у нас есть функция плагина add_vote() - записывает голос, в конец этой функции добавим событие:

function add_vote(){

	// код функции
	// тут определяется ID опроса - $poll_id и выбранный ответ - $answer
	// передадим эти данные в хук.

	// создаем хук
	do_action( 'my_plugin_add_vote', $poll_id, $answer );
}

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

add_action( 'my_plugin_add_vote', 'my_add_vote_logic', 10, 2 );

function my_add_vote_logic( $poll_id, $answer ){
	global $wpdb;

	// запишем в таблицу логов, заметку что кто-то проголосовал
	$wpdb->insert( $wpdb->log_table, [
		'user_id' => 5,
		'log_massage' => 'Проголосовали за опрос '. $get_poll( $poll_id )->name
	] );

}

Функции хуков в WordPress

do_action() Создает событие (возможность запустить php функции в нужный момент работы кода). Подключать php функцию к событию нужно с помощью add_action().
do_action_ref_array() Создает событие (хук), на который затем можно прикрепить PHP функции. Аргументы передаются в виде массива.
do_action_deprecated() Fires functions attached to a deprecated action hook.
add_action() Прикрепляет указанную PHP функцию на указанный хук. Указанная функция сработает в момент события, которое в свою очередь запускается с помощью do_action().
remove_action() Удаляет хук (событие или фильтр). Удаляет функцию прикрепленную к указанному хуку.
remove_all_actions() Удаляет все хуки у указанного события.
did_action() Получает число, сколько раз было вызвано указанное событие (хук).
current_action() Retrieves the name of the current action hook.
doing_action() Проверяет обрабатывается ли в текущий момент указанный хук (фильтр, событие).
has_action() Проверяет была ли зарегистрирована функция для хука-события.
apply_filters() Применяет прикрепленную к указанному фильтру PHP функцию.
apply_filters_ref_array() Выполняет функции прикрепленные к указанному хуку (фильтру). Параметры передаются в массиве. Позволяет передать параметр по ссылке.
apply_filters_deprecated() Fires functions attached to a deprecated filter hook.
add_filter() Прикрепляет указанную PHP функцию к указанному хуку-фильтру. Так, во время срабатывания фильтра значение будет обработано указанной PHP функцией.
remove_filter() Удаляет указанную функцию прикрепленную к указанному фильтру.
remove_all_filters() Удаляет все хуки у указанного фильтра.
current_filter() Получает название текущего фильтра.
has_filter() Проверяет была ли прикреплена к указанному фильтру какая-нибудь функция. Можно указать название конкретной функции.
doing_filter() Проверяет обрабатывается ли в текущий момент указанный хук (фильтр, событие).

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

В WordPress есть специальные функции, которые упрощают работу с фильтрами.

Функция Описание
__return_true() Просто возвращает true. Вспомогательная функция WordPress.
__return_false() Просто возвращает false. Вспомогательная функция WordPress.
__return_zero() Просто возвращает 0. Вспомогательная функция WordPress.
__return_empty_string() Просто возвращает пустую строку: ''. Вспомогательная функция WordPress.
__return_empty_array() Просто возвращает пустой массив: array(). Вспомогательная функция WordPress.
__return_null() Просто возвращает null. Вспомогательная функция WordPress.

Например, мы может отключить все стандартные виджеты WordPress с помощью фильтра load_default_widgets, так:

function is_load_default_widgets(){
	return false;
}
add_filter( 'load_default_widgets', 'is_load_default_widgets' );

Или можно не создавать отдельную функцию которая вернет false, а использовать уже готовую функцию из ядра WordPress: __return_false():

add_filter( 'load_default_widgets', '__return_false' );

Чтобы было понятнее как это работает, давайте посмотрим на вызов фильтра load_default_widgets:

function wp_maybe_load_widgets(){

	if ( ! apply_filters( 'load_default_widgets', true ) )
		return;

	require_once( ABSPATH . WPINC . '/default-widgets.php' );

	add_action( '_admin_menu', 'wp_widgets_add_menu' );
}

При вызове функции wp_maybe_load_widgets() срабатывает фильтр. По умолчанию он всегда возвращает true и условие не выполняется — виджет подключаются. А в примерах выше мы возвращаем false и условие выполняется — виджеты не подключаются.

Это демо пример из кода WordPress, чтобы объяснить принцип работы. В практике его лучше не использовать, для отключения виджетов используйте код из описания функции unregister_widget().

Аналогичный пример

Аналогичным образом можно выключить возможность публиковать записи по протоколу xmlrpc. Которой, кстати по умолчанию включен, но им мало кто пользуется.

// отключим публикацию по xmlrpc
add_filter( 'xmlrpc_enabled', '__return_false' );

Еще один пример

Закроем возможность сброса пароля, с помощью фильтра allow_password_reset:

add_filter( 'allow_password_reset', '__return_false' );

Теперь все пользователи не смогут сбрасывать пароли на сайте.

Список всех хуков WordPress

Получить список всех хуков может понадобится. В процессе разработки или при поиске ошибок.

Как я упоминал выше все хуки записываются в общий массив, а точнее в глобальную переменную $wp_filters. К слову, если удалить из $wp_filters элемент массива (хук), то хук перестанет работать...

Следующий код выведет список всех хуков (фильтров и событий), которые зарегистрированы на момент вызова этого кода:

/**
 * Выводит на экран список всех хуков WordPress и функций к ним прикрепленных.
 *
 * @param string $hook_name  Название хука, список фукнций которого нужно вывести.
 *
 * @version 3.0
 */
function get_hooks_list( string $hook_name = '' ): string {
	global $wp_filter;

	$wp_hooks = $wp_filter;

	// для версии 4.4 - переделаем в массив
	if( is_object( reset( $wp_hooks ) ) ){
		foreach( $wp_hooks as & $object ){
			$object = $object->callbacks;
		}
		unset( $object );
	}

	$hooks = [];

	if( $hook_name ){
		$hooks[ $hook_name ] = $wp_hooks[ $hook_name ] ?? null;

		if( ! is_array( $hooks[ $hook_name ] ) ){
			return "Nothing found for the '$hook_name' hook";
		}
	}
	else{
		$hooks = $wp_hooks;
		ksort( $wp_hooks );
	}

	$output = '';
	foreach( $hooks as $name => $hook_data ){
		ksort( $hook_data );

		$output .= "\nHook\t<b>$name</b>\n";

		foreach( $hook_data as $priority => $hooksdata ){
			$output .= $priority;

			foreach( $hooksdata as $key => $hdata ){
				$func = $hdata['function'];

				if( is_array( $func ) ){

					if( is_object( $func[0] ) ){
						$func_name = get_class( $func[0] ) . '->' . $func[1];
					}
					else {
						$func_name = $func[0] . '::' . $func[1];
					}
				}
				elseif( $func instanceof Closure ){
					$func_name = "Closure_$key";
				}
				else {
					$func_name = $key;
				}

				$output .= "\t$func_name()\n";
			}
		}
	}

	return sprintf( '<%1$s>%2$s</%1$s>', 'pre', $output );
}

Пример использования:

echo get_hooks_list();

/* Получим список такого формата:

хук wp_enqueue_scripts
10  lambda_2
99  theme_scripts_styles

хук wp_footer
0   0000000072b7ec0d00002b862c2211a0enqueue_jquery_if_need
10  0000000072b7edb400002b862c2211a0footer_scripts
	0000000072b7eb7b00002b862c2211a0main_js
20  wp_print_footer_scripts
99  0000000072b7ec0d00002b862c2211a0add_script_to_footer
	0000000072b7eb1600002b862c208180
	question_close_ajax_js
	add_question_rating_ajax_js
	add_comment_rating_ajax_js
999 0000000072b7edb600002b862c2211a0footer_script
1000    wp_admin_bar_render
9999999999  0000000072b7eb0b00002b862c208180

... и т.д. ...
*/

А так выглядит элемент массива в самой переменной $wp_filter:

global $wp_filter;

print_r( $wp_filter );

/*
	[wp_title] => WP_Hook Object
		(
			[callbacks] => Array
				(
					[10] => Array
						(
							[wptexturize] => Array
								(
									[function] => wptexturize
									[accepted_args] => 1
								)

							[convert_chars] => Array
								(
									[function] => convert_chars
									[accepted_args] => 1
								)

							[esc_html] => Array
								(
									[function] => esc_html
									[accepted_args] => 1
								)

						)

					[11] => Array
						(
							[capital_P_dangit] => Array
								(
									[function] => capital_P_dangit
									[accepted_args] => 1
								)

						)

				)

			[iterations:WP_Hook:private] => Array
				(
				)

			[current_priority:WP_Hook:private] => Array
				(
				)

			[nesting_level:WP_Hook:private] => 0
			[doing_action:WP_Hook:private] =>
		)

	[widget_title] => WP_Hook Object
		(
		............... и т.д.
*/

Как получить функции прикрепленные к указанному хуку?

Часто бывает нужно посмотреть, какие функции прикреплены к отдельному фильтру или событию.

Код выше позволит это сделать, для этого нужно указать в нем параметр $hook_name:

echo get_hooks_list( 'the_title' );

/* Получим:

хук the_title
10  wptexturize
	convert_chars
	trim
	func_title_add_brackets
11  capital_P_dangit

*/

Другой вариант - это просто получить данные массива

Используем глобальную переменную $wp_filters. В ней хранятся данные всех хуков.

Данные в $wp_filters добавляются по ходу обработки кода, поэтому имеет большое значение когда используется переменная $wp_filters: например, если её использовать в начале файла темы functions.php, то в ней будут все функции хуков который были добавлены до подключения этого файла, но не будет добавленных в этом файле или позднее.

/**
 * Выводит список функций прикрепленных к указанному хуку
 * @param (str) $hook Название хука, функции которого нужно вывести.
 */
function print_filters_for( $hook ){
	global $wp_filter;

	$data = isset( $wp_filter[$hook] ) ? $wp_filter[$hook] : "Хук `$hook` не найден...";

	echo '<pre>', print_r( $data, 1 ) .'</pre>';
}

Теперь, чтобы вывести список всех функций/методов прикрепленных к фильтру или событию нужно вызвать эту функцию, и указать ей название хука.

Например, получим все функции добавленные к событию wp_footer. В индексе callbacks мы получим все функции прикрепленные к хуку, в порядке приоритета их вызова.

print_filters_for( 'wp_footer' );

/* Выведет:

WP_Hook Object (

	[callbacks] => Array (

		[0] => Array (
			[echo_ads_tpls] => Array (
				[function] => echo_ads_tpls
				[accepted_args] => 1
			)
		)

		[20] => Array (
			[wp_print_footer_scripts] => Array (
				[function] => wp_print_footer_scripts
				[accepted_args] => 1
			)
		)

		[99] => Array (
			[question_close_ajax_js] => Array (
				[function] => question_close_ajax_js
				[accepted_args] => 1
			)

			[add_question_rating_ajax_js] => Array (
				[function] => add_question_rating_ajax_js
				[accepted_args] => 1
			)
		)

		[1000] => Array (
			[wp_admin_bar_render] => Array (
				[function] => wp_admin_bar_render
				[accepted_args] => 1
			)
		)
	)

	[iterations:WP_Hook:private] => Array()
	[current_priority:WP_Hook:private] => Array()
	[nesting_level:WP_Hook:private] => 0
	[doing_action:WP_Hook:private] =>
)
*/

Рекомендации

Именование динамических хуков

В документации WordPress есть интересная заметка об именовании динамических хуков.

Используйте фигурные скобки для переменных в названии динамических хуков:

// Правильно:
do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );

// Неправильно:
do_action( $new_status . '_' . $post->post_type, $post->ID, $post );

Это нужно для упрощения анализа кода, для быстрого поиска в редакторе кода, для удобной генерации документации по хукам и т.д.

Комментарии к динамическому хуку (PHPDoc)

Также, в PHP комментариях к динамическому хуку рекомендуется писать возможное варианты конкретного имени хука. Формат такой записи выглядит так:

/**
 * Fires before a specified login form action.
 *
 * Possible hook names include:
 *
 *  - `login_form_checkemail`
 *  - `login_form_confirm_admin_email`
 *  - `login_form_confirmaction`
 *  - `login_form_entered_recovery_mode`
 *  - `login_form_login`
 *  - `login_form_logout`
 *  - `login_form_lostpassword`
 *  - `login_form_postpass`
 *  - `login_form_register`
 *  - `login_form_resetpass`
 *  - `login_form_retrievepassword`
 *  - `login_form_rp`
 *
 * @since 2.8.0
 */
do_action( "login_form_{$action}" );

Быстрые и дешевые лайки на любые посты в Instagram можно приобрести на сайте Doctor SMM с гарантией на выполнение заказа. Только здесь Вы найдете ресурс на свой вкус! На сайте представлен широкий выбор формата лайков: русские, англоязычные, автолайки, тв-лайки, микс и пр. Делайте заказ сейчас и получайте выгодные оптовые скидки!

36 комментариев
Полезные 4 Все
    Войти