Розробка кастомного плагіна WordPress

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

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

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка кастомного плагіна WordPress
Середня
~3-5 робочих днів
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка кастомного плагіна WordPress

Коли готовий плагін робить 90% потрібного, а оставшиеся 10% не реалізувати без взлому його коду — пора писати власний. Кастомний плагін — це не обов'язково мегабібліотека: іноді це 200 рядків коду, які додають конкретну бізнес-логіку, недоступну в маркетплейсі. Розробка плагіна середньої складності займає від 3 до 10 робочих днів.

Структура плагіна

WordPress не вимагає жорсткої структури папок, але є устоявшиеся конвенції:

wp-content/plugins/my-plugin/
├── my-plugin.php          # Головний файл, точка входу
├── includes/
│   ├── class-my-plugin.php        # Основний клас
│   ├── class-my-plugin-admin.php  # Логіка для /wp-admin
│   └── class-my-plugin-public.php # Логіка для фронтенда
├── admin/
│   ├── css/admin.css
│   └── js/admin.js
├── public/
│   ├── css/public.css
│   └── js/public.js
└── languages/
    └── my-plugin-ru_RU.po

Головний файл містить заголовок та bootstrapping:

<?php
/**
 * Plugin Name:       My Custom Plugin
 * Plugin URI:        https://example.com/my-plugin
 * Description:       Опис функціональності плагіна.
 * Version:           1.0.0
 * Requires at least: 6.0
 * Requires PHP:      8.1
 * Author:            Company Name
 * Text Domain:       my-plugin
 */

if (!defined('ABSPATH')) {
    exit;
}

define('MY_PLUGIN_VERSION', '1.0.0');
define('MY_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('MY_PLUGIN_URL', plugin_dir_url(__FILE__));

require_once MY_PLUGIN_DIR . 'includes/class-my-plugin.php';

function my_plugin_init(): void {
    $plugin = new My_Plugin();
    $plugin->run();
}
add_action('plugins_loaded', 'my_plugin_init');

Основний клас та реєстр хуків

Паттерн «Loader» — реєстрація всіх хуків в одному місці замість розбору add_action по файлам:

class My_Plugin {
    private array $actions = [];
    private array $filters = [];

    public function __construct() {
        $this->define_admin_hooks();
        $this->define_public_hooks();
    }

    private function define_admin_hooks(): void {
        $admin = new My_Plugin_Admin();
        $this->add_action('admin_enqueue_scripts', $admin, 'enqueue_styles');
        $this->add_action('admin_menu', $admin, 'add_plugin_admin_menu');
    }

    private function add_action(string $hook, object $component, string $callback, int $priority = 10): void {
        $this->actions[] = compact('hook', 'component', 'callback', 'priority');
    }

    public function run(): void {
        foreach ($this->actions as $hook) {
            add_action($hook['hook'], [$hook['component'], $hook['callback']], $hook['priority']);
        }
        foreach ($this->filters as $hook) {
            add_filter($hook['hook'], [$hook['component'], $hook['callback']], $hook['priority'], $hook['accepted_args'] ?? 1);
        }
    }
}

Робота з БД

Для кастомних таблиць — створення через dbDelta при активації плагіна:

register_activation_hook(__FILE__, function () {
    global $wpdb;
    $table = $wpdb->prefix . 'my_plugin_data';
    $charset = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE {$table} (
        id bigint(20) NOT NULL AUTO_INCREMENT,
        user_id bigint(20) NOT NULL,
        data_key varchar(255) NOT NULL,
        data_value longtext,
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY user_id (user_id),
        KEY data_key (data_key)
    ) {$charset};";

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta($sql);

    add_option('my_plugin_db_version', MY_PLUGIN_VERSION);
});

Для запитів — тільки через $wpdb->prepare(), ніколи не конкатируйте рядки з користувацькими даними:

$results = $wpdb->get_results(
    $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}my_plugin_data WHERE user_id = %d AND data_key = %s",
        get_current_user_id(),
        $key
    )
);

