id_base = $id_base; $this->name = $name; $this->option_name = 'multiwidget_'.$id_base; $this->widget_options = wp_parse_args( $widget_options, array('classname'=>$this->option_name) ); $this->control_options = wp_parse_args( $control_options, array('id_base'=>$this->id_base) ); // Set true when we update the data after a POST submit - makes sure we // don't do it twice. $this->updated = false; } /** Helper function to be called by control_form(). * Returns an HTML name for the field. */ function get_field_name($field_name) { return 'widget-'.$this->id_base.'['.$this->number.']['.$field_name.']'; } /** Helper function to be called by control_form(). * Returns an HTML id for the field. */ function get_field_id($field_name) { return 'widget-'.$this->id_base.'-'.$this->number.'-'.$field_name; } /** Registers this widget-type. * Must be called during the 'widget_init' action. */ function register() { if( !$all_instances = get_option($this->option_name) ) $all_instances = array(); $registered = false; foreach( array_keys($all_instances) as $number ) { // Old widgets can have null values for some reason if( !isset($all_instances[$number]['__multiwidget']) ) continue; $this->_set($number); $registered = true; $this->_register_one($number); } // If there are none, we register the widget's existance with a // generic template if( !$registered ) { $this->_set(1); $this->_register_one(); } } // // PRIVATE FUNCTIONS. Don't worry about these. function _set($number) { $this->number = $number; $this->id = $this->id_base.'-'.$number; } function _get_widget_callback() { return array(&$this,'widget_callback'); } function _get_control_callback() { return array(&$this,'control_callback'); } /** Generate the actual widget content. * Just finds the instance and calls widget(). * Do NOT over-ride this function. */ function widget_callback($args, $widget_args = 1) { if( is_numeric($widget_args) ) $widget_args = array( 'number' => $widget_args ); $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); $this->_set( $widget_args['number'] ); // Data is stored as array: // array( number => data for that instance of the widget, ... ) $all_instances = get_option($this->option_name); if( isset($all_instances[$this->number]) ) $this->widget($args,$all_instances[$this->number]); } /** Deal with changed settings and generate the control form. * Do NOT over-ride this function. */ function control_callback($widget_args = 1) { global $wp_registered_widgets; if( is_numeric($widget_args) ) $widget_args = array( 'number' => $widget_args ); $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); // Data is stored as array: // array( number => data for that instance of the widget, ... ) $all_instances = get_option($this->option_name); if( !is_array($all_instances) ) $all_instances = array(); // We need to update the data if( !$this->updated && !empty($_POST['sidebar']) ) { // Tells us what sidebar to put the data in $sidebar = (string) $_POST['sidebar']; $sidebars_widgets = wp_get_sidebars_widgets(); if( isset($sidebars_widgets[$sidebar]) ) $this_sidebar =& $sidebars_widgets[$sidebar]; else $this_sidebar = array(); foreach( $this_sidebar as $_widget_id ) { // Remove all widgets of this type from the sidebar. We'll add the // new data in a second. This makes sure we don't get any duplicate // data since widget ids aren't necessarily persistent across multiple // updates if( $this->_get_widget_callback() == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) { $number = $wp_registered_widgets[$_widget_id]['params'][0]['number']; if( !in_array( $this->id_base.'-'.$number, $_POST['widget-id'] ) ) { // the widget has been removed. unset($all_instances[$number]); } } } foreach( (array)$_POST['widget-'.$this->id_base] as $number=>$new_instance) { $this->_set($number); if( isset($all_instances[$number]) ) $instance = $this->control_update($new_instance,$all_instances[$number]); else $instance = $this->control_update($new_instance,array()); if( !empty($instance) ) { $instance['__multiwidget'] = $number; $all_instances[$number] = $instance; } } update_option($this->option_name, $all_instances); $this->updated = true; // So that we don't go through this more than once } // Here we echo out the form if( -1 == $widget_args['number'] ) { // We echo out a template for a form which can be converted to a // specific form later via JS $this->_set('%i%'); $instance = array(); } else { $this->_set($widget_args['number']); $instance = $all_instances[ $widget_args['number'] ]; } $this->control_form($instance); } /** Helper function: Registers a single instance. */ function _register_one($number = -1) { wp_register_sidebar_widget( $this->id, $this->name, $this->_get_widget_callback(), $this->widget_options, array( 'number' => $number ) ); wp_register_widget_control( $this->id, $this->name, $this->_get_control_callback(), $this->control_options, array( 'number' => $number ) ); } } // end class MultiWidget /* // // Example MultiWidget. Use this as a template for your own. // class ExampleMultiWidget extends MultiWidget { function ExampleMultiWidget() { $this->MultiWidget( 'example-multi', // id_base 'ExampleMulti', // name array('description'=>__('Widget which allows multiple instances')) ); } // Echo the actual widget content. Subclasses should over-ride this function // to generate their widget code. function widget($args,$instance) { extract($args,EXTR_SKIP); echo $before_widget; echo $before_title . $instance['title'] . $after_title; echo $instance['content']; echo $after_widget; } // Update a particular instance. // This function should check that $new_instance is set correctly. // The newly calculated value of $instance should be returned. function control_update($new_instance, $old_instance) { if( !isset($new_instance['title']) ) // user clicked cancel return false; $instance = $old_instance; $instance['title'] = wp_specialchars( $new_instance['title'] ); $instance['content'] = wp_specialchars( $new_instance['content'] ); return $instance; } // Echo a control form for the current instance. // The form has inputs with names like widget-ID_BASE[$number][FIELD_NAME] // so that all data for that instance of the widget are stored in one // $_POST variable: $_POST['widget-ID_BASE'][$number] function control_form($instance) { ?>