Плагины WordPress PHP (хуки, фильтры, действия). PHP _SELF в атрибуте формы action ООП, классы, объекты и анонимные функции

“Не используйте оператор goto” – так твердили нам преподаватели в академии, и действительно, оператор сей превращает код в полнейшую кашу. Разработчики php решили проблему кардинально – в php3 и php4 его просто нет. Чем они изначально руководствовались? Может быть хотели привить всем нам правильный стиль программирования? Ну что же, можно сказать это им вполне удалось – мы все уже привыкли, то есть вернее сказать начисто отвыкли от этого оператора, может оно и к лучшему, потому что в свое время мне пришлось придумать логическую конструкцию, которая вполне компенсировала этот самый злосчастный goto .
Не знаю у кого как, а у меня, особенно часто возникало желание использовать goto при создании обработчика html формы, когда от пользователя на сервер отправляется множество данных, которые php скрипт должен поэтапно проверить. Процесс этот проходить, как правило, в несколько этапов: печать самой формы, проверка полученных данных, предварительны показ, ну и например сохранение. Причем некоторые этапы могут повторятся: если проверка данных не прошла удачно переходим на печать формы, или если предварительный показ не устроил пользователя он может вернутся к вводу данных. Короче говоря некоторые куски кода могут задействоваться многократно. Использовать функции в этих условиях тоже не очень удобно – много входных и выходных переменных, функция должна выполнять слишком сложные действия, вообще коряво получается и читабельность кода резко падает.
И я придумал такую вот конструкцию.

