13

I've been trying to load scripts and styles for a WordPress widget with the following conditions...

  1. The scripts MUST load in the HEAD (else they break).
  2. The scripts must ONLY load when the widget actually displays (they're quite heavy).

I've done a lot of searching, and this seems to be a common (unsolved) problem...but I'm hoping someone here has successfully implemented a workaround.

This is the best I've got so far...

The following is a simple widget that prints text to the sidebar. It successfully loads jQuery conditionally (when the widget is actually displayed)...though only ever in the footer! (Note: it may also only work on WordPress 3.3, though this hack may provide backwards compatibility).

class BasicWidget extends WP_Widget
{

    function __construct() {
        parent::__construct(__CLASS__, 'BasicWidget', array(
            'classname' => __CLASS__,
            'description' => "This is a basic widget template that outputs text to the sidebar"
        ));
    }

  function form($instance) {
    $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );
    $title = $instance['title'];
?>
  <p><label for="<?php echo $this->get_field_id('title'); ?>">Title: <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></label></p>
<?php
  }

  function update($new_instance, $old_instance) {
    $instance = $old_instance;
    $instance['title'] = $new_instance['title'];
    return $instance;
  }

  function widget($args, $instance) {

    extract($args, EXTR_SKIP);

    echo $before_widget;
    $title = empty($instance['title']) ? ' ' : apply_filters('widget_title', $instance['title']);

    if (!empty($title))
      echo $before_title . $title . $after_title;;

    echo "<h1>This is a basic widget!</h1>";

    echo $after_widget;

        // if we're echoing out content, enqueue jquery.

        if (!empty($after_widget)) {
            wp_enqueue_script('jquery');
        }
    }
}
add_action( 'widgets_init', create_function('', 'return register_widget("BasicWidget");') );

It seems once WordPress starts handling widgets, it's too late to enqueue (or even deregister something enqueued earlier).

Any ideas would be much appreciated!

Mark.

3 Answers 3

15

Wordpress as a nice function is_active_widget that you can use in your __construct and test if the widget is present in the current page and add your scripts/styles based on that ex:

function __construct() {
    parent::__construct(__CLASS__, 'BasicWidget', array(
        'classname' => __CLASS__,
        'description' => "This is a basic widget template that outputs text to the sidebar"
    ));
     if ( is_active_widget(false, false, $this->id_base) )
        add_action( 'wp_head', array(&$this, 'add_styles_and_scripts') );
}

function add_styles_and_scripts(){
    //since its wp_head you need to echo out your style link:
    echo '<link rel="stylesheet" href="http://example.com/css/style.css" type="text/css" />';
    //as for javascript it can be included using wp_enqueue_script and set the footer parameter to true:
    wp_enqueue_script( 'widget_script','http://example.com/js/script.js',array(),'',true );
}
4
  • Thanks for your answer, Bainternet! I've just been testing your code and unfortunately, while the javascript does indeed load conditionally, it still loads in the footer...even though it's being called in wp_head. Very strange! (btw, it still does this without the "true" footer instruction). Also, echoing the stylesheet makes it load regardless of whether the widget is on the page. Any ideas?
    – Mark Jeldi
    Commented Apr 2, 2012 at 14:03
  • wp_head is called after the head scripts are already printed out so it will only load them in the footer but you can echo it out (instead of en-queuing it) just like the stylesheet using echo '<script src="path/to/script.js"></script>'; and as for the stylesheet, its not possible that its loaded is the widgets is not active
    – Bainternet
    Commented Apr 2, 2012 at 15:19
  • try using wp_enqueue_scripts instead of wp_head in your action. This will allow you to put the javascript in either the head or the footer. http://codex.wordpress.org/Function_Reference/wp_enqueue_script
    – Nick
    Commented Apr 2, 2012 at 15:45
  • Thanks, Nick! I did try wp_enqueue_scripts, and while it does load the javascript in the head, it won't load conditionally.
    – Mark Jeldi
    Commented Apr 2, 2012 at 17:36
0

Alternatively you could try the "Widget Logic" plug-in ... it uses conditional statements for the widget loading.

That's quite thinking the other way around - but the result should be as expected.

wp_print_scripts & wp_print_styles might be the proper hooks, just add actions to these hooks with priority 100 something - to be the very last in queue. wp_enqueue_script(), wp_enqueue_style(), wp_deregister_script(), wp_deregister_style() ...

Your issues with the code above might be lacking the priority parameter (not tested)? WP codex

2
  • Thanks Syslogic! I did give Widget Logic a try too, thinking I could hook into its widget_content filter. No luck unfortunately. It uses ob_start to buffer widget output so you can manipulate it before it's printed to the screen, but this is still happening too late to fire off anything in the head. Unless maybe you know of a workaround?
    – Mark Jeldi
    Commented Apr 4, 2012 at 9:02
  • Maybe a combination of Bainternet's solution which seems just fine with widget-logic? Like this you could define which widget to load where - and also what shall been loaded. Adding own conditional statements to a theme's functions.php might help to improve further. Commented Apr 20, 2012 at 12:39
-1

You can simply use wp_enqueue_script or wp_enqueue_style in the widget method (function) in your custom Widget class and it will load the scripts only if the widget is active. See details and example here: https://wpshed.com/wordpress/load-scripts-styles-widget-active/

3
  • Link only answers are just bad as links break with time. You should at least summarize what is in the link. In any case, that is just wrong.as the OP needs the scripts in the header of the page. Commented Apr 11, 2016 at 5:44
  • function widget( $args, $instance ) { wp_enqueue_script( 'wpshed-front-end', plugin_dir_url( __FILE__ ) . 'wpshed-front-end.js', array( 'jquery' ), '1.0.0', false ); } The "false" at the and refers to loading the script in header or footer. To summarize again, use wp_enqueue_script or wp_enqueue_style in the widget method (function). This is how developers from WordPress.com/org are doing it.
    – iStefan
    Commented Apr 11, 2016 at 13:47
  • The comment should have been an edit to the answer ;) but when the widget is "displayed" you have already done the head part of the page and therefor can not enqueue JS itno it. Commented Apr 11, 2016 at 16:25

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.