Собственные плагины WordPress: от идеи до реализации

Раздел: WordPress -> Расширения WordPress

Создание и настройка плагинов WordPress: базовые принципы и варианты реализации

Как создать минимальный работоспособный плагин для WordPress?

Основной и наиболее эффективный способ создания плагина заключается в оформлении PHP файла с корректным заголовком и подключении его к системе хуков и фильтров. Плагин представляет собой папку в wp-content/plugins с главным файлом, содержащим в начале комментарий с описанием.


<?php
/*
Plugin Name: Мой первый плагин
Plugin URI: https://example.com
Description: Простой плагин для добавления приветственного сообщения.
Version: 1.0.0
Author: Ваше Имя
Author URI: https://example.com
License: GPL v2 or later
*/

// Хук для вывода сообщения в футере
add_action('wp_footer', 'my_first_plugin_footer_message');

function my_first_plugin_footer_message() {
    echo '<p>Спасибо, что используете наш сайт!</p>';
}

Wp plugins php (плагины wordpress)

После сохранения файла (например, my-first-plugin.php) в папке wp-content/plugins/my-first-plugin/ плагин появится в админке в разделе Плагины. После активации на всех страницах сайта в подвале будет выведено указанное сообщение.

Типичные ошибки:

  • Отсутствие закрывающего PHP тега? - не рекомендуется, но его отсутствие может вызвать ошибки при наличии пробелов после. Лучше опускать ?> в конце файла.
  • Конфликт имен функций: использование уникальных префиксов (например, my_plugin_) помогает избежать совпадений с другими плагинами или темой.
  • Прямой вызов файла: для безопасности в начало добавляют проверку if (!defined('ABSPATH')) exit;.

Как добавить страницу настроек в админку?

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


<?php
/*
Plugin Name: Плагин с настройками
*/

// Добавляем пункт меню в админку
add_action('admin_menu', 'my_settings_menu');

function my_settings_menu(){
    add_options_page(
        'Настройки моего плагина',
        'Мой плагин',
        'manage_options',
        'my-plugin-settings',
        'my_settings_page_html'
    );
}

// HTML страницы настроек
function my_settings_page_html(){
    ?>
    <div class="wrap">
        <h1>Настройки моего плагина</h1>
        <form action="options.php" method="post">
            <?php settings_fields('my_plugin_settings_group'); ?>
            <?php do_settings_sections('my-plugin-settings'); ?>
            <?php submit_button(); ?>
        </form>
    </div>
    <?php
}

// Регистрируем настройку
add_action('admin_init', 'my_plugin_register_settings');
function my_plugin_register_settings(){
    register_setting('my_plugin_settings_group', 'my_plugin_option');
    add_settings_section('my_plugin_main_section', 'Основные параметры', null, 'my-plugin-settings');
    add_settings_field('my_plugin_option_field', 'Текст сообщения', 'my_plugin_option_field_cb', 'my-plugin-settings', 'my_plugin_main_section');
}

function my_plugin_option_field_cb(){
    $value = get_option('my_plugin_option', '');
    echo '<input type="text" name="my_plugin_option" value="'.esc_attr($value).'" />';
}

Проблемы: данные не сохраняются - убедитесь, что settings_fields() и do_settings_sections() вызваны внутри формы; не забудьте, что страница настроек должна иметь capability manage_options для администратора.

Как создать шорткод для вставки динамического содержимого в записи?

Шорткоды позволяют пользователям вставлять функции плагина прямо в текст. Регистрация шорткода выполняется через add_shortcode().


<?php
/*
Plugin Name: Шорткод для карты
*/

add_shortcode('my_map', 'my_map_shortcode_handler');

function my_map_shortcode_handler($atts, $content = null){
    $atts = shortcode_atts(array(
        'lat' => '55.751244',
        'lng' => '37.618423',
        'zoom' => 10
    ), $atts);

    $lat = esc_attr($atts['lat']);
    $lng = esc_attr($atts['lng']);
    $zoom = intval($atts['zoom']);

    return '<div id="map" style="width:100%; height:400px;" data-lat="'.$lat.'" data-lng="'.$lng.'" data-zoom="'.$zoom.'"></div>';
}

Использование в записи: [my_map lat="55.751244" lng="37.618423" zoom="12"]. Шорткод возвращает HTML, который затем обрабатывается JavaScript карты.

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

Как расширить REST API WordPress собственным эндпоинтом?

