Versionarea @import a fișierului style.css din tema părinte
Context
Am creat o temă copil bazată pe Twenty Thirteen care funcționează destul de bine. După actualizarea temei părinte la versiunea 1.3, am observat un comportament ciudat la stilizare, cauzat de un fișier style.css
din tema părinte care era cache-uit.
Iată conținutul fișierului style.css
al temei mele copil (fără antet):
/* =Importă stilurile din tema părinte
-------------------------------------------------------------- */
@import url('../twentythirteen/style.css');
Deci fișierul style.css
al temei copil nu face altceva decât să importe fișierul style.css
al temei părinte.
Am un alt fișier CSS cu personalizările temei copil pe care îl încarc astfel în functions.php
:
// Încarcă style.css din tema părinte (mai rapid decât folosind @import în style.css)
$themeVersion = wp_get_theme()->get('Version');
// Încarcă personalizările temei copil
wp_enqueue_style('child_main', get_stylesheet_directory_uri() . '/css/main.css',
null, $themeVersion);
Aceasta îmi oferă un URL CSS frumos de genul: domain.com/wp-content/themes/toutprettoutbon/css/main.css?ver=1.0.1
care asigură reîncărcarea fișierului CSS când tema copil este actualizată.
Problema
Instrucțiunea @import url('../twentythirteen/style.css');
este complet independentă de versiunea temei părinte. De fapt, tema părinte poate fi actualizată fără a actualiza tema copil, dar browserele vor continua să folosească versiunile cache-uite ale vechiului ../twentythirteen/style.css
.
Codul relevant din Twenty Thirteen care încarcă style.css
:
function twentythirteen_scripts_styles() {
// ...
// Adaugă fontul Genericons, folosit în fișierul principal de stiluri
wp_enqueue_style( 'genericons', get_template_directory_uri() . '/genericons/genericons.css', array(), '3.03' );
// Încarcă fișierul principal de stiluri
wp_enqueue_style( 'twentythirteen-style', get_stylesheet_uri(), array(), '2013-07-18' );
// Observați folosirea get_stylesheet_uri() care de fapt încarcă child-theme/style.css
// Încarcă fișierul de stiluri specific pentru 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' );
Pot să mă gândesc la câteva soluții, dar niciuna nu este cu adevărat satisfăcătoare:
Actualizez tema copil de fiecare dată când tema părinte este actualizată pentru a schimba un șir de versiune în
style.css
(de ex.@import url('../twentythirteen/style.css?ver=NEW_VERSION');
). Aceasta creează o legătură inutilă și enervantă între versiunea temei părinte și copil.În
functions.php
al temei copil, 1)wp_dequeue_style
pentru fișierulstyle.css
al temei copil și 2)wp_enqueue_style
pentru fișierulstyle.css
al temei părinte direct CU șir de versiune. Aceasta încurcă ordinea încărcării fișierelor CSS în tema părinte.Folosesc filtrul
style_loader_tag
pentru a modifica tag-ul<link>
generat pentrustyle.css
și pentru a modifica calea să indice direct către fișierulstyle.css
al temei părinte CU un șir de versiune. Pare destul de obscur pentru o nevoie atât de comună (cache busting).Copiază conținutul fișierului
style.css
al temei părinte în fișierulstyle.css
al temei copil. La fel ca la (1), dar puțin mai rapid.Fac ca fișierul
style.css
al temei copil să fie un symlink către fișierulstyle.css
al temei părinte. Pare destul de hack-ish...
Am omis ceva? Aveți sugestii?
edit
Am adăugat fișierele genericicons.css
și ie.css
din tema părinte pentru a clarifica de ce nu pot schimba instrucțiunea CSS @import
cu wp_enqueue_style
în tema copil. În prezent, cu o instrucțiune @import
în fișierul style.css
al temei copil, am această ordine în paginile generate:
- twentythirteen/genericons/genericons.css -> încărcat de tema părinte
- child-theme/style.css -> încărcat de tema părinte, importă twentythirteen/style.css
- twentythirteen/css/ie.css -> încărcat de tema părinte
- child-theme/css/main.css -> încărcat de tema copil
Dacă încărc fișierul style.css
al temei părinte ca dependință a main.css
, ordinea devine:
- twentythirteen/genericons/genericons.css -> încărcat de tema părinte
- child-theme/style.css -> gol, încărcat de tema părinte
- twentythirteen/css/ie.css -> încărcat de tema părinte
- twentythirteen/style.css -> încărcat de tema copil ca dependință a main.css
- child-theme/css/main.css -> încărcat de tema copil
Observați că ie.css este acum inclus înaintea fișierului style.css
al temei părinte. Nu vreau să schimb ordinea încărcării fișierelor CSS ale temei părinte pentru că nu pot presupune că acest lucru nu va cauza probleme cu prioritatea regulilor CSS.

Nu trebuie să folosești @import. De fapt, este mai bine să nu o faci. Folosirea metodei de încărcare prin enqueue este probabil mai bună din toate punctele de vedere.
Iată partea relevantă din codul temei twentythirteen:
function twentythirteen_scripts_styles() {
...
// Încarcă fișierul nostru principal de stiluri.
wp_enqueue_style( 'twentythirteen-style', get_stylesheet_uri(), array(), '2013-07-18' );
...
}
add_action( 'wp_enqueue_scripts', 'twentythirteen_scripts_styles' );
Iată ce ar trebui să faci în codul tău:
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' );
Dacă main.css trebuie să fie încărcat după style.css al părintelui, atunci pur și simplu îl faci dependent de acesta.
Dacă ai și un fișier B.css în tema copil, atunci configurezi dependențele în consecință:
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' );
Asigură-te că dependențele pe care le definești pentru fiecare element reflectă realitatea. Dacă main.css trebuie să vină după B.css, atunci depinde de acesta. Dacă B.css trebuie să vină după style.css al părintelui, atunci B depinde de acesta. Sistemul de încărcare va rezolva ordinea pentru tine.
Și dacă nu folosești style.css al temei copil pentru nimic, atunci nu trebuie să-l încarci deloc. Poate fi doar un placeholder pentru informațiile din header-ul temei tale. Nu-l folosești? Nu-l încărca.
De asemenea, ce anume faci care este atât de dependent de ordinea de încărcare aici? În majoritatea situațiilor, CSS-ului nu îi pasă de ordinea de încărcare. CSS-ul depinde mai mult de specificitatea selectorilor. Dacă vrei să suprascrii ceva, faci selectorul tău mai specific. Poate veni primul, ultimul sau oriunde între, selectorul mai specific câștigă întotdeauna.
Editare
Citind comentariile tale și analizând mai atent codul, văd unde este greșeala. Codul twenty-thirteen încarcă "get_stylesheet_uri()", care în cazul unei teme copil, ar fi fișierul style.css al temei copil, nu al părintelui. De aceea @import funcționează și păstrează aceeași ordine (care, repet, nu contează atât de mult pe cât crezi).
În acest caz, dacă nu vrei să folosești import, aș recomanda să încarci style.css al părintelui direct. Astfel:
function child_scripts_styles() {
wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css', array() );
}
add_action( 'wp_enqueue_scripts', 'child_scripts_styles' );
Codul din functions.php al temei copil rulează primul, deci wp_enqueue_scripts personal va rula primul, iar acesta va încărca style.css al părintelui, pe care tema părinte nu-l încarcă singură (pentru că de fapt încarcă style.css al copilului tău). Prin a nu-l face dependent de nimic, la fel ca părintele, atunci va fi plasat corect în output. Reține că ordinea acestui fișier și genericons.css nu contează, deoarece originalul "twentythirteen-style" nu are genericons.css ca dependență listată.
style.css al copilului tău se va încărca și, sincer, aici ar trebui să pui modificările pentru tema copil, nu într-un main.css separat. Nu te împiedică nimic să pui modificările acolo, dar nu există un motiv real pentru a avea un fișier CSS în plus.

Sunt complet de acord că folosirea @import
nu este cea mai bună abordare. Vă rugăm să consultați secțiunea mea "edit" pentru informații mai precise. Nu am nevoi speciale legate de ordonarea fișierelor css. Pur și simplu nu doresc să modific ordonarea internă a fișierelor css ale temei părinte, deoarece aceasta poate cauza probleme cu prioritatea regulilor css.

Pentru a clarifica, B.css (acum schimbat în ie.css în întrebare) nu face parte din tema mea copil, ci de fapt face parte din tema părinte.

Dacă doriți ca stilul dumneavoastră să apară după stilul ie.css, atunci faceți ca stilul dumneavoastră să depindă de acesta. Numele său este "twentythirteen-ie". Ordinea este gestionată în întregime de dependențele pe care le declarați, dar din nou, în cazul CSS-ului, ordinea efectivă a acestora în document nu contează de obicei, așa că nu sunt sigur de ce ați fi atât de preocupat de acest aspect.

Da, cred că m-am lăsat dus de valul "necesității" de a păstra ordinea CSS. Dacă ordinea era cu adevărat importantă pentru tema părinte, ar fi trebuit să fie specificată în dependențe.

"Propriul tău fișier style.css al temei copil se va încărca și, sincer, aici ar trebui să pui modificările pentru tema copil, nu într-un fișier main.css separat." Asta este adevărat, dar vreau să adaug un șir de versiune la CSS-ul temei mele copil.
Dacă folosesc simpla încărcare a fișierului style.css al temei copil din tema părinte, părintele controlează versiunea deoarece apelează enqueue_style
. Vreau să pot actualiza tema copil și să schimb șirul de versiune al fișierelor sale de stil pentru a evita cache-ul, independent de versiunea temei părinte.

Aș fi curios să aud părerea ta despre noul răspuns mult mai simplu pe care tocmai l-am adăugat.

Actualizarea ta chiar ajută la rezolvarea multor probleme. Tema mea părinte avea bootstrap.css inclus înainte de style.css. Cu abordarea ta, a trebuit doar să specific bootstrap ca dependență pentru parent-style în style.css-ul temei copil. Și restul lucrurilor au funcționat perfect. Mulțumesc!

Nu e nimic în neregulă cu folosirea @import
, nu afectează performanța în niciun fel, te rog verifică codul sursă al temelor copil create cu oricare metodă, vei descoperi că se generează două cereri către server în ambele cazuri. O lectură utilă aici: https://wordpress.org/support/topic/needs-update-12/

Nu cred că poți evita încărcarea fișierului copil style.css
. Te rog verifică, acesta va fi încărcat chiar dacă nu îl încarci explicit.

Nu am suficiente reputații pentru a posta propriul răspuns, dar iată părerea mea: https://pastebin.com/iDr6Hy79

Răspunsul meu anterior este excesiv de complicat și poate nu respectă lanțul de dependențe al temei părinte (vezi nota din celălalt răspuns).
Iată o abordare mult mai simplă care ar trebui să funcționeze mult mai bine:
function use_parent_theme_stylesheet() {
// Folosește fișierul de stil al temei părinte
return get_template_directory_uri() . '/style.css';
}
function my_theme_styles() {
$themeVersion = wp_get_theme()->get('Version');
// Încarcă fișierul nostru style.css cu versiunea noastră
wp_enqueue_style('child-theme-style', get_stylesheet_directory_uri() . '/style.css',
array(), $themeVersion);
}
// Filtrează get_stylesheet_uri() pentru a returna fișierul de stil al temei părinte
add_filter('stylesheet_uri', 'use_parent_theme_stylesheet');
// Încarcă scripturile și stilurile acestei teme (după tema părinte)
add_action('wp_enqueue_scripts', 'my_theme_styles', 20);
Ideea este să filtrăm simplu apelul către get_stylesheet_uri()
în tema părinte pentru a returna propriul fișier de stil în locul celui al temei copil. Fișierul de stil al temei copil este încărcat mai târziu în acțiunea my_theme_styles
.

Doar pentru clarificare: 1) Codul tău va genera exact același HTML ca și versiunea veche cu @import
, fără niciun impact asupra performanței, vor fi două cereri separate către server pentru style.css 2) Acest răspuns elimină complet dependența... 3) Poți verifica ce fac get_template_directory_uri
și get_template_stylesheet_uri
aici: https://core.trac.wordpress.org/browser/tags/4.8/src/wp-includes/class-wp-theme.php#L9 Din nou, nu este nevoie de cea mai mare parte din acel cod.

avertisment
Această soluție nu respectă dependențele temei părinte! Schimbarea numelui handle-ului temei părinte afectează lanțul de dependențe setat în tema părinte. Vezi răspunsul meu mult mai simplu aici.
răspuns original
Deși răspunsul lui Otto este destul de bun, am ajuns la această implementare în functions.php al temei mele copil:
function my_theme_styles() {
global $wp_styles;
$parentOriginalHandle = 'twentythirteen-style';
$parentNewHandle = 'parent-style';
// Deregistrăm style.css care a fost încărcat de tema părinte; vrem
// să controlăm versiunea noi înșine.
$parentStyleVersion = $wp_styles->registered[$parentOriginalHandle]->ver;
$parentDeps = $wp_styles->registered[$parentOriginalHandle]->deps;
wp_deregister_style($parentOriginalHandle);
// Încărcăm style.css al temei părinte cu versiunea originală în loc
// să-l importăm via @import în style.css al temei copil
wp_register_style($parentNewHandle, get_template_directory_uri() . '/style.css',
$parentDeps, $parentStyleVersion);
// Încărcăm style.css al temei noastre cu propria versiune
$themeVersion = wp_get_theme()->get('Version');
wp_enqueue_style($parentOriginalHandle, get_stylesheet_directory_uri() . '/style.css',
[$parentNewHandle], $themeVersion);
}
// Rulează această acțiune după ce tema părinte a încărcat stilurile sale.
add_action('wp_enqueue_scripts', 'my_theme_styles', 20);
Menține ordinea și numerele de versiune ale fișierului style.css
al temei părinte, în timp ce controlează versiunea fișierului style.css
al temei copil.

Mi se pare incredibil că cel mai popular software pentru bloguri necesită peste 20 de linii de cod doar pentru a ajusta CSS-ul unui temă existentă. Presupun că asta înseamnă securitate jobului.

@CarlG: sintaxa de array pe care am folosit-o (paranteze pătrate) a fost introdusă în PHP 5.4.

Pentru cei care votează pozitiv: vă rugăm să consultați alt răspuns al meu care rezolvă problemele acestuia.

Este o mare neînțelegere, nu este nevoie de nimic din toate acestea. De fapt, vechea metodă @import
funcționează la fel de bine, vă rugăm să comparați ambele metode. În ceea ce privește dependența temei copil de tema părinte, nici pentru aceasta nu este nevoie. Fișierul copil style.css
este întotdeauna încărcat după cel părinte, cel puțin din testele mele. Aș fi bucuros să fiu contrazis.
