Версионирование @import стиля style.css родительской темы
Контекст
Я создал дочернюю тему на основе Twenty Thirteen, которая работает достаточно хорошо. После обновления родительской темы до версии 1.3, я заметил странное поведение со стилями, которое было вызвано кэшированной версией файла style.css
родительской темы.
Вот содержимое файла style.css
моей дочерней темы (без заголовков)
/* =Импорт стилей из родительской темы
-------------------------------------------------------------- */
@import url('../twentythirteen/style.css');
Таким образом, файл style.css
дочерней темы не делает ничего, кроме импорта файла style.css
родительской темы.
У меня также есть другой CSS-файл с настройками моей дочерней темы, который я подключаю в functions.php
следующим образом:
// Подключаем style.css родительской темы (быстрее, чем использование @import в нашем style.css)
$themeVersion = wp_get_theme()->get('Version');
// Подключаем настройки дочерней темы
wp_enqueue_style('child_main', get_stylesheet_directory_uri() . '/css/main.css',
null, $themeVersion);
Это дает мне очень хороший URL для CSS-файла, подобный этому: domain.com/wp-content/themes/toutprettoutbon/css/main.css?ver=1.0.1
, что гарантирует перезагрузку таблицы стилей при обновлении дочерней темы.
Теперь проблема
Выражение @import url('../twentythirteen/style.css');
полностью не зависит от версии родительской темы. Фактически, родительская тема может быть обновлена без обновления дочерней темы, но браузеры по-прежнему будут использовать кэшированные версии старого ../twentythirteen/style.css
.
Соответствующий код в Twenty Thirteen, который подключает style.css
:
function twentythirteen_scripts_styles() {
// ...
// Добавляем шрифт Genericons, используемый в основной таблице стилей.
wp_enqueue_style( 'genericons', get_template_directory_uri() . '/genericons/genericons.css', array(), '3.03' );
// Загружаем основную таблицу стилей.
wp_enqueue_style( 'twentythirteen-style', get_stylesheet_uri(), array(), '2013-07-18' );
// Обратите внимание на использование get_stylesheet_uri(), который фактически подключает child-theme/style.css
// Загружает таблицу стилей, специфичную для Internet Explorer.
wp_enqueue_style( 'twentythirteen-ie', get_template_directory_uri() . '/css/ie.css', array( 'twentythirteen-style' ), '2013-07-18' );
}
add_action( 'wp_enqueue_scripts', 'twentythirteen_scripts_styles' );
Я могу предложить несколько способов решения этой проблемы, но ни один из них не является по-настоящему удовлетворительным:
Обновлять мою дочернюю тему каждый раз, когда обновляется родительская тема, чтобы изменить строку версии в
style.css
(например,@import url('../twentythirteen/style.css?ver=NEW_VERSION');
). Это создает ненужную и раздражающую связь между версией родительской темы и дочерней.В файле
functions.php
моей дочерней темы, 1) использоватьwp_dequeue_style
для отключения подключенного файлаstyle.css
дочерней темы и 2) использоватьwp_enqueue_style
для прямого подключения файлаstyle.css
родительской темы С указанием версии. Это нарушает порядок подключения CSS в родительской теме.Использовать фильтр
style_loader_tag
для изменения сгенерированного тега<link>
дляstyle.css
и изменить путь, чтобы он указывал непосредственно наstyle.css
родительской темы С указанием версии. Кажется довольно странным для такой распространенной потребности (обход кэширования).Скопировать содержимое файла
style.css
родительской темы в файлstyle.css
моей дочерней темы. По сути то же самое, что и (1), но немного быстрее.Сделать файл
style.css
моей дочерней темы символической ссылкой на файлstyle.css
родительской темы. Это выглядит довольно хакерским решением...
Упустил ли я что-то? Какие есть предложения?
редактирование
Добавил таблицы стилей genericicons.css
и ie.css
в родительской теме, чтобы прояснить, почему я не могу изменить выражение @import
на wp_enqueue_style
в моей дочерней теме. В настоящее время с использованием выражения @import
в файле style.css
моей дочерней темы, я имею следующий порядок в сгенерированных страницах:
- twentythirteen/genericons/genericons.css -> подключено родительской темой
- child-theme/style.css -> подключено родительской темой, @imports twentythirteen/style.css
- twentythirteen/css/ie.css -> подключено родительской темой
- child-theme/css/main.css -> подключено дочерней темой
Если я подключу style.css
родительской темы как зависимость для main.css
, это станет:
- twentythirteen/genericons/genericons.css -> подключено родительской темой
- child-theme/style.css -> пустой, подключено родительской темой
- twentythirteen/css/ie.css -> подключено родительской темой
- twentythirteen/style.css -> подключено дочерней темой как зависимость для main.css
- child-theme/css/main.css -> подключено дочерней темой
Обратите внимание, что ie.css теперь включен перед файлом style.css
родительской темы. Я не хочу менять порядок подключения CSS-файлов родительской темы, потому что не могу предполагать, что это не вызовет проблем с приоритетом правил CSS.

