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);
wp_enqueue_script('make-a-new-map');
}
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: 🙂
- 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 theif
statement… - 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
2 questions so 2 answers 🙂
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
andwp_head
are called much earlier:wp_head
somewhere in your themesheader.php
file andwp_enqueue_scripts
duringwp_head
call.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)…
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).Loading Scripts and Styles Dynamically Using Shortcode
Advantages
strstr()
orstrpos()
. You could switch to regex if you need to accept args.Explanation of Code
Finds the shortcodes on page using the
save_post
hook only when the post is not a revision and matches the specifiedpost_type
.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 useupdate_option()
.Uses hook
wp_enqueue_scripts
to call ouradd_scripts_and_styles()
function.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
Code Example: Shortcode Dynamically Include Scripts and Styles
This works for me:
More info here: http://mikejolley.com/2013/12/sensible-script-enqueuing-shortcodes/
You can hook into an action after the main query has run and determine if you need to load your styles and scripts.
I would use
has_shortcode
to check the $post content and load the scripts using wp_enqueue_scripts but it depends on where your shortcodes are embedded.Swap out $tag with your shortcode tag in the above code.
Add to your child themes functions file and change the conditionals if needed.
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.
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.
You can simply do it like this:
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.
Loading Scripts and Styles Dynamically Using Shortcode
This is extended code for the solution provided by Commandz above.
I have found his method to be best and more feasible as the database option is available at almost all hooks.
It is changed to find the occurrences of shortcodes only for the current post content, instead of going through all posts – which may be slower when the number of posts is large.
It is changed here in two lines after passing another $post_id variable from the save_post action to function find_shortcode_occurences()
Changed code for both functions
Also, another variable has been added so you can have different names for the database option and the shortcode name.