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

24.6K

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

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


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

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






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

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

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






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

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

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

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

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

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

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

События

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

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

Function one() { echo 1; } function two() { echo 2; } function three() { echo 3; }

Добавляем функции к событию foo с помощью функции add_action() :

Add_action("foo", "one"); add_action("foo", "two"); add_action("foo", "three");

И выполняем наше событие с помощью функции do_action() :

Do_action("foo"); // выведет 123

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

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

Итак, наш пример вызовет функции one() , two() и three() по порядку, что выведет на экран 123. Конечно мы могли самостоятельно вызвать эти функции в этом же порядке на месте do_action() , что дало бы тот же самый результат. Так зачем использовать события?

Зачем использовать события

Любой другой плагин или тема смогут легко добавить или удалить функции из вашего события без необходимости изменять код вашего плагина. Такой подход делает ваш плагин более гибким. Например:

/* В другом плагине */ function four() { echo 4; } remove_action("foo", "three"); add_action("foo", "four");

Таким образом, когда дело дойдет до вызова события foo в вашем плагине, на экран выведется уже не 123, а 124, поскольку другой плагин удалил функцию three() из вашего события с помощью функции remove_action() , и добавил на ее место новую функцию four() .

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

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

Фильтры

Фильтры в WordPress очень похожи на события. Главным отличием является то, что у фильтров есть значение, которое они передают каждой привязанной функции, соответственно каждая функция должна вернуть это же или измененное значение. Рассмотрим простой пример:

Function plus_one($value) { $value = $value + 1; return $value; }

Эта функция принимает один аргумент, добавляет к нему единицу и возвращает результат. Добавим нашу функцию к новому фильтру с помощью add_filter() :

Add_filter("foo", "plus_one");

Теперь все функции добавленные к фильтру foo (в нашем случае это всего одна функция) можно легко вызвать или «применить» с помощью функции apply_filters() :

Echo apply_filters("foo", 5); // 6

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

В данном случае на экран выведется значение 6, поскольку значение 5 было пропущено через функцию plus_one() , которая изменила оригинальную переменную. Если убрать функцию у фильтра с помощью remove_filter() , то наш код выведет первоначальное значение 5:

Remove_filter("foo", "plus_one"); echo apply_filters("foo", 5); // 5

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

Пример хорошего фильтра

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

Function get_my_social_profiles() { $profiles = array("twitter" => "http://twitter.com/wpmagru", "facebook" => "http://facebook.com/wpmagru",); return $profiles; }

Возвращаемый массив можно использовать в цикле в нашем файле header.php:

$profiles = get_my_social_profiles(); foreach ($profiles as $service => $url) { printf("%s", esc_url($url), $service); }

/* В functions.php */ function get_my_social_profiles() { $profiles = array("twitter" => "http://twitter.com/wpmagru", "facebook" => "http://facebook.com/wpmagru",); return apply_filters("my_social_profiles", $profiles); }

Таким образом любой плагин или дочерняя тема смогут легко управлять списком социальных профилей, не трогая оригинальную тему. Например, убрать ссылку на Twitter и добавить ссылку на Google+ можно с помощью следующего кода в плагине:

Function change_my_social_profiles($profiles) { unset($profiles["twitter"]); $profiles["google-plus"] = "https://plus.google.com/+wpmagru"; return $profiles; } add_filter("my_social_profiles", "change_my_social_profiles");

Фильтры и события в ядре WordPress

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

Отключить комментирование

Отключить комментирование на всем сайте, на зависимо от настроек в параметрах можно с помощью следующего кода:

Function my_comments_open() { return false; } add_filter("comments_open", "my_comments_open");

Фильтр comments_open используется в ядре WordPress каждый раз для того, чтобы проверить открыты ли комментарии к той или иной статье. Наша функция всегда возвращает значение false для этого фильтра, поэтому комментарии будут закрыты везде.

Кстати, ядро WordPress определяет несколько вспомогательных функций для работы с подобными фильтрами:

  • __return_true() — возвращает true
  • __return_false() — возвращает false
  • __return_zero() — возвращает 0
  • __return_empty_string() — возвращает пустую строку
  • __return_empty_array() — возвращает пустой массив
  • __return_null() — возвращает null

То есть наш фильтр на comments_open можно переписать в одну строку:

Add_filter("comments_open", "__return_false");

Изменить длину автоматических цитат

За длину автоматических цитат отвечает фильтр excerpt_length:

Function my_excerpt_length($length) { $length = 10; return $length; } add_filter("excerpt_length", "my_excerpt_length");

С помощью фильтра excerpt_more можно изменить текст, который который ставится в конце автоматический цитаты, по умолчанию это [...] :

Function my_excerpt_more($more) { $more = "→"; return $more } add_filter("excerpt_more", "my_excerpt_more");

Добавить баннер к содержимому каждой статьи

Фильтр the_content выполняется перед выводом содержимого каждой статьи. Через фильтр проходит само содержимое статьи, поэтому в него легко добавить баннер «на лету» с помощью плагина:

Function my_banner($content) { $banner = ""; $content = $banner . $content; return $content; } add_filter("the_content", "my_banner");

Добавить favicon.ico в раздел

В разделе в каждой теме выполняется событие wp_head . Во время этого события можно вывести ссылку на файл favicon.ico, вставить произвольный код JavaScript или CSS и многое другое:

Function my_favicon() { echo ""; } add_action("wp_head", "my_favicon");

Учтите, что если вам необходимо подключить внешние.js или.css файлы, делать это стоит с помощью функций wp_enqueue_script() и wp_enqueue_style() во время события wp_enqueue_scripts , а не напрямую в wp_head .

