Make WordPress Core

Ticket #8441: multi_widget_class.php

File multi_widget_class.php, 11.3 KB (added by dcole07, 18 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?>