Создание плагина WordPress: пошаговое руководство

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

Создание плагина WordPress © Фото из открытых источников
Создание плагина WordPress © Фото из открытых источников

Что будет в руководстве

Много информации про создание плагина WordPress (далее также — WP) можно почерпнуть в Руководстве разработчика плагинов на сайте WordPress.org (см. ссылку выше). Независимо от того, являетесь ли вы новичком в разработке плагинов для WordPress или опытным разработчиком плагинов, вы сможете найти там ответы на многие вопросы, связанные с плагинами:

  1. Если вы новичок в разработке плагинов, начните с прочтения введения, а затем перейдите к основам.
  2. Раздел 3 познакомит вас с безопасностью плагина.
  3. С помощью хуков ваш плагин взаимодействует с WordPress. Узнайте все о них в разделе 4.
  4. Чтобы узнать больше о встроенных функциях WordPress, которые вы можете использовать в своем плагине, ознакомьтесь с разделами 5-11: меню администрирования, шорткоды, настройки, метаданные, пользовательские типы записей, таксономии и пользователи.
  5. Узнайте о получении данных с использованием HTTP API в разделе 12.
  6. Если вы используете JavaScript, jQuery или Ajax в своем плагине, вы найдете необходимую информацию в разделе 13.
  7. Чтобы узнать о задачах WordPress, основанных на времени, используя Cron, ознакомьтесь с разделом 14.
  8. Разделы 15-17 познакомят вас с интернационализацией вашего плагина, подготовкой его к выпуску на WordPress.org и некоторыми инструментами разработчика, которые могут оказаться полезными.

Как заявлено создателями — «руководство разработчика плагинов WordPress создано сообществом WordPress для сообщества WordPress».

Зачем нужны плагины?

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

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

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

Создание плагина WordPress — что нужно

Создание плагина WordPress не отличается от обычной разработки, поэтому нам понадобятся:

  • Текстовый редактор или IDE
  • FTP-доступ к вашему хостинг-аккаунту или локальный сервер
  • Работающая установка WordPress

Для написания кода плагина вам понадобится текстовый редактор или IDE (среда разработки). Среди наиболее популярных HTML-редакторов можно назвать Notepad++ и Atom. Я пользуюсь бесплатной версией Sublime Text 3 и Visual Studio Code от Microsoft.

После установки текстового редактора подключите его к вашему FTP-серверу для работы с кодом. В следующей статье я расскажу про подключение к FTP с помощью Notepad++ и других редакторов кода.

Затем настройте FTP-клиент для загрузки файлов плагина на ваш сайт. Рекомендую использовать FTP-приложение FileZilla, так как оно простое в настройке и многие пользуются данной программой. Кроме того, вы можете использовать программу WinSCP. Последнее время чаще всего я пользуюсь ей.

Убедитесь, что у вас установлена рабочая и актуальная версия WordPress. Существует несколько способов обновления основных файлов WordPress, если вы отключили автоматическое обновление, об этом в следующих статьях. Перед обновлением сайта создайте резервную копию файлов WordPress и копию Базы Данных, чтобы избежать потери данных.

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

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

Вкратце, вот шаги по созданию плагина WordPress с нуля:

  1. Создайте папку для хранения файлов плагина.
  2. Создайте главный файл для вашего плагина.
  3. Добавьте код в несколько файлов для функций плагина.
  4. Создайте страницу администрирования плагина.

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

Плагин или тема

Функциональность сайта WordPress можно изменить с помощью и плагинов и тем. Темы WordPress имеют файл functions.php, хранящийся в папке /wp-includes/, который позволяет добавлять пользовательский код для новых функций.

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

Это связано с тем, что функциональность, хранящаяся в файле functions.php, зависит от того, активна тема или нет. Отключение темы WordPress вернет изменения, внесенные в указанный файл, и вызовет ошибку, когда сайт обратится к отсутствующим функциям.

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

Вот почему создание пользовательского плагина является полезным. Это облегчает изменения стандартного поведения WordPress в соответствии с вашими потребностями.

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

1. Введение в разработку плагинов

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

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

Еще руководство про то, как работать в процессе — если вы найдете что что-то пропустили или является неполным, пожалуйста, вы сможете отредактировать это и сделать это лучше.

В WordPress есть три основных компонента:

  • ядро
  • темы
  • плагины

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

Почему мы делаем плагины

Есть одно кардинальное правило в разработке WordPress — не трогайте ядро WordPress. Это означает, что вы не редактируете основные файлы WordPress для добавления функциональности на ваш сайт.

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

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

Самый простой плагин представляет собой отдельный PHP-файл. Плагин Hello Dolly является примером такого плагина. Для PHP-файла плагина просто нужны заголовок плагина, пара PHP-функций и некоторые хуки для присоединения ваших функций.

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

Что такое плагин?

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

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

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

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

Hello Dolly, один из первых плагинов в котором всего 82 строки. «Привет Долли» показывает текст из знаменитой песни в админке WordPress. Некоторые CSS стили используются в файле PHP для управления стилями лирики.

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

2. Основы плагинов

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

Чтобы начать создавать новый плагин, выполните следующие действия.

  1. Перейдите в каталог wp-content установки WordPress.
  2. Откройте каталог плагинов — plugins.
  3. Создайте новый каталог и дайте ему соответствующее название, например, plugin-name.
  4. Откройте каталог (директорию) нового плагина.
  5. Создайте новый файл PHP. Его полезно назвать также, например, plugin-name.php.

Вот как выглядит процесс в командной строке Unix:

wordpress$ cd wp-content
wp-content$ cd plugins
plugins$ mkdir plugin-name
plugins$ cd plugin-name
plugin-name$ vi plugin-name.php

В приведенном выше примере «vi» — это имя текстового редактора. Используйте любой удобный для вас редактор.

Теперь, мы можем редактировать файл PHP своего нового плагина, и нам нужно добавить комментарий в заголовке плагина. Это специально отформатированный блочный комментарий PHP, содержащий метаданные о плагине, такие как его имя, автор, версия, лицензия и т.д. Комментарий в заголовке плагина должен соответствовать требованиям к заголовку и, как минимум, содержать имя плагина.

Только один файл в папке плагина должен иметь комментарий заголовка — если плагин имеет несколько файлов PHP, только один из этих файлов должен иметь комментарий заголовка.

<?php
/**
* Plugin Name: YOUR PLUGIN NAME
*/

После сохранения файла вы сможете увидеть свой плагин в списке плагинов на вашем сайте WordPress. Войдите в админку своего сайта WordPress и нажмите «Плагины» (Plugins) на левой панели навигации администратора WordPress. На этой странице отображается список всех плагинов, которые есть на вашем сайте. Ваш новый плагин теперь должен быть в этом списке!

Хуки (hooks): действия (actions) и фильтры

Хуки WordPress (hooks) позволяют вам подключаться к WordPress в определенных точках, чтобы изменить поведение WordPress без редактирования каких-либо основных файлов.

Создание плагина WordPress и темы всегда связано с двумя типами хуков: действия (actions) и фильтры (filters). Действия (actions) позволяют добавлять или изменять функциональные возможности WP, а фильтры (filters) позволяют изменять содержимое по мере его загрузки и отображения пользователю веб-сайта.

Хуки служат не только для разработчиков плагинов; Хуки широко используются для обеспечения функциональности по умолчанию самим ядром WordPress. Другие хуки — это неиспользуемые заполнители, к которым вы можете просто подключиться, когда вам нужно изменить работу WordPress. Это то, что делает WordPress таким гибким.

Основные хуки

3 основных хука, которые вам понадобятся при создании плагина, это:

  • register_activation_hook(),
  • register_deactivation_hook(),
  • register_uninstall_hook().

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

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

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

Добавление хуков

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

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

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

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

Вы можете узнать больше о создании хуков и взаимодействии с ними в разделе хуков этого руководства.

WordPress API

Знаете ли вы, что WordPress предоставляет несколько интерфейсов прикладного программирования (Application Programming Interfaces или API)? Эти API-интерфейсы могут значительно упростить создание плагина WordPress и ваш код, который вы пишете в своих плагинах. Вы не захотите изобретать велосипед, особенно когда очень много людей проделали до вас большую работу и проводили много тестов.

Наиболее распространенным из них является API параметров (Options API), который позволяет легко хранить данные в базе данных для вашего плагина. Если вы думаете об использовании cURL в своем плагине, то вам пригодится HTTP API.

Поскольку мы говорим о плагинах, вам нужно изучить API плагинов (Plugin API). Он имеет множество функций, которые помогут вам в разработке плагинов.

Как WordPress загружает плагины

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

Если весь ваш плагин состоит из одного PHP-файла, например, как Hello Dolly, этот файл может находиться непосредственно в корне папки плагинов. Но чаще всего файлы плагинов будут находиться в собственной папке, названной в честь плагина.

Распространение плагина

Иногда созданный плагин предназначен только для вашего сайта. Но многим нравится делиться своими плагинами с остальным сообществом WordPress.

Прежде чем делиться своим плагином, вам нужно выбрать лицензию. Это позволяет пользователю вашего плагина знать, как ему разрешено использовать ваш код. Для обеспечения совместимости с ядром WordPress рекомендуется выбрать лицензию, которая работает с GNU General Public License (GPLv2 +).

2.1 Требования к заголовку (header)

Как описано в разделе «Основы плагинов», основной файл PHP должен содержать комментарий заголовка, который сообщает WordPress, что файл является плагином, и предоставляет информацию о плагине.

Минимальные поля

Как минимум, заголовок комментария должен содержать имя плагина (Plugin Name):

<?php
/**
* Plugin Name: YOUR PLUGIN NAME
*/

Поля заголовка плагина

Доступные поля заголовка:

  • Plugin Name (обязательно): Название вашего плагина, который будет отображаться в списке плагинов в админке WordPress.
  • Plugin URI: Домашняя страница плагина, которая должна быть уникальным URL, желательно на вашем собственном сайте. Должно быть уникальным для вашего плагина. Вы здесь не можете использовать URL-адрес WordPress.org.
  • Description: Краткое описание плагина, которое показано в разделе плагинов в админке WordPress. Описание должно быть до 140 символов.
  • Version: Текущий номер версии плагина, например 1.0 или 1.0.3.
  • Requires at least: Самая низкая версия WordPress, над которой будет работать плагин.
  • Requires PHP: Минимальная требуемая версия PHP.
  • Author: Имя автора плагина. Несколько авторов могут быть перечислены с помощью запятых.
  • Author URI: Сайт автора или профиль на другом сайте, например WordPress.org.
  • License: Краткое название (slug, слаг) лицензии плагина (например, GPLv2). Более подробную информацию о лицензировании можно найти в руководствах WordPress.org.
  • License URI: Ссылка на полный текст лицензии (например, https://www.gnu.org/licenses/gpl-2.0.html).
  • Text Domain: Текстовый домен gettext плагина. Дополнительную информацию можно найти в разделе «Текстовый домен» (Text Domain) на странице «Как интернационализировать свой плагин» (How to Internationalize your Plugin).
  • Domain Path: Путь к домену позволяет WordPress знать, где найти переводы. Дополнительную информацию можно найти в разделе «Путь к домену» (Domain Path) на странице «Как интернационализировать свой плагин» (How to Internationalize your Plugin).
  • Network: Может ли плагин быть активирован только для всей сети. Может быть установлено только в true и должно быть пропущено, когда нет необходимости.

Правильный файл PHP с комментарием заголовка может выглядеть так:

<?php
/**
* Plugin Name: My Basics Plugin
* Plugin URI: https://example.com/plugins/the-basics/
* Description: Handle the basics with this plugin.
* Version: 1.10.3
* Requires at least: 5.2
* Requires PHP: 7.2
* Author: John Smith
* Author URI: https://author.example.com/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: my-basics-plugin
* Domain Path: /languages
*/

Вот еще один пример, который допускает файловый уровень PHPDoc DocBlock, а также заголовки файлов плагинов WordPress:

<?php
/**
* Plugin Name
*
* @package PluginPackage
* @author Your Name
* @copyright 2019 Your Name or Company Name
* @license GPL-2.0-or-later
*
* @wordpress-plugin
* Plugin Name: Plugin Name
* Plugin URI: https://example.com/plugin-name
* Description: Description of the plugin.
* Version: 1.0.0
* Requires at least: 5.2
* Requires PHP: 7.2
* Author: Your Name
* Author URI: https://example.com
* Text Domain: plugin-slug
* License: GPL v2 or later
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
*/

Замечание

При назначении номера версии вашему проекту, помните, что WordPress использует функцию PHP version_compare() для сравнения номеров версий плагина. Поэтому, прежде чем выпускать новую версию своего плагина, вы должны убедиться, что эта функция PHP считает, что новая версия «больше», чем старая. Например, 1.02 на самом деле больше, чем 1.1.

2.2 Включение лицензии на программное обеспечение

Большинство плагинов WordPress выпускаются под лицензией GPL, которая является той же лицензией, которую использует сам WordPress. Однако есть и другие варианты. Всегда лучше четко указать лицензию, которую использует ваш плагин.

В разделе «Требования к заголовку» мы кратко упомянули, как вы можете указать лицензию вашего плагина в комментарии к заголовку плагина. Другая распространенная и рекомендуемая практика — размещать комментарий к блоку лицензии в верхней части основного файла плагина (того же, в котором есть комментарий к заголовку плагина).

Этот комментарий к блоку лицензии обычно выглядит примерно так:

/*
{Plugin Name} is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
any later version.

{Plugin Name} is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with {Plugin Name}. If not, see {URI to Plugin License}.
*/

В сочетании с комментарием к заголовку плагина:

<?php
/*
Plugin Name: WordPress.org Plugin
Plugin URI: https://developer.wordpress.org/plugins/the-basics/
Description: Basic WordPress Plugin Header Comment
Version: 20160911
Author: WordPress.org
Author URI: https://developer.wordpress.org/
Text Domain: wporg
Domain Path: /languages
License: GPL2

{Plugin Name} is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
any later version.

{Plugin Name} is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with {Plugin Name}. If not, see {License URI}.
*/

2.3 Хуки активации / деактивации

Хуки активации и деактивации предоставляют способы выполнения действий, когда плагины активируются или деактивируются.

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

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

Внимание! Хук деактивации иногда путают с хуком удаления. Хук удаления лучше всего подходит для постоянного удаления всех данных, таких как удаление параметров плагина, пользовательских таблиц и т.д.

Активация

Чтобы настроить хук активации, используйте функцию register_activation_hook():

register_activation_hook( __FILE__, 'pluginprefix_function_to_run' );

Деактивация

Чтобы установить хук деактивации, используйте функцию register_deactivation_hook():

register_deactivation_hook( __FILE__, 'pluginprefix_function_to_run' );

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

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

Пример

Одним из наиболее распространенных способов использования хука активации является обновление постоянных ссылок WordPress, когда плагин регистрирует пользовательский тип записи. Это избавляет от неприятных 404 ошибок.

Давайте рассмотрим пример того, как это сделать:

/**
* Register the "book" custom post type
*/
function pluginprefix_setup_post_type() {
register_post_type( 'book', ['public' => true ] );
}
add_action( 'init', 'pluginprefix_setup_post_type' );


/**
* Activate the plugin.
*/
function pluginprefix_activate() {
// Trigger our function that registers the custom post type plugin.
pluginprefix_setup_post_type();
// Clear the permalinks after the post type has been registered.
flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'pluginprefix_activate' );

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

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

/**
* Deactivation hook.
*/
function pluginprefix_deactivate() {
// Unregister the post type, so the rules are no longer in memory.
unregister_post_type( 'book' );
// Clear the permalinks to remove our post type's rules from the database.
flush_rewrite_rules();
}
register_deactivation_hook( __FILE__, 'pluginprefix_deactivate' );

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

2.4 Методы деинсталляции

Вашему плагину может потребоваться некоторая очистка, когда он удаляется с сайта.

Плагин считается деинсталлированным, если пользователь деактивировал плагин, а затем кликает ссылку удаления в админке WordPress.

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

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

Эта таблица иллюстрирует различия между деактивацией и удалением.

СценарийХук деактивацииХук деинсталляции
Очистка кеш / временных файловДаНет
Очистка постоянных ссылокДаНет
Удаление параметров из {$wpdb-> prefix}_optionsНетДа
Удаление таблицы из wpdbНетДа

Метод 1: register_uninstall_hook

Чтобы настроить хук удаления, используйте функцию register_uninstall_hook():

register_uninstall_hook(__FILE__, 'pluginprefix_function_to_run');

Метод 2: uninstall.php

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

Например: /plugin-name/uninstall.php

Внимание! При использовании uninstall.php перед выполнением плагин всегда должен проверять константу WP_UNINSTALL_PLUGIN, чтобы предотвратить прямой доступ.

Константа будет определена WordPress во время вызова uninstall.php. Константа НЕ определяется, когда деинсталляция выполняется через register_uninstall_hook().

Вот пример удаления записей опций и удаления таблицы базы данных:

// если uninstall.php не вызван WordPress, die
if (!defined('WP_UNINSTALL_PLUGIN')) {
die;
}

$option_name = 'wporg_option';

delete_option($option_name);

// для опций сайтов в Мультисайте
delete_site_option($option_name);

// удалить пользовательскую таблицу базы данных
global $wpdb;
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}mytable");

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

2.5 Лучшие практики

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

Избегайте конфликтов имен

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

Процедурные

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

На переменные, которые определены внутри функций или классов, это не влияет.

Префикс для всего

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

Проверка существующих реализаций

PHP предоставляет ряд функций для проверки существования переменных, функций, классов и констант. Все они вернут истину (true), если сущность существует.

Пример

// создаем функцию "wporg_init" если она еще не существует
if ( !function_exists( 'wporg_init' ) ) {
function wporg_init() {
register_setting( 'wporg_settings', 'wporg_option_foo' );
}
}

// создаем функцию "wporg_get_foo" если она еще несуществует
if ( !function_exists( 'wporg_get_foo' ) ) {
function wporg_get_foo() {
return get_option( 'wporg_option_foo' );
}
}

ООП

Более простой способ решения проблемы коллизии имен — использовать класс для кода вашего плагина.

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

Пример

if ( !class_exists( 'WPOrg_Plugin' ) ) {
class WPOrg_Plugin
{
public static function init() {
register_setting( 'wporg_settings', 'wporg_option_foo' );
}

public static function get_foo() {
return get_option( 'wporg_option_foo' );
}
}

WPOrg_Plugin::init();
WPOrg_Plugin::get_foo();
}

Организация файлов

Корневой уровень вашей директории плагинов должен содержать ваш файл plugin-name.php и, необязательно, файл uninstall.php. Все остальные файлы должны быть организованы в подпапки, когда это возможно.

Структура папок

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

Вот пример структуры папок для справки:

/plugin-name
plugin-name.php
uninstall.php
/languages
/includes
/admin
/js
/css
/images
/public
/js
/css
/images

Архитектура плагина

Архитектура или организация кода, которую вы выбираете для своего плагина, вероятно, будет зависеть от размера вашего плагина.

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

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

Условная загрузка

Полезно отделить ваш код администратора от общедоступного кода. Используйте условный is_admin().

Например:

if ( is_admin() ) {
// мы в режиме админа
require_once __DIR__ . '/admin/plugin-name-admin.php';
}

Архитектурные паттерны

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

Объясненные паттернов архитектуры

Конкретные реализации более сложной из вышеперечисленных организаций кода уже были написаны в виде учебных пособий и слайдов:

  • Slash – Singletons, Loaders, Actions, Screens, Handlers (см. сайт jjj.blog)
  • Implementing the MVC Pattern in WordPress Plugins (см. сайт iandunn.name)

Стартовые точки Boilerplate (шаблона)

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

Это также служит дополнительными примерами различных, но сопоставимых архитектур.

  • WordPress Plugin Boilerplate: Основа для разработки плагинов WordPress, целью которой является предоставление четкого и последовательного руководства по созданию ваших плагинов.
  • WordPress Plugin Bootstrap: Базовый загрузчик для разработки плагинов WordPress с использованием Grunt, Compass, GIT и SVN.
  • WP Skeleton Plugin: Skeleton плагин, который фокусируется на модульных тестах и использовании композера для разработки.
  • WP CLI Scaffold: Команда Scaffold WP CLI создает каркасный плагин с такими параметрами, как файлы конфигурации CI.

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

2.6 Определение плагинов и директорий контента

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

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

WordPress позволяет пользователям размещать каталог wp-content в любом месте и переименовывать его по своему усмотрению. Никогда не думайте, что плагины будут в wp-content/plugins, загрузки будут в wp-content/uploads, или что темы будут в wp-content/themes.

Волшебная константа PHP __FILE__ автоматически разрешает символические ссылки, поэтому, если символические ссылки содержат wp-content или wp-content/plugins или даже отдельный каталог плагинов, жестко закодированные пути не будут правильно работать.

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

Если ваш плагин содержит файлы JavaScript, CSS-файлы или другие внешние файлы, вероятно, вам понадобится URL-адрес этих файлов, чтобы вы могли загрузить их на страницу. Для этого вы должны использовать функцию plugins_url() следующим образом:

plugins_url( 'myscript.js', _FILE_ );

Это вернет полный URL-адрес файла myscript.js, например:

example.com/wp-content/plugins/myplugin/myscript.js

Чтобы загрузить JavaScript или CSS ваших плагинов на страницу, вы должны использовать wp_enqueue_script() или wp_enqueue_style() соответственно, передавая результат plugins_url() в качестве URL файла.

Доступные функции

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

Плагины

plugins_url()
plugin_dir_url()
plugin_dir_path()
plugin_basename()

Темы

get_template_directory_uri()
get_stylesheet_directory_uri()
get_stylesheet_uri()
get_theme_root_uri()
get_theme_root()
get_theme_roots()
get_stylesheet_directory()
get_template_directory()

Главная страница

home_url()
get_home_path()

WordPress

admin_url()
site_url()
content_url()
includes_url()
wp_upload_dir()

Мультисайт

get_admin_url()
get_home_url()
get_site_url()
network_admin_url()
network_site_url()
network_home_url()

Константы

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

WP_CONTENT_DIR  // без косой черты, только полные пути
WP_CONTENT_URL // полный url
WP_PLUGIN_DIR // полный путь, без косой черты
WP_PLUGIN_URL // полный URL, без косой черты
// Доступно по умолчанию в Мультисайт, не устанавливается при установке на одном сайте
// Может использоваться в одиночной установке сайта (как обычно: на свой страх и риск)
UPLOADS // (Если установлено, загружает папку относительно ABSPATH) (например: /wp-content/uploads)

Каталоги WordPress

Каталоги WordPress:
home_url()Домашний URLhttp://www.example.com
site_url()URL каталога сайтаhttp://www.example.com или http://www.example.com/wordpress
admin_url()URL каталога администратораhttp://www.example.com/wp-admin
includes_url()URL-адрес каталога includeshttp://www.example.com/wp-includes
content_url()URL каталога содержимого (content)http://www.example.com/wp-content
plugins_url()URL каталога плагиновhttp://www.example.com/wp-content/plugins
wp_upload_dir()URL каталог uploads (возвращает массив)http://www.example.com/wp-content/uploads

2.7 Проверка активации плагина

Вы можете использовать class_exists в WordPress, чтобы проверить, активен ли плагин. Это необходимо сделать при использовании класса PHP плагина в вашей теме.

Официальная документация PHP — class_exists

Если вы не используете class_exists при использовании функций плагина в своей теме, вы получите сообщение об ошибке при загрузке страниц на сайте, если плагин деактивирован.

Давайте посмотрим на рабочий пример с использованием кода из очень популярного плагина WordPress Advanced Custom Fields (ACF).

Использование class_exists в вашей теме

Следующий код проверяет, активен ли плагин ACF. Используйте этот код с фрагментами кода, которые используют специальные функции ACF, такие как get_field();.

Если вы этого не сделаете, ваш код вызовет ошибки, если будет добавлен в файл темы, когда плагин ACF не активен.

Следующий код проверяет, активен ли плагин ACF, ища класс acf. Если класс acf не существует, оператор return немедленно завершает выполнение текущей функции.

if ( ! class_exists( 'acf' ) ) 
    return;

Пример кода

Следующий код будет работать нормально, если вы создали поле в ACF с именем after_header и активировали плагин.

add_action( 'genesis_before_loop', 'test_acf_function' );
function test_acf_function() {
    
    echo get_field( 'after_header' );
}

Однако вот что происходит, когда вы деактивируете плагин ACF:

Fatal error: Call to undefined function get_field()

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

Всегда добавляйте проверку для плагина при использовании функций плагина в вашей теме.

Вот обновленный код, который, как вы догадались, включает class_exists.

add_action( 'genesis_before_loop', 'test_acf_function' );
function test_acf_function() {
if ( ! class_exists( 'acf' ) ) 
    return;
    
    echo get_field( 'after_header' );
}

Приведенный выше код проверяет, если class_exists для плагина ACF, в противном случае возвращает false.

Другие методы

Другой метод с использованием тернарного оператора:

add_action( 'genesis_before_loop', 'test_acf_function' );
function test_acf_function() { 
    
$output = class_exists( 'acf' ) ? get_field( 'after_header' ) : get_post_meta( get_the_ID(), 'after_header', true );
    
echo $output;
}

Приведенный выше код проверяет, существует ли класс acf, что верно, когда подключаемый модуль ACF активен.

Если подключаемый модуль ACF активен, переменная $output использует функцию ACF get_field('after_header') в качестве своего значения.

В противном случае переменная $output равна get_post_meta( get_the_ID(), 'after_header', true );, что является функцией WordPress для настраиваемых (кастомных) полей и всегда работает в любой теме.

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

if ( ! class_exists( 'WooCommerce' ) )
    return;

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

2.8 Добавление CSS на фронтенд

Рассмотрим как добавляются стили CSS в плагине для отображения этих стилей во фронтенде WordPress.

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

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

<?php
/**
 * Plugin Name: plugin name
 * Plugin URI: http://www.pluginurl.com/
 * Description: plugin description
 * Version: 1.0
 * Author: author name
 * Author URI: http://www.authorurl.com/
 */

function wpsamurai_register_styles(){
    wp_register_style( 'wpsamurai_stylesheet', plugins_url( '/css/my-plugin.css', __FILE__ ) );
    wp_enqueue_style( 'wpsamurai_stylesheet' );
}

add_action( 'wp_enqueue_scripts', 'wpsamurai_register_styles' );

Файл стилей мы кладем в папку CSS в папке плагина. В нашем случае файл стилей мы назвали my-plugin.css, но название может быть любым, главное — не забыть поменять его в приведенном сниппете выше. Сам файл my-plugin.css может содержать все что угодно:

.classname { color: #000; }

Мы используем обычный хук действия wp_enqueue_scripts.

3. Безопасность плагинов

Поздравляем, ваш код работает! Но безопасно ли это? Как плагин защитит ваших пользователей, если их сайт будет взломан? Лучшие плагины в каталоге WordPress.org сохраняют информацию своих пользователей в безопасности.

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

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

3.1 Проверка возможностей пользователя

Если ваш плагин позволяет пользователям отправлять данные — будь то на Админ или на Публичной стороне — он должен проверить на User Capabilities (Возможности пользователя).

Роли пользователей и возможности

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

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

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

Например, основной пользователь вашего веб-сайта будет иметь роль User (Пользователь) администратора, в то время как у других пользователей могут быть роли типа Editor (Редактор) или Author (Автор). Вы можете назначить более одного пользователя на одну роль, т.е. на сайте может быть два администратора.

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

Например, администраторы имеют возможность «управлять_опциями» (manage_options), которая позволяет им просматривать, редактировать и сохранять опции сайта. Редакторы, с другой стороны, не имеют этой возможности, что препятствует их взаимодействию с опциями.

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

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

Иерархия

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

Например, «Администратор» (Administrator), которая является самой высокой пользовательской ролью на одном автономном сайте, наследует следующие роли и их возможности: «Подписчик» (Subscriber), «Участник» (Contributor), «Автор» (Author) и «Редактор» (Editor).

Пример (нет ограничений)

В примере, приведенном ниже, создается ссылка на фронтенде, которая дает возможность удалять статьи в корзину. Поскольку этот код не проверяет возможности пользователя, он позволяет любому посетителю удалять статьи!

<?php
/**
* создать ссылку Delete (удалить) на основе URL домашней страницы
*/
function wporg_generate_delete_link($content)
{
// запускать только для одного поста (single)
if (is_single() && in_the_loop() && is_main_query()) {
// добавить аргументы запроса: action, post
$url = add_query_arg(
[
'action' => 'wporg_frontend_delete',
'post' => get_the_ID(),
],
home_url()
);
return $content . ' <a href="' . esc_url($url) . '">' . esc_html__('Delete Post', 'wporg') . '</a>';
}
return null;
}

/**
* обработчик запросов
*/
function wporg_delete_post()
{
if (isset($_GET['action']) && $_GET['action'] === 'wporg_frontend_delete') {

// проверка на id поста
$post_id = (isset($_GET['post'])) ? ($_GET['post']) : (null);

// проверка наличия поста с таким номером
$post = get_post((int)$post_id);
if (empty($post)) {
return;
}

// удалить пост
wp_trash_post($post_id);

// перенаправление на страницу админа
$redirect = admin_url('edit.php');
wp_safe_redirect($redirect);

// готово
die;
}
}

/**
* добавить ссылку на удаление в конце статьи (content)
*/
add_filter('the_content', 'wporg_generate_delete_link');

/**
* зарегистрировать обработчик запроса с помощью хука init
*/
add_action('init', 'wporg_delete_post');

Пример (ограничения с конкретными возможностями)

Пример выше позволяет любому посетителю сайта нажать на ссылку «Удалить» (Delete) и удалить пост. Однако, мы хотим, чтобы только Редакторы и выше могли нажать на ссылку «Удалить».

Для этого мы проверим, что у текущего пользователя есть возможность редактирования постов edit_others_posts, которая есть только у редакторов и выше:

<?php
/**
* создать ссылку Delete на основе URL домашней страницы
*/
function wporg_generate_delete_link($content)
{
// запускать только для одного поста
if (is_single() && in_the_loop() && is_main_query()) {
// добавлять аргументы запроса: action, post
$url = add_query_arg(
[
'action' => 'wporg_frontend_delete',
'post' => get_the_ID(),
],
home_url()
);
return $content . ' <a href="' . esc_url($url) . '">' . esc_html__('Delete Post', 'wporg') . '</a>';
}
return null;
}

/**
* обработчик запросов
*/
function wporg_delete_post()
{
if (isset($_GET['action']) && $_GET['action'] === 'wporg_frontend_delete') {

// проверьте, есть ли у нас id поста
$post_id = (isset($_GET['post'])) ? ($_GET['post']) : (null);

// проверить наличие поста с таким номером
$post = get_post((int)$post_id);
if (empty($post)) {
return;
}

// удалить пост
wp_trash_post($post_id);

// перенаправление на страницу Админа
$redirect = admin_url('edit.php');
wp_safe_redirect($redirect);

// готово
die;
}
}

if (current_user_can('edit_others_posts')) {
/**
* добавить ссылку на удаление в конце публикации
*/
add_filter('the_content', 'wporg_generate_delete_link');

/**
* зарегистрировать обработчик запроса с помощью хука init
*/
add_action('init', 'wporg_delete_post');
}

3.2 Валидация данных

Валидация данных — это процесс анализа данных по предопределенному шаблону (или шаблонам) с окончательным результатом: действительным или недействительным.

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

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

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

Валидацию данных следует проводить как можно раньше. Это означает, что перед выполнением каких-либо действий необходимо проверить данные.

Валидация может быть выполнена с помощью JavaScript на фронтенде и с помощью PHP на бекэнде.

Проверка данных

Существует как минимум три способа: встроенные функции PHP, основные функции WordPress и пользовательские функции, которые вы пишете.

Встроенные функции PHP

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

  • isset() и empty() для проверки, существует ли переменная и не пуста ли она
  • mb_strlen() или strlen() для проверки, что строка имеет ожидаемое количество символов
  • preg_match(), strpos() для проверки на наличие вхождения одних строк в другие
  • count() для проверки количества элементов в массиве
  • in_array() для проверки, существует ли что-то в массиве

Функции ядра WordPress

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

  • is_email() будет проверять действительность адреса электронной почты
  • term_exists() проверяет, существует ли тег, категория или другой таксономический термин
  • функция username_exists() проверяет, существует ли имя пользователя
  • validate_file() подтвердит, что введенный путь к файлу является реальным путем (но не существует ли файл!)

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

Поиск функций с подобными названиями: *exists(), *_validate() и is*(). Не все из них являются функциями проверки, но многие из них полезны.

Пользовательские функции PHP и JavaScript

Вы можете написать свои собственные PHP и JavaScript функции и включить их в свой плагин. При написании функции валидации вы захотите назвать ее как вопрос (примеры: is_phone, is_available, is_us_zipcode).

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

Пример 1

Допустим, у вас есть поле ввода почтового индекса США, которое отправляет пользователь.

<input id="wporg_zip_code" type="text" maxlength="10" name="wporg_zip_code">

Текстовое поле позволяет вводить до 10 символов без ограничений по типу используемых символов. Пользователь может ввести что-то действительное, например 1234567890 или что-то недействительное (и злое), например eval().

Атрибут максимальной длины (maxlength) в нашем поле ввода вводится только браузером, поэтому вам все равно придется проверять длину вводимого значения на сервере. Если вы этого не сделаете, атакующий может изменить значение maxlength.

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

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

<?php
function is_us_zip_code($zip_code)
{
// сценарий 1: empty (пусто)
if (empty($zip_code)) {
return false;
}

// сценарий 2: более 10 символов
if (strlen(trim($zip_code)) > 10) {
return false;
}

// сценарий 3: неверный формат
if (!preg_match('/^\d{5}(\-?\d{4})?$/', $zip_code)) {
return false;
}

// успешно пройден
return true;
}

При обработке формы ваш код должен проверить поле wporg_zip_code и выполнить действие на основании результата:

if (isset($_POST['wporg_zip_code']) && is_us_zip_code($_POST['wporg_zip_code'])) {
// выше действие
}

Пример 2

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

Данный пример кода проверяет входящий ключ сортировки (хранящийся во входном параметре «orderby«) на корректность, сравнивая его с массивом разрешенных ключей сортировки с помощью встроенной PHP-функции in_array. Это предотвращает передачу пользователем вредоносных данных и потенциальную угрозу для сайта.

Перед проверкой входящего ключа сортировки по массиву, ключ передается во встроенную функцию WordPress sanitize_key. Эта функция, помимо прочего, гарантирует, что ключ находится в строчном регистре (in_array выполняет поиск с учетом регистра).

Передача «true» в третий параметр in_array позволяет выполнить строгую проверку типа, которая говорит функции не только сравнивать значения, но и типы значений. Это позволяет коду быть уверенным, что входящий ключ сортировки — это строка, а не какой-то другой тип данных.

<?php
$allowed_keys = ['author', 'post_author', 'date', 'post_date'];

$orderby = sanitize_key($_POST['orderby']);

if (in_array($orderby, $allowed_keys, true)) {
// изменить запрос, чтобы отсортировать его по порядковым ключам
}

3.3 Безопасность Ввода

Защита ввода данных — это процесс очищения (фильтрации) входных данных.

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

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

Очистка данных

Самый простой способ очистки данных — это встроенные функции WordPress.

Ряд вспомогательных функций sanitize_*() очень полезен, так как эти функции гарантируют, что вы получите безопасные данные, и это требует минимальных усилий с вашей стороны:

Пример

Допустим, у нас есть поле ввода с именем title.

<input id="title" type="text" name="title">

Очистить входные данные можно с помощью функции sanitize_text_field():

$title = sanitize_text_field($_POST['title']);
update_post_meta($post->ID, 'title', $title);

Функция sanitize_text_field() делает следующее:

  • Проверки на недействительный UTF-8
  • Преобразовывает одиночные символы (<) в сущность
  • Удаляет теги
  • Удаляет разрывы строк, табуляции и дополнительное белое пространство
  • Удаляет октеты

3.4 Безопасность Вывода

Обеспечение безопасности вывода — это процесс экранирования выходных данных.

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

Всякий раз, когда вы визуализируете данные, убедитесь, что они правильно экранируются. Экранирование выходных данных предотвращает XSS атаки (межсайтовый скриптинг).

Межсайтовый скриптинг (XSS) — это тип уязвимости компьютерной безопасности, обычно встречающейся в веб-приложениях. XSS позволяет злоумышленникам внедрять клиентские скрипты в веб-страницы, просматриваемые другими пользователями. Уязвимость межсайтового скриптинга может использоваться злоумышленниками для обхода контроля доступа, например, с помощью правила ограничения домена (same-origin policy).

Escaping (экранирование)

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

  • esc_html() — Используйте эту функцию в любое время, когда HTML-элемент заключает в себе участок отображаемых данных.
  • esc_url() — Используйте эту функцию для всех URL, включая те, которые находятся в атрибутах src и href HTML-элемента.
  • esc_js() — Используйте эту функцию для встроенного Javascript.
  • esc_attr() — Используйте эту функцию для всего остального, что выводится в атрибут HTML-элемента.

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

Эскейпинг с локализацией

Вместо того, чтобы использовать echo для вывода данных, обычно используются функции локализации WordPress, такие как _e() или __().

Эти функции просто обертывают функцию локализации внутри экранирующей функции:

esc_html_e( 'Hello World', 'text_domain' );
// точно так же, как
echo esc_html( __( 'Hello World', 'text_domain' ) );

Эти вспомогательные функции сочетают в себе локализацию и экранирование:

Собственный Escaping

В случае, если вам необходимо экранировать ваш вывод определенным образом, вам пригодится функция wp_kses() (произносится как «поцелуй» — kisses).

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

$allowed_html = [
'a' => [
'href' => [],
'title' => [],
],
'br' => [],
'em' => [],
'strong' => [],
];
echo wp_kses( $custom_content, $allowed_html );

wp_kses_post() — функция обёртывания для wp_kses, где $allowed_html — набор правил, используемых для содержимого записи.

echo wp_kses_post( $post_content );

3.5 Одноразовые числа (nonces)

Nonces — это генерируемые числа, используемые для проверки происхождения и интента (намерение) запросов в целях безопасности. Каждое число может быть использована только один раз.

Nonce так и расшифровывается — «число, используемое один раз» (англ. — number used once). Некоторые пользователи называют их токенами.

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

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

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

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

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

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

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

Подробный пример

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

<?php
/**
* generate a Delete link based on the homepage url
*/
function wporg_generate_delete_link($content)
{
// run only for single post page
if (is_single() && in_the_loop() && is_main_query()) {
// add query arguments: action, post, nonce
$url = add_query_arg(
[
'action' => 'wporg_frontend_delete',
'post' => get_the_ID(),
'nonce' => wp_create_nonce('wporg_frontend_delete'),
],
home_url()
);
return $content . ' <a href="' . esc_url($url) . '">' . esc_html__('Delete Post', 'wporg') . '</a>';
}
return null;
}

/**
* request handler
*/
function wporg_delete_post()
{
if (
isset($_GET['action']) &&
isset($_GET['nonce']) &&
$_GET['action'] === 'wporg_frontend_delete' &&
wp_verify_nonce($_GET['nonce'], 'wporg_frontend_delete')
) {

// verify we have a post id
$post_id = (isset($_GET['post'])) ? ($_GET['post']) : (null);

// verify there is a post with such a number
$post = get_post((int)$post_id);
if (empty($post)) {
return;
}

// delete the post
wp_trash_post($post_id);

// redirect to admin page
$redirect = admin_url('edit.php');
wp_safe_redirect($redirect);

// we are done
die;
}
}

if (current_user_can('edit_others_posts')) {
/**
* add the delete link to the end of the post content
*/
add_filter('the_content', 'wporg_generate_delete_link');

/**
* register our request handler with the init hook
*/
add_action('init', 'wporg_delete_post');
}

3.6 Защита файлов плагина

Создание плагина WordPress подразумевает и защиту файлов плагина от прямого доступа.

<?php 
    if ( ! defined( 'ABSPATH' ) ) {
        exit; // выйти если обращаются напрямую
    }
?>

Предотвращает пользователям прямой доступ к вашим .php-файлам по URL. Иначе, если ваш файл содержит некоторые операции ввода/вывода, он может быть вызван (злоумышленником), и это может привести к неожиданному поведению.

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

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

  • может быть размещен в верхней части любого из ваших PHP-файлов (темы и плагинов);
  • может быть размещен в верхней части вашего wp-config.php.

ABSPATH — это константа PHP, определяемая WordPress в нижней части wp-config.php:

/* That's all, stop editing! Happy blogging. */

/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');

Как видно из блока комментариев выше, WordPress не рекомендует изменять эти строки кода — вероятно, потому, что многие плагины и темы полагаются на ABSPATH для проверки того, выполняются ли их PHP-файлы в среде WordPress.

Если вы используете этот фрагмент в верхней части вашего файла wp-config.php, вы остановите выполнение wp-config.php, потому что ABSPATH на тот момент еще не был определен. А другие файлы, зависящие от wp-config.php, не будут работать (т.е. вы сломаете свой сайт).

Этот сниппет широко используется PHP-файлами плагинов и тем только условно. Теоретически это означает, что вы можете добавить свою собственную константу в нижней части wp-config.php, и вы получите тот же практический результат.

Ваш wp-config.php:

if ( !defined('MY_CONSTANT') )
    define('MY_CONSTANT', 'fool');

Ваш файл темы или плагина:

<?php 
    if ( ! defined( 'MY_CONSTANT' ) ) {
        exit; // выйти если обращаются напрямую
    }

Более подробно об этом почитать можно на официальном сайта PHP в справке по синтаксису констант и волшебным константам.

4. Хуки (Hooks)

Как я писал ранее создание плагина WordPress без хуков — невозможно. Плагины WordPress взаимодействуют с основным кодом с помощью именно хуков (крючков). Существует два разных типа хуков WordPress:

  • Хуки действий (экшенов) — добавление или удаление функций
  • Хуки фильтров — изменяют данные, созданные функциями

На английском языке в руководствах они называются Action hooks (действия) и Filter hooks (фильтры). В дальнейшем мы часто будем использовать эти два слова — экшены и фильтры.

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

Есть два типа хуков: Действия (Actions) и Фильтры (Filters). Чтобы использовать любой из них, вам нужно написать пользовательскую функцию, известную как Callback, а затем зарегистрировать ее с помощью хука WordPress для конкретного действия или фильтра.

Callback-функции — это Функции обратного вызова.

Действия (Actions) позволяют добавлять данные или изменять работу WordPress. Функции обратного вызова для Actions будут выполняться в определенных точках при выполнении WordPress, и могут выполнять какие-то задачи, например, выводить данные пользователю или вставлять что-то в базу данных. Экшены не возвращают ничего обратно в вызывающий хук.

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

Основное различие между действием и фильтром можно резюмировать следующим образом:

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

Другими словами:

  • действие прерывает поток кода, чтобы что-то сделать, а затем возвращается в нормальный поток, ничего не изменяя;
  • фильтр используется для модификации чего-либо определенным образом, так что модификация затем используется кодом.

«Что-то» — это список параметров, посылаемый через определение хука. Подробнее об этом в следующих разделах.

4.1 Действия (Actions или экшены)

Действия — один из двух видов Хуков (Hooks). Они обеспечивают способ выполнения функции в определенных точках выполнения в ядре WordPress Core, плагинах и темах. Они являются аналогом Фильтров (Filters). Дополнительная информация о разнице между действиями и фильтрами ниже.

Действие (action) — это функция PHP, вызываемая через определенный хук действия при посещении пользователем страницы WordPress. Веб-разработчики могут добавлять собственные функции в список действий или удалять уже существующие, добавляя скрипт хука действия wp_head() перед закрывающим тегом (</head>) любой страницы.

Хуки действий являются контекстными, что означает, что не все страницы WordPress вызывают их. На странице WordPress Plugin Action Reference представлен полный список хуков действий и контекстов, в которых они вызываются.

Добавление действия

Процесс добавления действия включает в себя два этапа:

Создание функции обратного вызова (callback)

Сначала создайте функцию обратного вызова (callback function). Эта функция будет запущена, когда будет выполнено действие, к которому она привязана (или зацеплена хуком).

Функция обратного вызова похожа на обычную функцию: она должна быть префиксной и должна быть в файле functions.php или где-нибудь в вызываемом месте. Параметры, которые она должна принять, будут определяться действием (action), к которому вы подключаетесь (цепляетесь хуком); большинство хуков хорошо определены, поэтому просмотрите документацию хуков, чтобы увидеть, какие параметры выбранное вами действие будет передавать в вашу функцию.

Присваивание (хук) вашей функции обратного вызова

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

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

  1. строка (string) $tag — название действия, к которому вы цепляетесь (hook)
  2. вызываемая $function_to_add имя вашей функции обратного вызова

В примере ниже будет запущена функция wporg_callback() при выполнении инициализации хука:

function wporg_callback() {
// сделать что-то
}
add_action( 'init', 'wporg_callback' );

Список доступных хуков можно найти в главе «Хуки».

Как только у вас появится больше опыта, просмотр исходного кода ядра WordPress позволит вам находить наиболее подходящие хуки.

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

add_action() может принимать два дополнительных параметра, int $priority для приоритета, отдаваемого функции обратного вызова, и int $accepted_args для количества аргументов, которые будут переданы функции обратного вызова.

Приоритет

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

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

Вот некоторые важные факты о приоритетах:

  • приоритеты — положительные целые числа, обычно от 1 до 20
  • приоритет по умолчанию (т.е. приоритет, назначенный, когда значение приоритета не задается вручную) равен 10
  • теоретически нет верхнего предела для значения приоритета, но реалистичный верхний предел составляет 100

Функция с приоритетом 11 будет выполняться после функции с приоритетом 10; а функция с приоритетом 9 будет выполняться перед функцией с приоритетом 10.

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

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

add_action('init', 'wporg_callback_run_me_late', 11);
add_action('init', 'wporg_callback_run_me_normal');
add_action('init', 'wporg_callback_run_me_early', 9);
add_action('init', 'wporg_callback_run_me_later', 11);

В примере выше:

  • Первой выполняемой функцией будет функция wporg_call_backrun_me_early(), так как она имеет ручной приоритет 9
  • Далее, wporg_callback_run_me_normal(), потому что она не имеет установленного приоритета, а значит, ее приоритет 10
  • Далее выполняется функция wporg_callback_run_me_late(), поскольку ее ручной приоритет 11
  • Наконец, запущена функция wporg_callback_run_me_later(): она также имеет приоритет 11, но была подключена после wporg_callback_run_me_late().

Количество аргументов

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

Например, когда WordPress сохраняет запись и запускает хук save_post, он передаёт в функцию обратного вызова два параметра: идентификатор сохраняемой записи и сам объект записи:

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

Когда функция обратного вызова зарегистрирована для хука save_post, то она может указать, что хочет получить эти два параметра. Она делает это, сказав add_action ожидать их, поместив 2 в качестве четвертого аргумента:

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

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

function wporg_custom( $post_id, $post ) {
// сделать что-то
}

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

Добавление функций к хуку действия в файле плагина требует вызова функции add_action() как минимум с двумя параметрами.

// Хук для действия 'init', которое вызывается после того, как WordPress закончит загрузку основного кода

add_action( 'init', 'add_Cookie' );

// Установка cookie с текущим временем суток

function add_Cookie() {
 setcookie("last_visit_time", date("r"), time()+60*60*24*30, "/");
}

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

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

Справка. Callback (англ. call — вызов, англ. back — обратный) или функция обратного вызова в программировании — передача исполняемого кода в качестве одного из параметров другого кода.

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

Пример кода плагина для отображения текста после футера каждой страницы

Этот пример плагина вызывает хук действия wp_footer() перед закрывающим тегом </body> каждой страницы и добавляет новую функцию mfp_Add_Text(). Поскольку эта функция является частью плагина, она будет работать даже после смены темы.

Сохраните этот пример как PHP-файл и загрузите его в папку plugins, которая находится внутри папки wp-content.

<?php
/*
Plugin Name: Add Text To Footer
*/
// Цепляем хук действия 'wp_footer', добавляем в него функцию с именем 'mfp_Add_Text'

add_action("wp_footer", "mfp_Add_Text");
 
// Определяем функцию 'mfp_Add_Text'

function mfp_Add_Text()
{
  echo "<p style='color: black;'>After the footer is loaded, my text is added!</p>";
}

На скриншоте ниже видим, что после активации плагина через панель администратора WordPress выводит на сайте следующее:

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

Удаление функций из хука действия с помощью remove_action()

Чтобы удалить действие из хука действия, напишите новую функцию remove_action(), а затем вызовите написанную функцию с помощью add_action().

Функция remove_action() также должна содержать как минимум 2 параметра.

// В действие 'init', которое вызывается после завершения загрузки кода ядра WordPress, добавьте функцию 'remove_My_Meta_Tags'.

add_action( 'init', 'remove_My_Meta_Tags' );

// Удалите функцию 'add_My_Meta_Tags' из хука действия wp_head

function remove_My_Meta_Tags()
{
  remove_action( 'wp_head', 'add_My_Meta_Tags');
}

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

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

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

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

<?php
// Подцепите действие 'wp_footer', запустите функцию с именем 'mfp_Add_Text()'.

add_action("wp_footer", "mfp_Add_Text");

// Подцепите действие 'wp_head', запустите функцию с именем 'mfp_Remove_Text()'.

add_action("wp_head", "mfp_Remove_Text");

// Определяем функцию с именем 'mfp_Add_Text('), которая просто выводит простой текст методом echo

function mfp_Add_Text()
{
  echo "<p style='color: #FFF;'>After the footer is loaded, my text is added!</p>";
}

// Определяем функцию с именем 'mfp_Remove_Text()', чтобы удалить нашу предыдущую функцию из действия 'wp_footer'

function mfp_Remove_Text()
{
  if (date("l") === "Monday") {

    // удаляем из 'wp_footer' функцию 'mfp_Add_Text' с учетом условия if выше

    remove_action("wp_footer", "mfp_Add_Text");
  }
}

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

4.2 Фильтры (Filters)

Фильтры — один из двух типов Хуков (hooks).

Они дают возможность функциям изменять данные других функций. Они являются аналогом действий (Action-ов).

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

Добавить фильтр

Процесс добавления фильтра включает в себя два этапа.

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

Вы будете использовать функцию add_filter(), передавая как минимум два параметра, string $tag, вызываемую $function_to_add.

Пример ниже будет запущен при выполнении the_title.

<?php
function wporg_filter_title($title)
{
return 'The ' . $title . ' was filtered';
}
add_filter('the_title', 'wporg_filter_title');

Допустим, у нас есть заголовок публикации «Learning WordPress», в приведенном выше примере он будет изменен на «The Learning WordPress was filtered».

Этот блок имеет неожидаемое или неверное содержимое.

Попытка восстановления блока

Список доступных хуков можно найти в главе «b>Хуки».

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

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

add_filter() может принимать два дополнительных параметра, int $priority для приоритета, отдаваемого функции обратного вызова, и int $accepted_args для количества аргументов, которые будут переданы функции обратного вызова.

Подробное объяснение этих параметров можно найти в статье о действиях.

Пример

Добавление класса CSS к тегу при выполнении определенного условия:

<?php
function wporg_css_body_class($classes)
{
if (!is_admin()) {
$classes[] = 'wporg-is-awesome';
}
return $classes;
}
add_filter('body_class', 'wporg_css_body_class');

Фильтер (filter) — это функция PHP, вызываемая определенным хуком filter, которая изменяет данные, возвращаемые существующими функциями. Как и хуки действий, хуки фильтров также зависят от контекста.

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

Добавление фильтров с помощью функции add_filter()

Добавление функции фильтра к хуку фильтра в файле плагина требует вызова функции add_filter() как минимум с 2 параметрами.

// Подцепите хук фильтра 'the_content' (содержимое любой статьи), запустите функцию с именем 'mfp_Fix_Text_Spacing'.

add_filter("the_content", "mfp_Fix_Text_Spacing");

// Автоматическое исправление двойных пробелов в любой записи

function mfp_Fix_Text_Spacing($the_Post)
{
 $the_New_Post = str_replace("  ", " ", $the_Post);
 return $the_New_Post;
}

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

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

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

Пример плагина для изменения отрывка поста

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

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

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

<?php
/*
Plugin Name: Add Excerpt 
*/
// Подцепите хук фильтра get_the_excerpt, запустите функцию mfp_Add_Text_To_Excerpt

add_filter("get_the_excerpt", "mfp_Add_Text_To_Excerpt");

// Берем отрывок, добавляем перед ним текст и возвращаем новый отрывок

function mfp_Add_Text_To_Excerpt($old_Excerpt)
{
  $new_Excerpt = "<b>Excerpt: </b>" . $old_Excerpt;
  return $new_Excerpt;
}

Удаление фильтров с помощью remove_filter()

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

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

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

// Перехватите хук фильтра get_the_excerpt, запустите функцию с именем mfp_Add_Text_To_Excerpt.

add_filter("get_the_excerpt", "mfp_Add_Text_To_Excerpt");

// Если сегодня четверг, удалите фильтр из the_excerpt()

if (date("l") === "Thursday") {
  remove_filter("get_the_excerpt", "mfp_Add_Text_To_Excerpt");
}

// Возьмите отрывок, добавьте перед ним текст и верните новый отрывок

function mfp_Add_Text_To_Excerpt($old_Excerpt)
{
  $new_Excerpt = "<b>Excerpt: </b>" . $old_Excerpt;
  return $new_Excerpt;
}

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

Важно! Использование тестового сайта WordPress для тестирования новых плагинов поможет вам избежать ошибок, которые могут привести к простою. Существует два способа создания среды тестирования — вручную или с помощью плагина, например, WP Staging. В качестве альтернативы установите WordPress локально на свой компьютер.

4.3 Пользовательские хуки

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

Пользовательские хуки создаются и вызываются так же, как и хуки ядра WordPress.

Создание хука

Для создания пользовательского хука используйте do_action() для экшенов и apply_filters() для фильтров.

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

Добавление Callback на Хук

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

Конфликты с названиями

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

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

Название функции wporg_email_body (где wporg_ является уникальным префиксом для вашего плагина) позволит избежать любых конфликтов.

Расширяемый экшен: Форма настроек

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

Foo: 
Bar:
<?php
do_action( 'wporg_after_settings_page_html' );
}

Теперь другой плагин может зарегистрировать функцию обратного вызова (callback) для хука wporg_after_settings_page_html и вставить новые настройки:

New 1: 
<?php
}
add_action( 'wporg_after_settings_page_html', 'myprefix_add_settings' );

Расширяемый фильтр: Пользовательский тип записи

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

<?php
function wporg_create_post_type()
{
$post_type_params = [/* ... */];

register_post_type(
'post_type_slug',
apply_filters( 'wporg_post_type_params', $post_type_params )
);
}

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

<?php 
function myprefix_change_post_type_params( $post_type_params ) {
$post_type_params['hierarchical'] = true;
return $post_type_params;
}
add_filter( 'wporg_post_type_params', 'myprefix_change_post_type_params' );

Дополнительные ресурсы:

  • Extendable Extensions Майкла Филдса
  • The Pluggable Plugin Брендана Дова
  • WordPress Plugin Pet Peeves #3: Not Being Extensible Уилла Норриса (см. сайт willnorris.com)

4.4 Продвинутые возможности

Удаление действий и фильтров

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

Чтобы удалить функцию обратного вызова с хука, необходимо вызвать функцию remove_action() или remove_filter(), в зависимости от того, была ли функция обратного вызова добавлена как Action или как Filter.

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

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

Пример

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

Проанализируем код темы, заглянув в function.php.

<?php
function my_theme_setup_slider()
{
// ...
}
add_action('template_redirect', 'my_theme_setup_slider', 9);

Функция my_theme_setup_slider добавляет слайдер, который нам не нужен, который, вероятно, загружает огромный CSS-файл с последующим инициализационным файлом JavaScript, использующим пользовательскую написанную библиотеку размером 1MB. Мы можем от этого избавиться.

Так как мы хотим зацепиться (хук) в WordPress после регистрации функции обратного вызова my_theme_setup_slider (выполняется functions.php), наш лучший вариант — хук after_setup_theme.

<?php
function wporg_disable_slider()
{
// make sure all parameters match the add_action() call exactly
remove_action('template_redirect', 'my_theme_setup_slider', 9);
}
// make sure we call remove_action() after add_action() has been called
add_action('after_setup_theme', 'wporg_disable_slider');

Удаление всех Callback-функций

Вы также можете удалить все функции обратного вызова, связанные с хуком, с помощью функций remove_all_actions() / remove_all_filters().

Определение текущего хука

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

Вы можете использовать current_action() / current_filter() для определения текущего экшена / фильтра.

<?php
function wporg_modify_content($content)
{
switch (current_filter()) {
case 'the_content':
// do something
break;
case 'the_excerpt':
// do something
break;
}
return $content;
}
add_filter('the_content', 'wporg_modify_content');
add_filter('the_excerpt', 'wporg_modify_content');

Проверка, сколько раз был запущен хук

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

В этой ситуации вы можете проверить, сколько раз хук выполнялся с помощью функции did_action().

<?php
function wporg_custom()
{
if (did_action('save_post') !== 1) {
return;
}
// ...
}
add_action('save_post', 'wporg_custom');

Отладка хуком «all»

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

<?php
function wporg_debug()
{
echo '<p>' . current_action() . '</p>';
}
add_action('all', 'wporg_debug');

5. Меню администрирования

Меню администрирования — это интерфейсы, отображаемые в панели администрирования WordPress. Они позволяют вам добавлять страницы опций для вашего плагина.

Информацию об управлении навигационными меню см. в главе «Навигационные меню» Руководства для разработчиков тем.

Меню верхнего уровня и подменю

Меню верхнего уровня отображается в левой части панели администрирования WordPress. Каждое меню может содержать набор подменю.

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

Внимание! Мы рекомендуем разработчикам с одной опционной страницей добавить ее в качестве Подменю в одно из существующих меню верхнего уровня; например, «Настройки» (Settings) или «Инструменты» (Tools).

5.1 Меню верхнего уровня

Для добавления нового меню верхнего уровня в WordPress Administration используйте функцию add_menu_page().

<?php
add_menu_page(
string $page_title,
string $menu_title,
string $capability,
string $menu_slug,
callable $function = '',
string $icon_url = '',
int $position = null
);

Пример

Допустим, мы хотим добавить новое меню верхнего уровня под названием «WPOrg».

Первым шагом будет создание функции, которая будет выводить HTML. В этой функции мы выполним необходимые проверки безопасности и отобразим зарегистрированные нами опции с помощью Settings API (Настройки API).

Мы рекомендуем обернуть ваш HTML с помощью <div> с классом wrap.
<?php
function wporg_options_page_html() {
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<form action="options.php" method="post">
<?php
// output security fields for the registered setting "wporg_options"
settings_fields( 'wporg_options' );
// output setting sections and their fields
// (sections are registered for "wporg", each field is registered to a specific section)
do_settings_sections( 'wporg' );
// output save settings button
submit_button( __( 'Save Settings', 'textdomain' ) );
?>
</form>
</div>
<?php
}
?>

Вторым шагом будет регистрация нашего меню WPOrg. Регистрация должна произойти во время перехвата ([erf) действия admin_menu.

<?php
add_action( 'admin_menu', 'wporg_options_page' );
function wporg_options_page() {
add_menu_page(
'WPOrg',
'WPOrg Options',
'manage_options',
'wporg',
'wporg_options_page_html',
plugin_dir_url(__FILE__) . 'images/icon_wporg.png',
20
);
}
?>

Список параметров и то, что каждый из них делает, смотрите в справке add_menu_page().

Использование PHP-файла для HTML

Лучшей практикой для переносимого кода было бы создание функции обратного вызова (Callback), которая требует/включает в себя ваш PHP-файл.

Для полноты и облегчения понимания унаследованного кода мы покажем другой способ: передача пути к PHP-файлу в виде параметра $menu_slug с параметром null $function.

<?php
add_action( 'admin_menu', 'wporg_options_page' );
function wporg_options_page() {
add_menu_page(
'WPOrg',
'WPOrg Options',
'manage_options',
plugin_dir_path(__FILE__) . 'admin/view.php',
null,
plugin_dir_url(__FILE__) . 'images/icon_wporg.png',
20
);
}
?>

Удаление меню верхнего уровня

Чтобы удалить зарегистрированное меню из администрирования WordPress, используйте функцию remove_menu_page().

<?php
remove_menu_page(
string $menu_slug
);
?>

Удаление меню не помешает пользователям получить к ним прямой доступ. Это никогда не должно использоваться как способ ограничить возможности пользователей.

Пример

Допустим, мы хотим убрать меню «Инструменты» (Tools).

<?php
add_action( 'admin_menu', 'wporg_remove_options_page', 99 );
function wporg_remove_options_page() {
remove_menu_page( 'tools.php' );
}
?>

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

Отправка форм

Чтобы обработать отправку форм на страницах параметров, вам понадобятся две вещи:

  1. Используйте URL-адрес страницы в качестве атрибута действия формы.
  2. Добавьте хук со слагом (slug), возвращаемый add_menu_page.

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

Атрибут действия формы

Используйте параметр $menu_slug страницы параметров в качестве первого параметра menu_page_url(). Функция автоматически экранирует URL и выводит его по умолчанию, поэтому вы можете напрямую использовать его в теге <form>:

<form action="<?php menu_page_url( 'wporg' ) ?>" method="post">

Обработка формы

$function, указанная вами при добавлении страницы, будет вызываться только тогда, когда пришло время отобразить страницу, что делает ее неуместной, если вам нужно отправить заголовки (например, перенаправления) обратно в браузер.

add_menu_page возвращает $hookname, а WordPress запускает действие «load-$hookname» перед любым выводом HTML. Вы можете использовать это, чтобы назначить функцию, которая может обрабатывать форму.

«load-$hookname» будет выполняться каждый раз перед отображением страницы параметров, даже если форма не отправляется.

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

add_action( 'admin_menu', 'wporg_options_page' );
function wporg_options_page() {
$hookname = add_menu_page(
'WPOrg',
'WPOrg Options',
'manage_options',
'wporg',
'wporg_options_page_html',
plugin_dir_url(__FILE__) . 'images/icon_wporg.png',
20
);

add_action( 'load-' . $hookname, 'wporg_options_page_submit' );
}

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

  1. Отправляется ли форма ('POST' === $_SERVER['REQUEST_METHOD']).
  2. Проверка CSRF
  3. Валидация (Validation)
  4. Очистка (Sanitization)

5.2 Подменю

Добавление подменю

Чтобы добавить новое Подменю в панели администрирования WordPress, используйте функцию add_submenu_page().

add_submenu_page(
string $parent_slug,
string $page_title,
string $menu_title,
string $capability,
string $menu_slug,
callable $function = ''
);

Пример

Допустим, мы хотим добавить подменю «Параметры WPOrg» (WPOrg Options) в меню верхнего уровня «Инструменты» (Tools).

Первым шагом будет создание функции, которая будет выводить HTML. В этой функции мы выполним необходимые проверки безопасности и отобразим зарегистрированные нами опции с помощью Settings API.

Мы рекомендуем обернуть ваш HTML с помощью <div> с классом wrap.
function wporg_options_page_html() {
// check user capabilities
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<form action="options.php" method="post">
<?php
// output security fields for the registered setting "wporg_options"
settings_fields( 'wporg_options' );
// output setting sections and their fields
// (sections are registered for "wporg", each field is registered to a specific section)
do_settings_sections( 'wporg' );
// output save settings button
submit_button( __( 'Save Settings', 'textdomain' ) );
?>
</form>
</div>
<?php
}

Вторым шагом будет регистрация нашего подменю «WPOrg Options». Регистрация должна произойти во время перехвата действия admin_menu.

function wporg_options_page()
{
add_submenu_page(
'tools.php',
'WPOrg Options',
'WPOrg Options',
'manage_options',
'wporg',
'wporg_options_page_html'
);
}
add_action('admin_menu', 'wporg_options_page');

Список параметров и то, что каждый из них делает, смотрите в справке add_submenu_page().

Предопределённые подменю

Было бы здорово, если бы у нас были вспомогательные функции, определяющие $parent_slug для встроенного меню верхнего уровня WordPress и избавляющие нас от ручного поиска по исходному коду?

Ниже приведен список родительских слагов и их вспомогательных функций:

Удаление подменю

Процесс удаления подменю точно такой же, как и удаление меню верхнего уровня.

Отправка форм

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

add_submenu_page() вместе со всеми функциями для предопределенных подменю (add_dashboard_page, add_posts_page и т.д.) вернет $hookname, которое вы можете использовать в качестве первого параметра add_action для обработки отправки форм на пользовательских страницах:

function wporg_options_page() {
$hookname = add_submenu_page(
'tools.php',
'WPOrg Options',
'WPOrg Options',
'manage_options',
'wporg',
'wporg_options_page_html'
);

add_action( 'load-' . $hookname, 'wporg_options_page_html_submit' );
}

add_action('admin_menu', 'wporg_options_page');

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

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

Оригинал статьи
Опубликовано 12 февраля 2023 в 23:47
Обновлено 25 сентября 2023 в 01:30
Категория: Блог
Теги: