Versionado de @import del style.css del tema padre
Contexto
Construí un tema hijo basado en Twenty Thirteen que funciona bastante bien. Después de actualizar el tema padre a la versión 1.3, noté un comportamiento extraño con los estilos que fue causado por una versión en caché del style.css
del tema padre.
Aquí está el contenido de mi style.css
del tema hijo (omitiendo encabezados)
/* =Importa estilos del tema padre
-------------------------------------------------------------- */
@import url('../twentythirteen/style.css');
Entonces el style.css
del tema hijo no hace nada más que importar el style.css
del tema padre.
También tengo otro archivo css con las personalizaciones de mi tema hijo que encolo así en functions.php
:
// Encola style.css del tema padre (más rápido que usar @import en nuestro style.css)
$themeVersion = wp_get_theme()->get('Version');
// Encola personalizaciones del tema hijo
wp_enqueue_style('child_main', get_stylesheet_directory_uri() . '/css/main.css',
null, $themeVersion);
Esto me da una URL css muy agradable como esta: domain.com/wp-content/themes/toutprettoutbon/css/main.css?ver=1.0.1
que asegura que la hoja de estilos se recargue cuando se actualiza el tema hijo.
Ahora el problema
La declaración @import url('../twentythirteen/style.css');
es completamente independiente de la versión subyacente del tema padre. De hecho, el tema padre puede actualizarse sin actualizar el tema hijo pero los navegadores seguirán usando versiones en caché del antiguo ../twentythirteen/style.css
.
Código relevante en Twenty Thirteen que encola el style.css
:
function twentythirteen_scripts_styles() {
// ...
// Agrega la fuente Genericons, usada en la hoja de estilos principal.
wp_enqueue_style( 'genericons', get_template_directory_uri() . '/genericons/genericons.css', array(), '3.03' );
// Carga nuestra hoja de estilos principal.
wp_enqueue_style( 'twentythirteen-style', get_stylesheet_uri(), array(), '2013-07-18' );
// Nota el uso de get_stylesheet_uri() que en realidad encola child-theme/style.css
// Carga la hoja de estilos específica para 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' );
Puedo pensar en algunas formas de resolver este problema pero ninguna es realmente satisfactoria:
Actualizar mi tema hijo cada vez que se actualiza el tema padre para cambiar una cadena de versión en
style.css
(por ejemplo@import url('../twentythirteen/style.css?ver=NEW_VERSION');
). Esto crea un vínculo innecesario y molesto entre la versión del tema padre y el hijo.En mi
functions.php
del hijo, 1)wp_dequeue_style
elstyle.css
incluido del tema hijo y 2)wp_enqueue_style
elstyle.css
del tema padre directamente CON cadena de versión. Esto desordena el orden de los css encolados en el tema padre.Usar el filtro
style_loader_tag
para modificar la etiqueta<link>
css generada parastyle.css
y modificar la ruta para apuntar directamente alstyle.css
del tema padre CON una cadena de versión. Parece bastante oscuro para una necesidad tan común (invalidación de caché).Volcar el
style.css
del tema padre en elstyle.css
de mi tema hijo. Igual que (1) realmente, pero un poco más rápido.Hacer que el
style.css
de mi tema hijo sea un enlace simbólico alstyle.css
del tema padre. Esto parece bastante improvisado...
¿Me he perdido algo? ¿Alguna sugerencia?
edición
Agregué las hojas de estilo genericicons.css
y ie.css
en el tema padre para aclarar por qué no puedo cambiar la declaración css @import
a wp_enqueue_style
en mi tema hijo. Actualmente, con una declaración @import
en el style.css
de mi tema hijo, tengo este orden en las páginas generadas:
- twentythirteen/genericons/genericons.css -> encolado por el tema padre
- child-theme/style.css -> encolado por el tema padre, @imports twentythirteen/style.css
- twentythirteen/css/ie.css -> encolado por el tema padre
- child-theme/css/main.css -> encolado por el tema hijo
Si encolo el style.css
del padre como una dependencia de main.css
, esto se convertirá en:
- twentythirteen/genericons/genericons.css -> encolado por el tema padre
- child-theme/style.css -> vacío, encolado por el tema padre
- twentythirteen/css/ie.css -> encolado por el tema padre
- twentythirteen/style.css -> encolado por el tema hijo como dependencia de main.css
- child-theme/css/main.css -> encolado por el tema hijo
Nótese que ie.css ahora está incluido antes del style.css
del tema padre. No quiero cambiar el orden de encolado de los archivos css del tema padre porque no puedo presumir que esto no causará problemas con la prioridad de las reglas css.

