Make WordPress Core

Ticket #8441: multi_widget_class.php

File multi_widget_class.php, 11.3 KB (added by dcole07, 16 years ago)

Multi-Widget Class with commented Example

Line 
1<?php 
2
3if(!class_exists('MultiWidget')):
4
5/*
6Copyright (c) 2008 Alex Tingle.
7(Based upon pattern for multi-widget, in Wordpress 2.6 wp-includes/widget.php.)
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22
23*/
24
25
26/** This class wraps up lots of secret knowledge about how to make
27 *  Wordpress "multi" widgets. These are widgets that allow more than one
28 *  instance to be created. The standard "Text" widget is a simple example.
29 *
30 *  You must extend this class and over-ride three member functions.
31 *  Scroll to the bottom of the file for a fully working example.
32 */
33class MultiWidget
34{
35  //
36  // Interesting member variables.
37
38  var $id_base;         ///< Root id for all widgets of this type.
39  var $name;            ///< Name for this widget type.
40  var $widget_options;  ///< Option array passed to wp_register_sidebar_widget()
41  var $control_options; ///< Option array passed to wp_register_widget_control()
42
43  var $number =false; ///< Unique ID number of the current instance.
44  var $id =false; ///< Unique ID string of the current instance (id_base-number)
45
46
47  //
48  // Member functions that you must over-ride.
49
50  /** Echo the actual widget content. Subclasses should over-ride this function
51   *  to generate their widget code. */
52  function widget($args,$instance)
53  {
54    die('function MultiWidget::widget() must be over-ridden in a sub-class.');
55  }
56
57
58  /** Update a particular instance.
59   *  This function should check that $new_instance is set correctly.
60   *  The newly calculated value of $instance should be returned. */
61  function control_update($new_instance, $old_instance)
62  {
63    die('function MultiWidget::control_update() must be over-ridden in a sub-class.');
64  }
65
66
67  /** Echo a control form for the current instance. */
68  function control_form($instance)
69  {
70    die('function MultiWidget::control_form() must be over-ridden in a sub-class.');
71  }
72
73
74  //
75  // Functions you'll need to call.
76
77  /** CONSTRUCTOR
78   *   widget_options: passed to wp_register_sidebar_widget()
79   *   - description
80   *   - classname
81   *   control_options: passed to wp_register_widget_control()
82   *   - width
83   *   - height
84   */
85  function MultiWidget(
86      $id_base,
87      $name,
88      $widget_options = array(),
89      $control_options = array()
90    )
91  {
92    $this->id_base = $id_base;
93    $this->name = $name;
94    $this->option_name = 'multiwidget_'.$id_base;
95    $this->widget_options =
96      wp_parse_args( $widget_options, array('classname'=>$this->option_name) );
97    $this->control_options =
98      wp_parse_args( $control_options, array('id_base'=>$this->id_base) );
99    // Set true when we update the data after a POST submit - makes sure we
100    // don't do it twice.
101    $this->updated = false;
102  }
103
104
105  /** Helper function to be called by control_form().
106   *  Returns an HTML name for the field. */
107  function get_field_name($field_name)
108  {
109    return 'widget-'.$this->id_base.'['.$this->number.']['.$field_name.']';
110  }
111
112
113  /** Helper function to be called by control_form().
114   *  Returns an HTML id for the field. */
115  function get_field_id($field_name)
116  {
117    return 'widget-'.$this->id_base.'-'.$this->number.'-'.$field_name;
118  }
119
120
121  /** Registers this widget-type.
122   *  Must be called during the 'widget_init' action. */
123  function register()
124  {
125    if( !$all_instances = get_option($this->option_name) )
126      $all_instances = array();
127
128    $registered = false;
129    foreach( array_keys($all_instances) as $number )
130    {
131      // Old widgets can have null values for some reason
132      if( !isset($all_instances[$number]['__multiwidget']) )
133        continue;
134      $this->_set($number);
135      $registered = true;
136      $this->_register_one($number);
137    }
138
139    // If there are none, we register the widget's existance with a
140    // generic template
141    if( !$registered )
142    {
143      $this->_set(1);
144      $this->_register_one();
145    }
146  }
147
148
149  //
150  // PRIVATE FUNCTIONS. Don't worry about these.
151
152  function _set($number)
153  {
154    $this->number = $number;
155    $this->id = $this->id_base.'-'.$number;
156  }
157
158
159  function _get_widget_callback()
160  {
161    return array(&$this,'widget_callback');
162  }
163
164
165  function _get_control_callback()
166  {
167    return array(&$this,'control_callback');
168  }
169
170
171  /** Generate the actual widget content.
172   *  Just finds the instance and calls widget().
173   *  Do NOT over-ride this function. */
174  function widget_callback($args, $widget_args = 1)
175  {
176    if( is_numeric($widget_args) )
177      $widget_args = array( 'number' => $widget_args );
178    $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
179    $this->_set( $widget_args['number'] );
180
181    // Data is stored as array:
182    //  array( number => data for that instance of the widget, ... )
183    $all_instances = get_option($this->option_name);
184    if( isset($all_instances[$this->number]) )
185      $this->widget($args,$all_instances[$this->number]);
186  }
187
188
189  /** Deal with changed settings and generate the control form.
190   *  Do NOT over-ride this function. */
191  function control_callback($widget_args = 1)
192  {
193    global $wp_registered_widgets;
194
195    if( is_numeric($widget_args) )
196      $widget_args = array( 'number' => $widget_args );
197    $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
198
199    // Data is stored as array:
200    //  array( number => data for that instance of the widget, ... )
201    $all_instances = get_option($this->option_name);
202    if( !is_array($all_instances) )
203      $all_instances = array();
204
205    // We need to update the data
206    if( !$this->updated && !empty($_POST['sidebar']) )
207    {
208      // Tells us what sidebar to put the data in
209      $sidebar = (string) $_POST['sidebar'];
210
211      $sidebars_widgets = wp_get_sidebars_widgets();
212      if( isset($sidebars_widgets[$sidebar]) )
213        $this_sidebar =& $sidebars_widgets[$sidebar];
214      else
215        $this_sidebar = array();
216
217      foreach( $this_sidebar as $_widget_id )
218      {
219        // Remove all widgets of this type from the sidebar.  We'll add the
220        // new data in a second.  This makes sure we don't get any duplicate
221        // data since widget ids aren't necessarily persistent across multiple
222        // updates
223        if( $this->_get_widget_callback() ==
224              $wp_registered_widgets[$_widget_id]['callback'] &&
225            isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) )
226        {
227          $number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
228          if( !in_array( $this->id_base.'-'.$number, (array)$_POST['widget-id'] ) )
229          {
230            // the widget has been removed.
231            unset($all_instances[$number]);
232          }
233        }
234      }
235
236      foreach( (array)$_POST['widget-'.$this->id_base] as $number=>$new_instance)
237      {
238        $this->_set($number);
239        if( isset($all_instances[$number]) )
240          $instance = $this->control_update($new_instance,$all_instances[$number]);
241        else
242          $instance = $this->control_update($new_instance,array());
243        if( !empty($instance) )
244        {
245          $instance['__multiwidget'] = $number;
246          $all_instances[$number] = $instance;
247        }
248      }
249
250      update_option($this->option_name, $all_instances);
251      $this->updated = true; // So that we don't go through this more than once
252    }
253
254    // Here we echo out the form
255    if( -1 == $widget_args['number'] )
256    {
257      // We echo out a template for a form which can be converted to a
258      // specific form later via JS
259      $this->_set('%i%');
260      $instance = array();
261    }
262    else
263    {
264      $this->_set($widget_args['number']);
265      $instance = $all_instances[ $widget_args['number'] ];
266    }
267    $this->control_form($instance);
268  }
269
270
271  /** Helper function: Registers a single instance. */
272  function _register_one($number = -1)
273  {
274    wp_register_sidebar_widget(
275        $this->id,
276        $this->name,
277        $this->_get_widget_callback(),
278        $this->widget_options,
279        array( 'number' => $number )
280      );
281    wp_register_widget_control(
282        $this->id,
283        $this->name,
284        $this->_get_control_callback(),
285        $this->control_options,
286        array( 'number' => $number )
287      );
288  }
289
290} // end class MultiWidget
291
292
293
294/*
295
296//
297// Example MultiWidget. Use this as a template for your own.
298//
299
300class ExampleMultiWidget extends MultiWidget {
301        function ExampleMultiWidget() {
302                $this->MultiWidget(
303                        'example-multi', // id_base
304                        'ExampleMulti', // name
305                        array('description'=>__('Widget which allows multiple instances'))
306                );
307        }
308
309        // Echo the actual widget content. Subclasses should over-ride this function
310        // to generate their widget code.
311        function widget($args,$instance) {
312                extract($args,EXTR_SKIP);
313                echo $before_widget;
314                echo $before_title . $instance['title'] . $after_title;
315                echo $instance['content'];
316                echo $after_widget;
317        }
318
319        // Update a particular instance.
320        // This function should check that $new_instance is set correctly.
321        // The newly calculated value of $instance should be returned.
322        function control_update($new_instance, $old_instance) {
323                if( !isset($new_instance['title']) ) // user clicked cancel
324                        return false;
325                $instance = $old_instance;
326                $instance['title'] = wp_specialchars( $new_instance['title'] );
327                $instance['content'] = wp_specialchars( $new_instance['content'] );
328                return $instance;
329        }
330
331        // Echo a control form for the current instance.
332        // The form has inputs with names like widget-ID_BASE[$number][FIELD_NAME]
333        // so that all data for that instance of the widget are stored in one
334        // $_POST variable: $_POST['widget-ID_BASE'][$number]
335        function control_form($instance){
336        ?>
337                <p>
338                <label for="<?php echo $this->get_field_id('title') ?>">
339                <?php _e('Title:'); ?>
340                <input class="widefat" id="<?php echo $this->get_field_id('title') ?>"
341                name="<?php echo $this->get_field_name('title') ?>" type="text"
342                value="<?php echo htmlspecialchars($instance['title'],ENT_QUOTES) ?>" />
343                </label>
344
345                <label for="<?php echo $this->get_field_id('content') ?>">
346                <?php _e('Content:'); ?>
347                <input class="widefat" id="<?php echo $this->get_field_id('content') ?>"
348                name="<?php echo $this->get_field_name('content') ?>" type="text"
349                value="<?php echo htmlspecialchars($instance['content'],ENT_QUOTES) ?>" />
350                </label>
351
352                <input type="hidden" id="<?php echo $this->get_field_id('submit') ?>"
353                name="<?php echo $this->get_field_name('submit') ?>" value="1" />
354        </p>
355        <?php
356        }
357
358} // end class ExampleMultiWidget
359
360// Finally create an object for the widget-type and register it.
361$example_multi = new ExampleMultiWidget();
362add_action( 'widgets_init', array($example_multi,'register') );
363
364*/
365 
366endif;
367?>