How to late enqueue inline CSS in WordPress

So you are building a super duper cool plugin™ that, say, does something with widgets or shortcodes and you need to apply some CSS conditionally. No worries, that’s what wp_add_inline_style() is there for. But can you actually use it?

The problem

There are a few problems however. For starters, wp_add_inline_style() requires the handle of a registered style (via wp_register_style() or wp_enqueue_style()) as its first parameter. And that handle’s stylesheet, must not have been already printed. Now, assuming you are enqueuing your styles properly, the printing takes place during the wp_head action hook, which is a lot earlier than that place in the widgets that you hooked in.

You could perhaps force your style to print on the footer, but there is no such parameter in wp_register_style(). The only way you can do it is enqueuing after the during or after the wp_head action, but that means you are not properly enqueuing your stylesheets.

Or even worse, you might now have a stylesheet to load in the first place. Perhaps all your CSS is dynamic in nature, and a .css file just won’t cut it. Depending on the theme’s main stylesheet file (i.e. style.css) isn’t happening either, as each theme names its handle differently.

So, what do you do?

The solution

There’s a little-known workaround that we’ve used while building our MaxSlider plugin, where we needed to enqueue some generated CSS styles from within a shortcode, however all stylesheets were printed in the header. Without further ado, this is the gist of the workaround:

<?php
add_action( 'some_hook', 'maxslider_enqueue_slider_css' );
function maxslider_enqueue_slider_css() {
	$css = '';

	// ...

	if ( true === $something ) {
		$css = 'body { background-color: ' . $color . '; }';
	}

	// ...

	wp_register_style( 'maxslider-footer', false );
	wp_enqueue_style( 'maxslider-footer' );
	wp_add_inline_style( 'maxslider-footer', $css );
}

The last three lines are the most important.

First, we register a new style handle as usual, but without a file path or URL. This is perfectly valid and will be further explained later. Then, we enqueue that same empty style, and we finally provide it with some CSS to print. These last two lines can swap positions and it will still work just fine.

But how can you enqueue a stylesheet without a path?“, you ask.

The theory is simple:
The wp_*_style() functions use an instance of the WP_Styles class, which extends the WP_Dependencies class. Similarly, the wp_*_script() functions use an instance of the WP_Scripts class, which extends (you guessed it!) the WP_Dependencies class.

Why does it matter? Well, you can pretty much do the same things with both styles and scripts. Take a look at this specific WordPress source code:

$scripts->add( 'jquery', false, array( 'jquery-core', 'jquery-migrate' ), '1.12.4' );

That’s what really happens when you enqueue ‘jquery’. It’s not a real script file, but rather an alias/group that depends upon jquery-core and jquery-migrate. Scripts (and therefore, styles) don’t need a source file, as long as they have some kind of dependency attached to them, be it another script/style, or inline css/js code.

I hope you found the above information useful. Let me know in the comments section below if, where and how it helped you!

