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!

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?

Solutions Collecting From Web of "Is it possible to enqueue a script from a widget method (of extended WP_Widget object)?"

It’s not true that you have to use wp_localise_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 widet to an array, and then using wp_localise_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");'));

wp_enqueue_scripts has already happened. enqueue the script directly in your widget function and output it in the footer.