Is it possible to enqueue a script from a widget method (of extended WP_Widget object)?

I am creating a widget plugin that a user could potentially use multiple iterations of the widget multiple times on a single widget-area / multiple widget-areas on a single page. Because of its functionality there will be differing widget-level variables that I will need to individually pass from PHP to JavaScript to take action on (via jQuery). I have used a $widget_id to wrap around the widget which works fine HTML-wise.

However I am having trouble passing the information to JavaScript — at least when attempting to use wp_localize_script to pass info to the JavaScript file. My attempt to accomplish this was done by adding the action-hook to enqueue the JavaScript in the widget method. Unfortunately it appears that I can’t even get the JavaScript to be enqueued from there, let alone am able to pass it information!

Read More

Here’s what I have:

class my_widget extends WP_Widget {
   private $widget_id;
   private $variable; 
   private $plugin_location;

  function my_widget() {
    parent::WP_Widget(false, $name = 'My Widget Plugin');
    $this->plugin_location = plugin_dir_url(__FILE__);
  }

  function widget($args, $instance) {   
    $this->widget_id="widget-".time().rand(1,100).rand(1,100); //make a unique id for widget, i know there are probably better ways to do this... but this works for now...
    extract( $args );
    $this->variable = $instance['variable'];
    add_action('wp_enqueue_scripts', array( &$this, 'plugin_scripts' ));
    echo '<div id="' . $this->widget_id . '">';
    ...
    create & output widget
    ..
    echo '</div>';
   }

   ... irrelevant widget administration functions ...
  public function plugin_scripts(){
    //here we set up & pass relevant information specific to EACH INDIVIDUAL widget (can have multiple in a single widget-area) for jQuery to execute functions & methods on to the JavaScript file
    $widget_info_to_pass = array(
      "widget_id"  =>  $this->widget_id,
      "variables"  =>  $this->variables
    );

    wp_register_script( 'my-site-script'.$this->widget_id, $this->plugin_location . "js/my.js", array('jquery'),'1.2.0');
    wp_enqueue_script( 'my-site-script'.$this->widget_id );
    wp_localize_script('my-site-script'.$this->widget_id, 'php_params', $widget_id_to_pass);
  }      

}

  add_action('widgets_init', create_function('', 'return register_widget("my_widget");'));

This doesn’t enqueue the script, I am fairly certain because widget doesn’t fire until after wp_enqueue_scripts hook has come and gone.

Important to note: it appears that to use wp_localize_script you have to call the function before wp_head.

To that note, I tried most of the hooks and was unable to even have the script enqueue at all let alone enqueue before wp_head. If I could even get the widget method to enqueue a script I can somehow manually add embedded JavaScript defining the information for each widget instance (maybe an associative array?) – but I can’t get it to enqueue any scripts at all.

Is it possible to enqueue a script from the widget method of the extended WP_Widget object or am I fighting an unwinnable battle here? Are the other ways to do this that I am missing?

——————- UPDATE ———————

I updated it using your advice like such:

class my_widget extends WP_Widget {
   private $widget_id;
   private $variable; 
   private $plugin_location;

  function my_widget() {
    parent::WP_Widget(false, $name = 'My Widget Plugin');
    $this->plugin_location = plugin_dir_url(__FILE__);
  }

  function widget($args, $instance) {   
    $this->widget_id="widget-".time().rand(1,100).rand(1,100); //make a unique id for widget, i know there are probably better ways to do this... but this works for now...
    extract( $args );
    $this->variable = $instance['variable'];
   //here we set up & pass relevant information specific to EACH INDIVIDUAL widget (can have multiple in a single widget-area) for jQuery to execute functions & methods on to the javascript file
    $widget_info_to_pass = array(
      "widget_id"  =>  $this->widget_id,
      "variable"  =>  $this->variable
    );
    wp_register_script( 'my-site-script'.$this->widget_id, $this->plugin_location . "js/my.js", array('jquery'),'1.2.0');
    wp_enqueue_script( 'my-site-script'.$this->widget_id );
    wp_localize_script('my-site-script'.$this->widget_id, 'php_params', $widget_id_to_pass);
    echo '<div id="' . $this->widget_id . '">';
    ...
    create & output widget
    ..
    echo '</div>';
   }

   ... irrelevant widget administration methods ...

}

  add_action('widgets_init', create_function('', 'return register_widget("my_widget");'));

To make sure I am being passed the proper info, I made my.js contain the following:

widget_id = php_params.widget_id;
variable = php_params.variable;
console.log(widget_id + "---" + variable);

Unfortunately it only outputs to the console the FINAL widget_id and variable three times.

Any reason why this happens? Any idea how to make it output the proper iterations?

Related posts

Leave a Reply

2 comments

  1. It’s not true that you have to use wp_localize_script before the wp_head.

    Since 3.3 you can use wp_enqueue_script in the body of the document (i.e. in a widget or shortcode callback) and the script is loaded in the footer.

    Here’s a skeleton class I’ve used for adding variables for each instance of a widget to an array and then using wp_localize_script to add that entire array to the document. This loads the script, and the variables in the footer.

    First register your script on the init hook.

    class my_widget extends WP_Widget {
    
      static $variables=array();
    
      function my_widget() {
          //initialiser function
      }
    
      function widget($args, $instance) {   
         //Display widget
    
         //Then make sure our options will be added in the footer
         add_action('wp_footer', array(__CLASS__, 'add_options_to_script'));
    
         //Enqueue the script (registered on init)
         wp_enqueue_script( 'my_script');
    
         //Add the data to the (static) class variable `$variables`, using the widget ID.
         $id = $args['widget_id'];
         self::$variables[$id] = 'my variable for this instance'
       }
    
       //... irrelevant widget administration functions ...
    
      function add_options_to_script(){
           //If there is data to add, add it
           if(!empty(self::$widget_cal))
                wp_localize_script( 'my_script', 'my_var', self::$variables);   
      }      
    
    }
    
      add_action('widgets_init', create_function('', 'return register_widget("my_widget");'));