Не обязательно использовать @import. На самом деле, лучше этого не делать. Использование подхода с enqueue, вероятно, будет лучше во всех отношениях.
Вот соответствующая часть кода темы twentythirteen:
function twentythirteen_scripts_styles() {
...
// Загружает наш основной таблицу стилей.
wp_enqueue_style( 'twentythirteen-style', get_stylesheet_uri(), array(), '2013-07-18' );
...
}
add_action( 'wp_enqueue_scripts', 'twentythirteen_scripts_styles' );
Вот что вам нужно сделать в вашем коде:
function child_scripts_styles() {
wp_enqueue_style( 'child-style', get_stylesheet_directory_uri().'/css/main.css', array('twentythirteen-style'), 'YOUR_THEME_VERSION' );
}
add_action( 'wp_enqueue_scripts', 'child_scripts_styles' );
Если ваш main.css должен загружаться после style.css родительской темы, просто укажите эту зависимость.
Если у вас также есть файл B.css в дочерней теме, настройте зависимости соответствующим образом:
function child_scripts_styles() {
wp_enqueue_style( 'child-B-style', get_stylesheet_directory_uri().'/B.css', array('twentythirteen-style'), 'YOUR_THEME_VERSION' );
wp_enqueue_style( 'child-style', get_stylesheet_directory_uri().'/css/main.css', array('child-B-style'), 'YOUR_THEME_VERSION' );
}
add_action( 'wp_enqueue_scripts', 'child_scripts_styles' );
Убедитесь, что указанные вами зависимости действительно отражают реальные отношения между файлами. Если main.css должен загружаться после B.css, то он зависит от него. Если B.css должен загружаться после style.css родительской темы, то B.css зависит от него. Система enqueue сама разберётся с порядком загрузки.
И если вы на самом деле не используете style.css дочерней темы, вам вообще не нужно его подключать. Этот файл может быть просто заглушкой для хранения информации о теме в заголовке. Не используете его? Не загружайте.
Кстати, зачем вам так важен порядок загрузки? В большинстве случаев CSS не зависит от порядка загрузки. CSS больше зависит от специфичности селекторов. Если вы хотите переопределить что-то, сделайте ваш селектор более специфичным. Он может быть первым, последним или где-то посередине - более специфичный селектор всегда побеждает.
Обновление
Прочитав ваши комментарии и внимательнее изучив код, я понял, в чём ошибка. Код twenty-thirteen использует "get_stylesheet_uri()", что в случае дочерней темы будет ссылаться на style.css дочерней темы, а не родительской. Вот почему @import работает и сохраняет тот же порядок (который, повторюсь, не так важен, как вам кажется).
В таком случае, если вы не хотите использовать import, я рекомендую напрямую подключить style.css родительской темы. Вот так:
function child_scripts_styles() {
wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css', array() );
}
add_action( 'wp_enqueue_scripts', 'child_scripts_styles' );
Код в functions.php дочерней темы выполняется первым, поэтому ваш wp_enqueue_scripts сработает раньше, и это подключит style.css родительской темы, который сама родительская тема не подключает (потому что она подключает style.css вашей дочерней темы). Не указывая зависимости (так же, как и родительская тема), мы обеспечиваем правильный порядок вывода. Заметьте, что порядок этого файла и genericons.css не важен, потому что оригинальный "twentythirteen-style" не указывает genericons.css в зависимостях.
Ваш собственный style.css дочерней темы загрузится, и, честно говоря, именно здесь вы должны размещать изменения для дочерней темы, а не в отдельном main.css. Ничто не мешает вам использовать дополнительные CSS-файлы, но в этом нет особой необходимости.

Я полностью согласен, что использование @import
— не лучший вариант. Пожалуйста, ознакомьтесь с моим разделом "edit" для более точной информации. У меня нет особых требований к порядку загрузки CSS. Я просто не хочу изменять внутренний порядок CSS-файлов родительской темы, что может вызвать проблемы с приоритетами CSS-правил.

Для уточнения: B.css (теперь изменён на ie.css в вопросе) не является частью моей дочерней темы, а фактически принадлежит родительской теме.

Если вы хотите, чтобы ваш стиль загружался после стиля ie.css, сделайте ваш стиль зависимым от него. Его название — "twentythirteen-ie". Порядок полностью управляется объявленными зависимостями, но опять же, в CSS фактический порядок их в документе обычно не имеет значения, поэтому я не уверен, почему вы так сильно заботитесь об этом.

Да, пожалуй, я слишком увлёкся "необходимостью" сохранить порядок CSS. Если порядок действительно важен для родительской темы, это должно быть указано в зависимостях.

"Собственный style.css вашей дочерней темы загрузится, и, честно говоря, именно здесь вы должны размещать свои изменения для дочерней темы, а не в отдельном main.css." Это верно, но я хочу добавить строку версии к CSS моей дочерней темы.
Если я просто использую подключение style.css дочерней темы через родительскую тему, то версию контролирует родительская тема, поскольку именно она вызывает enqueue_style
. Я хочу иметь возможность обновлять дочернюю тему и изменять строку версии её таблиц стилей для сброса кэша независимо от версии родительской темы.

