A common problem that many Genesis/WooCommerce developers face is, "How do I override WooCommerce styles in Genesis?"
There are many, many websites built upon the Genesis Framework that use the WooCommerce plugin. Site developers frequently need to override delivered WooCommerce styles to meet stakeholder requirements. For example, take a look at this site that I built for a company based in Sweden using Genesis/WooCommerce: http://shop.adoniasverige.se/. To achieve this look and feel, this custom theme required a significant amount of WooCommerce style overrides.
The Wrong Way
I've inherited a number of WooCommerce sites that were built by other developers. For one reason or another, the relationship between the site owner and developer soured, presenting me with the opportunity to pick up the pieces. Depending on the developer's skill level, I have seen a couple of approaches to overriding WooCommerce styles. I believe these approaches are dead wrong.
Styles Injected into a Post or Page
The first approach is overriding WooCommerce styles by injecting the new styles directly into the top of the post or page. In many cases, the developer added complete styles sheets into the post or page. Why is this Wrong? Inline styles may have a detrimental effect on page load speed. Wherever possible, styles should be removed from their inline position and added to the theme's style sheet as a new class. Yes, I realize that this isn't always possible, so please consider using inline styles sparingly at best.
The second reason this is wrong is because good coding practice dictates that styles belong in the document's <head></head> or <footer></footer> sections. Placing them directly into the content is a mistake and may cause rendering issues in browsers.
The third reason this is wrong is because it bypasses a safety mechanism built into WordPress, wp_enqueue_style(). In earlier versions of WordPress, wp_enqueue_style() could only be called in the theme's functions.php file. Since WordPress Version 3.3 however, wp_enqueue_style() can be called mid-page (in the content). This loads the style in the footer. So if you insist on including your styles in your content, using wp_enqueue_style() will at least place them in a correct position when rendering the page's HTML.
Changing woocommerce-layout.css
Another common mistake I regularly see is directly modifying woocommerce-layout.css. The woocommerce-layout.css file can be found in the /wp-content/plugins/woocommerce/assets/css directory. This file contains the styles for screen elements, i.e. buttons, images, etc.. I know of developers that directly modify this file and keep a copy on hand to override the delivered version when WooCommerce updates their plugin. Does it work? Yes. Is it right? NO! This is wrong on so many levels. Never, ever, ever modify a plugin's delivered core files. It creates an absolute maintenance and support nightmare!
The Right Way
To override WooCommerce styles the right way, it's important to understand how CSS styles are loaded and prioritized. CSS styles are sequential. If we were to think of a style in terms of an inventory item, we are looking at a LIFO methodology. LIFO means Last In First Out. If you have styles of the same class defined in multiple places, the style that is loaded last is the one that will rendered in the browser. As a model, it looks like the following where the "newest stylesheet" receives the priority:
Cascading and inheritance also play a role as w3.org explains"
The cascading mechanism is used when a number of style rules all apply directly to an element. The mechanism allows the user agent to sort the rules by specificity, to determine which rule to apply. If no rule can be found, the next step depends on whether the style property can be inherited or not. Not all properties can be inherited. For these properties the style sheet language provides default values for use when there are no explicit rules for a particular element.
How Genesis Loads Style Sheets
As a Genesis page renders, the Framework executes the genesis_meta action in header.php. The genesis_meta action consolidates calls to several other actions:
- genesis_load_stylesheet()—Echo reference to the style sheet
- genesis_seo_meta_description()—Output the meta description based on contextual criteria
- genesis_seo_meta_keywords()—Output the meta keywords based on contextual criteria
- genesis_robots_meta()—Output the 'index', 'follow', 'noodp', 'noydir', 'noarchive' robots meta code in the document 'head'
- genesis_responsive_viewport()—Optionally output the responsive CSS viewport tag
After Genesis loads its parts, WordPress then loads the plugin style sheets and does whatever housekeeping it needs to assure a clean, safe HTML page rendering. The genesis_load_stylesheet() function as shown below is defined in genesis/lib/css/load-styles.php. The function simply calls the WordPress wp_enqueue_scripts action to load the child theme's main style sheet. The important element to notice is the number "5" at the end of the add_action line. This is the wp_enqueue_scripts load priority. This parameter tells WordPress the order in which to load the style sheets. The lower the number, the lower the CSS priority. In other words, the lower the number, the earlier in the sequence the file will load.
function genesis_load_stylesheet() { add_action( 'wp_enqueue_scripts', 'genesis_enqueue_main_stylesheet', 5 ); }
Under the default Genesis setting, the WooCommerce style sheets load after the Genesis Child Theme style sheet as in the following example.
To allow the Genesis Child Theme style sheet to override the WooCommerce styles, we have to unhook the default Genesis action and change the priority for the child theme style sheet to load after the WooCommerce style sheets. Add the following code to your theme's functions.php and you will be able to override any WooCommerce styles by making the changes in your theme's style.css file.
//* Load main style sheet after WooCommerce */ remove_action( 'genesis_meta', 'genesis_load_stylesheet' ); add_action( 'wp_enqueue_scripts', 'genesis_enqueue_main_stylesheet', 30 ); //change load priority
The results of the above code:
Don't Forget Inline Styles
Some of the newer Studio Press themes, like Infinity Pro, include a custom feature that generates inline styles and inserts them in the site's header. In a comment below, Lars points out:
One problem I have found however, with both yours and hers [Carrie Dills] solution is when a Genesis child theme uses inline styles like for example “Infinity Pro” does.
In that case, the inline styles are removed along with the main stylesheet, but they aren’t being included again with a higher priority like the main stylesheet.
With Infinity Pro, the inline styles are generated by lib/output.php and inserted into the header area with the WordPress wp_add_inline_style function. Normally, output.php and the child theme style sheet have nothing to do with each other. But in this case, the wp_add_inline_style function only works if the stylesheet has already been added. Since we changed the priority of adding the style sheet to 30, output.php has to be changed as well so the inline styles are created as expected.
The first executable line in output.php reads:
add_action( 'wp_enqueue_scripts', 'infinity_css' );
Unless otherwise specified, the default add_action for WordPress carries a priority of 10. The priority determines where in the call stack the function executes. Since we changed the style sheet load priority to 30 and the inline styles are executing at priority 10, they are executing too early in the stack. To fix this, we have to change the above line to give it a priority higher than 30. If you give the above line a priority of 31 or higher, everything will work as expected because the stylesheet will be loaded first. Here is the corrected code.
add_action( 'wp_enqueue_scripts', 'infinity_css', 40 );
Victor, brilliant informative post for genesis using woocommerce.
I’m facing a problem. My site’s head section seems to load after a part of the body has already loaded. Which gives the loading a bad look. Any thoughts?
I would have to look at your site to see what’s going on. Please provide a link.
Hi Victor, this is a great solution, much in line with Carries Dills’ solution: https://carriedils.com/woocommerce-genesis-important-style/
One problem I have found however, with both yours and hers solution is when a Genesis child theme uses inline styles like for example “Infinity Pro” does.
In that case, the inline styles are removed along with the main stylesheet, but they aren’t being included again with a higher priority like the main stylesheet.
You can easily see this happening here: https://www.diffchecker.com/crQi1pbq
Thanks for pointing this out Lars. This is interesting and there is a solution! With Infinity Pro, the inline styles are generated by lib/output.php and inserted into the header area with the WordPress wp_add_inline_style function. Normally, output.php and the child theme style sheet have nothing to do with each other. But in this case, the wp_add_inline_style function only works if the stylesheet has already been added. Since we changed the priority of adding the style sheet to 30, output.php has to be changed as well so the inline styles are created as expected.
The first executable line in output.php reads:
add_action( 'wp_enqueue_scripts', 'infinity_css' );
Unless otherwise specified, the default add_action for WordPress carries a priority of 10. The priority determines where in the call stack the function executes. Since we changed the style sheet load priority to 30 and the inline styles are executing at priority 10, they are executing too early in the stack. To fix this, we have to change the above line to give it a priority higher than 30. If you give the above line a priority of 31 or higher, everything will work as expected because the stylesheet will be loaded first. Here is the corrected code.
add_action( 'wp_enqueue_scripts', 'infinity_css', 40 );
Brilliant Victor, this works perfectly.
Thanks for getting back to me on this. Happy New Year.
Victor, you’re awesome! This worked the first time for me, and I’d been searching through multiple woocommerce and my genesis child theme css stylesheets for my problem. Don’t know how I missed it, but you found it straight away. The above article was helpful on so many levels. Thank you for not only providing the fix, but for explaining it so that I know why it works.