do {

switch ($action ) {

default :

break ;

case "PRINT_FORM" :

Печатаем главную форму

break ;

case "CHECK_FORM" :

Проверяем правильность данных

break ;

case "PREVIEW_FORM" :

Предворительный просмотр

break ;

case "SAVE_FORM" :

Сохраняем данные

break ;

} while (true ) ;

Здесь основной оператор множественного выбора switch заключен в бесконечный цикл do-while – таким образом мы группируем нужные действия в секциях case: break; и можем неограниченно переходить из одной секции к другой. В секции default: удобно сделать предварительный разбор данных например если входных данных нет то $action = ‘PRINT_FORM’ печатаем форму, если есть например $_POST [‘submit’] то тогда отправляем на обработку полученных данных $action = ‘CHECK_FORM’ . Передача управления между блоками switch происходит с помощью изменения переменной $action , ну а выход из цикла с помощью break 2; или exit ;
Так например в блоке печати основной формы можно смело поставить break 2; т.к вывод формы предполагает окончание скрипта.
Конструкция очень гибкая и читабельная. Но есть один недостаток – если неправильно обработаны данные можно попасть в бесконечный цикл и скрипт зависает – это неприятно придется ждать целых 30 сек.
Давайте установим ограничение на кол-во циклов оператора do-while , 20 хватит с головой. Теперь если мы что-то накасячили скрипт намотает 20 оборотов, остановится и вывалит предупреждение об екстренном останове.
Отлаживать такую кострукцию очень удобно – достаточно после оператора swith распечатывать переменную $action и мы получим полную последовательность исполнения блоков.

DO { // в начале каждого цикла печатаем название // выполненной секции очень удобно для отладки echo $action." "; SWITCH ($action) { default: break; case "PRINT_FORM": /* печатаем главную форму */ break; case "CHECK_FORM": /* проверяем правильность данных */ break; case "PREVIEW_FORM": /* предворительный просмотр */ break; case "SAVE_FORM": /* сохраняем данные */ break; }// end switch } WHILE ((($i++) < 20) or die("Принудительный останов цикла"));

DO {

// в начале каждого цикла печатаем название

// выполненной секции очень удобно для отладки

echo $action . " " ; < / strong >

SWITCH ($action ) {

default :

break ;

case "PRINT_FORM" :

печатаем главную форму

break ;

Мы создали фундамент для будущего плагина, который распознает система WordPress. Сегодня мы займемся непосредственно изменением базового функционала системы.

Поможет нам в этом система «хуков» (hooks), «событий» (actions) и фильтров (filters). Эти три понятия и есть основа каждого плагина для WordPress.

Hooks

В WordPress есть два типа хуков:

  • Action hook: помечает место в коде, которое выполняет определенное действие, например, необходимо внести какие-либо данные и сохранить в базе.
  • Filter hook: помечает фильтр, который будет изменять какое-либо значение (переменную), так что в дальнейшем код будет использовать модифицированное значение.

Actions

Работа с событиями (actions)

Общая логика управления событиями в WordPress проста:

  1. Пометить место, где действие должно выполниться с помощью хука (action hook) с необходимыми параметрами.
  2. Создать функцию, которая будет выполнять нужные действия, используя параметры переданные хуком.
  3. Зарегистрировать событие, которое будет выполняться при срабатывании хука, с определенным приоритетом.
  4. Когда WordPress загружает страницу и находит hook, система выполнит все функции, которые зарегистрированы на этот хук.

Для выполнения первого пункта система предоставляет функцию ‘do_action’:

Do_action($tag, $arg_1, $arg_2, ... , $arg_n);

Она принимает следующие аргументы: $tag – название “хука”, $arg_1, $arg_2, … , $arg_n – параметры, с которыми будет вызвана функция. Аргументов может быть любое количество, либо 0.

Система сама по себе имеет много уже определенных хуков:

Do_action("init");

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

Do_action("save_post", $post_id, $post);

В этом примере хук срабатывает при сохранении записи с двумя аргументами post_id — идентификатор записи и post — сама запись.

Создание хуков доступно любому разработчику для создания собственного плагина (или темы). Благодаря этому мы имеем мощный инструмент для управления поведением системы.

Do_action("my_truly_custom_hook");

Когда мы создали хук и написали функцию, нам необходимо зарегистрировать функцию с помощью «add_action»

Add_action($tag, $function_to_add, $priority, $accepted_args_number);

Функция ‘add_action’ принимает два обязательных параметра: $tag: название соответствующего хука и $function_to_add: имя функции, которую необходимо вызвать. Другие два параметра дополнительные: $priority: целочисленная переменная, которая определяет порядок выполнения функции (по-умолчанию — 10), $accepted_args_number: количество аргументов, которое принимает функция (по-умолчанию — 1).

Рассмотрим пример, чтобы понять весь процесс. Допустим, мы хотим добавить небольшое уведомление внизу нашего сайта. Мы можем использовать хук ‘wp_footer’ для этого, потому что он является обязательной частью кода, который использует каждая тема.

Function msp_helloworld_footer_notice(){ echo "

Hello, I"m your custom notice
"; } add_action("wp_footer", "msp_helloworld_footer_notice");

В этом примере мы создали функцию, которая просто выводит разметку для оповещения и зарегистрировали её в ‘wp_footer’. Как только мы добавим этот код в файл нашего плагина (см. предыдущий ) мы увидим результат на странице:

Оповещение плагина WordPress

Работа с фильтрами (filters)

Фильтры работают по той же схеме, что и события. Но фильтры не просто выполняют определенный кусок кода, они изменяют значения, переданные им хуком. Это означает, что каждый фильтр имеет связанное с ним значение (переменную), с которым он работает.

Функция-фильтр будет принимать это значение и преобразовывать его для дальнейшего использования. Хуки для фильтров немного отличаются от хуков для событий (action hooks).

Apply_filters($tag, $value_to_filter, $arg_1, $arg_2, ... , $arg_n);

Функция ‘apply_filter’ создает хук для фильтра с именем $tag и обязательным параметром $value_to_filter (он может быть пустым, но должен быть объявлен). Остальные аргументы необязательны работают так же как и для событий.

Filter_function($value_to_filter, $arg_1, $arg_2, ... , $arg_n){ //фильтр return $value_to_filter; //значение необходимо вернуть }

Это «скелет» фильтра, который демонстрирует, что фильтр должен:

  1. принимать хотя бы 1 аргумент;
  2. возвращать модифицированное значение.
add_filter($tag, $function_to_add, $priority, $accepted_args);

Функция ‘add_filter’ регистрирует функцию с названием, содержащимся в $function_to_add для хука $tag. Остальные аргументы - $priority и $accepted_args — работают так же как и у хуков для событий.

Рассмотрим пример: обычная для плагина задача — добавить что-нибудь в конец поста. Если подробнее рассмотреть функцию ‘the_content’, которая используется для вывода содержимого записи, мы найдем такой хук:

$content = apply_filters("the_content", $content);

Используя его мы можем легко добавить что-либо в конец поста.

Function msp_helloworld_post_footer($content) { $content .= "

"; return $content; } add_filter("the_content", "msp_helloworld_post_footer", 100);

Обратите внимание, что мы используем большое число для приоритета, что убедиться, что до выполнения ‘msp_helloworld_post_footer’ все стандартные фильтры отработают. После включения кода в наш плагин мы увидим результат:


Как найти хук

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

«Кодекс» WordPress предоставляет списки хуков для фильтров и событий Action Reference и Filter Reference .

Дополнительные действия с хуками

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

Удалить события можно так:

Remove_action($tag, $function_to_remove, $priority, $accepted_args); remove_all_actions($tag, $priority);

Как вы догадались, ‘remove_action’ удаляет определенное событие, зарегистрированное для данного хука (необходимо правильно указать приоритет и количество аргументов, так как было указано при регистрации), и ‘remove_all_actions’ помогает удалить все события, зарегистрированные для хука (если приоритет опущен, функция удалит все события).

Фильтры можно удалять так же:

Remove_filter($tag, $function_to_remove, $priority, $accepted_args); remove_all_filters($tag, $priority);

API для плагинов в WordPress также предоставляет функции для проверки зарегистрирована ли функция для данного хука:

Has_action($tag, $function_to_check); has_filter($tag, $function_to_check);

Обе функции проверяют зарегистрирована ли данная функция для хука и возвращают true в случае успеха, иначе flase. Внутри функции у нас есть возможность проверить, что хук вызвал её:

If("hook_to_check_name" === current_filter()){}

Несмотря на название ‘current_filter’ работает не только с фильтрами но и с событиями.

Нетривиальный пример

Оживим «скелет» нашего плагина, который мы подготовили в прошлом уроке.

Заполним файл ‘core.php’ (главная часть нашего плагина, в которой сосредоточена основная часть функций) кодом, который решает задачу, которая реально может возникнуть в ходе работы. Для её решения мы будем использовать actions и filters.

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

Создадим собственную таксономию для обработки имя автора и его короткой биографии. Мы сможем использовать имя автора как другие термины таксономии (теги, например) в посте. Код:

/** регистрация фильтров и событий **/ function msp_helloworld_init(){ add_action("init", "msp_helloworld_taxonomies"); add_filter("the_content", "msp_helloworld_author_block_filter"); add_filter("post_class", "msp_helloworld_post_class"); } add_action("plugins_loaded", "msp_helloworld_init"); /** taxonomy **/ function msp_helloworld_taxonomies(){ $args = array("labels" => array("name" => "Guest authors", "singular_name" => "Guest author"), "show_in_nav_menus" => false); register_taxonomy("gauthor", array("post"), $args); } /** разметка блока автора **/ function msp_helloworld_author_block(){ global $post; $author_terms = wp_get_object_terms($post->ID, "gauthor"); if(empty($author_terms)) return; $name = stripslashes($author_terms->name); $url = esc_url(get_term_link($author_terms)); $desc = wp_filter_post_kses($author_terms->description); $out = "

"; $out .= "
This is a guest post by {$name}
"; $out .= "
{$desc}
"; return $out; } /** добавить разметку в конец поста **/ function msp_helloworld_author_block_filter($content){ if(is_single()) $content .= msp_helloworld_author_block(); return $content; } /** добавить CSS class к посту **/ function msp_helloworld_post_class($post_class){ global $post; $author_terms = wp_get_object_terms($post->ID, "gauthor"); if(!empty($author_terms)){ $post_class = "gauthor"; } return $post_class; }

Как видите, мы создали функцию для регистрации собственной таксономии и привязали её к хуку ‘init’. После мы создали шаблон, отвечающий за отображение блока автора, используя функцию WordPress ‘wp_get_object_terms’. После мы вставили блок с информацией об авторе в конец поста с помощью фильтра ‘the_content’. И, наконец, мы добавили собственный CSS класс. Результат работы:


24.6K

Ни для кого не является секретом, что наиболее распространенным способом взаимодействия html-страницы с сайтом является форма. Форма (то есть, html-элемент образуемый тегом form) используется и бесплатными почтовыми службами, электронными магазинами и многими другими типами сайтов.

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


Рассмотрим подробнее варианты для разных типов полей.

Текстовые поля

Под текстовыми полями в этой статье понимаются элементы, создаваемые тегам input со значением параметра type равным text и тегом textarea . Организовать обработку формы состоящей из нескольких таких полей проще всего. На листинге ниже приведен листинг с html-разметкой для такой формы.






Как видно из листинга, имена для элементов формы, с точки зрения PHP , являются элементами массива. Поэтому PHP -сценарий, который будет обрабатывать эту форму, будет воспринимать все множество текстовых полей этой формы как единый массив. К отдельным элементам можно обращаться по индексам или использовать перечисление при помощи команд list и each , как это сделано в следующем примере.

n"; ?>

Переключатели

Переключателями (checkbox ) в этой статье называются элементы, создаваемые тегам input со значением параметра type равным checkbox . Форма для использования переменного количества «переключателей » строится абсолютно так же. Обратите внимание, что выбор конкретного значения переключателя (то есть значение свойства value) не важен. Пример приведен в листинге ниже:






Однако обработка такой формы отличается от обработки, описанной для текстовых полей. В данном случае необходимо определить, включил или нет посетитель сайта тот или иной переключатель. Если включил — то соответствующий элемент массива существует, если нет — то отсутствует. В следующем листинге приведен пример PHP сценария, который распечатывает включенные переключатели:

Радио-кнопки

Перед тем как описывать обработку радио-кнопок необходимо вспомнить, как они работают. Суть радио-кнопок (элементы созданные тегами input со значением параметра type равным radio ) заключается в том что, выбирая одну кнопку, пользователь автоматически снимает выделение с другой кнопки из этого же набора. Кнопки объединяются в набор очень просто: у всех кнопок в наборе одно и тоже имя.

А вот значения (то есть параметры value ) у кнопок в наборе — разные. И на сайт будет отправлено значение выбранной кнопки с именем набора. Так же как и в случае с текстовыми полями и переключателями имена наборов радио-кнопок должны оформляться как имена элементов массива в PHP. Пример такой формы приведен в следующем листинге:

// первый набор кнопок
// второй набор кнопок
// третий набор кнопок

Обработка радио-кнопок объединяет идеи, использование при обработке, как текстовых полей, так и переключателей. Если автор html-страницы не установил значение по умолчанию, а пользователь не выбрал определенную кнопку в наборе радио-кнопок, то данный элемент будет отсутствовать в массиве (как для переключателей).

Прикрепляет указанную PHP функцию на указанный хук. Указанная функция сработает в момент события, которое в свою очередь запускается с помощью do_action() .

Хук на который цепляется функция создается (инициализируется) с помощью функции do_action() .

Действия (actions), в отличии от фильтров (add_filter()), нужны, чтобы выполнить какое-либо действие в нужный момент, тогда как фильтры передают и получают обратно данные, которые затем используются.

Неофициально: фильтры - это те же самые события, работают они точно также и их можно использовать как события (вместо add_filter() можно использовать функцию add_action() и наоборот). Например, можно не изменяя возвращать полученные данные, но помимо этого выполнять какую-нибудь операцию (например запись в БД). Правда это бывает нужно очень редко. Все места где нужно вмешаться в код движка, разработчики, пытаются предусмотреть и вставить в это место событие.

✈ 1 раз = 0.000018с = очень быстро | 50000 раз = 0.07с = скорость света | PHP 7.0.8, WP 4.7

Хуков нет.

Возвращает

Всегда true.

Использование

add_action($tag, $function_to_add, $priority, $accepted_args); $tag(строка) (обязательный) Название действия, к которому будем цеплять функцию. $function_to_add(строка/замыкание) (обязательный) Название функции, которая должна быть вызвана во время срабатывания действия, т.е. функция которую цепляем к хуку. Формат передачи функции - обычно строка, . $priority(число) Приоритет выполнения функции. Если на этот же хук "прицеплены" еще функции, то приоритет будет решать последовательность их выполнения. Меньше число - раньше выполняется, т.е. 10 будет выполняться раньше чем 20.
По умолчанию: 10 $accepted_args(число) Число аргументов, которые принимает функция. Разумеется действие должно передавать это число аргументов.
По умолчанию: 1

Примеры

#1 Обычный хук

Будем отправлять письмо друзьям, при публикации нового поста:

Add_action("publish_post", "email_friends"); function email_friends($post_ID){ $friends = "[email protected], [email protected]"; wp_mail($friends, "sally"s blog updated", "I just put something on my blog: http://blog.example.com"); return $post_ID; }

Точно так же можно зарегистрировать этот хук через add_filter():

Add_filter("publish_post", "email_friends");

#2 Получение аргумента

do_action() передает аргумент в функцию и его можно использовать. В предыдущем примере это был ID поста, но мы его не использовали, потому он нам не был нужен. Теперь, пример того, как использовать передаваемый аргумент:

Add_action("comment_id_not_found", "echo_comment_id", 10, 1); function echo_comment_id($comment_ID){ echo "I just received ". $comment_ID; }

#3 Анонимная функция

В качестве колбэк функции можно передавать анонимную функцию, например:

Add_action("wp_head", function(){ echo "something"; });

Такие анонимные функции не работают совместно с PHP ускорителями.

#4 Добавление события из PHP класса

Если для события нужно использовать как-либо метод PHP класса, то во втором аргументе, вместо названия функции, нужно указать массив, где первым аргументом будет название класса (для static метода) или экземпляр класса (для public метода), а вторым название метода этого класса.

Экземпляр класса находится в переменной $this:

// Подключение метода класса за пределами класса add_action("wp_head", array("My_Class", "my_static_method")); class My_Class { public function __construct() { // Подключение метода класса внутри класса add_action("save_post", array($this, "my_public_method")); add_action("save_post", array(__CLASS__, "my_static_method")); } public function my_public_method($post_id) { // код функции } static function my_static_method($post_id) { // код функции } }

Заметки

Чтобы узнать сколько аргументов передает действие, найдите его в коде и посмотрите. Например, тут передается 2 аргумента:

Do_action("save_post", $post_ID, $post);

и для такого хука, код зацепки будет выглядеть так:

Add_action("save_post", "my_save_post", 10, 2);

а функция будет иметь 2 аргумента:

Function my_save_post($post_ID, $post){ // здесь код функции }

Загрузка...
Top