Loading scripts only if a particular shortcode or widget is present

I needed a way to filter a page/posts content before it was loaded so I could add scripts to the header if a specific shortcode was present. After much searching I came across this on http://wpengineer.com

function has_my_shortcode($posts) {
    if ( empty($posts) )
        return $posts;

    $found = false;

    foreach ($posts as $post) {
        if ( stripos($post->post_content, '[my_shortcode') )
            $found = true;
            break;
        }

    if ($found){
        $urljs = get_bloginfo( 'template_directory' ).IMP_JS;

    wp_register_script('my_script', $urljs.'myscript.js' );

    wp_print_scripts('my_script');
}
    return $posts;
}
add_action('the_posts', 'has_my_shortcode');

which is absolutely brilliant and did exactly what I needed.

Read More

Now I need to extend it a bit further and do the same for sidebars. It can be by a particular widget type, shortcode, code snippet or anything else that would work to identify when the script needs to be loaded.

The problem is I can’t figure out how to access the sidebars content before the sidebar is loaded (the theme in question will have several sidebars)

Related posts

Leave a Reply

4 comments

  1. You can use the function is_active_widget . E.g.:

    function check_widget() {
        if( is_active_widget( '', '', 'search' ) ) { // check if search widget is used
            wp_enqueue_script('my-script');
        }
    }
    
    add_action( 'init', 'check_widget' );
    

    To load the script in the page where the widget is loaded only, you will have to add the is_active_widget() code, in you widget class. E.g., see the default recent comments widget (wp-includes/default-widgets.php, line 602):

    class WP_Widget_Recent_Comments extends WP_Widget {
    
        function WP_Widget_Recent_Comments() {
            $widget_ops = array('classname' => 'widget_recent_comments', 'description' => __( 'The most recent comments' ) );
            $this->WP_Widget('recent-comments', __('Recent Comments'), $widget_ops);
            $this->alt_option_name = 'widget_recent_comments';
    
            if ( is_active_widget(false, false, $this->id_base) )
                add_action( 'wp_head', array(&$this, 'recent_comments_style') );
    
            add_action( 'comment_post', array(&$this, 'flush_widget_cache') );
            add_action( 'transition_comment_status', array(&$this, 'flush_widget_cache') );
        }
    
  2. Just wanted to share a solution I worked on which allowed me to be a bit more versatile with my implementation. Rather than having the function check for a variety of shortcodes, I modified it to seek out a single shortcode that references a script/style function that needs to be enqueued. This will work for both methods in other classes (such as plugins that may not do this themselves) and in-scope functions. Just drop the below code in functions.php and add the following syntax to any page/post where you want specific CSS & JS.

    Page/Post Syntax: [loadCSSandJS function=”(class->method/function name)”]

    functions.php code:

    function page_specific_CSSandJS( $posts ) {
      if ( empty( $posts ) )
        return $posts;
    
      foreach ($posts as $post) {
    
        $returnValue = preg_match_all('#[loadCSSandJS function="([A-z->]+)"]#i', $post->post_content, $types);
    
        foreach($types[1] as $type) {
          $items = explode("->",$type);
          if (count($items) == 2) {
            global $$items[0];      
            if( method_exists( $$items[0], $items[1] ))
              add_action( 'wp_enqueue_scripts', array(&$$items[0], $items[1]) );
          }
          else if( !empty( $type ) && function_exists( $type ))
            add_action( 'wp_enqueue_scripts', $type );
        }
      }
    
      return $posts;
    }
    

    This will also allow you to add as many as you want on a page. Keep in mind that you do need a method/function to load.

  3. with WordPress 4.7 there is another way to achieve this in your functions.php file,

    add_action( 'wp_enqueue_scripts', 'register_my_script');
    function register_my_script(){
      wp_register_script('my-shortcode-js',$src, $dependency, $version, $inFooter);
    }
    

    first you register your script, which doesn’t actually get printed on your page unless your enqueue it if your shortcode is called,

    add_filter( 'do_shortcode_tag','enqueue_my_script',10,3);
    function enqueue_my_script($output, $tag, $attr){
      if('myShortcode' != $tag){ //make sure it is the right shortcode
        return $output;
      }
      if(!isset($attr['id'])){ //you can even check for specific attributes
        return $output;
      }
      wp_enqueue_script('my-shortcode-js'); //enqueue your script for printing
      return $output;
    }
    

    the do_shortcode_tag was introduced in WP 4.7 and can be found in the new developers documentation pages.

  4. Thank you for sharing this tip!
    It gave me a little headache, because at first it wasn’t working. I think there are a couple of mistakes (maybe typos) in the code above has_my_shortcode and I re-written the function as below:

    function has_my_shortcode( $posts ) {
    
            if ( empty($posts) )
                return $posts;
    
            $shortcode_found = false;
    
            foreach ($posts as $post) {
    
                if ( !( stripos($post->post_content, '[my-shortcode') === false ) ) {
                    $shortcode_found = true;
                    break;
                }
            }
    
            if ( $shortcode_found ) {
                $this->add_scripts();
                $this->add_styles();
            }
            return $posts;
        }
    

    I think there were two main issues: the break wasn’t in the scope of the if statement, and that caused the loop to always break at the first iteration. The other problem was more subtle and difficult to discover. The code above doesn’t work if the shortcode is the very first thing written in a post. I had to use the === operator to solve this.

    Anyway, thank you so much for sharing this technique, it helped a lot.