WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Context

I built a child theme based on Twenty Thirteen which works quite well. After updating the parent theme to version 1.3, I noticed strange behavior with the styling which was caused by a cached parent theme's style.css.

Here is the content of my child theme's style.css (omitting headers)

/* =Imports styles from the parent theme
-------------------------------------------------------------- */
@import url('../twentythirteen/style.css');

So the child theme's style.css does nothing more than import the parent theme's style.css.

I also have another css file with my child theme's customizations which I enqueue like so in functions.php:

// Enqueue parent theme's style.css (faster than using @import in our style.css)
$themeVersion = wp_get_theme()->get('Version');

// Enqueue child theme customizations
wp_enqueue_style('child_main', get_stylesheet_directory_uri() . '/css/main.css',
    null, $themeVersion);

This gives me a very nice css url like this: domain.com/wp-content/themes/toutprettoutbon/css/main.css?ver=1.0.1 that makes sure the style sheet is reloaded when the child theme is updated.

Now the problem

The statement @import url('../twentythirteen/style.css'); is completely independent of the underlying parent theme's version. In fact, the parent theme can be updated without updating the child theme but browsers will still use cached versions of the old ../twentythirteen/style.css.

Relevant code in Twenty Thirteen that enqueues the style.css:

function twentythirteen_scripts_styles() {
    // ...

    // Add Genericons font, used in the main stylesheet.
    wp_enqueue_style( 'genericons', get_template_directory_uri() . '/genericons/genericons.css', array(), '3.03' );

    // Loads our main stylesheet.
    wp_enqueue_style( 'twentythirteen-style', get_stylesheet_uri(), array(), '2013-07-18' );
    // Note usage of get_stylesheet_uri() which actually enqueues child-theme/style.css

    // Loads the Internet Explorer specific stylesheet.
    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' );

I can think of a few ways to solve this problem but none are really satisfactory:

  1. Update my child theme every time the parent theme is updated to change a version string in style.css (e.g. @import url('../twentythirteen/style.css?ver=NEW_VERSION');). This creates an unnecessary and annoying link between parent theme version and child.

  2. In my child's functions.php, 1) wp_dequeue_style the included child theme's style.css and 2) wp_enqueue_style the parent theme's style.css directly WITH version string. This messes up the order of queued css in the parent theme.

  3. Use the style_loader_tag filter to modify the generated css <link> tag for style.css and modify the path to point directly to the parent theme's style.css WITH a version string. Seems rather obscure for such a common need (cache busting).

  4. Dump the parent theme's style.css in my child theme's style.css. Same as (1) really, but a bit faster.

  5. Make my child theme's style.css be a symlink to the parent theme's style.css. This seems quite hackish...

Have I missed something? Any suggestions?

edit

Added genericicons.css and ie.css style sheets in parent theme to clarify why I can't change the @import css statement to wp_enqueue_style in my child theme. Currently, with an @import statement in my child theme's style.css, I have this order in generated pages:

  1. twentythirteen/genericons/genericons.css -> enqueued by parent theme
  2. child-theme/style.css -> enqueued by parent theme, @imports twentythirteen/style.css
  3. twentythirteen/css/ie.css -> enqueued by parent theme
  4. child-theme/css/main.css -> enqueued by child theme

If I enqueue the parent's style.css as a dependency of main.css, this will become:

  1. twentythirteen/genericons/genericons.css -> enqueued by parent theme
  2. child-theme/style.css -> empty, enqueued by parent theme
  3. twentythirteen/css/ie.css -> enqueued by parent theme
  4. twentythirteen/style.css -> enqueued by child theme as dependency of main.css
  5. child-theme/css/main.css -> enqueued by child theme

Note that ie.css is now included before the parent theme's style.css. I do not want to change the enqueuing order of the parent theme's css files because I cannot presume that this won't cause problems with the priority of css rules.

share|improve this question
3  
Never use @import, set the parent theme’s stylesheet as a dependency of your own stylesheet instead. – toscho Oct 3 '14 at 1:03
    
I know it's not the best approach but it's recommended here: codex.wordpress.org/Child_Themes – bernie Oct 3 '14 at 1:09
    
Also, doing what you suggested does not fix my issue. The parent theme's style.css would not be included at the same place as it is now. The parent includes other css files which must come between its style.css and my child theme's css. – bernie Oct 3 '14 at 1:10
2  
Please ignore the codex completely. It is full of misinformation. Using the dependency parameter will include the stylesheets in the correct order. – toscho Oct 3 '14 at 1:11
    
Please see my edit. – bernie Oct 3 '14 at 16:53

You don't have to use @import. It's best not to, actually. Using an enqueued approach is probably better all around.

Here's the relevant part of twentythirteen's code:

function twentythirteen_scripts_styles() {
...
    // Loads our main stylesheet.
    wp_enqueue_style( 'twentythirteen-style', get_stylesheet_uri(), array(), '2013-07-18' );
...
}
add_action( 'wp_enqueue_scripts', 'twentythirteen_scripts_styles' );

Here's what you do in your code:

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' );

If your main.css has to come after the parent's style.css, then you just make it dependent on that.

Now, if you also have a B.css in the child, then you set up the dependencies accordingly:

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' );

Make the dependencies that you define for each item actually reflective of what those dependencies really are. If main.css must come after B.css, then it depends on it. If B.css must come after the parent's style.css, then B depends on that. The enqueue system will sort it out for you.

And if you're not actually using the child's style.css for anything, then you don't have to enqueue it at all. It can be just a placeholder to hold your theme's header information. Not using it? Don't load it.