Хотелось бы узнать ваше мнение о новом, более простом ответе, который я только что добавил.

Ваше обновление действительно помогает решить множество проблем. В моей родительской теме bootstrap.css подключался до style.css. С вашим подходом мне просто нужно было указать bootstrap как зависимость для parent-style в style.css дочерней темы. И все остальное встало на свои места. Спасибо!

Нет ничего плохого в использовании @import
, это никак не влияет на производительность, пожалуйста, проверьте исходный код дочерних тем, созданных любым из методов - вы увидите, что в обоих случаях генерируется два запроса к серверу. Полезное чтение здесь: https://wordpress.org/support/topic/needs-update-12/

Я думаю, что вы не сможете избежать загрузки дочернего style.css
. Проверьте, он будет загружаться, даже если вы специально не ставите его в очередь.

У меня недостаточно репутации, чтобы опубликовать свой собственный ответ, но вот мое решение: https://pastebin.com/iDr6Hy79

Мой предыдущий ответ слишком сложен и потенциально не учитывает цепочку зависимостей родительской темы (см. примечание в другом ответе).
Вот более простое решение, которое должно работать гораздо лучше:
function use_parent_theme_stylesheet() {
// Используем таблицу стилей родительской темы
return get_template_directory_uri() . '/style.css';
}
function my_theme_styles() {
$themeVersion = wp_get_theme()->get('Version');
// Подключаем наш style.css с собственной версией
wp_enqueue_style('child-theme-style', get_stylesheet_directory_uri() . '/style.css',
array(), $themeVersion);
}
// Фильтруем get_stylesheet_uri() для возврата таблицы стилей родительской темы
add_filter('stylesheet_uri', 'use_parent_theme_stylesheet');
// Подключаем скрипты и стили этой темы (после родительской темы)
add_action('wp_enqueue_scripts', 'my_theme_styles', 20);
Идея заключается в том, чтобы просто отфильтровать вызов get_stylesheet_uri()
в родительской теме, чтобы он возвращал собственную таблицу стилей вместо таблицы стилей дочерней темы. Таблица стилей дочерней темы затем подключается позже через хук действия my_theme_styles
.

Для протокола: 1) Ваш код сгенерирует точно такой же HTML, как при использовании старой версии с @import
, никакого влияния на производительность, будет два отдельных запроса style.css к серверу 2) Этот ответ полностью избавляет от зависимости... 3) Вы можете проверить, что делают get_template_directory_uri
и get_template_stylesheet_uri
здесь: https://core.trac.wordpress.org/browser/tags/4.8/src/wp-includes/class-wp-theme.php#L9 Опять же, большая часть этого кода не нужна.

Предупреждение
Это решение не учитывает зависимости родительской темы! Изменение имени handle родительской темы влияет на цепочку зависимостей, установленных в родительской теме. Смотрите мой более простой другой ответ.
Оригинальный ответ
Хотя ответ Otto довольно хорош, в итоге я использовал следующий код в файле functions.php дочерней темы:
function my_theme_styles() {
global $wp_styles;
$parentOriginalHandle = 'twentythirteen-style';
$parentNewHandle = 'parent-style';
// Дерегистрируем наш style.css, который был подключен родительской темой; мы хотим
// сами контролировать версионирование.
$parentStyleVersion = $wp_styles->registered[$parentOriginalHandle]->ver;
$parentDeps = $wp_styles->registered[$parentOriginalHandle]->deps;
wp_deregister_style($parentOriginalHandle);
// Подключаем style.css родительской темы с той же версией, вместо
// использования @import в style.css дочерней темы
wp_register_style($parentNewHandle, get_template_directory_uri() . '/style.css',
$parentDeps, $parentStyleVersion);
// Подключаем наш style.css с собственной версией
$themeVersion = wp_get_theme()->get('Version');
wp_enqueue_style($parentOriginalHandle, get_stylesheet_directory_uri() . '/style.css',
[$parentNewHandle], $themeVersion);
}
// Запускаем это действие после того, как родительская тема подключила свои стили
add_action('wp_enqueue_scripts', 'my_theme_styles', 20);
Этот подход сохраняет порядок подключения и номера версий для style.css
родительской темы, при этом позволяя контролировать версию файла style.css
дочерней темы.

Меня поражает, что для самого популярного блог-софта требуется 20+ строк кода, чтобы просто подправить CSS существующей темы. Видимо, это называется "гарантия занятости".

@CarlG : синтаксис массивов, который я использовал (квадратные скобки), был введён в PHP 5.4.

Тем, кто голосует за: пожалуйста, ознакомьтесь с моим другим ответом, который решает проблемы этого.

Это огромное недоразумение, всё это не нужно. На самом деле старый метод @import
работает так же хорошо, сравните оба метода. Что касается зависимости дочерней темы от родительской — это тоже не нужно. Дочерний style.css
всегда загружается после родительского, по крайней мере, согласно моим тестам. Буду рад, если кто-то докажет обратное.
