Skip to content

Всё для WordPress, веб-разработки — и не только

🛠 Правильное подключение JavaScript в темах WordPress

🛠 Правильное подключение JavaScript в темах WordPress

Обновили WordPress, и галерея перестала работать. Знакомо?

Почти всегда причина в том, что JavaScript подключен напрямую в header.php, без хуков, без зависимостей, без учёта того, что плагин кеширования может перетасовать порядок загрузки. Один плагин тянет jQuery, второй, свою версию jQuery, а ваш скрипт оказывается между ними и падает с $ is not defined.

На практике хватает одного вызова wp_enqueue_script в нужном месте, чтобы забыть о конфликтах навсегда. Ниже, полный разбор: от ошибок новичков до стратегий defer/async и тонких настроек, которые появились в WordPress 6.6.

💡 Быстрый обзор:

  • Не вставляйте тег script напрямую в header.php или footer.php: это создаёт конфликты с плагинами и ломает дочерние темы
  • Подключайте JavaScript через wp_enqueue_script в functions.php с хуком wp_enqueue_scripts: WordPress сам расставит теги в head или перед /body
  • Для коротких вставок используйте wp_add_inline_script, а не голый script-тег: сохраняет порядок выполнения и даёт плагинам шанс перехватить код
  • На WordPress 6.3+ указывайте стратегию defer или async прямо в параметрах вызова, а с 6.6, ещё и fetchpriority
  • Выгружайте чужие скрипты через wp_dequeue_script, если плагин тормозит сайт: приоритет хука решает

Как неправильно добавляют JavaScript в WordPress

Типичный сценарий: нужно подключить свой custom.js, и разработчик вставляет в header.php строчку:

1<script src="<?php echo get_template_directory_uri(); ?>/js/custom.js"></script>

С виду работает. Но такой подход создаёт три проблемы.

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

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

Нет зависимостей. Браузер грузит ваш скрипт до jQuery, и получает $ is not defined. Скрипт грузится на всех страницах, даже там где он не нужен, и лишние запросы замедляют сайт.

Правильный способ: wp_enqueue_script

WordPress предоставляет систему очередей для скриптов и стилей. Вы не вставляете <script> вручную, а регистрируете скрипт через PHP, указываете зависимости и место загрузки. WordPress сам расставляет теги в <head> или перед </body>.

Минимальный рабочий пример для functions.php вашей темы:

1/**
2 * Подключаем основной скрипт темы.
3 */
4function mytheme_enqueue_scripts() {
5 wp_enqueue_script(
6 'mytheme-main', // $handle — уникальное имя
7 get_template_directory_uri() . '/js/main.js', // $src — путь к файлу
8 array( 'jquery' ), // $deps — зависимости
9 '1.0.0', // $ver — версия для сброса кеша
10 true // $in_footer — грузить в подвале
11 );
12}
13add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_scripts' );

Функция wp_enqueue_script принимает пять параметров. $handle, уникальный идентификатор: если другой плагин уже зарегистрировал скрипт с таким же handle, повторной загрузки не будет. $deps, массив handle-зависимостей: WordPress сам подгрузит нужные скрипты перед вашим. $in_footer со значением true помещает тег <script> перед </body>, это ускоряет отрисовку страницы.

Обратите внимание: get_template_directory_uri() указывает на папку родительской темы. В дочерней теме используйте get_stylesheet_directory_uri(), URL будет вести в папку дочерней, и ваш скрипт не потеряется при обновлении родительской темы.

Стратегии загрузки: defer, async и fetchpriority

С WordPress 6.3 параметр $args принимает массив с дополнительными настройками:

1wp_enqueue_script(
2 'mytheme-main',
3 get_template_directory_uri() . '/js/main.js',
4 array( 'jquery' ),
5 '1.0.0',
6 array(
7 'in_footer' => true,
8 'strategy' => 'defer',
9 )
10);

