Проблема / Необходимость
Если вы уже создали сайт на Elementor, и клиент спрашивает вас: «Мне нужен виджет» заказ«Но без установки 12 дополнений» у вас уже сформировался правильный рефлекс: нужно просмотреть код.
Elementor (бесплатная/профессиональная версия) предоставляет достаточно стабильный API с хуками и событиями для корректной настройки конструктора: добавление категории виджетов, сохранение пользовательского виджета, внедрение элементов управления, принудительное присвоение значений по умолчанию, загрузка скриптов только при необходимости и даже добавление динамического поля с помощью тега.
Типичная бизнес-задача: внедрение в производство многократно используемых компонентов (призывы к действию, блоки с информацией об авторе, описания товаров, таблицы, баннеры GDPR и т. д.) с сохранением пользовательского интерфейса Elementor. В итоге вы научитесь структурировать чистый и совместимый мини-плагин. WordPress При использовании PHP 6.9.4 и выше, вы получите многоразовую основу для своих проектов.
Краткое резюме
- Создайте мини-плагин WordPress (не одноразовый фрагмент кода), который интегрируется с Elementor, не нарушая его работу.и.
- Используйте правильные хуки Elementor:
elementor/init,elementor/widgets/register,elementor/elements/categories_registered,elementor/frontend/after_register_scripts. - Добавьте пользовательский виджет «Значок» (заголовок + текст + цвет + иконка) с элементами управления, безопасным отображением и стилями.
- Добавьте динамический тег (расширенная опция), чтобы внедрить значение из метаданных пользователя (например, должность/роль).
- Загружайте CSS/JS только в том случае, если присутствует виджет из вашего плагина (это позволяет избежать "загрузки всего и везде").
Когда использовать это решение
- Вам нужен стабильный компонент с версионированием, который можно повторно использовать на нескольких сайтах (агентство, фриланс, команда).
- Необходимо придерживаться руководства по стилю (цвета, типографика, интервалы), не оставляя при этом клиенту 50 «опасных» вариантов.
- Вам необходима точная отрисовка интерфейса без использования сторонних дополнений, которые могут внезапно измениться.
- Вы хотите повысить производительность: ресурсы должны загружаться только при необходимости, без «больших наборов» виджетов.
- Вы хотите интегрировать данные WordPress (метатеги, параметры, ACF/Pods и т. д.) с помощью динамических тегов.
Когда НЕ следует использовать это решение
- Потребность носит исключительно визуальный и эпизодический характер: декриминализовано Для этого может быть достаточно шаблона Elementor, контейнера и немного CSS.
- Вы не можете контролировать техническое обслуживание: использование пользовательского виджета подразумевает следование инструкциям Elementor (а иногда и его устаревшим функциям).
- Если вы хотите основательно «изменить» Elementor (например, модифицировать внутреннее поведение редактора), то знайте, что он редко бывает стабильным. Лучше использовать официальные расширения или смириться с определенным техническим долгом.
- Ваш клиент в основном использует Gutenberg/блоки: в этом случае пользовательский блок (Block API) часто оказывается более подходящим. См. официальную документацию: Справочник редактора блоков.
Предварительные условия / перед началом обучения
- WordPress 6.9.4+ и PHP 8.1+ (в идеале 8.2/8.3 к 2026 году, если ваш хостинг-провайдер сможет поддерживать эти версии).
- Elementor установлен и активирован (для этого примера виджета достаточно бесплатной версии). Для сложных динамических тегов часто используется Elementor Pro, но мы по возможности придерживаемся общедоступных API.
- Перед внесением каких-либо изменений крайне важны тестовая среда и резервная копия. Я часто видел, как фрагменты кода, вставленные в рабочую среду, вызывают критическую ошибку и блокируют административный интерфейс.
- Плагин для ведения логов (или хотя бы)
WP_DEBUG_LOG) для чтения ошибок PHP.
Полезные справочные материалы по WordPress:
- Плагин Руководство разработчика
- Нонсы (безопасность)
- wp_enqueue_script ()
- esc_html()
- Руководство по PHP
Наивный подход (и почему его следует избегать)
Классический подход: вставить большой фрагмент кода в functions.php Используйте тему оформления (часто без дочерней темы), сохраняйте скрипты везде и создавайте экземпляры классов Elementor при загрузке.
Типичный пример (антипаттерн)
<?php
// ❌ Exemple volontairement mauvais : ne copiez pas tel quel.
add_action('init', function () {
// ❌ Elementor n'est pas forcément chargé ici, et cette classe peut ne pas exister.
$widgets_manager = ElementorPlugin::instance()->widgets_manager;
require_once __DIR__ . '/widgets/badge.php';
$widgets_manager->register(new My_Badge_Widget());
// ❌ Charge CSS/JS sur toutes les pages, même si le widget n'est pas utilisé.
wp_enqueue_style('my-badge', get_stylesheet_directory_uri() . '/badge.css');
});
Почему оно ломается (часто)
- тайминг На момент запуска Elementor еще не завершил инициализацию своих менеджеров.
init(в зависимости от версий/контекста). - Фатальная ошибка : если Elementor отключен,
ElementorPluginне существует. - Эффективности CSS/JS загружаются повсюду, в том числе на страницах, которые не используют Elementor.
- Обслуживание Код теряется в теме оформления, невозможно корректно отслеживать версии, нестабилен при смене тем.
Правильный подход — пошаговое руководство
Мы собираемся создать мини-плагин, содержащий:
- Bootstrap, проверяющий, активен ли Elementor.
- специальная категория виджетов,
- пользовательский виджет,
- условная нагрузка на активы,
- Дополнительный вариант «Динамическая метка» для иллюстрации расширенного фильтра/регистра.
Шаг 1 — Создайте плагин
Создайте эту папку: wp-content/plugins/bpcab-elementor-hooks/
Затем этот файл: wp-content/plugins/bpcab-elementor-hooks/bpcab-elementor-hooks.php
Шаг 2 — Проверка Bootstrap + Elementor
Мы прикрепляем наш код к plugins_loaded затем мы ждем elementor/initГлавное: никогда не вызывайте классы Elementor, пока плагин не будет готов.
Шаг 3 — Сохраните категорию и виджет
Elementor предоставляет специальные действия. На практике они остаются стабильными на протяжении нескольких версий:
elementor/elements/categories_registeredдобавить категорию,elementor/widgets/registerЧтобы сохранить виджет.
Настаиваю: избегайте использования хуков «наугад» (например, init ou wp_loaded) для взаимодействия с Elementor. Проблема редко возникает в коде виджета, а скорее в момент его выполнения.
Шаг 4 — Загрузка CSS/JS в нужное время
Активы учитываются посредством elementor/frontend/after_register_styles / elementor/frontend/after_register_scripts, тогда мы Ставить только если виджет фактически отобразился.
Шаг 5 — (Необязательно) Добавьте динамический тег
Если вы используете Elementor Pro (или если ваша платформа поддерживает динамические теги), пользовательский тег часто оказывается более удобным решением, чем шорткод. Вы предоставляете доступ к данным, а Elementor обрабатывает их внедрение в свои «динамические» элементы управления.
Полный код
Скопируйте и вставьте весь текст ниже. Плагин является самодостаточным, и вы сможете добавить виджеты позже.
Файл 1 — bpcab-elementor-hooks.php
<?php
/**
* Plugin Name: BPCAB - Personnalisation Elementor par hooks
* Description: Exemple pédagogique : catégorie + widget custom + assets conditionnels + (option) Dynamic Tag.
* Version: 1.0.0
* Requires at least: 6.9
* Requires PHP: 8.1
* Author: BPCAB
* License: GPLv2 or later
*/
declare(strict_types=1);
if (!defined('ABSPATH')) {
exit;
}
final class BPCAB_Elementor_Hooks_Plugin {
public const VERSION = '1.0.0';
public const SLUG = 'bpcab-elementor-hooks';
private static ?self $instance = null;
public static function instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action('plugins_loaded', [$this, 'bootstrap']);
}
public function bootstrap(): void {
// Elementor définit généralement ELEMENTOR_VERSION quand il est actif.
if (!defined('ELEMENTOR_VERSION')) {
// Pas d'Elementor : on ne fait rien. Évitez d'afficher une notice agressive en front.
add_action('admin_notices', [$this, 'admin_notice_missing_elementor']);
return;
}
// On attend l'initialisation d'Elementor avant d'appeler ses classes/managers.
add_action('elementor/init', [$this, 'on_elementor_init']);
}
public function admin_notice_missing_elementor(): void {
if (!current_user_can('activate_plugins')) {
return;
}
$plugin_name = esc_html__('BPCAB - Personnalisation Elementor par hooks', 'bpcab');
$message = esc_html__('Elementor doit être activé pour utiliser ce plugin.', 'bpcab');
echo '<div class="notice notice-warning">';
echo '<p><strong>' . $plugin_name . '</strong> — ' . $message . '</p>';
echo '</div>';
}
public function on_elementor_init(): void {
// 1) Catégorie de widgets.
add_action('elementor/elements/categories_registered', [$this, 'register_category']);
// 2) Widgets.
add_action('elementor/widgets/register', [$this, 'register_widgets']);
// 3) Assets : on les enregistre au bon moment côté front.
add_action('elementor/frontend/after_register_styles', [$this, 'register_frontend_styles']);
add_action('elementor/frontend/after_register_scripts', [$this, 'register_frontend_scripts']);
// 4) Option : Dynamic Tag (si l'API est disponible).
add_action('elementor/dynamic_tags/register', [$this, 'register_dynamic_tags']);
}
public function register_category($elements_manager): void {
// $elements_manager est typiquement une instance de ElementorElements_Manager.
$elements_manager->add_category(
'bpcab',
[
'title' => esc_html__('BPCAB', 'bpcab'),
'icon' => 'fa fa-plug',
]
);
}
public function register_widgets($widgets_manager): void {
// Chargement des classes de widgets.
require_once __DIR__ . '/includes/widgets/class-bpcab-widget-badge.php';
// Enregistrement.
$widgets_manager->register(new BPCAB_Widget_Badge());
}
public function register_frontend_styles(): void {
wp_register_style(
'bpcab-badge',
plugins_url('assets/css/badge.css', __FILE__),
[],
self::VERSION
);
}
public function register_frontend_scripts(): void {
wp_register_script(
'bpcab-badge',
plugins_url('assets/js/badge.js', __FILE__),
[],
self::VERSION,
true
);
}
public function register_dynamic_tags($dynamic_tags_manager): void {
// Certains sites n'utilisent pas cette feature : on protège le require.
require_once __DIR__ . '/includes/dynamic-tags/class-bpcab-dynamic-tag-user-position.php';
// Enregistrement du tag.
$dynamic_tags_manager->register(new BPCAB_Dynamic_Tag_User_Position());
}
}
BPCAB_Elementor_Hooks_Plugin::instance();
Файл 2 — includes/widgets/class-bpcab-widget-badge.php
<?php
declare(strict_types=1);
if (!defined('ABSPATH')) {
exit;
}
use ElementorWidget_Base;
use ElementorControls_Manager;
use ElementorIcons_Manager;
final class BPCAB_Widget_Badge extends Widget_Base {
public function get_name(): string {
return 'bpcab_badge';
}
public function get_title(): string {
return esc_html__('Badge (BPCAB)', 'bpcab');
}
public function get_icon(): string {
return 'eicon-badge';
}
public function get_categories(): array {
return ['bpcab'];
}
public function get_keywords(): array {
return ['badge', 'label', 'cta', 'bpcab'];
}
public function get_style_depends(): array {
// Elementor enqueuera ce style seulement si le widget est présent.
return ['bpcab-badge'];
}
public function get_script_depends(): array {
// Idem pour le script.
return ['bpcab-badge'];
}
protected function register_controls(): void {
$this->start_controls_section(
'section_content',
[
'label' => esc_html__('Contenu', 'bpcab'),
'tab' => Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'label' => esc_html__('Titre', 'bpcab'),
'type' => Controls_Manager::TEXT,
'default' => esc_html__('Nouveau', 'bpcab'),
'placeholder' => esc_html__('Ex: Nouveau', 'bpcab'),
'label_block' => true,
]
);
$this->add_control(
'text',
[
'label' => esc_html__('Texte', 'bpcab'),
'type' => Controls_Manager::TEXTAREA,
'default' => esc_html__('Offre limitée', 'bpcab'),
'placeholder' => esc_html__('Ex: Offre limitée', 'bpcab'),
'rows' => 3,
]
);
$this->add_control(
'icon',
[
'label' => esc_html__('Icône', 'bpcab'),
'type' => Controls_Manager::ICONS,
'default' => [
'value' => 'fas fa-star',
'library' => 'fa-solid',
],
]
);
$this->end_controls_section();
$this->start_controls_section(
'section_style',
[
'label' => esc_html__('Style', 'bpcab'),
'tab' => Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'bg_color',
[
'label' => esc_html__('Couleur de fond', 'bpcab'),
'type' => Controls_Manager::COLOR,
'default' => '#111827',
'selectors' => [
'{{WRAPPER}} .bpcab-badge' => 'background-color: {{VALUE}};',
],
]
);
$this->add_control(
'text_color',
[
'label' => esc_html__('Couleur du texte', 'bpcab'),
'type' => Controls_Manager::COLOR,
'default' => '#ffffff',
'selectors' => [
'{{WRAPPER}} .bpcab-badge' => 'color: {{VALUE}};',
],
]
);
$this->add_responsive_control(
'padding',
[
'label' => esc_html__('Padding', 'bpcab'),
'type' => Controls_Manager::DIMENSIONS,
'size_units' => ['px', 'em', 'rem'],
'default' => [
'top' => 12,
'right' => 14,
'bottom' => 12,
'left' => 14,
'unit' => 'px',
],
'selectors' => [
'{{WRAPPER}} .bpcab-badge' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
// Sanitization/escaping : Elementor stocke des valeurs, mais vous devez sortir du HTML propre.
$title = isset($settings['title']) ? sanitize_text_field((string) $settings['title']) : '';
$text = isset($settings['text']) ? wp_kses_post((string) $settings['text']) : '';
// Icône : Elementor fournit Icons_Manager pour rendre proprement.
$icon = $settings['icon'] ?? null;
echo '<div class="bpcab-badge" role="note">';
echo '<div class="bpcab-badge__head">';
if (!empty($icon) && is_array($icon)) {
echo '<span class="bpcab-badge__icon" aria-hidden="true">';
Icons_Manager::render_icon($icon, ['aria-hidden' => 'true']);
echo '</span>';
}
if ($title !== '') {
echo '<strong class="bpcab-badge__title">' . esc_html($title) . '</strong>';
}
echo '</div>';
if ($text !== '') {
// wp_kses_post permet un sous-ensemble HTML (liens, strong, em, etc.).
echo '<div class="bpcab-badge__text">' . $text . '</div>';
}
echo '</div>';
}
}
Файл 3 — includes/dynamic-tags/class-bpcab-dynamic-tag-user-position.php
<?php
declare(strict_types=1);
if (!defined('ABSPATH')) {
exit;
}
use ElementorCoreDynamicTagsTag;
final class BPCAB_Dynamic_Tag_User_Position extends Tag {
public function get_name(): string {
return 'bpcab-user-position';
}
public function get_title(): string {
return esc_html__('Utilisateur : Poste (BPCAB)', 'bpcab');
}
public function get_group(): string {
// Groupe "Site" ou "User" selon votre organisation.
return 'site';
}
public function get_categories(): array {
// Catégorie TEXT pour insertion dans des champs texte.
return [ElementorModulesDynamicTagsModule::TEXT_CATEGORY];
}
protected function register_controls(): void {
// Exemple : choisir une meta key (simple). En prod, vous pourriez proposer une liste.
$this->add_control(
'meta_key',
[
'label' => esc_html__('Meta key utilisateur', 'bpcab'),
'type' => ElementorControls_Manager::TEXT,
'default' => 'position',
'placeholder' => 'position',
]
);
}
public function render(): void {
$user_id = get_current_user_id();
if (!$user_id) {
return;
}
$settings = $this->get_settings();
$meta_key = isset($settings['meta_key']) ? sanitize_key((string) $settings['meta_key']) : 'position';
$value = get_user_meta($user_id, $meta_key, true);
if (!is_scalar($value) || $value === '') {
return;
}
echo esc_html((string) $value);
}
}
Файл 4 — assets/css/badge.css
.bpcab-badge{
display:block;
border-radius:12px;
line-height:1.35;
}
.bpcab-badge__head{
display:flex;
gap:10px;
align-items:center;
}
.bpcab-badge__icon{
display:inline-flex;
}
.bpcab-badge__title{
font-weight:700;
}
.bpcab-badge__text{
margin-top:8px;
opacity:.95;
}
Файл 5 — assets/js/badge.js
(function () {
// Script minimal : exemple de point d'accroche.
// Ici, on ne fait rien de critique. Gardez vos widgets robustes sans JS si possible.
})();
Код Пояснение
1) Почему именно плагин (а не functions.php)?
Плагин обеспечивает четкий жизненный цикл, активацию/деактивацию, версионирование и стабильное местоположение для ваших классов. Я часто видел, как после обновления сайтов на Avada/Divi небольшой фрагмент кода в теме исчезает или становится несовместимым.
2) Ключевой момент: время зацепов крючком.
plugins_loadedWordPress загрузил плагины. Мы можем проверить, установлен ли Elementor.elementor/initElementor инициализировал свой основной контейнер. Здесь вы можете добавить свои хуки Elementor.elementor/widgets/registerВы получаете менеджер виджетов и сохраняете свои классы.elementor/elements/categories_registered: вы объявляете категорию, видимую в пользовательском интерфейсе конструктора.
Такой подход позволяет избежать классической ошибки: «Класс 'ElementorPlugin' не найден» или «Вызов метода register() для объекта null».
3) Условная загрузка активов
Дуэт get_style_depends() / get_script_depends() Этот механизм используется недостаточно эффективно. Тем не менее, это один из самых удобных способов загрузки ресурсов только тогда, когда Elementor отображает ваш виджет.
За кулисами: Elementor собирает зависимости виджетов на странице и запрашивает соответствующие дескрипторы. Вам просто... wp_register_style() / wp_register_script() в нужное время.
4) Безопасная отрисовка: санитаризация + экранирование
- запись Elementor хранит значения в базе данных. Вам все равно потребуется очищать их в зависимости от контекста.
- Sortie :
esc_html()для текста,wp_kses_post()если вы разрешаете использование ограниченного HTML.
Самая распространенная ловушка, которую я вижу: сразу выходить из дома. $settings['text'] без wp_kses_post() «Потому что это администратор». На сайте с несколькими авторами это становится угрозой XSS-атаки.
5) Динамический тег: почему он полезен
Динамический тег устраняет необходимость в шорткодах в полях Elementor. Вы предоставляете доступ к данным (метаданные пользователя, параметры, поле ACF), а пользователь выбирает тег в пользовательском интерфейсе. Это проще в обслуживании, чем шорткод, вставленный в 30 виджетов.
Варианты и сценарии использования
Вариант 1 — Принудительная «блокировка» значений (меньше вариантов выбора для клиента)
Если вы хотите запретить клиенту изменять определенные параметры, вы можете:
- не выставлять напоказ элемент управления (нет)
add_control), - или открыть закрытый список (SELECT),
- или установить значение в
render().
Пример: присвоение CSS-класса на основе «типа»:
// Dans register_controls()
$this->add_control(
'type',
[
'label' => esc_html__('Type', 'bpcab'),
'type' => Controls_Manager::SELECT,
'default' => 'info',
'options' => [
'info' => esc_html__('Info', 'bpcab'),
'warning' => esc_html__('Alerte', 'bpcab'),
],
]
);
// Dans render()
$type = isset($settings['type']) ? sanitize_key((string) $settings['type']) : 'info';
$type_class = in_array($type, ['info', 'warning'], true) ? 'is-' . $type : 'is-info';
echo '<div class="bpcab-badge ' . esc_attr($type_class) . '">...</div>';
Вариант 2 — Добавить элемент управления URL и создать чистую ссылку
Кликабельная кнопка призыва к действию (CTA) появляется постоянно. Elementor предоставляет элемент управления URL-адресом с опциями «открыть в новой вкладке» и «nofollow».
// Contrôle URL
$this->add_control(
'link',
[
'label' => esc_html__('Lien', 'bpcab'),
'type' => Controls_Manager::URL,
'options' => ['url', 'is_external', 'nofollow'],
'default' => [
'url' => '',
],
]
);
// Dans render()
$link = $settings['link'] ?? [];
$url = isset($link['url']) ? esc_url((string) $link['url']) : '';
if ($url) {
$target = !empty($link['is_external']) ? ' target="_blank"' : '';
$rel = !empty($link['nofollow']) ? ' rel="nofollow noopener"' : ' rel="noopener"';
echo '<a class="bpcab-badge" href="' . $url . '"' . $target . $rel . '>...</a>';
return;
}
Примечание: Если вы откроете ссылку в новой вкладке, сохраните noopener (безопасность).
Вариант 3 — Загрузка ресурса только на определенных страницах (еще более строгие правила).
Если у вас сложный скрипт, вы можете объединить зависимость от виджета с условием WordPress. Например: только на страницах (а не на статьи):
public function register_frontend_scripts(): void {
wp_register_script(
'bpcab-badge',
plugins_url('assets/js/badge.js', __FILE__),
[],
self::VERSION,
true
);
// ⚠️ Ne faites pas wp_enqueue_script ici : Elementor gère l'enqueue via get_script_depends().
// Si vous voulez vraiment empêcher le chargement sur certains contextes, vous pouvez deregister :
if (!is_page()) {
wp_deregister_script('bpcab-badge');
}
}
Я редко его использую: может быть неожиданно, если виджет используется в шаблоне, который отображается в другом месте. Протестируйте его тщательно.
Совместимость с Divi 5 / Elementor / Avada
Elementor
- Указанный выше плагин интегрируется в Elementor, не завися от темы оформления.
- Если вы используете шаблоны Elementor (конструктор тем), виджет останется доступным везде.
- Предоставление активов обусловлено определенными условиями: это важный момент для сайтов с высокой загрузкой.
Дива 5
Divi 5 не использует API Elementor. Ваш виджет не будет отображаться в Divi, и это нормально.
Если ваша цель — повторно использовать один и тот же компонент на страницах Divi, я рекомендую стратегию, не зависящую от используемого конструктора:
- создать шорткод WordPress (или, что еще лучше, блок Gutenberg),
- затем вставьте его в Divi с помощью модуля Code/Shortcode.
- и оставлять Elementor в качестве «наложения пользовательского интерфейса», когда он присутствует.
По моему опыту, это единственный работающий подход, если у вас парк, где расположены несколько застройщиков.
Авада (конструктор Fusion)
Здесь действует та же логика: Avada не будет использовать виджеты Elementor. Однако ваш плагин останется полезным, если на некоторых страницах сайта используется Elementor.
Для Avada наиболее аккуратная схема также выглядит следующим образом: короткий код или блок, затем элемент «Блок кода» / «Короткий код» в Fusion Builder.
Послемонтажные проверки
- Активируйте плагин в Расширения.
- Откройте страницу с помощью Elementor.
- В панели виджетов найдите категорию. БПКАБ затем виджет Значок (BPCAB).
- Разместите его на странице, отредактируйте заголовок/текст/цвета и опубликуйте.
- На лицевой стороне страницы внимательно осмотрите ее: вы должны увидеть
bpcab-badge.cssзагружено (а не на страницах, которые не используют виджет).
Диаграмма быстрой диагностики
| симптом | Причина вероятна | проверка | Решение |
|---|---|---|---|
| Категория BPCAB не отображается. | Хук так и не был выполнен (элементар не загружен). | Проверь это ELEMENTOR_VERSION определено, и Elementor активен. |
Активируйте Elementor, проверьте наличие конфликтов/mu-плагинов. |
| Фатальная ошибка «Класс ElementorWidget_Base не найден» | Файл виджета был загружен слишком рано / Elementor неактивен | Просмотрите лог PHP + трассировку стека | Для подключения виджета требуется только сам виджет. elementor/widgets/register после elementor/init |
| CSS/JS не загружен | Незарегистрированные ручки или неисправный крючок регистрации | инспектировать wp_head / wp_footer + консоль |
Контрольник after_register_styles/scripts et get_style_depends() |
| Виджет отображается, но стили не отображаются. | Кэширование (плагин/CDN) или агрессивная минификация | Отключите кэш, очистите CDN, протестируйте в режиме приватного просмотра. | Исключить файлы из кэша/минификации, повысить версию. |
| Динамический тег не найден | Функция недоступна (в зависимости от конфигурации/Pro) или не сработала. | Проверьте, присутствует ли панель «Динамический» в текстовом поле. | При необходимости установите/активируйте Elementor Pro или удалите раздел тегов. |
Если это не сработает
- Подтвердите версии WordPress 6.9.4+, PHP 8.1+, Elementor обновлен до последней версии. Устаревшая версия PHP вызывает ошибки.
declare(strict_types=1)или типов?self. - Включить ведение журнала в
wp-config.php(на стадии подготовки):
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false); - открытый
wp-content/debug.logи выполните поиск по запросу «BPCAB» или «Elementor». - Временно отключить Плагины для создания фрагментов кода. Я уже видел фрагмент кода "из старого руководства по Elementor", в котором объявлялся класс с тем же именем, что приводило к фатальному конфликту.
- Очистите кэш : кэш плагинов, серверный кэш, CDN, кэш браузера. В Elementor агрессивное кэширование также может сохранять отсутствующие ресурсы.
- Перегенерировать CSS-файлы Elementor (если ваш сайт использует функцию генерации CSS). В Elementor обычно есть функция перегенерации в разделе «Инструменты/Настройки производительности».
- Попробуйте с нейтральной тематикой. (временно): Twenty Twenty-* или облегченная тема. Тема может отменить регистрацию скриптов/стилей.
Распространенные ошибки и ловушки
| ERREUR | Вызывать | Решение |
|---|---|---|
| Код вставлен не в тот файл. | Добавлено в functions.php вместо плагина |
Создайте плагин, определите его версию, правильно активируйте/деактивируйте его. |
| «Ошибка синтаксического анализа: синтаксическая ошибка» | Отсутствует точка с запятой, лишняя фигурная скобка, неполное копирование-вставка. | Просмотрите указанную в журнале строку, используя IDE с поддержкой форматирования PHP. |
| Элемент Hook не подходит | использование init / wp_loaded сохранить виджет |
Utiliser elementor/init затем elementor/widgets/register |
| «Класс ElementorPlugin не найден» | Элементар отключен или загружен после выполнения вашего кода. | Контрольник defined('ELEMENTOR_VERSION') и никогда не звоните в Elementor раньше elementor/init |
| CSS/JS не загружен | Неправильная рукоятка, неправильный крючок или кэширование/минификация | Сохранить через after_register_styles/scriptsобъявляйте зависимости через get_*_depends()очистить кэш |
| конфликт названий классов | Два плагина объявляют BPCAB_Widget_Badge (или неправильно настроенный автозагрузчик) |
При внедрении новых технологий всегда используйте префиксы и пространства имен. |
| Путаница между действием и фильтром. | Вы пытаетесь "вернуться" к акциям. | Действия: побочные эффекты. Фильтры: возвращают значение. Проверьте используемый хук. |
| Прямое тестирование в производственной среде | Нет подготовки, нет резервного копирования | План подготовки + резервного копирования + отката (при необходимости деактивация плагина через FTP) |
| Несогласованные постоянные ссылки/шаблоны | Вы проводите тестирование на шаблоне, отличном от того, который отображается (конструктор тем). | Проверьте, какой именно шаблон Elementor был применен, и очистите кеш. |
Советы по безопасности, производительности и техническому обслуживанию
Безопасность
- Систематическое бегство : всё, что выводится в HTML, должно быть экранировано в соответствии с контекстом.
esc_html,esc_attr,esc_url,wp_kses_post). Ссылка : WordPress: Проверка данных. - Нет вариантов «бесплатного HTML». для пользователей без административных ролей. На сайтах с несколькими авторами это является вектором XSS-атаки.
- Выполнение PHP-кода через виджет невозможно. (Это кажется очевидным, но я уже видел несколько самодельных "виджетов кода").
Эффективности
- Условные активы с помощью
get_style_depends()/get_script_depends()Это оптимальное соотношение затраченных усилий и достигнутого результата. - Избегайте зацикливания запросов. в
render()Если вам необходимо загрузить данные (посты, метаданные), кэшируйте их (временный/объектный кэш) или подготовьте с помощью оптимизированного запроса. - Минималистичный CSS : виджет = небольшой файл. Если у вас их 20, сгруппируйте их разумно (но сохраните условие).
Обслуживание
- Версия Используйте плагин (Git) и помечайте свои релизы тегами. Когда Elementor изменит API, вы будете знать, что нужно развернуть.
- Избегайте «старых» руководств. которые используют устаревшие хуки. Если вы повторно используете фрагмент кода 2021-2023 годов, убедитесь, что он совместим с текущей версией Elementor и WordPress 6.9.4.
- Разработайте запасную стратегию. Если Elementor отключен, ваш плагин должен «ничего не делать», и это не приведет к фатальной ошибке.
Ресурсы
- Руководство разработчика плагинов WordPress
- WordPress Noces
- Экранирование символов в WordPress (безопасность)
- wp_register_style()
- wp_register_script()
- Elementor на WordPress.org
- Ядро WordPress (GitHub)
- WordPress Core Trac
- Руководство по PHP
FAQ
Работает ли этот код с WordPress 6.9.4?
Да: плагин соответствует стандартным практикам WordPress (хуки, добавление в очередь запросов) и ориентирован на PHP 8.1+. Основная проблема совместимости по-прежнему связана с версией Elementor (следите за её обновлением).
Почему бы не использовать плагин для создания фрагментов кода?
Для быстрого тестирования это вполне подойдёт. Но для многоразового виджета Elementor более надёжным вариантом будет настоящий плагин: контролируемая загрузка, упорядоченные файлы, версионирование и корректная деактивация в случае поломки.
Мой виджет отображается, но он находится не в той категории.
Проверь это get_categories() повернись ['bpcab']и что категория зарегистрирована через elementor/elements/categories_registered.
Как добавить несколько виджетов?
Добавить больше файлов в includes/widgets/ и сохранить их в register_widgets()Один файл = один класс.
Как избежать загрузки JavaScript, если он мне не нужен?
удалять get_script_depends() или вернуть пустой массив. Старайтесь, чтобы виджет работал без JavaScript насколько это возможно.
Можно ли использовать автозагрузчик (Composer)?
Да, особенно если у вас более 10 виджетов. В контексте WordPress будьте осторожны и не навязывайте Composer конечному сайту. Распространенный подход — включение автозагрузчика PSR-4 в плагин.
Зачем использовать wp_kses_post() Что касается текста?
Потому что текстовое поле может содержать HTML-код, если это позволяет Elementor (или если пользователь вставляет контент). wp_kses_post() позволяет получить безопасное подмножество данных, в отличие от необработанного эхо-сигнала.
Динамический тег не отображается: это нормально?
Это зависит от настроек вашего Elementor. Убедитесь, что для ваших полей доступен «Динамический» интерфейс. Если ваш сайт не поддерживает динамические теги, удалите соответствующую часть. elementor/dynamic_tags/register и соответствующий файл.
Как правильно провести тестирование, не сломав редактор?
Протестируйте в тестовом режиме, включите логирование и начните с минимального виджета (отрисованный + один элемент управления). Добавляйте элементы управления по одному. Ошибки Elementor часто не отображаются на стороне пользовательского интерфейса, но видны в консоли и логах PHP.
Совместимо ли это с дочерней темой Divi/Avada?
Да, потому что это плагин. Однако виджет будет отображаться только в Elementor. Для Divi/Avada используйте шорткод или блок, если хотите, чтобы компонент можно было использовать в разных конструкторах.