WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

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

I'm running a function on pages where the shortcode [make-me-a-map] is used. It enqueues javascript to the page and makes a map. That part works fine (woot!) but I'm having trouble with adding the stylesheets to only those pages in a similar fashion.

functions.php (Current)

add_shortcode("make-me-a-map", "create_new_map");
add_action("wp_head", "style_my_new_map");

function create_new_map () {
    global $new_map_called_for;
    $map_called_for = true;

    wp_register_script('make-a-new-map', get_template_directory_uri() . '/js/new-map.js', array('jquery'), '0.1', true);

function style_my_new_map() {
    global $new_map_called_for;
    if ($new_map_called_for == true) {
        $tDir = get_template_directory_uri();

        // Echo stylesheets because wp_register_style & wp_enqueue_style don't work atm
        // And add_action('wp_enqueue_script', 'style_my_new_maps') with those functions would add style to all pages
        // Not just the ones with [make-me-a-map] shortcode
        echo "<link rel='stylesheet' href='", $tDir, "/css/new-map.css' />", PHP_EOL;

        // Echo Javascript straight to page (couldn't do it with wp_enqueue_script) to let js code know the template directory
        echo '<script type="text/javascript">var templateDir = "', get_template_directory_uri(), '";</script>', PHP_EOL;
        $map_called_for = false;

This doesn't seem to be working unfortunately. The styles are being added to all pages.

I didn't use wp_register_style & wp_enqueue_style because this bug is still adding <Link /> tags to the footer from those functions.

I could have used add_action("wp_enqueue_scripts", "style_my_new_map") instead of add_action('wp-head', "style_my_new_map") but as far as I can see and have checked, there's no difference? Still adds the stylesheets to all pages.

So my question is actually in two parts: :)

  1. Why is the current functions.php not working and adding styles to all pages? I'm not sure if it's the global call or the if statement...
  2. What's the best way for me to add the stylesheets to the header of only the pages that the above shortcode is used on, assuming I will not know the page ids, etc?

Thanks in advance! P

share|improve this question
Better discussion here: wordpress.stackexchange.com/questions/165754/… – JannieT Mar 9 '15 at 11:06
up vote 1 down vote accepted

2 questions so 2 answers :)

Why is the current functions.php not working and adding styles to all pages? I'm not sure if it's the global call or the if statement...

It doesn't work because of the order in which these functions are called. Your shortcode callback is called during rendering post content (most probably the_content function call).

Both wp_enqueue_scripts and wp_head are called much earlier: wp_head somewhere in your themes header.php file and wp_enqueue_scripts during wp_head call.

What's the best way for me to add the stylesheets to the header of only the pages that the above shortcode is used on, assuming I will not know the page ids, etc?

I don't think there is such "best" way. It's not a good idea at all. Browsers cache CSS files. So if you have the same CSS on all pages, browser will get it only once. If there are many CSS files for different pages, browser will have to get all of them. So I wouldn't do it at all, and include these CSS styles in global css file.

Although if you have to include it only on pages that use this shortcode, then (2 solutions, the choice which is better is yours; I think 2nd one is nicer)...

  1. You can add these styles as inline styles. Just be careful to not include them many times. So output them with your shortcode and assure they will be printed only once.
  2. Since posts are already selected, when wp_head/wp_enqueue_scripts is called, you can add some function to this hook, loop through selected posts, check if they're containing your shortcode and enqueue your CSS if it's needed. (Of course it won't be very efficient).
share|improve this answer
Yeah, #2 might be less efficient but definitely nicer than inline =) Got it working now, cheers! – Padraic Aug 3 '13 at 8:46

Loading Scripts and Styles Dynamically Using Shortcode


  • Does not search through all the posts every time the shortcode is called.
  • Able to add styles as well as scripts dynamically only when shortcode is on the page.
  • Does not use regexes since they tend to be slower than strstr() or strpos(). You could switch to regex if you need to accept args.
  • Reduces file calls

Explanation of Code

  1. Finds the shortcodes on page using the save_post hook only when the post is not a revision and matches the specified post_type.

  2. Saves the found post ids as an array using add_option() with autoload set to yes unless the entry is already present. Then it will use update_option().

  3. Uses hook wp_enqueue_scripts to call our add_scripts_and_styles() function.

  4. That function then calls get_option() to retrieve our array of page ids. If the current $page_id is in the $option_id_array then it adds the scripts and styles.

Please note: I converted the code from OOP Namespaced classes so I may have missed something. Let me know in the comments if I did.

Code Example: Finding Shortcode Occurences

function find_shortcode_occurences($shortcode, $post_type = 'page')
    $found_ids = array();
    $args         = array(
        'post_type'   => $post_type,
        'post_status' => 'publish',
        'posts_per_page' => -1,
    $query_result = new \WP_Query($args);
    foreach ($query_result->posts as $post) {
        if (false !== strpos($post->post_content, $shortcode)) {
            $found_ids[] = $post->ID;
    return $found_ids;

function save_option_shortcode_post_id_array( $post_id ) {
    if ( wp_is_post_revision( $post_id ) OR 'page' != get_post_type( $post_id )) {
    $option_name = 'yourprefix-yourshortcode';
    $id_array = find_shortcode_occurences($option_name);
    $autoload = 'yes';
    if (false == add_option($option_name, $id_array, '', 'yes')) update_option($option_name, $id_array);

add_action('save_post', 'save_option_shortcode_id_array' );

Code Example: Shortcode Dynamically Include Scripts and Styles

function yourshortcode_add_scripts_and_styles() {
    $page_id = get_the_ID();
    $option_id_array = get_option('yourprefix-yourshortcode');
    if (in_array($page_id, $option_id_array)) {
        wp_enqueue_script( $handle, $src, $deps, $ver, $footer = true );
        wp_enqueue_style( $handle, $src , $deps);

add_action('wp_enqueue_scripts', 'yourshortcode_add_scripts_and_styles');
share|improve this answer

A much simpler solution that worked for me was to register the script outside of the shortcode function and then enqueue the script within the function. Then it only loads the script on pages using your shortcode.

wp_register_script('make-a-new-map', get_template_directory_uri() . '/js/new-map.js', array('jquery'), '0.1', true);
wp_register_style('make-a-new-map-style', get_template_directory_uri() . '/css/new-map.css');

add_shortcode("make-me-a-map", "create_new_map");
add_action("wp_head", "style_my_new_map");

function create_new_map () {

   global $new_map_called_for;
   $map_called_for = true;

A description of that method can be found here: http://mikejolley.com/2013/12/sensible-script-enqueuing-shortcodes/

Note that this does load the CSS in the footer, which may not be desirable or W3C valid. In my case that was not an issue.

share|improve this answer

You can simply do it like this:

// shortcode hook
add_shortcode("make-me-a-map", "create_new_map");

// shortcode callback
function style_my_new_map() {
    global $new_map_called_for;
    if ($new_map_called_for == true) {
  wp_register_script('make-a-new-map', get_template_directory_uri() . '/js/new-map.js', array('jquery'), '0.1', true);

// the rest of your codes

It's also works for stylesheets. To load your stylesheet at the last, then add numbers to your shortcode hook, like this:

add_shortcode("make-me-a-map", "create_new_map", 9999);

I've tested it and it works.

share|improve this answer

You can hook into an action after the main query has run and determine if you need to load your styles and scripts.

add_action('template_include', 'custom_template_include');
function custom_template_include($template) {
    if (is_single() || is_page()) {
          global $post;
          if (has_shortcode($post->post_content, 'your_short_code')) {
              add_action('wp_enqueue_scripts, 'custom_enqueue_scripts');

function custom_enqueue_scripts() {
    //Enqueue your stuff here. 
share|improve this answer

This works for me:

function register_my_css () {
    wp_register_style('my-style', plugins_url('styles.css', __FILE__));

function register_my_scripts () {
    wp_register_script('my-script', plugins_url('scripts.js', __FILE__));

// only enqueue the scripts / styles when the short code is called
function do_my_shortcode () {

    // do short code stuff...

// register css
add_action('wp_enqueue_scripts', 'register_my_css');

// register javascript
add_action('wp_enqueue_scripts', 'register_my_scripts');

// register shortcode
add_shortcode('my-shortcode', 'do_my_shortcode');

More info here: http://mikejolley.com/2013/12/sensible-script-enqueuing-shortcodes/

share|improve this answer
Nope, that will output the shortcode on top of the content. – toscho Jul 16 '15 at 11:23
The problem here is that the styles will be linked to in the footer. It will probly work. But it's 'wrong' and is not guaranteed to work. – Doug Cassidy Mar 11 at 16:16

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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