В каждой версии WordPress добавляются все больше и больше новых и полезных фильтров и событий. Список большинства фильтров и событий в ядре можно посмотреть на сайте Адама Брауна , или просканировав файлы ядра на «do_action» и «apply_filters».

Приоритеты

Функции добавленные к фильтрам и событиям выполняются в том же порядке, в котором они были добавлены, но порядок легко изменить с помощью приоритетов. Приоритет указывается третьим аргументом к функциям add_action() и add_filter() .

Без указания этого аргумента функции к фильтрам и событиям добавляются по умолчанию с приоритетом 10 . Функции выполняются от меньшего приоритета к большему, т.е. чем меньше приоритет, тем раньше выполняется функция.

Вернемся к примеру с цифрами:

Add_action("foo", "one"); add_action("foo", "two"); add_action("foo", "three"); do_action("foo"); // выведет 123

Если изменить приоритет выполнения функции three() на 9, то она выполнится раньше остальных:

Add_action("foo", "one"); add_action("foo", "two"); add_action("foo", "three", 9); do_action("foo"); // выведет 312

Подобным образом, указав приоритет 11 для функции one() , она выполнится позднее всех остальных, несмотря на то, что она была добавлена первой с помощью add_action() :

Add_action("foo", "one", 11); add_action("foo", "two"); add_action("foo", "three", 9); do_action("foo"); // выведет 321

Дополнительные параметры

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

Do_action("foo", $arg1, $arg2, $arg3); $value = apply_filters("foo", $value, $arg1, $arg2, $arg3);

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

Например, если в функции к событию foo мы хотим принять все три аргумента, необходимо указать 3 в качестве четвертого параметра к add_action() :

Function my_func($arg1, $arg2, $arg3) { ... } add_action("foo", "my_func", 10, 3);

Подобным образом, если в функции добавленной к фильтру мы хотим принять только $arg1 в качестве дополнительного аргумента, то просим add_filter() передать всего два аргумента — первый аргумент $value , и второй дополнительный аргумент $arg1:

Function my_func($value, $arg1) { ... } add_filter("foo", "my_func", 10, 2);

Пример

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

Add_filter("allow_password_reset", "__return_false");

Это запретит сброс пароля для всех пользователей на сайте, но если нам необходимо запретить сброс пароля только супер-администраторам в сети (в целях безопасности), мы можем воспользоваться дополнительным аргументом:

Function my_filter($allow, $user_id) { if (is_super_admin($user_id)) $allow = false; return $allow; } add_filter("allow_password_reset", "my_filter", 10, 2);

Учтите, что функции привязанные к фильтрам могут изменять только первый аргумент, передаваемый в фильтр. То есть функция приведенная выше может изменить только аргумент $allow , но не $user_id .

Для того, чтобы дать функциям возможно изменять более одного передаваемого аргумента, фильтры (и события) могут воспользоваться передачей переменных и объектов по ссылке в PHP, как это делает например событие pre_get_posts .

ООП, классы, объекты и анонимные функции

Разработчики тем и плагинов WordPress часто предпочитают объектно-ориентированный стиль программирования, где большая часть кода выполняется внутри объекта, а не в глобальном пространстве. Если функциям add_action() и add_filter() необходимо передать не функцию для вызова, а метод объекта, его необходимо передать в специальном формате массивом:

Class My_Class { function __construct() { add_filter("the_content", array($this, "filter_content")); } function filter_content($content) { // ... return $content; } } new My_Class();

Похожим образом можно передать статический метод класса:

Add_filter("the_content", array("My_Class", "filter_content")); add_filter("the_content", "My_Class::filter_content"); // PHP >= 5.2.3

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

Add_filter("the_content", create_function("$content", "return $content;")); add_filter("the_content", function($content) { return $content; }); // PHP >= 5.3

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

Заключение

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

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

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

Одно из главнейших достоинств 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.

В этой статье подробно говорится об использовании переменной PHP _SELF.

Что за переменная PHP _SELF?

Переменная PHP _SELF возвращает имя и путь к текущему файлу (относительно корня документа). Вы можете использовать эту переменную в атрибуте формы action. Существуют также некоторые нюансы, которые вы должны знать. Мы, конечно, никак не можем обойти стороной эти нюансы.

Давайте рассмотрим несколько примеров.

Echo $_SERVER["PHP_SELF"];

1) Предположим, что ваш php файл расположен по следующему адресу:

Http://www.yourserver.com/form-action.php

В этом случае переменная PHP _SELF будет содержать:

"/form-action.php"

2) Предположим, ваш php файл расположен по такому адресу:

Http://www.yourserver.com/dir1/form-action.php

PHP _SELF будет:

"/dir1/form-action.php"

PHP _SELF в атрибуте формы action. Для чего она там понадобилась?

Обычно переменную PHP _SELF используют в атрибуте action тега form . В атрибуте action указывается адрес, по которому будет отослано содержание формы после подтверждения (клик пользователем по кнопке с type="submit"). Как правило это таже самая страница, с которой ушла форма.

Однако, если вы переименуете файл, на который ссылается форма, вам понадобится переименовать название файла в атрибуте action , иначе форма работать не будет.

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

Допустим, у вас есть файл с формой form-action.php, и вы хотите, чтобы после подтверждения форма отправлялась на тот же самый файл. Обычно пишут так:

Но вы можете использовать переменную PHP _SELF вместо form-action.php. В этом случае код будет выглядеть: