9

I'm creating a WordPress theme in which I've allowed users to add some custom css from the Theme Options. This css code then directly gets echoed out in the head section of the page, with the following code:

add_action('wp_head', 'theme_dynamic_css');
function theme_dynamic_css(){
  global $my_theme_options;
  $custom_css = '';
  if (isset($my_theme_options['custom-css'])) {
    $custom_css .= $my_theme_options['custom-css']."\r\n";
  }
  echo '<style id="my-theme-custom-css">'.$custom_css.'</style>';
}

Should I be using esc_html(); here? At first I assumed if the code is between the style tags, then it shouldn't be a problem, but now I'm confused.

Please help.

4
  • 1
    Have you considered using wp_add_inline_style?
    – Tom J Nowell
    Commented Jul 8, 2014 at 12:42
  • I believe you should be able to use single quotes when echoing your CSS, as long as all your CSS code uses double quotes? Can you put a var_dump() of $custom_css on here? (or at least part of it)
    – Dan
    Commented Jul 8, 2014 at 13:07
  • @TomJNowell I'm actually looking into that right now. I think I tried wp_add_inline_style earlier but was having some complications. Commented Jul 8, 2014 at 13:45
  • I'm not aware of any appropriate escaping functions, but wordpress.stackexchange.com/q/53970/3898 has some info about CSS sanitization.
    – Ian Dunn
    Commented Nov 22, 2015 at 14:23

3 Answers 3

1

What you (and probably 99% of the theme authors) are trying to do is just wrong. Users should not be expected to know CSS to customize a theme, and if they do need to go into such a low level, the right thing for them to do is to create a child theme and insert their modifications into its CSS file.

Inputting a CSS in the way you describe is tricky as CSS is not general html and can not be escaped in the same way, but it is also impossible to sanitize and remove potentially insecure code from it. What you end up with is a situation in which you have to output the user's CSS "as is" in order to be sure you do not break it, but then in the place where such a feature is most useful - multisite, it is too insecure to be used.

2
  • -1. When you say "Users should not be expected to know CSS to customize a theme", don't forget that a big chunk of those users are WP developers setting up a site, who indeed should be writing CSS. If you need to add one rule to tweak a theme, it's hardly worth the trouble to setup a child theme when you have an "Add Custom CSS" or similar function at your disposal. I would say, though, that there's no reason to bake that feature into a theme rather than using the one that already exists in the Customizer.
    – scott8035
    Commented Mar 18, 2022 at 0:15
  • lol, so when you write such a code you make sure that the site owner will not have access to it unless it passes some tests that will prove he understands CSS. You probably haven't seen what site owners do ti save some money instead of paying a developer. But hi, if you want to be hostile to your users it is truly your choice. lots of things are popular even when they have bad UX. Commented Mar 18, 2022 at 2:40
1

You must use the strip_tags() function to escape custom css.

For example:

/**
 * Add theme custom css to head
 */
function my_theme_custom_css() {
    $styles = get_theme_mod( 'my_theme_custom_css' );

    if ( $styles || is_customize_preview() ) :
        ?>
        <style id="my-theme-custom-css">
            <?php
            // Note that esc_html() cannot be used because `div &gt; span` is not interpreted properly.
            echo strip_tags( $styles );
            ?>
        </style>
    <?php
    endif;
}

add_action( 'wp_head', 'my_theme_custom_css' );
-1

Instead of directly printing the CSS in the header (which is not the best practice) you can add your CSS via wp_add_inline_style. Hook into the wp_enqueue_scripts and add your CSS after your theme's stylesheet.

So, this is how your code is gonna look like:

add_action('wp_enqueue_scripts', 'theme_dynamic_css');
function theme_dynamic_css(){
  global $my_theme_options;
  if (isset($my_theme_options['custom-css'])) {
    $custom_css .= $my_theme_options['custom-css']."\r\n";
  }
  wp_add_inline_style('style', $custom_css);
}

You should use this after you already enqueued your theme's main stylesheet, by using:

wp_enqueue_style( 'style', get_stylesheet_uri());

Also pay attention to the ID that you've chosen for your stylesheet.

2
  • Please be aware that wp_add_inline_style does NOT escape or sanitize its output.You'll have to use esc_html or wp_strip_all_tags to add some basic output sanitization...
    – RavanH
    Commented Sep 16, 2019 at 15:11
  • This answer doesn't address the OP's question...should they use esc_html()?
    – scott8035
    Commented Mar 18, 2022 at 0:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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