No es necesario usar @import. De hecho, es mejor no hacerlo. Utilizar el enfoque de encolado probablemente sea mejor en todos los aspectos.
Aquí está la parte relevante del código de twentythirteen:
function twentythirteen_scripts_styles() {
...
// Carga nuestra hoja de estilos principal.
wp_enqueue_style( 'twentythirteen-style', get_stylesheet_uri(), array(), '2013-07-18' );
...
}
add_action( 'wp_enqueue_scripts', 'twentythirteen_scripts_styles' );
Esto es lo que debes hacer en tu código:
function child_scripts_styles() {
wp_enqueue_style( 'child-style', get_stylesheet_directory_uri().'/css/main.css', array('twentythirteen-style'), 'TU_VERSION_DEL_TEMA' );
}
add_action( 'wp_enqueue_scripts', 'child_scripts_styles' );
Si tu main.css debe cargarse después del style.css del tema padre, simplemente lo haces dependiente de él.
Ahora, si también tienes un B.css en el tema hijo, configuras las dependencias acordemente:
function child_scripts_styles() {
wp_enqueue_style( 'child-B-style', get_stylesheet_directory_uri().'/B.css', array('twentythirteen-style'), 'TU_VERSION_DEL_TEMA' );
wp_enqueue_style( 'child-style', get_stylesheet_directory_uri().'/css/main.css', array('child-B-style'), 'TU_VERSION_DEL_TEMA' );
}
add_action( 'wp_enqueue_scripts', 'child_scripts_styles' );
Define las dependencias para cada elemento que realmente reflejen cuáles son esas dependencias. Si main.css debe ir después de B.css, entonces depende de él. Si B.css debe ir después del style.css del tema padre, entonces B depende de él. El sistema de encolado lo resolverá por ti.
Y si en realidad no estás usando el style.css del tema hijo para nada, entonces no necesitas encolarlo en absoluto. Puede ser solo un marcador de posición para guardar la información del encabezado de tu tema. ¿No lo usas? No lo cargues.
Además, ¿qué es exactamente lo que estás haciendo que depende tanto del orden aquí? A CSS no le importa el orden de carga en la mayoría de las situaciones. CSS depende más de la especificidad de los selectores. Si quieres sobrescribir algo, haces que tu selector sea más específico. Puede ir primero, o último, o en cualquier lugar intermedio, el selector más específico siempre gana.
Edición
Leyendo tus comentarios y mirando más de cerca el código, veo dónde está el error aquí. El código de twenty-thirteen está encolando "get_stylesheet_uri()", que en el caso de un tema hijo sería el archivo style.css de tu tema hijo, no el del tema padre. Por eso el @import funciona, y mantiene el mismo orden (que nuevamente, no importa tanto como crees).
En ese caso, si no quieres usar import, recomendaría encolar directamente el style.css del tema padre. Así:
function child_scripts_styles() {
wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css', array() );
}
add_action( 'wp_enqueue_scripts', 'child_scripts_styles' );
El código en el functions.php del tema hijo se ejecuta primero, así que tu propio wp_enqueue_scripts correrá primero, y esto encolará el style.css del tema padre, lo cual el tema padre no está haciendo por sí mismo (porque en realidad está encolando el style.css de tu tema hijo). Al no hacerlo dependiente de nada, igual que el tema padre, simplemente se coloca en la salida correctamente. Nota que el orden de este archivo y el genericons.css no importa, porque el "twentythirteen-style" original no tiene a genericons.css como una dependencia listada.
Tu propio style.css del tema hijo se cargará, y honestamente, aquí es donde deberías poner los cambios para tu tema hijo, no en un main.css separado. No hay nada que te impida poner tus cambios ahí, pero no hay una razón real para tener un archivo css extra.

Estoy totalmente de acuerdo en que los @import
no son la mejor opción. Por favor, revisa mi sección de "edición" para información más precisa. No tengo necesidades particulares respecto al orden del css. Simplemente no quiero modificar el orden interno de los archivos css del tema padre, lo que puede causar problemas con la prioridad de las reglas css.

Para aclarar, B.css (ahora cambiado a ie.css en la pregunta) no es parte de mi tema hijo, sino que en realidad es parte del tema padre.

Si quieres que tu estilo venga después del estilo ie.css, entonces haz que tu propio estilo dependa de él. Su nombre es "twentythirteen-ie". El orden se gestiona completamente por las dependencias que declares, pero nuevamente, con CSS, el orden real de estos en el documento generalmente no importa, así que no estoy seguro de por qué te preocuparía demasiado por ello.

Sí, supongo que me dejé llevar por la "necesidad" de mantener el orden del css. Si el orden fuera realmente importante para el tema padre, debería indicarse en las dependencias.

"Tu propio style.css del hijo se cargará, y honestamente, aquí es donde deberías poner los cambios para el tema hijo, no en un main.css separado." Esto es cierto, pero quiero agregar una cadena de versión al css de mi tema hijo.
Si simplemente uso el enqueue del tema padre para el style.css del tema hijo, el padre controla la versión ya que es él quien llama a enqueue_style
. Quiero poder actualizar el tema hijo y cambiar la cadena de versión de sus hojas de estilo para el cache busting independientemente de la versión del tema padre.

Me encantaría conocer tu opinión sobre la nueva respuesta mucho más simple que acabo de añadir.

