Настройка

События и фильтры в WordPress. PHP и формы #4 Добавление события из PHP класса

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

Хуки (от анг. слова hook - крючок, зацепка) - это созданные пользователями функции (то есть нами), которые привязываются к функциям WordPress (заложены в самом коде движка WordPress). То есть при каждом выполнении функции движка будет проверяться - не привязана ли к этой функции какая-нибудь пользовательская функция и если таковая есть, то одновременно с функцией движка будет выполнена пользовательская функция.

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

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

Фильтры (filters) предназначены для “фильтрования” (изменения) любых данных перед тем как они будут выведены на странице или добавлены для хранения в базу данных. Это фильтрация спама, ошибок или просто ошибочного ввода в формах, откуда собственно и произошло английское название.

Действия (actions) предназначены для замены различных действий ядра вашими действиями (например изменения строки запроса к базе данных), в программировании такое изменение действий базового функционала ещё называют перегрузкой.

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

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

  1. apply_filters() - вызывается там, где применяется фильтр. Запускает добавленные к фильтру PHP функции.
  2. add_filter() - добавляет/прикрепляет PHP функции к указанному фильтру. Используется до того, как фильтр будет применен/вызван/запущен с помощью apply_filters(). Нужно это для того, чтобы, во время срабатывания фильтра, PHP функция уже была подключена к фильтру и обработала переданное значение (отфильтровала его).

apply_filters()

Применяет прикрепленную к указанному фильтру PHP функцию. Прикрепляется функция с помощью add_filter().
Используется там, где нужно изменить значение переменной (например текст).
Используется в плагинах и темах, для создания хуков-фильтров (зацепок пользовательских функций).
Новые фильтры должны иметь уникальные названия и не должны совпадать с уже имеющимися в WP названиями фильтров.

Возвращает

Отфильтрованное значение $value, которое передается функции-обработчику хука.

apply_filters ( $tag , $value , $var . . . ) ;

$tag (строка) (обязательный)

Названиефильтра.

Поумолчанию: нет

$value (строка/ массив/ число/ объект/ логический) (обязательный)

Значение, которое будет передаваться функции в её первом аргументе, другимисловами — значение, которое нужно отфильтровать.

Поумолчанию: нет

$var (строка/ массив/ число/ объект/ логический)

Дополнительныезначения, которые будет передавать фильтр функции.

Поумолчанию: нет

$myvar = apply_filters ( $tag , $value ) ;

$myvar = apply_filters ( $tag , $value , $var1 , $var2 , . . . ) ;

add_filter ()

Прикрепляет указанную PHP функцию к указанному хукe-фильтру. Так, во время срабатывания фильтра значение будет обработано указанной PHP функцией.

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

add_filter() не делает никаких проверок: существует ли прикрепляемая функция или передается ли название функции в виде строки и т.д.. Сделано это, чтобы add_filter() работала максимально быстро.

true или false, в зависимости от того удалось или нет добавить новый фильтр.

add_filter ( $tag , $function_to_add , $priority , $accepted_args ) ;

$tag (строка) (обязательный)
Название фильтра, для которого будет срабатывать функция определенная в параметре $function_to_add.
По умолчанию: нет
$function_to_add (строка) (обязательный)
Название функции, которая будет срабатывать для указанного в предыдущем параметре фильтра. Название функции нужно указывать в виде строки: ‘название_функции’. Для функций внутри классов указываем массив: array(‘название_класса’, ‘название_функции’)
По умолчанию: нет
$priority (число)
Приоритет выполнения функций для одного и того же фильтра. Чем больше число, тем позднее будет выполнятся функция: например, сначала 10 потом 20. Функции с одинаковым приоритетом, будут выполнятся в порядке их добавления к массиву фильтров.
По умолчанию: 10
$accepted_args (число)
Количество аргументов передаваемых фильтром функции. Некоторые фильтры могут передавать больше чем 1 аргумент, допустим - 2, для таких случаев нужно указывать 2 в этом параметре.
По умолчанию: 1

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

#1. Обычный пример, показывающий как можно добавить любую надпись в конец каждой статьи, через фильтр the_content:

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

События

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

События или действия (actions) в WordPress очень похожи на события в JavaScript. Событие выполняется вызовом функции do_action(), а добавить функцию к любому событию можно с помощью функции add_action().

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

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

do_action()

Создает событие (зацепку для произвольной функции). Чтобы функция сработала в момент события её нужно подключить к этому событию с помощью функции add_action().

