Версионирование @import стиля style.css родительской темы

3 окт. 2014 г., 03:50:31
Просмотры: 97.1K
Голосов: 29

Контекст

Я создал дочернюю тему на основе 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' );

Я могу предложить несколько способов решения этой проблемы, но ни один из них не является по-настоящему удовлетворительным:

  1. Обновлять мою дочернюю тему каждый раз, когда обновляется родительская тема, чтобы изменить строку версии в style.css (например, @import url('../twentythirteen/style.css?ver=NEW_VERSION');). Это создает ненужную и раздражающую связь между версией родительской темы и дочерней.

  2. В файле functions.php моей дочерней темы, 1) использовать wp_dequeue_style для отключения подключенного файла style.css дочерней темы и 2) использовать wp_enqueue_style для прямого подключения файла style.css родительской темы С указанием версии. Это нарушает порядок подключения CSS в родительской теме.

  3. Использовать фильтр style_loader_tag для изменения сгенерированного тега <link> для style.css и изменить путь, чтобы он указывал непосредственно на style.css родительской темы С указанием версии. Кажется довольно странным для такой распространенной потребности (обход кэширования).

  4. Скопировать содержимое файла style.css родительской темы в файл style.css моей дочерней темы. По сути то же самое, что и (1), но немного быстрее.

  5. Сделать файл style.css моей дочерней темы символической ссылкой на файл style.css родительской темы. Это выглядит довольно хакерским решением...

Упустил ли я что-то? Какие есть предложения?

редактирование

Добавил таблицы стилей genericicons.css и ie.css в родительской теме, чтобы прояснить, почему я не могу изменить выражение @import на wp_enqueue_style в моей дочерней теме. В настоящее время с использованием выражения @import в файле style.css моей дочерней темы, я имею следующий порядок в сгенерированных страницах:

  1. twentythirteen/genericons/genericons.css -> подключено родительской темой
  2. child-theme/style.css -> подключено родительской темой, @imports twentythirteen/style.css
  3. twentythirteen/css/ie.css -> подключено родительской темой
  4. child-theme/css/main.css -> подключено дочерней темой

Если я подключу style.css родительской темы как зависимость для main.css, это станет:

  1. twentythirteen/genericons/genericons.css -> подключено родительской темой
  2. child-theme/style.css -> пустой, подключено родительской темой
  3. twentythirteen/css/ie.css -> подключено родительской темой
  4. twentythirteen/style.css -> подключено дочерней темой как зависимость для main.css
  5. child-theme/css/main.css -> подключено дочерней темой

Обратите внимание, что ie.css теперь включен перед файлом style.css родительской темы. Я не хочу менять порядок подключения CSS-файлов родительской темы, потому что не могу предполагать, что это не вызовет проблем с приоритетом правил CSS.

5
Комментарии

Никогда не используйте @import, вместо этого установите таблицу стилей родительской темы как зависимость вашей собственной таблицы стилей.

fuxia fuxia
3 окт. 2014 г. 04:03:52

Я знаю, что это не лучший подход, но он рекомендуется здесь: http://codex.wordpress.org/Child_Themes

bernie bernie
3 окт. 2014 г. 04:09:44

Кроме того, предложенное вами решение не исправляет мою проблему. Таблица стилей style.css родительской темы не будет подключена в том же месте, где она находится сейчас. Родительская тема подключает другие CSS-файлы, которые должны находиться между её style.css и CSS моего дочернего шаблона.

bernie bernie
3 окт. 2014 г. 04:10:54

Пожалуйста, полностью игнорируйте кодекс. Он полон недостоверной информации. Использование параметра dependency обеспечит правильный порядок подключения таблиц стилей.

fuxia fuxia
3 окт. 2014 г. 04:11:47

Пожалуйста, ознакомьтесь с моими изменениями.

bernie bernie
3 окт. 2014 г. 19:53:33
Все ответы на вопрос 3
11
19

Не обязательно использовать @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-файлы, но в этом нет особой необходимости.

3 окт. 2014 г. 20:25:45
Комментарии

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

bernie bernie
3 окт. 2014 г. 22:13:45

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

bernie bernie
3 окт. 2014 г. 22:26:46

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

Otto Otto
3 окт. 2014 г. 23:12:02

Отредактировал свой ответ, включив в него альтернативный подход.

Otto Otto
3 окт. 2014 г. 23:29:48

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

bernie bernie
4 окт. 2014 г. 17:20:16

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

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

bernie bernie
4 окт. 2014 г. 17:23:16

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

bernie bernie
23 мар. 2015 г. 19:19:45

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

roshan roshan
3 апр. 2016 г. 18:53:50

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

bg17aw bg17aw
1 сент. 2017 г. 01:11:49

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

bg17aw bg17aw
1 сент. 2017 г. 01:14:42

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

360path 360path
2 апр. 2020 г. 20:51:48
Показать остальные 6 комментариев
2

Мой предыдущий ответ слишком сложен и потенциально не учитывает цепочку зависимостей родительской темы (см. примечание в другом ответе).

Вот более простое решение, которое должно работать гораздо лучше:

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.

23 мар. 2015 г. 19:13:13
Комментарии

Для протокола: 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 Опять же, большая часть этого кода не нужна.

bg17aw bg17aw
1 сент. 2017 г. 01:19:58

@bg17aw использование wp_enqueue_style автоматически добавляет строку запроса для сброса кеша к генерируемому URL (например, ?ver=2013-07-18) на основе версии темы. Это не делается при использовании оператора @import.

bernie bernie
14 сент. 2017 г. 21:01:58
6

Предупреждение

Это решение не учитывает зависимости родительской темы! Изменение имени 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 дочерней темы.

6 окт. 2014 г. 21:25:47
Комментарии

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

Carl G Carl G
25 янв. 2015 г. 23:45:39

Мне пришлось заменить [$parentNewHandle] на array($parentNewHandle)

Carl G Carl G
26 янв. 2015 г. 00:24:18

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

bernie bernie
26 янв. 2015 г. 06:47:14

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

bernie bernie
23 мар. 2015 г. 19:21:06

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

bg17aw bg17aw
1 сент. 2017 г. 01:23:01

@bg17aw использование wp_enqueue_style автоматически добавляет строку запроса для обхода кеша к генерируемому URL (например, ?ver=2013-07-18) на основе версии темы. Это не делается при использовании @import.

bernie bernie
14 сент. 2017 г. 21:02:12
Показать остальные 1 комментариев