Tu actualización realmente ayuda a resolver muchos problemas. Mi tema padre tenía bootstrap.css incluido antes de style.css. Con tu enfoque solo tuve que especificar bootstrap como dependencia para parent-style en el style.css del tema hijo. Y todo lo demás encaja perfectamente. ¡Gracias!

No hay nada malo en usar @import
, no afecta el rendimiento de ninguna manera, por favor revisa el código fuente de temas hijos creados con cualquier método, encontrarás que se generan dos solicitudes al servidor en cualquier caso. Una buena lectura aquí: https://wordpress.org/support/topic/needs-update-12/

No creo que puedas evitar cargar el archivo style.css
del tema hijo. Por favor verifica, se cargará incluso si no lo encolas específicamente.

No tengo suficiente reputación para publicar mi propia respuesta, pero aquí está mi aporte: https://pastebin.com/iDr6Hy79

Mi respuesta anterior es demasiado complicada y potencialmente no respeta la cadena de dependencias del tema padre (ver nota en la otra respuesta).
Aquí hay un enfoque mucho más simple que debería funcionar mejor:
function use_parent_theme_stylesheet() {
// Usar la hoja de estilos del tema padre
return get_template_directory_uri() . '/style.css';
}
function my_theme_styles() {
$themeVersion = wp_get_theme()->get('Version');
// Cargar nuestro style.css con nuestra propia versión
wp_enqueue_style('child-theme-style', get_stylesheet_directory_uri() . '/style.css',
array(), $themeVersion);
}
// Filtrar get_stylesheet_uri() para devolver la hoja de estilos del tema padre
add_filter('stylesheet_uri', 'use_parent_theme_stylesheet');
// Cargar los scripts y estilos de este tema (después del tema padre)
add_action('wp_enqueue_scripts', 'my_theme_styles', 20);
La idea es simplemente filtrar la llamada a get_stylesheet_uri()
en el tema padre para que devuelva su propia hoja de estilos en lugar de la del tema hijo. La hoja de estilos del tema hijo se carga después en el gancho de acción my_theme_styles
.

Solo para dejar constancia: 1) Tu código generará exactamente el mismo html que usar la versión antigua con @import
, sin impacto en el rendimiento, habrá dos solicitudes separadas de style.css al servidor 2) Esta respuesta elimina por completo todo el tema de dependencias... 3) Puedes ver qué hacen get_template_directory_uri
y get_template_stylesheet_uri
aquí: https://core.trac.wordpress.org/browser/tags/4.8/src/wp-includes/class-wp-theme.php#L9 Nuevamente, no es necesario la mayor parte de ese código.

advertencia
¡Esta solución no respeta las dependencias del tema padre! Cambiar el nombre del handle del tema padre afecta la cadena de dependencias establecida en el tema padre. Consulta mi respuesta mucho más simple.
respuesta original
Aunque la respuesta de Otto es bastante buena, terminé usando esto en el functions.php de mi tema hijo:
function my_theme_styles() {
global $wp_styles;
$parentOriginalHandle = 'twentythirteen-style';
$parentNewHandle = 'parent-style';
// Desregistramos nuestro style.css que fue encolado por el tema padre; queremos
// controlar la versión nosotros mismos.
$parentStyleVersion = $wp_styles->registered[$parentOriginalHandle]->ver;
$parentDeps = $wp_styles->registered[$parentOriginalHandle]->deps;
wp_deregister_style($parentOriginalHandle);
// Encolamos el style.css del tema padre con la versión que usaba en lugar
// de importarlo con @import en el style.css del tema hijo
wp_register_style($parentNewHandle, get_template_directory_uri() . '/style.css',
$parentDeps, $parentStyleVersion);
// Encolamos nuestro style.css con nuestra propia versión
$themeVersion = wp_get_theme()->get('Version');
wp_enqueue_style($parentOriginalHandle, get_stylesheet_directory_uri() . '/style.css',
[$parentNewHandle], $themeVersion);
}
// Ejecutamos esta acción después de que el tema padre haya encolado sus estilos.
add_action('wp_enqueue_scripts', 'my_theme_styles', 20);
Mantiene el orden y los números de versión del style.css
del tema padre mientras controla la versión del style.css
del tema hijo.

Me sorprende que el software de blogs más popular requiera más de 20 líneas de código solo para ajustar el CSS de un tema existente. Supongo que eso es seguridad laboral.

@CarlG : la sintaxis de array que usé (corchetes) se introdujo en PHP 5.4.

A los votantes positivos: por favor lean mi otra respuesta que soluciona los problemas con esta.

Todo es un gran malentendido, no hay necesidad de nada de eso. De hecho, el antiguo método @import
funciona igual de bien, por favor comparen ambos métodos. En cuanto a la dependencia del tema hijo del tema padre, tampoco hay necesidad de eso. El style.css
del tema hijo siempre se carga después del padre, al menos según mis pruebas. Me encantaría que me demostraran lo contrario.