Для добавления кастомных маршрутов используется класс WP_REST_Server и функция register_rest_route().


<?php
/*
Plugin Name: REST кастомный эндпоинт
*/

add_action('rest_api_init', function(){
    register_rest_route('myplugin/v1', '/data/', array(
        'methods' => 'GET',
        'callback' => 'my_rest_data_callback',
        'permission_callback' => '__return_true'
    ));
});

function my_rest_data_callback($request){
    $params = $request->get_params();
    return new WP_REST_Response(array(
        'status' => 'ok',
        'message' => 'Данные получены',
        'params' => $params
    ), 200);
}

После активации плагина по адресу /wp-json/myplugin/v1/data/ будет доступен JSON ответ. Для защиты добавьте проверку nonce или авторизацию.

Типичная проблема: эндпоинт недоступен - проверьте, что используется rest_api_init, а не init. Также убедитесь, что permission_callback возвращает true для открытого доступа.

Как создать виджет для боковой панели?

Виджеты регистрируются через расширение класса WP_Widget.


<?php
/*
Plugin Name: Мой виджет
*/

class My_Custom_Widget extends WP_Widget {

    public function __construct(){
        parent::__construct(
            'my_custom_widget',
            'Мой виджет',
            array('description' => 'Выводит приветствие')
        );
    }

    public function widget($args, $instance){
        echo $args['before_widget'];
        echo $args['before_title'].'Приветствие'.$args['after_title'];
        echo '<p>Здравствуйте! Спасибо за визит.</p>';
        echo $args['after_widget'];
    }

    public function form($instance){ ?>
        <p>Настроек нет</p>
    <?php }

    public function update($new_instance, $old_instance){
        return $new_instance;
    }
}

add_action('widgets_init', function(){
    register_widget('My_Custom_Widget');
});

После активации виджет появится в списке доступных виджетов в админке (Внешний вид -> Виджеты).

Ошибка: класс виджета не найден - убедитесь, что файл с классом подключен до хука widgets_init. Проблемы с кэшированием - сбросьте кэш WordPress.

Как создать собственный тип записи (Custom Post Type)?

Для регистрации произвольного типа записи используется функция register_post_type().


<?php
/*
Plugin Name: Тип записи Книга
*/

add_action('init', 'my_book_post_type');

function my_book_post_type(){
    $labels = array(
        'name'               => 'Книги',
        'singular_name'      => 'Книга',
        'add_new'            => 'Добавить новую',
        'add_new_item'       => 'Добавить новую книгу',
        'edit_item'          => 'Редактировать книгу',
        'new_item'           => 'Новая книга',
        'view_item'          => 'Просмотреть книгу',
        'search_items'       => 'Искать книги',
        'not_found'          => 'Книги не найдены',
        'not_found_in_trash' => 'В корзине книг нет'
    );

    $args = array(
        'labels'      => $labels,
        'public'      => true,
        'has_archive' => true,
        'menu_icon'   => 'dashicons-book',
        'supports'    => array('title', 'editor', 'thumbnail')
    );

    register_post_type('book', $args);
}

В админке появится новый раздел «Книги» с возможностью добавлять записи. Для отображения архивов создайте файл archive-book.php в теме.

Проблема: 404 ошибка на странице архива - необходимо сбросить правила перезаписи, зайдя в Настройки -> Постоянные ссылки и нажав «Сохранить изменения».

Расширенные примеры разработки плагинов WordPress

Пример: плагин с использованием классов и автозагрузкой через Composer

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

Пример

my-advanced-plugin/
├── composer.json
├── src/
│   └── MyPlugin.php
├── my-advanced-plugin.php
└── vendor/

composer.json:

Пример

{
    "name": "my/advanced-plugin",
    "autoload": {
        "psr-4": {
            "MyAdvancedPlugin\\": "src/"
        }
    }
}

src/MyPlugin.php:

Пример

<?php
namespace MyAdvancedPlugin;

class MyPlugin {
    public static function init(){
        add_action('wp_footer', [self::class, 'footer_message']);
    }

    public static function footer_message(){
        echo '<p>Расширенный плагин с автозагрузкой.</p>';
    }
}

my-advanced-plugin.php:

Пример

<?php
/*
Plugin Name: Продвинутый плагин
*/

require_once __DIR__ . '/vendor/autoload.php';

\MyAdvancedPlugin\MyPlugin::init();

После выполнения composer install плагин готов к активации. Результат: в футере выводится сообщение.

Пример: работа с транзакциями в базе данных WordPress

При массовых операциях важно обеспечить атомарность. Используйте глобальный объект $wpdb и его методы query() с явным управлением транзакциями (только для InnoDB).

Пример

<?php
/*
Plugin Name: Транзакции
*/

add_action('init', 'my_transaction_example');
function my_transaction_example(){
    global $wpdb;
    $table = $wpdb->prefix . 'my_table';

    $wpdb->query('START TRANSACTION');

    $result1 = $wpdb->insert($table, array('data' => 'value1'));
    $result2 = $wpdb->insert($table, array('data' => 'value2'));

    if($result1 === false || $result2 === false){
        $wpdb->query('ROLLBACK');
        error_log('Транзакция отменена из-за ошибки вставки');
    } else {
        $wpdb->query('COMMIT');
    }
}

Результат: обе вставки выполнятся только при успехе обеих. Внимание: таблица должна поддерживать транзакции (InnoDB).

Ошибки: использование MyISAM - транзакции не поддерживаются; необходимо сменить движок таблицы на InnoDB.

Пример: интеграция с внешним REST API с кэшированием ответов

Используйте wp_remote_get() для запросов и транзиентное кэширование для снижения нагрузки.

Пример

<?php
/*
Plugin Name: Интеграция с API погоды
*/

add_shortcode('weather', 'weather_shortcode');
function weather_shortcode($atts){
    $atts = shortcode_atts(array('city' => 'Moscow'), $atts);
    $city = sanitize_text_field($atts['city']);
    $transient_key = 'weather_' . md5($city);
    $cached = get_transient($transient_key);
    if($cached !== false){
        return $cached;
    }

    $url = 'https://api.openweathermap.org/data/2.5/weather?q=' . urlencode($city) . '&appid=YOUR_API_KEY&units=metric';
    $response = wp_remote_get($url);

    if(is_wp_error($response)){
        return 'Ошибка получения данных.';
    }

    $body = wp_remote_retrieve_body($response);
    $data = json_decode($body, true);
    if(isset($data['main']['temp'])){
        $temperature = $data['main']['temp'];
        $output = 'Температура в ' . esc_html($city) . ': ' . $temperature . '°C';
        set_transient($transient_key, $output, 3600); // кэш на 1 час
        return $output;
    }
    return 'Не удалось определить погоду.';
}

Результат: шорткод [weather city="London"] выводит текущую температуру, данные кэшируются на час.

Проблемы: превышение лимитов API - используйте кэширование; неверный API ключ - проверьте консоль ошибок WordPress.

Пример: создание планировщика задач (WP Cron) для периодической очистки логов

Используйте wp_schedule_event() и хук cron_schedules для добавления нестандартных интервалов.

Пример

<?php
/*
Plugin Name: Планировщик очистки
*/

// Добавляем интервал 'weekly'
add_filter('cron_schedules', 'my_weekly_cron_schedule');
function my_weekly_cron_schedule($schedules){
    $schedules['weekly'] = array(
        'interval' => 604800,
        'display'  => 'Раз в неделю'
    );
    return $schedules;
}

// При активации планируем событие
register_activation_hook(__FILE__, 'my_cron_activation');
function my_cron_activation(){
    if(!wp_next_scheduled('my_weekly_cleanup')){
        wp_schedule_event(time(), 'weekly', 'my_weekly_cleanup');
    }
}

// При деактивации очищаем
register_deactivation_hook(__FILE__, 'my_cron_deactivation');
function my_cron_deactivation(){
    $timestamp = wp_next_scheduled('my_weekly_cleanup');
    wp_unschedule_event($timestamp, 'my_weekly_cleanup');
}

// Обработчик
add_action('my_weekly_cleanup', 'my_cleanup_logs');
function my_cleanup_logs(){
    global $wpdb;
    $table = $wpdb->prefix . 'my_log';
    $wpdb->query("DELETE FROM $table WHERE created_at < NOW() - INTERVAL 30 DAY");
}

Результат: каждую неделю удаляются записи старше 30 дней.

Ошибки: cron не срабатывает - проверьте, что на сервере работает системный cron, иначе WP Cron срабатывает только при посещениях сайта; используйте внешний cron-демон для надежности.

Плагины WordPress - comments

En
Wp plugins php (php)