Стратегия defer говорит браузеру: «грузи скрипт параллельно, выполняй после построения DOM». Порядок выполнения гарантирован, скрипты с defer выполняются в том порядке, в котором добавлены в DOM. Стратегия async, «выполняй как только загрузился», порядок не гарантирован. Для скриптов темы, зависящих от DOM, выбирайте defer.

С WordPress 6.6 в массиве $args появились ещё два параметра. fetchpriority управляет приоритетом загрузки ('high' или 'low'), пригодится для критических скриптов, которые должны загрузиться раньше остальных. module_dependencies принимает массив ID модулей для динамического импорта, это уже для продвинутых сценариев с ES-модулями. Важно: при указании module_dependencies скрипт обязан грузиться в подвале (in_footer => true) или со стратегией defer, иначе карта импорта модулей не будет готова к моменту выполнения скрипта.

Какие скрипты уже есть в WordPress

WordPress «из коробки» регистрирует десятки JavaScript-библиотек: jQuery, jQuery UI, Backbone, wp-api, MediaElement.js и другие. Полный список, в официальной документации.

Главное правило: никогда не подключайте jQuery с CDN вроде Google или cdnjs, если тема работает в экосистеме WordPress. WordPress сам предоставляет jQuery с handle jquery. Чтобы использовать его, просто укажите array( 'jquery' ) в зависимостях, WordPress загрузит свою версию, протестированную на совместимость со всем ядром.

Проверить, зарегистрирована ли библиотека, можно через wp_script_is():

1if ( wp_script_is( 'jquery-ui-datepicker', 'registered' ) ) {
2 // Библиотека доступна — просто добавьте в $deps
3}

Использование хука wp_enqueue_scripts

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

Для админки используйте отдельный хук:

1add_action( 'admin_enqueue_scripts', 'mytheme_admin_scripts' );
2function mytheme_admin_scripts( $hook_suffix ) {
3 // $hook_suffix содержит текущую страницу админки
4 if ( 'post.php' !== $hook_suffix ) {
5 return; // грузим скрипт только на странице редактирования записи
6 }
7 wp_enqueue_script( 'mytheme-admin', get_template_directory_uri() . '/js/admin.js', array(), '1.0', true );
8}

Условная загрузка экономит ресурсы: скрипт для страницы опций не должен грузиться на всех страницах админки. Параметр $hook_suffix передаётся WordPress автоматически, используйте его.

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

1add_action( 'wp_enqueue_scripts', 'mytheme_global_scripts' );
2add_action( 'admin_enqueue_scripts', 'mytheme_global_scripts' );

Добавление встроенного JavaScript: wp_add_inline_script

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

1function mytheme_inline_config() {
2 wp_enqueue_script( 'mytheme-main', get_template_directory_uri() . '/js/main.js', array(), '1.0', true );
3 wp_add_inline_script(
4 'mytheme-main',
5 'const MYTHEME_AJAX_URL = "' . admin_url( 'admin-ajax.php' ) . '";',
6 'before'
7 );
8}
9add_action( 'wp_enqueue_scripts', 'mytheme_inline_config' );

Третий параметр, 'before' или 'after', определяет, куда вставится код относительно указанного скрипта. Это удобно для проброса PHP-переменных в JavaScript: URL AJAX-обработчика, nonce-ключ безопасности, ID текущей записи.

Важный нюанс: wp_add_inline_script работает только с зарегистрированным скриптом. Если передать handle, которого нет в очереди, код не выведется. Поэтому сначала wp_enqueue_script, потом wp_add_inline_script.

Альтернатива для дочерних тем: wp_head и wp_footer

Если вы работаете в дочерней теме и не хотите создавать отдельный файл, можно вывести код напрямую через хуки wp_head<head>) или wp_footer (перед </body>):

1add_action( 'wp_footer', function() { ?>
2 <script>
3 ( function( $ ) {
4 'use strict';
5 $( function() {
6 // Ваш код здесь — DOM уже готов
7 } );
8 } ( jQuery ) );
9 </script>
10<?php } );

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

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

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

