During the past month or so a new method for inheriting parent styles in WordPress child themes has been established, replacing the old method of importing parent styles with an @import call in the child theme style.css file.
The new method involves enqueueing first the parent and then the child style.css file through a functions.php file in the child theme.
While at first glance this seems a valid and much improved approach, further testing has uncovered an inherent flaw in its logic: The new method makes several assumptions about the scenario in which it would be used that make it hard to use and prone to failure.
The current (new) method is described as follows in the Codex:
<?php
add_action( 'wp_enqueue_scripts', 'enqueue_child_theme_styles', PHP_INT_MAX);
function enqueue_child_theme_styles() {
wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css' );
wp_enqueue_style( 'child-style', get_stylesheet_uri(), array('parent-style') );
}
The Theme Handbook describes a variant of this same approach:
<?php
function get_parent_theme_css() {
wp_enqueue_style( 'your-child-theme-name', get_template_directory_uri() . '/style.css' );
}
add_action( 'wp_enqueue_scripts', 'get_parent_theme_css' );
In both cases one important assumption is made: That the parent theme has one main stylesheet with the filename “style.css” and that it does not use any other stylesheets. This is not a realistic situation, and in cases where the parent theme relies on stylesheet dependencies it can cause some serious issues.
What happens
First, let’s look at each of the examples and see what happens:
In the Codex example we set up an action that hooks onto the wp_enqueue_scripts event and calls in a function. The function contains within it two calls to enqueue first the parent theme style.css file and then the child theme style.css file. This results in the parent theme style.css file loading first, then the child theme style.css file, and you get page markup where new styles added to the child theme style.css file will override the parent theme styles. This is as intended and in line with how things worked with the @import function. This works as long as all parent theme styles are contained within a file called “style.css” which as we will see in a bit is not always the case.
The Handbook example sets up the same way but only calls the parent theme style.css file. Because of how WordPress works, this overrides the inherent logic and prevents the child theme stylesheet from loading. As a result any style change added to the child theme style.css file will not take effect making changes to styles through this file unavailable. This is likely an omission in the documentation so not worth dwelling on further.
The Problem of Dependencies
Now for the problem: As indicated above not all parent themes operate with a single style.css file that contains within it all styles. In many cases themes use a series of stylesheets to achieve optional layouts or other effects. These are normally enqueued as dependencies to ensure everything is added in the correct order.
Take this example: A theme ships with two layouts, right sidebar and no sidebar. To achieve this without cluttering up the style.css file with two different sets of layout styles the theme developer has separated out the layout styles in their own stylesheets under a dedicated folder. This is common and the recommended approach in the _s starter theme.
To get it all to work in the parent theme we have something like this:
<?php
// Create function to enqueue styles
function themename_scripts() {
// Register main stylesheet with the handle 'themename-style'
wp_register_style( 'themename-style', get_template_directory_uri().'/style.css' );
// Test for nosidebar template or no sidebar and select correct layout stylesheet.
// Layout stylesheet is enqueued with the label ‘themename-layout’ and made dependent on 'themename-style' above
if (is_page_template('page-templates/page-nosidebar.php') || ! is_active_sidebar( 'sidebar-1' )) {
wp_enqueue_style( 'themename-layout' , get_template_directory_uri() . '/layouts/no-sidebar.css', array('themename-style') );
} else {
wp_enqueue_style( 'themename-layout' , get_template_directory_uri() . '/layouts/content-sidebar.css', array('themename-style') );
}
}
add_action( 'wp_enqueue_scripts', 'themename_scripts' );
The function above is typical and straight-forward: When the parent theme is loaded a test is run for the current layout condition and based on its result one of the two layout stylesheets are enqueued. These stylesheets are made dependent on the main style.css file which has been registered with the handle “themename-style”. When a page is loaded the dependency (style.css) is loaded first,, then the layout styles.
This means for the theme to display properly with the correct layouts it is the layout styles that are called, not the style.css file.
Now consider the proposed approach in the codex: Here the child theme explicitly calls for the main stylesheet – style.css. That means when a child theme is activated the layout styles are not loaded!
A possible (but not user friendly or uniform) solution
The problem described above is caused by the assumption that the parent theme uses the style.css file as its only stylesheet and ignores other circumstances like a theme that uses dependencies. To solve this problem the approach must be changed to something like this:
<?php
function enqueue_child_theme_styles() {
wp_enqueue_style( 'child-style', get_stylesheet_uri(), array('[parent_theme_name]-style') );
}
add_action( 'wp_enqueue_scripts', 'enqueue_child_theme_styles', PHP_INT_MAX);
In this example we are enqueueing only the child theme stylesheet and making it dependent on the parent theme stylesheet stack in whatever way that is set up. This preserves any dependencies in the parent theme and provides the correct ordering of all stylesheets. The problem of dependencies is solved, but this solution puts the onus on the child theme author to know what stylesheet is “in control” of the parent theme and know what its label is. That means tunnelling into the parent theme functions.php file and finding the correct enqueue function – something requiring a level of skill previously not needed for building child themes. As a result the threshold on getting started with building child themes and eventually themes becomes much higher than it used to be.
Moving forward
The change in recommendation about how to inherit styles from parent themes brings up important questions about the role of child themes in the overall training philosophy of WordPress. Some would argue increasing the difficulty level of creating child themes as this new approach does is a good thing because it takes away some of the “hand holding” that in some cases leave users with the ability to do things they do not fully understand. On the other hand increasing the difficulty level also makes entry into the space and non-destructive customization of themes harder, something that goes against the original reasoning for introducing child themes in the first place.
As I see it we need to provide a simple and consistent approach to creating child themes and inheriting parent theme styles that does not require this in-depth understanding of how WordPress themes work. To facilitate this a new function or filter could be created to get parent- and child theme stylesheets queued up correctly.
In the end there are only three scenarios in play here that need to be made available:
- Child theme only uses its own style.css file. No inheritance.
- Child theme loads parent theme styles as they are loaded in the parent theme and then loads its own style.css file to add / override styles.
- Child theme only uses parent theme styles and is built to add other features that do not include CSS.
And this means the new function or filter would only have to do one of three things:
- Load only the child theme style.css file
- Load the full stack of parent theme stylesheet files as they are loaded in the parent theme, then the child theme style.css file
- Load only the full stack of parent theme stylesheet files as they are loaded in the parent theme
How exactly this function or filter would be built should be handled by developers wiser than myself.
36 replies on “Challenges with the new method for inheriting parent styles in WordPress child themes”
Thank you for analyzing the current method for inheriting parent theme styles. I didn’t know it was quite so new. That explains the disconnect between the examples in the codex and handbooks and actually developing child themes in the wild!
If we want to enable users to customize theme styles beyond the few options in the customizer, but don’t want them to make changes on the stylesheet directly, we have to educate them about child themes. Perhaps make a flashy note in the comments of style.css and point them to a newbie-friendly resource.
If we want to make it even easier, we can load the child theme style.css for them. That way, the only file they need to have in their child theme is style.css (no need to bother with functions.php). Here’s a Gist that conditionally adds an action to the
wp_enqueue_scripts
hook in functions.php.Functions and filters are great, but I’m not sure that they would be appreciated by people who just want to make changes to the style.css that persist after a theme update!
Hey,
Thank you for taking a look at this. I have written two blog posts on this subject.
https://ulrich.pogson.ch/how-to-load-the-parent-styles-in-child-themes
https://ulrich.pogson.ch/child-themes-ie8-media-queries
In my blog posts I ignored the dependency because when enqueued the styles will load automatically without needing to define the dependency.
Recently on the theme review mailing list Justin Tadlock mentioned that the use of
get_stylesheet_uri()
was required and to change it thestylesheet_uri
filter should be used.With that I created a new gist that shows my old method and the new one using the
stylesheet_uri
filter.I did not ask this question on the mailing list but it came to mind is “For what reason would a child theme/ plugin author want to pull
get_stylesheet_uri()
? Is it to get the style.css header information or is it to get the styles? If it for the styles then there is a problem if the theme is loading multiple stylesheets.”To the three scenarios.
1. You can use
wp_dequeue_style()
to remove the parent styles. If you define the parent styles as dependencies to the child themes styles then this would be difficult. I think this is normally more of an edge case.2. This is the standard method
3. It possible to dequeue the style here again if needed.
Let me know if you have any questions. I would love to involved in any future discussions.
P.s. I think you need to be careful with
is_active_sidebar()
It will return true when there are widgets in the sidebar in general on not specific to the page that you are on.Some good points there @ulrich. I think the issue here is that we don’t have clear guidelines for how themes label and enqueue styles with dependencies and because of this we can’t make a unified system that works for all child themes. My concern is always with the end-user and in this case how we make a simple method for inexperienced users to add new styles to their sites though child themes while retaining whatever dependency setup the parent theme has without also having to know in detail how the parent theme lines up its child themes.
Also, interesting interjection about is_active_sidebar(). I have to think about that one and see if it’s an issue and if so how I can get around it.
Let’s assume that parent theme loads styles like in Twenty-default themes like this:
function twentyfifteen_scripts() {
// Load our main stylesheet.
wp_enqueue_style( 'twentyfifteen-style', get_stylesheet_uri() );
}
add_action( 'wp_enqueue_scripts', 'twentyfifteen_scripts' );
Then I load styles in child theme like in Codex example:
function twentyfifteen_child_theme_styles() {
wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
wp_enqueue_style( 'child-style', get_stylesheet_uri(), array( 'parent-style' ) );
}
add_action( 'wp_enqueue_scripts', 'twentyfifteen_child_theme_styles' );
Now I’m loading child theme style.css twice! First in parent theme and second in child theme. That’s not right. You could use wp_dequeue_style-function but you need to know parent theme style handle.
For me child theme style.css loads just fine using The Handbook example. Assuming that we’re using default themes way of loading main style sheet.
I’d say parent theme should load all the styles (parent and child theme style.css and some extra if needed) and child themers should not worry about using wp_enqueue_style-functions even if it is just copy paste.
Here is the gist how I’d load styles in parent theme.
Oh I didn’t know about
wp_dequeue_style
. So the handbook example should includewp_dequeue_style
, no? Seems like this wouldn’t be a problem in the first place ifget_template_directory_uri
was used instead ofget_stylesheet_uri
.After looking at your gist, I now have to refactor mine. 🙂
No, but the Codex example should. For some reason
wp_dequeue_style
didn’t work butwp_deregister_style
worked. So if you don’t want load child themes style.css twice, Codex example would be like this.function twentyfifteen_child_theme_styles() {
wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
wp_enqueue_style( 'child-style', get_stylesheet_uri(), array( 'parent-style' ) );
wp_deregister_style( 'twentyfifteen-style' );
}
add_action( 'wp_enqueue_scripts', 'twentyfifteen_child_theme_styles', 11 );
Note the priority 11 so that hook
wp_enqueue_scripts
is run after the parent theme.But this is not good way in my opinion because user have to know some code and the handle name (for example twentyfifteen-style).
The code in your gist doesn’t address the issue I raise about style dependencies in the parent theme. If the parent theme uses different layout stylesheets for different scenarios, these need to be loaded after the main style.css file meaning the parent theme will only load the layout styles and make them dependent on the style.css file to get the order right when equeueing. Calling in the style.css file alone bypasses the layouts entirely and causes the child theme to break.
the string function enqueue_child_theme_styles() does not work on my computer, could please someone tell me what is the matter with this? thank you for the very wanted answer
I have the same problem mate!
bari&Bari: In what way it didn’t work because it does work for twenty fifteen for example. This also depends on the parent theme how this should be done.
Part of the problem here is that there is no official or uniform method for adding parent theme stylesheets. Different applications require different methods. The child theme function has to take this into account somehow.
_s and default themes always lead the way for many. But I’m still suggesting that parent theme should do all the heavy lifting. And provide example/blank child theme so that users don’t have to guess what should be done.
I agree completely. I think what this issue has uncovered is a discrepancy in how we think about inheriting stylesheets from parent themes and how those stylesheets are actually set up. In a conversation with Mark Jaquith at WCSF he pointed out that there is no reason to assume the style.css file in the parent theme does anything other than list out the metadata for the theme. A theme author can choose to offload all the styles to entirely separate documents.
One possible way around this is to create a naming convention that the leading stylesheet of the parent theme (whatever stylesheet is being called and then has dependencies) is always labled “[themename]-styles”. That way the child theme can always make the child theme style.css file dependent on “[themename]-styles” and everything gets loaded in order. That is not the case now though because afaik there is no directive that instructs theme authors to set things up that way.
Another solution might be to simply use a style.css in your theme and @import all the other stylesheets required via that file. We typically concatenate all our styles into one style.css file and minify it prior to release. Sure, you could split out smaller .css files and load them separately, but the overhead in doing separate calls might be greater than simply loading the extra style information all the time.
In WPtouch we actually have a modified parent/child architecture where the parent’s functions.php (in the form of a root-functions.php) is loaded as well as the child theme’s functions.php. This basically ensures all the scripts/stylesheets (in addition to admin menu items, etc.) the parent needs are always included in the child.
In my use case scenario layouts are controlled by using separate stylesheets. In the case of Simone, that was necessary because the layouts are quite complex and require a lot of code. Serving up all that CSS for all sites and then using class names to filter is not a workable solution and doesn’t produce easily maintainable code. This of course mostly applies to verbose themes with documentation, but that’s the type of themes people are most likely to build child themes off of.
Most CSS editors allow you to easily group sections using CSS comments, which is what we typically do. I personally find that easily maintainable as I can scan and see exactly which CSS code is meant to affect each visual section. It’s then trivial to work on particular sections of CSS that are tied to functionality. A simple body class filter where you inject a class name is enough to select which CSS section you are using. You can always include the original CSS files (with verbose documentation) in your theme and simply merge/minify them before release.
Another option (if you control the parent and the child theme) might be to simply include all the code that handles the script and JS enqueues in the parent into a separate PHP file, and simply pull that in into the appropriate place in both the parent and the child.
I meant using @import religiously in the parent theme, not child.
Yes, I like this approach. If WP is going to be pushing this new method going forward, yours sounds like a great adjustment and probably what WP were going for, assuming the vast vast majority of sites would only have one style.css and the rest would be clever enough to concatenate.
interesting article,
been working with the theme presentation-lite from wordpress.org. if you load the parent style in with the child theme css as ulrich (see above) mentioned, this works but because there are more than just the parent style file, the css files are loaded with some of the parent css files being loaded after the child style sheet is loaded. this poses a problem I guess but only as long as you don’t want to change those files.
to get around this, I used the technique used in superhero/sidekick and dequeued the stylesheets and then added them in the order I want them. Chris Coyier suggested another alternative, the plugin MinQueue, to minify and queue files in the order that you want. This also works and will load in all of the additional css files used by the parent theme and then loads in the css used by the child theme.
I am working with an already established theme precoded in its own manner and have to deal with the conditions it imposes on me, so I guess those are my two solutions to the challenge. I also have been testing to see whether the dependency can be coded into the wp_enqueue_style function itself in the array parameter. still flailing with that.
Al
Al
the Codex must have been updated recently, have not seen the enqueue method mentioned there before, just checked.
Al
presentation-lite loads 3 css files in, the theme’s style.css, a color.css file and fontawesome css file. the theme loads the css file in by using the get_stylesheet_uri() command.
in my child theme of presentation-lite, if I load the style sheets as described in the Codex into my child theme, then the css file for the child theme is loaded, then the 2nd css file from the parent theme, then the 3rd file from the parent them, then the parent theme style sheet, and finally the child theme style sheet. not quite what I want, this does not work as well as just adding the css file using the method described above in ulrich’s article.
Al
Dequeueing styles works, but I don’t think it is fair to demand that new users with little to no coding experience familiarize themselves with such advanced functions. That was the impetus of my article.
I definitely agree with the premise of your article. but sure don’t like what the suggested code generates. Any test I have done generates a double load of the child style.css code. not good as far as I can see. It seems to work but is dirty code.
A child theme is easy to create with the exception of the child functions.php file. Then it becomes complicated and must address how the enqueues are done in the parent theme, and this can generate many variations in what you need to code to make it work. It is just not as simple as what they have set up in the Codex. Also, this new method forces you to use a child functions.php file.
For me, this all started with my investigation into how to load in the css files in the order I wanted in a child theme of presentation-lite (from wordpress.org), I wanted the child theme to work with IE8 so created the child theme code to do that. I use dequeue/enqueue functions to accomplish this, based on what I saw used in superhero/sidekick (from wordpress.org).
I still want to set up a child theme of “simone” and add code to support my IE8 browser. Again, this runs into the problem of how to load in the parent and child css files, in the order they should be added in. It would be nice to be able to put code in the child theme style.css file that could modify any of the theme’s css files loaded prior to it but I don’t believe using the recommended procedure would generate the code to allow this. We will see…
Al
The current development version of Simone (available on Github and soon to be released on WordPress.org) sets up the styles in the way described in the article and ensures that a child theme loads the parent styles properly. What you are experiencing is caused by using a new approach on an older version of the theme.
I am having some problems, probably I use a different method for adding parent theme stylesheets. I am working on it and I’ll tell you when I’ll solve it
Justin Tadlock on his blog has just chimed in on this topic, and he makes some interesting comments on this.
Al
I’m going to start using Justin’s method in my themes.
I confess that I was one of the people who made the change in the Codex, which has led to me fielding a lot of questions on the official WP.org support forums about how to prevent the child theme’s stylesheet from loading twice. Argh.
Note that the Codex method of loading the parent style sheet has been changed.
The change now reflects the original method documented by ulrich pogson in his article published last year. Not sure if he is the originator of the technique but he seems to be one of the first to mention this technique.
Al
I saw that. The method does not solve the problems raised in my article. It still assumes the parent theme uses only one stylesheet and that that stylesheet is called “style.css”.
So given that the issue is different with every theme (based on the structure of the parent theme) – would you recommend just using the old @import method for now?
BTW – thanks for the post explaining why the standard codex way doesn’t always work – I’ve racked my brain for hours trying to figure it out (Obviously I’m not a master coder)… your post explained it perfectly.
I can tell you that @import definitely does not work in a commercial theme I’m trying to create a child of – the ThemeForest “Newspaper” theme.
The theme authors even setup a pre-defined child theme folder structure to drag and drop into wp-content\themes which uses @import in style.css from the parent. But when I look at the Hello World page in the child (without making any changes to styles.css in the child – only the @import line is there), one can easily see that many of the parent styles are not applied.
Ironically, I was using Morten’s Lynda.com Child Theme for WP3 Tutorial (recorded before these new practices of child theme css importing were in place) to find more answers about this, and then discovered his blog post here.
So, I have to do some looking to see how the parent theme css structure is set up. I’m a WP newb, btw. So, it’s all a learning process for me.
Morton,
I tried the latest version from Github and when I use a child theme, the content area of posts still gets pushed to the far left over the top of the author, date etc.
Of course this make it problematic for using Simone with your Lynda courses.
Suggestions?
Thanks,
-John
I have been trying to get child themes to work on two blog themes for over a month. Nothing worked untill I read this article. I used the simple possible but not friendly solution and ¡it worked! Many thanks. Hope you manage to work out some friendly standard solution for us earthlings so that all the wrong advise in the internet desapears soon.
maybe you need to put quotes around “data-role” (or escape the ones on \”listview\” if they’re internal to a value)
My programmer is trying to convince me to move to .net from PHP.
I have always disliked the idea because of the costs.
But he’s tryiong none the less. I’ve been using WordPress on several websites for about a
year and am anxious about switching to another platform.
I have heard excellent things about blogengine.net.
Is there a way I can transfer all my wordpress posts into it?
Any help would be really appreciated!
Just a few notes:
1) “That means tunnelling into the parent theme functions.php file and finding the correct enqueue function – something requiring a level of skill previously not needed for building child themes” – The correct parent style.css handle is not always in the functions.php file! Example: Avada. The the parent style handle for Avada theme (avada-stylesheet) is NOT in functions.php file, but in two files found in the Avada/includes directory.
2) You could find the handle by looking in the source of a page (Ctrl+U) and look at the ID of the style.css stylesheet, “<link rel='stylesheet' id='avada-stylesheet-css' href=…"
3) Avada comes with a blank child theme, and the code used it is only loading child style.css and making it dependent on the 'avada-stylesheet' handle, and that is it for the css part (this is the method recommended in this article). However:
4) The Codex is now (Aug 2017) linking to a rather poor question on Stackexchange (maybe you/others could improve that?) is now recommending a different method than the one in this article. The confusion continues 3 years later… Good job, WordPress team.
5) There is no advantage in using this new method over the old @import method from what I can see. And nobody clearly explained why the new method is better… Faster to load? No. Still two requests for two files.