26 comments

  1. Pete says:

    Complete waste of time, you should never have CSS inline, end of story.

    1. Anastis Sourgoutsidis says:

      The method described above is adding a <style> tag, as opposed to the style="" attribute which should be indeed avoided.

    2. René Hermenau says:

      Awesome mate. With that workaround i was able to fix an issue in my AdSense plugin WP QUADS where i was forced to register an empty css file just for the purpose of being able to use the wp_add_inline function.

      So, thanks very much!

  2. Pete says:

    I meant what I said, all CSS should be in external files

    1. Anastis Sourgoutsidis says:

      Unfortunately this isn’t always possible, as CSS must sometimes be generated on the fly. For those cases, wp_add_inline_style() is the way to go.

    2. Mike P says:

      “All CSS should be in external files” – What are your for not at least considering inlining a portion of your styles? Optimizing your critical rendering path will avoid FOUC (flash of un-styled content) and make your site load faster.

      Having a single huge css file might be simpler, but that doesn’t mean it should be applied to every scenario. You’ve got to read up on render blocking css and critical rendering path… Broaden your horizons and all that…

  3. Pete says:

    Not true at all, if you can include it inline you can add a reference to an external file and do it properly.

    1. Ilya says:

      No, There are a lot of moments, when it is not possible.
      People generates settings, then CSS setting are generating. And YOU CAN NOT ADD IN IT FILE!

    2. Alex Mustin says:

      I am using this in the Customizer, where a user can override existing styles by picking colors.

      How else do you recommend doing that dynamically, Pete?

  4. ilya says:

    Your enqueuing of inline CSS not working at all.

    1. Anastis Sourgoutsidis says:

      Perhaps I could help you more if you explained the issue you’re facing, providing more details on what code doesn’t work, where did you place it, etc etc.

  5. Uncleserj says:

    Very cool workaround, thank you!

  6. Sergunik says:

    Thanks!
    Thats what I need!

  7. Carisa says:

    Thank you for this great solution! Have been looking for this a long time…

    Have one question, why is it wise to put it in the footer (at least, that is was I get when I use this solution) Do you know how to add it to the header?

    1. Anastis Sourgoutsidis says:

      It’s not wise, it’s just the only option in some scenarios. If you call wp_add_inline_style() after the wp_head action executes, then it gets outputted on the footer. You can’t do something now for something that has already happened ;)

      If you do however call it earlier, e.g. on init, then it will get outputted on the header.

      1. Carisa says:

        Many thanks Mr Sourgoutsidis!
        I was asking because of faster rendering of the page above the fold when it’s put in the header. So I understand that this is just not possible with optional css, because that information is presented after init and after wp_head?

        1. Anastis Sourgoutsidis says:

          Yes.
          It does depend on your case however. If, for example, you’re enqueuing CSS that the user provided via the customizer / settings page / meta field, most likely you can enqueue it early so that it will be printed on the header.

  8. Carisa says:

    It’s css which depends on shortcode input variables which are put on a page. So first the shortcode is translated into code and then the accompanying css is defined.
    This solution works the best so far, it’s ok to put it in the footer when there is no other way.
    Many thanks for your help.

  9. Paul says:

    I can get this to work perfectly, thanks for sharing.

    However, I have a created a template with a built in slider. I’d like the user to be able to create unique styles for each page which uses the template.

    I’ve tried to use the above code inside the new template file and it doesn’t work.

    Is there a specific reason why wp_add_inline_style doesn’t work inside template files?

    I’d love to understand this better.

    Thanks,
    Paul

    1. Anastis Sourgoutsidis says:

      Hi Paul,
      it should work just fine, as long as the related style handle isn’t yet ‘done’. Try enqueuing the style also in the template file, just before the wp_add_inline_style() call.
      You can also use the wp_style_is() function to determine the style’s status.

  10. DeoThemes says:

    I wonder, how about sanitization? How to escape these CSS values properly to avoid security leaks?

    1. Anastis Sourgoutsidis says:

      Sanitization will depend on where your values come from, and their type, but it should always happen before saving the value.

      For example, if $color has a related customizer option, the sanitization should be done through the ‘sanitize_callback’ argument of the related WP_Customize_Manager::add_setting() call. In this case, sanitize_hex_color() would be the appropriate sanitization function.

      1. What I meant is escaping, not sanitization. Is it safe enough to print variable that way without escaping?

        1. Anastis Sourgoutsidis says:

          Again, it depends on your use-case, where the values are coming from, what those values are, etc.
          For example, if you’re printing a width (or any size/numeric value for that matter), there’s nothing to escape because the variable should be holding a number. That should have been made sure during sanitization/validation, so, there are no quotes to escape, no special HTML characters to convert, etc. You can however (and perhaps you should) re-pass it through absint(), intval() or even floatval() (whichever makes sense) at the time of printing. In my eyes, this is re-applying sanitization, but it does kind of acts as “escaping” as well.

          At the very end, you can pass the whole CSS through strip_tags() (that’s what WordPress does with the customizer’s css).

  11. Harish says:

    is same performance benefit from the inline styles CSS plugin, or better?

    https://wordpress.org/plugins/speed-demon-littlebizzy/

    1. Anastis Sourgoutsidis says:

      It’s for completely different use-cases.
      The plugin you mention takes any external CSS (which 99% of the times is static) and bundles it inline into the page.

      The late enqueuing method I describe is only good for conditional AND dynamically generated CSS, that can only be determined after the wp_head hook executes.

Leave a Reply

Your email address will not be published. Required fields are marked *