Also, what exactly are you doing that is so dependent on ordering here? CSS doesn't care about load order in most situations. CSS is more dependent on specificity of the selectors. If you want to override something, you make your selector for it more specific. It can come first, or last, or anything in between, the more specific selector always wins.

Edit

Reading your comments and looking closer at the code, I see where the mistake is here. The twenty-thirteen code is enqueueing the "get_stylesheet_uri()", which in a child theme case, would be your child theme's style.css file, not the parent's file. That's why the @import works, and keeps the same ordering (which again, does not matter nearly as much as you think it does).

In that case, if you don't want to use import, I would recommend enqueueing the parent's style.css directly. Like so:

function child_scripts_styles() {
    wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css', array() );
}
add_action( 'wp_enqueue_scripts', 'child_scripts_styles' );

Code in the child theme's functions.php runs first, so your own wp_enqueue_scripts will run first, and this will enqueue the parent theme's style.css, which the parent theme is not doing itself (because it's actually enqueueing your child's style.css). By not making it depend on anything, same as the parent, then it simply gets put in the output correctly. Note that the order of this file and the genericons.css does not matter, because the original "twentythirteen-style" does not have the genericons.css as a listed dependency.

Your own child's style.css will load, and honestly, this is where you should put your changes for the child theme, not into a separate main.css. There's nothing preventing you from putting your changes there, but there's no real reason to have an extra css file.

share|improve this answer
    
I totally agree that @imports are not the best way to go. Please see my "edit" section for more precise information. I don't have any particular needs regarding ordering of css. I simply don't want to modify the internal ordering of the parent theme's css files which can cause problems with css rules priority. – bernie Oct 3 '14 at 19:13
    
To clarify, B.css (now changed to ie.css in question) is not part of my child theme, but actually part of the parent theme. – bernie Oct 3 '14 at 19:26
2  
If you want your style to come after the ie.css style, then make your own style depend on it. Its name is "twentythirteen-ie". The order is entirely managed by what dependencies you declare, but again, with CSS, the actual order of them in the document doesn't usually matter, so I'm not sure why you'd care about it overly much. – Otto Oct 3 '14 at 20:12
2  
Edited my answer to include a different approach. – Otto Oct 3 '14 at 20:29
    
Yeah I guess I got carried away with the "need" to keep the css ordering. If the order was really important for the parent theme, it should be stated in the dependencies. – bernie Oct 4 '14 at 14:20
up vote 4 down vote accepted

My previous answer is overly complicated and potentially doesn't respect the parent theme's dependency chain (see note in other answer).

Here's another much simpler take that should work much better:

function use_parent_theme_stylesheet() {
    // Use the parent theme's stylesheet
    return get_template_directory_uri() . '/style.css';
}

function my_theme_styles() {
    $themeVersion = wp_get_theme()->get('Version');

    // Enqueue our style.css with our own version
    wp_enqueue_style('child-theme-style', get_stylesheet_directory_uri() . '/style.css',
        array(), $themeVersion);
}

// Filter get_stylesheet_uri() to return the parent theme's stylesheet 
add_filter('stylesheet_uri', 'use_parent_theme_stylesheet');

// Enqueue this theme's scripts and styles (after parent theme)
add_action('wp_enqueue_scripts', 'my_theme_styles', 20);

The idea is to simply filter the call to get_stylesheet_uri() in the parent theme to return it's own stylesheet instead of the child theme's. The child theme's stylesheet is then enqueued later in the action hook my_theme_styles.

share|improve this answer

warning

This solution doesn't respect the parent theme's dependencies! Changing the parent theme's handle name affects the chain of dependencies set in the parent theme. See my much simpler other answer.

orignal answer

Although Otto's answer is pretty good, I ended up with this in my child theme's functions.php

function my_theme_styles() {
    global $wp_styles;
    $parentOriginalHandle = 'twentythirteen-style';
    $parentNewHandle = 'parent-style';

    // Deregister our style.css which was enqueued by the parent theme; we want
    // to control the versioning ourself.
    $parentStyleVersion = $wp_styles->registered[$parentOriginalHandle]->ver;
    $parentDeps = $wp_styles->registered[$parentOriginalHandle]->deps;
    wp_deregister_style($parentOriginalHandle);

    // Enqueue the parent theme's style.css with whatever version it used instead
    // of @import-ing it in the child theme's style.css
    wp_register_style($parentNewHandle, get_template_directory_uri() . '/style.css',
        $parentDeps, $parentStyleVersion);

    // Enqueue our style.css with our own version
    $themeVersion = wp_get_theme()->get('Version');
    wp_enqueue_style($parentOriginalHandle, get_stylesheet_directory_uri() . '/style.css',
        [$parentNewHandle], $themeVersion);
}

// Run this action action the parent theme has enqueued its styles.
add_action('wp_enqueue_scripts', 'my_theme_styles', 20);

It maintains the parent theme's style.css ordering and version numbers while controlling the version of the child theme's style.css.

share|improve this answer
2  
It boggles my mind that the most popular blog software requires 20+ lines of code just to tweak the CSS of an existing theme. I guess that's job security. – Carl G Jan 25 '15 at 21:45
    
I had to change [$parentNewHandle] to array($parentNewHandle) – Carl G Jan 25 '15 at 22:24
    
@CarlG : the array syntax I used (brackets) was introduced in PHP 5.4. – bernie Jan 26 '15 at 4:47
    
Gotcha. Thanks! – Carl G Jan 26 '15 at 16:47
    
To upvoters: please see my other answer which solves problems with this one. – bernie Mar 23 '15 at 17:21

protected by Community Feb 24 '15 at 19:15

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.