Сторінка налаштувань у адмінці

Settings API — стандартний спосіб додати сторінку налаштувань з нативним інтерфейсом WordPress:

class My_Plugin_Admin {
    public function add_plugin_admin_menu(): void {
        add_options_page(
            'Налаштування My Plugin',
            'My Plugin',
            'manage_options',
            'my-plugin',
            [$this, 'display_plugin_setup_page']
        );
    }

    public function __construct() {
        add_action('admin_init', [$this, 'register_settings']);
    }

    public function register_settings(): void {
        register_setting('my_plugin_options', 'my_plugin_api_key', [
            'type'              => 'string',
            'sanitize_callback' => 'sanitize_text_field',
        ]);

        add_settings_section('my_plugin_main', 'Основні налаштування', null, 'my-plugin');

        add_settings_field('api_key', 'API ключ', function () {
            $value = get_option('my_plugin_api_key', '');
            printf('<input type="text" name="my_plugin_api_key" value="%s" class="regular-text">', esc_attr($value));
        }, 'my-plugin', 'my_plugin_main');
    }

    public function display_plugin_setup_page(): void {
        if (!current_user_can('manage_options')) {
            return;
        }
        echo '<div class="wrap"><h1>' . esc_html(get_admin_page_title()) . '</h1>';
        echo '<form method="post" action="options.php">';
        settings_fields('my_plugin_options');
        do_settings_sections('my-plugin');
        submit_button();
        echo '</form></div>';
    }
}

AJAX-обработчики

// Реєстрація обработчика
add_action('wp_ajax_my_plugin_action', [$this, 'handle_ajax']);
add_action('wp_ajax_nopriv_my_plugin_action', [$this, 'handle_ajax']); // для незалогиненних

public function handle_ajax(): void {
    check_ajax_referer('my_plugin_nonce', 'nonce');

    $input = sanitize_text_field($_POST['data'] ?? '');

    // бізнес-логіка
    $result = $this->process($input);

    wp_send_json_success(['result' => $result]);
    // або wp_send_json_error(['message' => 'Помилка'], 400);
}

На клієнті:

fetch(childTheme.ajaxUrl, {
  method: 'POST',
  body: new URLSearchParams({
    action: 'my_plugin_action',
    nonce: childTheme.nonce,
    data: inputValue,
  }),
})
  .then(r => r.json())
  .then(r => { if (r.success) console.log(r.data.result) });

REST API замість AJAX

Для сучасних інтерфейсів на React/Vue перевагу REST API. Детальніше — в окремій послузі.

Інтернаціоналізація

Всі рядки у плагіні обернути у функції перекладу з вказанням text domain:

__('Рядок для перекладу', 'my-plugin')
_e('Вивести рядок', 'my-plugin')
esc_html__('Безпечний вивід', 'my-plugin')
sprintf(__('Привіт, %s!', 'my-plugin'), $username)

.pot-файл генерується через WP-CLI: wp i18n make-pot . languages/my-plugin.pot.

Деактивація та видалення

register_deactivation_hook(__FILE__, function () {
    // Убираємо cron-завдання, тимчасові дані
    wp_clear_scheduled_hook('my_plugin_cron');
});

register_uninstall_hook(__FILE__, 'my_plugin_uninstall');

function my_plugin_uninstall(): void {
    // Видаляємо тільки якщо користувач погодився
    if (get_option('my_plugin_delete_data_on_uninstall')) {
        global $wpdb;
        $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}my_plugin_data");
        delete_option('my_plugin_api_key');
    }
}

Типові терміни за складністю

Простий плагін (шорткод + сторінка налаштувань) — 2–3 дні. Плагін зі своїми таблицями, AJAX-інтерфейсом та інтеграцією зі сторонній API — 5–8 днів. Плагін з метабоксами, кастомними таблицями у списку записів, складною логікою ролей — від 10 днів.