do_action ( $tag , $arg ) ;

Функции можно передавать бесконечное множество аргументов:
do_action($tag, $arg_a, $arg_b, …);

$tag (строка) (обязательный)
Название создаваемого хука.
По умолчанию: нет
$arg (строка/массив/число/объект/логический) Значение аргумента(ов), который будет передаваться через хук. Действия отличаются от фильтров, тем что передаваемые действием данные, не возвращаются обратно в функцию и не используются там в дальнейшем, а всего-лишь передаются для использования в функции хука.

add_action()

Регистрирует хук-событие. При регистрации указывается PHP функция, которая сработает в момент события, которое вызывается с помощью do_action().

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

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

false или true, в зависимости от того удалось ли зарегистрировать хук.

add_action ( $tag , $function_to_add , $priority , $accepted_args ) ;

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

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

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

add_filter(‘publish_post’, ’email_friends’);

При выполнении события или действия, выполняются все функции, добавленные к событию в определенном порядке. Это легче всего понять с помощью простого примера. Определяем три функции, которые будут выводить 1, 2 и 3 соответственно:

function one () { echo 1 ; }

“Не используйте оператор 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 ;

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){ // здесь код функции }

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

Пример #1 Простейшая форма HTML

Ваше имя:

Ваш возраст:

В этой форме нет ничего особенного. Это обычная форма HTML без каких-либо специальных тегов. Когда пользователь заполнит форму и нажмет кнопку отправки, будет вызвана страница action.php . В этом файле может быть что-то вроде:

Пример #2 Выводим данные формы

Здравствуйте, .
Вам лет.

Пример вывода данной программы:

Здравствуйте, Сергей. Вам 30 лет.

Если не принимать во внимание куски кода с htmlspecialchars() и (int) , принцип работы данного кода должен быть прост и понятен. htmlspecialchars() обеспечивает правильную кодировку "особых" HTML-символов так, чтобы вредоносный HTML или Javascript не был вставлен на вашу страницу. Поле age, о котором нам известно, что оно должно быть число, мы можем просто преобразовать в integer , что автоматически избавит нас от нежелательных символов. PHP также может сделать это автоматически с помощью расширения filter . Переменные $_POST["name"] и $_POST["age"] автоматически установлены для вас средствами PHP. Ранее мы использовали суперглобальную переменную $_SERVER , здесь же мы точно так же используем суперглобальную переменную $_POST , которая содержит все POST-данные. Заметим, что метод отправки (method) нашей формы - POST. Если бы мы использовали метод GET , то информация нашей формы была бы в суперглобальной переменной $_GET . Кроме этого, можно использовать переменную $_REQUEST , если источник данных не имеет значения. Эта переменная содержит смесь данных GET, POST, COOKIE.

15 years ago

According to the HTTP specification, you should use the POST method when you"re using the form to change the state of something on the server end. For example, if a page has a form to allow users to add their own comments, like this page here, the form should use POST. If you click "Reload" or "Refresh" on a page that you reached through a POST, it"s almost always an error -- you shouldn"t be posting the same comment twice -- which is why these pages aren"t bookmarked or cached.

You should use the GET method when your form is, well, getting something off the server and not actually changing anything. For example, the form for a search engine should use GET, since searching a Web site should not be changing anything that the client might care about, and bookmarking or caching the results of a search-engine query is just as useful as bookmarking or caching a static HTML page.

2 years ago

Worth clarifying:

POST is not more secure than GET.

The reasons for choosing GET vs POST involve various factors such as intent of the request (are you "submitting" information?), the size of the request (there are limits to how long a URL can be, and GET parameters are sent in the URL), and how easily you want the Action to be shareable -- Example, Google Searches are GET because it makes it easy to copy and share the search query with someone else simply by sharing the URL.

Security is only a consideration here due to the fact that a GET is easier to share than a POST. Example: you don"t want a password to be sent by GET, because the user might share the resulting URL and inadvertently expose their password.

However, a GET and a POST are equally easy to intercept by a well-placed malicious person if you don"t deploy TLS/SSL to protect the network connection itself.

All Forms sent over HTTP (usually port 80) are insecure, and today (2017), there aren"t many good reasons for a public website to not be using HTTPS (which is basically HTTP + Transport Layer Security).

As a bonus, if you use TLS you minimise the risk of your users getting code (ADs) injected into your traffic that wasn"t put there by you.