1function mytheme_dequeue_plugin_scripts() {
2 if ( ! is_page( 'contacts' ) ) {
3 wp_dequeue_script( 'plugin-handle' );
4 }
5}
6add_action( 'wp_enqueue_scripts', 'mytheme_dequeue_plugin_scripts', 20 );

Приоритет 20 (третий аргумент add_action) ставит вашу функцию позже регистрации плагина, иначе handle ещё не будет в очереди. Узнать handle конкретного скрипта можно через консоль браузера: откройте исходный код страницы и найдите атрибут id у тега <script>, handle обычно совпадает с id без суффикса -js.

Если нужно полностью заменить скрипт, сначала снимите старый через wp_deregister_script, затем зарегистрируйте новый:

1function mytheme_replace_script() {
2 wp_deregister_script( 'old-handle' );
3 wp_enqueue_script( 'old-handle', get_template_directory_uri() . '/js/replacement.js', array(), '2.0', true );
4}
5add_action( 'wp_enqueue_scripts', 'mytheme_replace_script', 20 );

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

На видео выше, пошаговый разбор подключения CSS и JavaScript в теме WordPress через wp_enqueue_script и wp_enqueue_style. Если вы новичок в теме хуков, начните с него, а затем возвращайтесь к текстовому руководству за деталями.

⁉️🤔 Частые вопросы

Обязательно ли использовать wp_enqueue_script для каждого js-файла?

На практике, да, для всех скриптов, которые подключаются глобально. Для скрипта, который работает на одной-единственной странице и генерируется динамически, допустимо вставить <script> прямо в шаблон. Но как только скриптов становится два и больше, очередь через wp_enqueue_script экономит часы отладки.

Чем wp_register_script отличается от wp_enqueue_script?

wp_register_script только регистрирует скрипт в системе (задаёт handle, путь, зависимости), но не выводит тег на страницу. wp_enqueue_script регистрирует И сразу ставит в очередь на вывод. Разделение полезно, когда скрипт нужен не всегда: регистрируете один раз в functions.php, а вызываете wp_enqueue_script('my-handle') только на нужных страницах.

Можно ли загружать скрипты с внешнего CDN?

Технически, да, передайте полный URL вторым параметром. Но для jQuery и других библиотек из ядра WordPress это плохая практика: WordPress уже включает их и тестирует совместимость. Внешний CDN оправдан для сторонних сервисов, Google Analytics, reCAPTCHA, виджеты чатов. Там URL указывайте как есть.

Как проверить, что скрипт действительно загрузился?

Откройте инструменты разработчика (F12), вкладка Network, отфильтруйте по JS и обновите страницу. Ваш файл должен быть в списке с кодом 200. Если скрипта нет, проверьте, что хук wp_enqueue_scripts срабатывает на этой странице и что путь к файлу корректен. Для отладки выведите get_template_directory_uri() отдельно и сверьте URL.

Что делать, если после обновления темы скрипты перестали работать?

Скорее всего, обновление затёрло ваш functions.php. Решение, дочерняя тема: создайте её, перенесите туда свои функции и активируйте. После этого обновления родительской темы ваш код останется на месте.

Что означает ошибка «$ is not defined» при использовании jQuery?

WordPress загружает jQuery в режиме noConflict, переменная $ не занята jQuery, чтобы избежать конфликтов с другими библиотеками. Используйте полное имя jQuery вместо $ либо оберните код в самовызывающуюся функцию: (function($) { ... })(jQuery);.

Стоит ли заморачиваться с wp_enqueue_script для пары скриптов?

Если на сайте больше одного плагина, стоит. Очередь скриптов в WordPress устроена так, что один плагин, подключивший jQuery напрямую, ломает полсайта при первой же установке плагина кеширования. wp_enqueue_script убирает этот класс проблем целиком.

Для темы из пяти файлов, берите wp_enqueue_script. Для одной короткой вставки на конкретную страницу, сойдёт wp_add_inline_script или хук wp_footer. Но как только скриптов становится два и больше, возвращайтесь к очереди. Час, потраченный на правильное подключение сейчас, экономит вечер отладки после очередного обновления WordPress.