Короткий ответ: подключайте стили и скрипты WordPress через функции wp_enqueue_style() и wp_enqueue_script() внутри хука wp_enqueue_scripts. Для файлов темы используйте URI для адреса и путь на диске для вычисления версии через filemtime(). Такой способ сохраняет зависимости, не создает дубли и позволяет WordPress правильно разместить ресурсы на странице.
Ниже приведен готовый пример для дочерней темы, а затем разобраны версии файлов, defer, jQuery, условная загрузка и передача данных из PHP в JavaScript.

Почему не стоит добавлять link и script вручную
Теги <link> в header.php и <script> в footer.php могут работать, но WordPress не узнает о подключенных файлах. Из-за этого тема или плагин не смогут проверить зависимость, отменить загрузку, изменить атрибуты или избежать повторного подключения.
Очередь WordPress решает сразу несколько задач:
- не выводит один ресурс дважды, если используется одинаковый уникальный дескриптор;
- соблюдает порядок зависимостей;
- добавляет версию файла для корректного обновления кеша;
- позволяет подключать ресурсы только на нужных страницах;
- дает плагинам кеширования и оптимизации предсказуемую структуру.
Готовое подключение CSS и JavaScript в дочерней теме
Создайте файлы assets/css/project.css и assets/js/project.js в дочерней теме. Затем добавьте этот код в ее functions.php:
<?php
/**
* Подключает ресурсы дочерней темы на публичной части сайта.
*/
function inkognitod_enqueue_project_assets() {
$theme_dir = get_stylesheet_directory();
$theme_uri = get_stylesheet_directory_uri();
$style_path = $theme_dir . '/assets/css/project.css';
$script_path = $theme_dir . '/assets/js/project.js';
$style_version = file_exists( $style_path )
? (string) filemtime( $style_path )
: wp_get_theme()->get( 'Version' );
$script_version = file_exists( $script_path )
? (string) filemtime( $script_path )
: wp_get_theme()->get( 'Version' );
wp_enqueue_style(
'inkognitod-project',
$theme_uri . '/assets/css/project.css',
array(),
$style_version,
'all'
);
wp_enqueue_script(
'inkognitod-project',
$theme_uri . '/assets/js/project.js',
array(),
$script_version,
array(
'strategy' => 'defer',
'in_footer' => true,
)
);
}
add_action( 'wp_enqueue_scripts', 'inkognitod_enqueue_project_assets' );
Этот пример рассчитан на WordPress 6.3 и новее. В нем последний аргумент wp_enqueue_script() передается массивом с параметрами стратегии загрузки. Для старой версии WordPress используйте вместо массива значение true, чтобы вывести скрипт перед закрывающим тегом </body>.
Как устроены параметры wp_enqueue_style
wp_enqueue_style(
$handle,
$src,
$deps,
$ver,
$media
);
$handleзадает уникальное имя ресурса, напримерinkognitod-project.$srcсодержит публичный URL файла, а не путь на диске.$depsперечисляет дескрипторы стилей, которые должны загрузиться раньше.$verдобавляется к адресу как параметр?ver=.$mediaзадает тип носителя, обычноall.
Если второй файл зависит от первого, укажите дескриптор первого в массиве зависимостей:
wp_enqueue_style(
'inkognitod-catalog',
$theme_uri . '/assets/css/catalog.css',
array( 'inkognitod-project' ),
$catalog_version
);
Как устроены параметры wp_enqueue_script
wp_enqueue_script(
$handle,
$src,
$deps,
$ver,
$args
);
Первые четыре параметра работают так же, как у стилей. В WordPress 6.3 и новее массив $args поддерживает два полезных значения:
in_footerпереносит вывод скрипта в нижнюю часть документа;strategyзадает стратегиюdeferилиasync.
defer подходит для большинства интерфейсных скриптов: файл загружается параллельно и выполняется после разбора HTML с сохранением порядка зависимостей. async выполняется сразу после загрузки, поэтому порядок нескольких файлов не гарантирован. Его стоит использовать только для независимых ресурсов, например некоторых счетчиков.
Если скрипту нужен jQuery
Не подключайте собственную копию jQuery с CDN. Укажите зарегистрированный в WordPress дескриптор:
wp_enqueue_script(
'inkognitod-filter',
$theme_uri . '/assets/js/filter.js',
array( 'jquery' ),
$script_version,
array(
'strategy' => 'defer',
'in_footer' => true,
)
);
WordPress сам добавит jQuery раньше зависимого файла и не выведет его повторно, если библиотека уже нужна другому компоненту.
Версия через filemtime и обновление кеша
После изменения CSS пользователь может продолжать видеть старую версию из кеша. Значение filemtime() меняется вместе с датой изменения файла, поэтому URL ресурса тоже обновляется:
$file_path = get_stylesheet_directory() . '/assets/css/project.css';
$version = file_exists( $file_path )
? (string) filemtime( $file_path )
: wp_get_theme()->get( 'Version' );
Не подставляйте time() в параметр версии на рабочем сайте. Он создает новый адрес при каждом запросе и фактически отключает браузерное кеширование.
Путь файла и URL файла: в чем разница
Для браузера нужен URL, а для file_exists() и filemtime() нужен путь на сервере. Не смешивайте эти значения.
get_stylesheet_directory()возвращает путь к активной, в том числе дочерней, теме.get_stylesheet_directory_uri()возвращает URL активной темы.get_template_directory()иget_template_directory_uri()указывают на родительскую тему.
В дочерней теме почти всегда нужны функции со словом stylesheet. Подробную структуру такой темы разберем в отдельной статье. Готовый пример вывода фрагментов кода в материалах есть в заметке «Вывод кода в статьях на WordPress».
Подключение файлов из плагина
В плагине используйте функции, привязанные к его основному файлу:
function inkognitod_plugin_enqueue_assets() {
$style_path = plugin_dir_path( __FILE__ ) . 'assets/css/plugin.css';
$style_url = plugins_url( 'assets/css/plugin.css', __FILE__ );
$version = file_exists( $style_path )
? (string) filemtime( $style_path )
: '1.0.0';
wp_enqueue_style(
'inkognitod-plugin',
$style_url,
array(),
$version
);
}
add_action( 'wp_enqueue_scripts', 'inkognitod_plugin_enqueue_assets' );
Если код находится не в главном файле плагина, передайте путь к главному файлу через константу или используйте уже принятую в проекте структуру. Иначе URL может вычисляться относительно вложенной папки.
Как загружать ресурсы только на нужных страницах
Большой слайдер или фильтр каталога не должен загружаться на каждой странице. Добавьте условие до вызова функций очереди:
function inkognitod_enqueue_catalog_assets() {
if ( ! is_post_type_archive( 'product' ) && ! is_tax( 'product_cat' ) ) {
return;
}
wp_enqueue_style(
'inkognitod-catalog',
get_stylesheet_directory_uri() . '/assets/css/catalog.css',
array(),
'1.0.0'
);
}
add_action( 'wp_enqueue_scripts', 'inkognitod_enqueue_catalog_assets' );
Для обычной страницы применяйте is_page(), для записи заданного типа is_singular(), для архива is_post_type_archive(). Условные теги работают в wp_enqueue_scripts, потому что к этому моменту WordPress уже определил текущий запрос.
Как передать данные из PHP в JavaScript
URL AJAX-обработчика, nonce и другие динамические значения не нужно вписывать в JavaScript вручную. Сначала поставьте основной файл в очередь, затем добавьте конфигурацию перед ним:
$config = array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'inkognitod_filter' ),
);
wp_add_inline_script(
'inkognitod-filter',
'window.InkognitodFilter = ' . wp_json_encode( $config ) . ';',
'before'
);
wp_add_inline_script() сработает только для уже поставленного в очередь дескриптора. Значения кодируются через wp_json_encode(), а nonce все равно нужно проверить в AJAX-обработчике.
Отдельные хуки для админки и страницы входа
wp_enqueue_scripts предназначен для публичной части сайта. Для других экранов используйте отдельные хуки:
admin_enqueue_scriptsдля панели управления;login_enqueue_scriptsдля страницы входа.
Не подключайте административный CSS на всем сайте. В обработчике admin_enqueue_scripts можно дополнительно проверить параметр $hook_suffix и оставить ресурс только на экране конкретного плагина.
Частые ошибки
Файл отдает 404
Проверьте, что для $src используется функция с окончанием _uri(), а не путь на диске. В дочерней теме также проверьте выбор между stylesheet и template.
Стили подключились дважды
Найдите ручной тег в header.php, Elementor Custom Code или настройках оптимизатора. Затем проверьте дескрипторы: одинаковый файл с разными $handle WordPress считает разными ресурсами.
Новая версия CSS не видна
Убедитесь, что в URL изменился параметр ?ver=. После этого очистите кеш плагина, сервера и CDN. Если версия задана строкой 1.0.0, увеличьте ее вручную или перейдите на filemtime().
Скрипт не появился внизу страницы
Проверьте наличие wp_footer() перед закрывающим тегом </body>. Для стилей и скриптов в верхней части документа нужен wp_head() внутри <head>.
JavaScript выполняется слишком рано
Используйте defer и запускайте работу с DOM после события DOMContentLoaded, если это требуется архитектурой файла. Не заменяйте defer на async для цепочки зависимых скриптов.
Как проверить подключение
- Откройте исходный код страницы и найдите уникальный дескриптор или имя файла.
- В DevTools перейдите на вкладку Network, обновите страницу и проверьте статус 200.
- Убедитесь, что у измененного файла обновляется параметр
?ver=. - Проверьте порядок: зависимость должна находиться раньше основного скрипта.
- Откройте страницу, где ресурс не нужен, и убедитесь, что условная загрузка не добавила его.
- Проверьте консоль, мобильную версию и страницу без авторизации.
Ответы на вопросы
Куда вставлять код wp_enqueue?
В functions.php дочерней темы или в кастомный плагин. Не изменяйте родительскую тему и файлы стороннего плагина напрямую, иначе правки могут исчезнуть после обновления.
Можно ли подключить CSS только для одной страницы?
Да. Внутри функции на хуке wp_enqueue_scripts проверьте is_page( 123 ) или постоянный идентификатор страницы. Для повторно используемой логики лучше проверять шаблон, тип записи или наличие конкретного блока.
Нужно ли всегда ставить in_footer?
Для большинства собственных интерфейсных скриптов это разумный вариант. Но критический код, который должен выполниться в <head>, может требовать другого размещения. Решение зависит от назначения файла и его зависимостей.
Что лучше: defer или async?
defer безопаснее для зависимых файлов и интерфейса страницы. async используйте для полностью независимого кода, которому не важен порядок выполнения.
Итог
Для правильного подключения CSS и JavaScript используйте хук wp_enqueue_scripts, уникальные дескрипторы и корректные URL темы или плагина. Версию локальных файлов формируйте через filemtime(), зависимости передавайте массивом, а тяжелые ресурсы ограничивайте условиями. Для JavaScript в WordPress 6.3 и новее используйте массив с strategy => defer и in_footer => true, если это подходит логике файла.
Официальная документация: хук wp_enqueue_scripts, wp_enqueue_style(), wp_enqueue_script() и wp_add_inline_script().
Нужна доработка WordPress-сайта?
Inkognitod помогает аккуратно дорабатывать WordPress, WooCommerce, ACF, формы, шаблоны и JavaScript-логику без правок ядра и хаоса в теме.

