0

I'm not sure I correctly "insert" scripts in my pages.

Concrete example: I need to generate a map with the google API, and decided to write a plugin to do that. Question now is what is the correct way to handle scrip insertion.

First attempt, my plugin file uses add_shortcode to attach a function that just returns <script type=\"text/javascript\" src=\"... in the middle of the page/post. That works, but I understand it's better to put scripts in hearder/footer and I should enqueue them, only when needed.

So here's my second attempt:

<?php 
if ( ! defined( 'ABSPATH' ) ) exit;

add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );
add_shortcode( 'mymapshortcode', 'do_mymapshortcode');

function my_enqueue_scripts() {
    // enqueue scripts if main query is for a page or post that has the shortcode
    if ( isset($GLOBALS['wp_the_query']) 
        && is_a($GLOBALS['wp_the_query']->get_queried_object(),'WP_Post')
        && has_shortcode($GLOBALS['wp_the_query']->get_queried_object()->post_content, 'mymapshortcode') ){

        $target=plugin_dir_url( __FILE__ ) . 'mymapshortcode.js';
        wp_enqueue_script('gmapscript','http://maps.google.com/maps/api/js?sensor=false');
        wp_enqueue_script('mygmapscript',$target,false,null,false);
    }
}

function do_mymapshortcode() {
    // retrun a div for the map to be written
    return "<div id=\"themap\" style=\"width:500px; height:500px;\">
        <p>Loading map...</p><noscript><p>Cannot show map because js is disabled</p></noscript>
        </div>";
}
?>

And then, if I'd decide to inline my script (so small it's not worth the overhead of fetching it from a separate file), I'd go with something like that:

<?php 
if ( ! defined( 'ABSPATH' ) ) exit;

add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts2' );
add_action( 'wp_head', 'my_wp_head2' );
add_shortcode( 'mymapshortcode2', 'do_mymapshortcode2');

function my_wp_head2() {
    // echo inline script if main query is for a page or post that has the shortcode
    if ( isset($GLOBALS['wp_the_query']) 
        && is_a($GLOBALS['wp_the_query']->get_queried_object(),'WP_Post')
        && has_shortcode($GLOBALS['wp_the_query']->get_queried_object()->post_content, 'mymapshortcode2') ){

        $output= <<<'EOT'
<script>/* my min js goes here */ </script>
EOT;
    echo $output;
    }
}

function my_enqueue_scripts2() {
    // enqueue script if main query is for a page or post that has the shortcode
    if ( isset($GLOBALS['wp_the_query']) 
        && is_a($GLOBALS['wp_the_query']->get_queried_object(),'WP_Post')
        && has_shortcode($GLOBALS['wp_the_query']->get_queried_object()->post_content, 'mymapshortcode2') ){

        wp_enqueue_script('gmapscript2','http://maps.google.com/maps/api/js?sensor=false');
    }
}

function do_mymapshortcode2() {
    // retrun a div for the map to be written
    return "<div id=\"themap\" style=\"width:500px; height:500px;\">
        <p>Loading map...<noscript><p>Cannot show map because js is disabled</noscript></p>
        </div>";
}
?>

Is it how it is supposed to be done or am I doing it wrong?

Also, is it possible / better to move the tests for has_shortcode to enclose the add_action so that it's tested only once, like the following:

if ( isset($GLOBALS['wp_the_query']) 
        && is_a($GLOBALS['wp_the_query']->get_queried_object(),'WP_Post')
        && has_shortcode($GLOBALS['wp_the_query']->get_queried_object()->post_content, 'mymapshortcode') ){
    add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts2' );
    add_action( 'wp_head', 'my_wp_head2' );
}
-2

Scripts which are very specific to shortcodes can be loaded directly inside the shortcode and do not have to be registered through the wp_enqueue_scripts hook. This has the advantage of you do not need to run extra code and checks to load the script conditionally, so the has_shortcode() check can be dropped. There is also nothing wrong with running inline scripts here, so feel free to use them as well

You can probably do something like this

<?php 
if ( ! defined( 'ABSPATH' ) ) exit;

add_shortcode( 'mymapshortcode2', 'do_mymapshortcode2');

function do_mymapshortcode2() {

    if (    !isset($GLOBALS['wp_the_query']) 
         || !is_a($GLOBALS['wp_the_query']->get_queried_object(),'WP_Post')
    )
        return '';

    // Enqueue your custom scripts here
    wp_enqueue_script( 'gmapscript2', 'http://maps.google.com/maps/api/js?sensor=false' );

    // return a div for the map to be written
    return "<script>/* my min js goes here */ </script>
        <div id=\"themap\" style=\"width:500px; height:500px;\">
        <p>Loading map...<noscript><p>Cannot show map because js is disabled</noscript></p>
        </div>";
}
?>

Also, is it possible / better to move the tests for has_shortcode to enclose the add_action

It is always better to run conditional checks inside your callback function due to issues you might have with a specific scope.

  • Thanks @Pieter. So my do_shortcode should return either the plain script or the path to the js file. Ok. BUT, I acually tried earlier what you suggest, and enqueuing the google script from within the do_shortcode puts it in the footer, whatever last argument of wp_enqueue_script I use. That led me to believe that I was doing it wrong, probably because my do_shortcode was executed too late for the script to be enqueued in the header. That's the reason I moved it to a add_action('wp_enqueue_scripts',..) callback. Am I missing something? – Mat Feb 28 '16 at 16:16
  • When you enqueue scripts inside your shortcode, it does load that particular script inside the footer, which is correct. That is totally correct and actually better. Scripts, IMO, should be loaded in the footer – Pieter Goosen Feb 28 '16 at 16:19
  • That makes sense. I guess I was mislead by the documentation saying the last arg of wp_enqueue_script() allows to choose either header or footer (default=header) and did not mention that it was handled in a particular way in shortcodes. Thanks @pieter for the help. – Mat Feb 28 '16 at 16:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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