]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/widgets.php
Wordpress 2.7.1
[autoinstalls/wordpress.git] / wp-includes / widgets.php
1 <?php
2 /**
3  * API for creating dynamic sidebar without hardcoding functionality into
4  * themes. Includes both internal WordPress routines and theme use routines.
5  *
6  * This functionality was found in a plugin before WordPress 2.2 release which
7  * included it in the core from that point on.
8  *
9  * @link http://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
10  * @link http://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
11  *
12  * @package WordPress
13  * @subpackage Widgets
14  */
15
16 /* Global Variables */
17
18 /** @ignore */
19 global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls;
20
21 /**
22  * Stores the sidebars, since many themes can have more than one.
23  *
24  * @global array $wp_registered_sidebars
25  * @since 2.2.0
26  */
27 $wp_registered_sidebars = array();
28
29 /**
30  * Stores the registered widgets.
31  *
32  * @global array $wp_registered_widgets
33  * @since 2.2.0
34  */
35 $wp_registered_widgets = array();
36
37 /**
38  * Stores the registered widget control (options).
39  *
40  * @global array $wp_registered_widget_controls
41  * @since 2.2.0
42  */
43 $wp_registered_widget_controls = array();
44
45 /* Template tags & API functions */
46
47 /**
48  * Creates multiple sidebars.
49  *
50  * If you wanted to quickly create multiple sidebars for a theme or internally.
51  * This function will allow you to do so. If you don't pass the 'name' and/or
52  * 'id' in $args, then they will be built for you.
53  *
54  * The default for the name is "Sidebar #", with '#' being replaced with the
55  * number the sidebar is currently when greater than one. If first sidebar, the
56  * name will be just "Sidebar". The default for id is "sidebar-" followed by the
57  * number the sidebar creation is currently at.
58  *
59  * @since 2.2.0
60  *
61  * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
62  * @uses parse_str() Converts a string to an array to be used in the rest of the function.
63  * @uses register_sidebar() Sends single sidebar information [name, id] to this
64  *      function to handle building the sidebar.
65  *
66  * @param int $number Number of sidebars to create.
67  * @param string|array $args Builds Sidebar based off of 'name' and 'id' values.
68  */
69 function register_sidebars($number = 1, $args = array()) {
70         global $wp_registered_sidebars;
71         $number = (int) $number;
72
73         if ( is_string($args) )
74                 parse_str($args, $args);
75
76         for ( $i=1; $i <= $number; $i++ ) {
77                 $_args = $args;
78
79                 if ( $number > 1 ) {
80                         $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i);
81                 } else {
82                         $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar');
83                 }
84
85                 if (isset($args['id'])) {
86                         $_args['id'] = $args['id'];
87                 } else {
88                         $n = count($wp_registered_sidebars);
89                         do {
90                                 $n++;
91                                 $_args['id'] = "sidebar-$n";
92                         } while (isset($wp_registered_sidebars[$_args['id']]));
93                 }
94
95                 register_sidebar($_args);
96         }
97 }
98
99 /**
100  * Builds the definition for a single sidebar and returns the ID.
101  *
102  * The $args parameter takes either a string or an array with 'name' and 'id'
103  * contained in either usage. It will be noted that the values will be applied
104  * to all sidebars, so if creating more than one, it will be advised to allow
105  * for WordPress to create the defaults for you.
106  *
107  * Example for string would be <code>'name=whatever;id=whatever1'</code> and for
108  * the array it would be <code>array(
109  *    'name' => 'whatever',
110  *    'id' => 'whatever1')</code>.
111  *
112  * name - The name of the sidebar, which presumably the title which will be
113  *     displayed.
114  * id - The unique identifier by which the sidebar will be called by.
115  * before_widget - The content that will prepended to the widgets when they are
116  *     displayed.
117  * after_widget - The content that will be appended to the widgets when they are
118  *     displayed.
119  * before_title - The content that will be prepended to the title when displayed.
120  * after_title - the content that will be appended to the title when displayed.
121  *
122  * <em>Content</em> is assumed to be HTML and should be formatted as such, but
123  * doesn't have to be.
124  *
125  * @since 2.2.0
126  * @uses $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
127  * @uses parse_str() Converts a string to an array to be used in the rest of the function.
128  * @usedby register_sidebars()
129  *
130  * @param string|array $args Builds Sidebar based off of 'name' and 'id' values
131  * @return string The sidebar id that was added.
132  */
133 function register_sidebar($args = array()) {
134         global $wp_registered_sidebars;
135
136         if ( is_string($args) )
137                 parse_str($args, $args);
138
139         $i = count($wp_registered_sidebars) + 1;
140
141         $defaults = array(
142                 'name' => sprintf(__('Sidebar %d'), $i ),
143                 'id' => "sidebar-$i",
144                 'before_widget' => '<li id="%1$s" class="widget %2$s">',
145                 'after_widget' => "</li>\n",
146                 'before_title' => '<h2 class="widgettitle">',
147                 'after_title' => "</h2>\n",
148         );
149
150         $sidebar = array_merge($defaults, (array) $args);
151
152         $wp_registered_sidebars[$sidebar['id']] = $sidebar;
153
154         return $sidebar['id'];
155 }
156
157 /**
158  * Removes a sidebar from the list.
159  *
160  * @since 2.2.0
161  *
162  * @uses $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
163  *
164  * @param string $name The ID of the sidebar when it was added.
165  */
166 function unregister_sidebar( $name ) {
167         global $wp_registered_sidebars;
168
169         if ( isset( $wp_registered_sidebars[$name] ) )
170                 unset( $wp_registered_sidebars[$name] );
171 }
172
173 /**
174  * Register widget for sidebar with backwards compatibility.
175  *
176  * Allows $name to be an array that accepts either three elements to grab the
177  * first element and the third for the name or just uses the first element of
178  * the array for the name.
179  *
180  * Passes to {@link wp_register_sidebar_widget()} after argument list and
181  * backwards compatibility is complete.
182  *
183  * @since 2.2.0
184  * @uses wp_register_sidebar_widget() Passes the compiled arguments.
185  *
186  * @param string|int $name Widget ID.
187  * @param callback $output_callback Run when widget is called.
188  * @param string $classname Classname widget option.
189  * @param mixed $params,... Widget parameters.
190  */
191 function register_sidebar_widget($name, $output_callback, $classname = '') {
192         // Compat
193         if ( is_array($name) ) {
194                 if ( count($name) == 3 )
195                         $name = sprintf($name[0], $name[2]);
196                 else
197                         $name = $name[0];
198         }
199
200         $id = sanitize_title($name);
201         $options = array();
202         if ( !empty($classname) && is_string($classname) )
203                 $options['classname'] = $classname;
204         $params = array_slice(func_get_args(), 2);
205         $args = array($id, $name, $output_callback, $options);
206         if ( !empty($params) )
207                 $args = array_merge($args, $params);
208
209         call_user_func_array('wp_register_sidebar_widget', $args);
210 }
211
212 /**
213  * Register widget for use in sidebars.
214  *
215  * The default widget option is 'classname' that can be override.
216  *
217  * The function can also be used to unregister widgets when $output_callback
218  * parameter is an empty string.
219  *
220  * @since 2.2.0
221  *
222  * @uses $wp_registered_widgets Uses stored registered widgets.
223  * @uses $wp_register_widget_defaults Retrieves widget defaults.
224  *
225  * @param int|string $id Widget ID.
226  * @param string $name Widget display title.
227  * @param callback $output_callback Run when widget is called.
228  * @param array|string Optional. $options Widget Options.
229  * @param mixed $params,... Widget parameters to add to widget.
230  * @return null Will return if $output_callback is empty after removing widget.
231  */
232 function wp_register_sidebar_widget($id, $name, $output_callback, $options = array()) {
233         global $wp_registered_widgets;
234
235         $id = strtolower($id);
236
237         if ( empty($output_callback) ) {
238                 unset($wp_registered_widgets[$id]);
239                 return;
240         }
241
242         $defaults = array('classname' => $output_callback);
243         $options = wp_parse_args($options, $defaults);
244         $widget = array(
245                 'name' => $name,
246                 'id' => $id,
247                 'callback' => $output_callback,
248                 'params' => array_slice(func_get_args(), 4)
249         );
250         $widget = array_merge($widget, $options);
251
252         if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) )
253                 $wp_registered_widgets[$id] = $widget;
254 }
255
256 /**
257  * Retrieve description for widget.
258  *
259  * When registering widgets, the options can also include 'description' that
260  * describes the widget for display on the widget administration panel or
261  * in the theme.
262  *
263  * @since 2.5.0
264  *
265  * @param int|string $id Widget ID.
266  * @return string Widget description, if available. Null on failure to retrieve description.
267  */
268 function wp_widget_description( $id ) {
269         if ( !is_scalar($id) )
270                 return;
271
272         global $wp_registered_widgets;
273
274         if ( isset($wp_registered_widgets[$id]['description']) )
275                 return wp_specialchars( $wp_registered_widgets[$id]['description'] );
276 }
277
278 /**
279  * Alias of {@link wp_unregister_sidebar_widget()}.
280  *
281  * @see wp_unregister_sidebar_widget()
282  *
283  * @since 2.2.0
284  *
285  * @param int|string $id Widget ID.
286  */
287 function unregister_sidebar_widget($id) {
288         return wp_unregister_sidebar_widget($id);
289 }
290
291 /**
292  * Remove widget from sidebar.
293  *
294  * @since 2.2.0
295  *
296  * @param int|string $id Widget ID.
297  */
298 function wp_unregister_sidebar_widget($id) {
299         wp_register_sidebar_widget($id, '', '');
300         wp_unregister_widget_control($id);
301 }
302
303 /**
304  * Registers widget control callback for customizing options.
305  *
306  * Allows $name to be an array that accepts either three elements to grab the
307  * first element and the third for the name or just uses the first element of
308  * the array for the name.
309  *
310  * Passes to {@link wp_register_widget_control()} after the argument list has
311  * been compiled.
312  *
313  * @since 2.2.0
314  *
315  * @param int|string $name Sidebar ID.
316  * @param callback $control_callback Widget control callback to display and process form.
317  * @param int $width Widget width.
318  * @param int $height Widget height.
319  */
320 function register_widget_control($name, $control_callback, $width = '', $height = '') {
321         // Compat
322         if ( is_array($name) ) {
323                 if ( count($name) == 3 )
324                         $name = sprintf($name[0], $name[2]);
325                 else
326                         $name = $name[0];
327         }
328
329         $id = sanitize_title($name);
330         $options = array();
331         if ( !empty($width) )
332                 $options['width'] = $width;
333         if ( !empty($height) )
334                 $options['height'] = $height;
335         $params = array_slice(func_get_args(), 4);
336         $args = array($id, $name, $control_callback, $options);
337         if ( !empty($params) )
338                 $args = array_merge($args, $params);
339
340         call_user_func_array('wp_register_widget_control', $args);
341 }
342
343 /**
344  * Registers widget control callback for customizing options.
345  *
346  * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
347  * option is never used. The 'width' option is the width of the fully expanded
348  * control form, but try hard to use the default width. The 'id_base' is for
349  * multi-widgets (widgets which allow multiple instances such as the text
350  * widget), an id_base must be provided. The widget id will end up looking like
351  * {$id_base}-{$unique_number}.
352  *
353  * @since 2.2.0
354  *
355  * @param int|string $id Sidebar ID.
356  * @param string $name Sidebar display name.
357  * @param callback $control_callback Run when sidebar is displayed.
358  * @param array|string $options Optional. Widget options. See above long description.
359  * @param mixed $params,... Optional. Additional parameters to add to widget.
360  */
361 function wp_register_widget_control($id, $name, $control_callback, $options = array()) {
362         global $wp_registered_widget_controls;
363
364         $id = strtolower($id);
365
366         if ( empty($control_callback) ) {
367                 unset($wp_registered_widget_controls[$id]);
368                 return;
369         }
370
371         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
372                 return;
373
374         $defaults = array('width' => 250, 'height' => 200 ); // height is never used
375         $options = wp_parse_args($options, $defaults);
376         $options['width'] = (int) $options['width'];
377         $options['height'] = (int) $options['height'];
378
379         $widget = array(
380                 'name' => $name,
381                 'id' => $id,
382                 'callback' => $control_callback,
383                 'params' => array_slice(func_get_args(), 4)
384         );
385         $widget = array_merge($widget, $options);
386
387         $wp_registered_widget_controls[$id] = $widget;
388 }
389
390 /**
391  * Alias of {@link wp_unregister_widget_control()}.
392  *
393  * @since 2.2.0
394  * @see wp_unregister_widget_control()
395  *
396  * @param int|string $id Widget ID.
397  */
398 function unregister_widget_control($id) {
399         return wp_unregister_widget_control($id);
400 }
401
402 /**
403  * Remove control callback for widget.
404  *
405  * @since 2.2.0
406  * @uses wp_register_widget_control() Unregisters by using empty callback.
407  *
408  * @param int|string $id Widget ID.
409  */
410 function wp_unregister_widget_control($id) {
411         return wp_register_widget_control($id, '', '');
412 }
413
414 /**
415  * Display dynamic sidebar.
416  *
417  * By default it displays the default sidebar or 'sidebar-1'. The 'sidebar-1' is
418  * not named by the theme, the actual name is '1', but 'sidebar-' is added to
419  * the registered sidebars for the name. If you named your sidebar 'after-post',
420  * then the parameter $index will still be 'after-post', but the lookup will be
421  * for 'sidebar-after-post'.
422  *
423  * It is confusing for the $index parameter, but just know that it should just
424  * work. When you register the sidebar in the theme, you will use the same name
425  * for this function or "Pay no heed to the man behind the curtain." Just accept
426  * it as an oddity of WordPress sidebar register and display.
427  *
428  * @since 2.2.0
429  *
430  * @param int|string $index Optional, default is 1. Name or ID of dynamic sidebar.
431  * @return bool True, if widget sidebar was found and called. False if not found or not called.
432  */
433 function dynamic_sidebar($index = 1) {
434         global $wp_registered_sidebars, $wp_registered_widgets;
435
436         if ( is_int($index) ) {
437                 $index = "sidebar-$index";
438         } else {
439                 $index = sanitize_title($index);
440                 foreach ( (array) $wp_registered_sidebars as $key => $value ) {
441                         if ( sanitize_title($value['name']) == $index ) {
442                                 $index = $key;
443                                 break;
444                         }
445                 }
446         }
447
448         $sidebars_widgets = wp_get_sidebars_widgets();
449
450         if ( empty($wp_registered_sidebars[$index]) || !array_key_exists($index, $sidebars_widgets) || !is_array($sidebars_widgets[$index]) || empty($sidebars_widgets[$index]) )
451                 return false;
452
453         $sidebar = $wp_registered_sidebars[$index];
454
455         $did_one = false;
456         foreach ( (array) $sidebars_widgets[$index] as $id ) {
457                 $params = array_merge(
458                         array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
459                         (array) $wp_registered_widgets[$id]['params']
460                 );
461
462                 // Substitute HTML id and class attributes into before_widget
463                 $classname_ = '';
464                 foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
465                         if ( is_string($cn) )
466                                 $classname_ .= '_' . $cn;
467                         elseif ( is_object($cn) )
468                                 $classname_ .= '_' . get_class($cn);
469                 }
470                 $classname_ = ltrim($classname_, '_');
471                 $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
472
473                 $params = apply_filters( 'dynamic_sidebar_params', $params );
474
475                 $callback = $wp_registered_widgets[$id]['callback'];
476
477                 if ( is_callable($callback) ) {
478                         call_user_func_array($callback, $params);
479                         $did_one = true;
480                 }
481         }
482
483         return $did_one;
484 }
485
486 /**
487  * Whether widget is registered using callback with widget ID.
488  *
489  * Will only check if both parameters are used. Used to find which sidebar the
490  * widget is located in, but requires that both the callback and the widget ID
491  * be known.
492  *
493  * @since 2.2.0
494  *
495  * @param callback $callback Widget callback to check.
496  * @param int $widget_id Optional, but needed for checking. Widget ID.
497 /* @return mixed false if widget is not active or id of sidebar in which the widget is active.
498  */
499 function is_active_widget($callback, $widget_id = false) {
500         global $wp_registered_widgets;
501
502         $sidebars_widgets = wp_get_sidebars_widgets(false);
503
504         if ( is_array($sidebars_widgets) ) foreach ( $sidebars_widgets as $sidebar => $widgets )
505                 if ( is_array($widgets) ) foreach ( $widgets as $widget )
506                         if ( isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback )
507                                 if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
508                                         return $sidebar;
509
510
511         return false;
512 }
513
514 /**
515  * Whether the dynamic sidebar is enabled and used by theme.
516  *
517  * @since 2.2.0
518  *
519  * @return bool True, if using widgets. False, if not using widgets.
520  */
521 function is_dynamic_sidebar() {
522         global $wp_registered_widgets, $wp_registered_sidebars;
523         $sidebars_widgets = get_option('sidebars_widgets');
524         foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
525                 if ( count($sidebars_widgets[$index]) ) {
526                         foreach ( (array) $sidebars_widgets[$index] as $widget )
527                                 if ( array_key_exists($widget, $wp_registered_widgets) )
528                                         return true;
529                 }
530         }
531         return false;
532 }
533
534 /* Internal Functions */
535
536 /**
537  * Retrieve full list of sidebars and their widgets.
538  *
539  * Will upgrade sidebar widget list, if needed. Will also save updated list, if
540  * needed.
541  *
542  * @since 2.2.0
543  * @access private
544  *
545  * @param bool $update Optional, default is true. Whether to save upgrade of widget array list.
546  * @return array Upgraded list of widgets to version 2 array format.
547  */
548 function wp_get_sidebars_widgets($update = true) {
549         global $wp_registered_widgets, $wp_registered_sidebars;
550
551         $sidebars_widgets = get_option('sidebars_widgets', array());
552         $_sidebars_widgets = array();
553
554         if ( !isset($sidebars_widgets['array_version']) )
555                 $sidebars_widgets['array_version'] = 1;
556
557         switch ( $sidebars_widgets['array_version'] ) {
558                 case 1 :
559                         foreach ( (array) $sidebars_widgets as $index => $sidebar )
560                         if ( is_array($sidebar) )
561                         foreach ( (array) $sidebar as $i => $name ) {
562                                 $id = strtolower($name);
563                                 if ( isset($wp_registered_widgets[$id]) ) {
564                                         $_sidebars_widgets[$index][$i] = $id;
565                                         continue;
566                                 }
567                                 $id = sanitize_title($name);
568                                 if ( isset($wp_registered_widgets[$id]) ) {
569                                         $_sidebars_widgets[$index][$i] = $id;
570                                         continue;
571                                 }
572
573                                 $found = false;
574
575                                 foreach ( $wp_registered_widgets as $widget_id => $widget ) {
576                                         if ( strtolower($widget['name']) == strtolower($name) ) {
577                                                 $_sidebars_widgets[$index][$i] = $widget['id'];
578                                                 $found = true;
579                                                 break;
580                                         } elseif ( sanitize_title($widget['name']) == sanitize_title($name) ) {
581                                                 $_sidebars_widgets[$index][$i] = $widget['id'];
582                                                 $found = true;
583                                                 break;
584                                         }
585                                 }
586
587                                 if ( $found )
588                                         continue;
589
590                                 unset($_sidebars_widgets[$index][$i]);
591                         }
592                         $_sidebars_widgets['array_version'] = 2;
593                         $sidebars_widgets = $_sidebars_widgets;
594                         unset($_sidebars_widgets);
595
596                 case 2 :
597                         $sidebars = array_keys( $wp_registered_sidebars );
598                         if ( !empty( $sidebars ) ) {
599                                 // Move the known-good ones first
600                                 foreach ( (array) $sidebars as $id ) {
601                                         if ( array_key_exists( $id, $sidebars_widgets ) ) {
602                                                 $_sidebars_widgets[$id] = $sidebars_widgets[$id];
603                                                 unset($sidebars_widgets[$id], $sidebars[$id]);
604                                         }
605                                 }
606
607                                 // Assign to each unmatched registered sidebar the first available orphan
608                                 unset( $sidebars_widgets[ 'array_version' ] );
609                                 while ( ( $sidebar = array_shift( $sidebars ) ) && $widgets = array_shift( $sidebars_widgets ) )
610                                         $_sidebars_widgets[ $sidebar ] = $widgets;
611
612                                 $_sidebars_widgets['array_version'] = 3;
613                                 $sidebars_widgets = $_sidebars_widgets;
614                                 unset($_sidebars_widgets);
615                         }
616
617                         if ( $update )
618                                 update_option('sidebars_widgets', $sidebars_widgets);
619         }
620
621         if ( isset($sidebars_widgets['array_version']) )
622                 unset($sidebars_widgets['array_version']);
623
624         $sidebars_widgets = apply_filters('sidebars_widgets', $sidebars_widgets);
625         return $sidebars_widgets;
626 }
627
628 /**
629  * Set the sidebar widget option to update sidebars.
630  *
631  * @since 2.2.0
632  * @access private
633  *
634  * @param array $sidebars_widgets Sidebar widgets and their settings.
635  */
636 function wp_set_sidebars_widgets( $sidebars_widgets ) {
637         if ( !isset( $sidebars_widgets['array_version'] ) )
638                 $sidebars_widgets['array_version'] = 3;
639         update_option( 'sidebars_widgets', $sidebars_widgets );
640 }
641
642 /**
643  * Retrieve default registered sidebars list.
644  *
645  * @since 2.2.0
646  * @access private
647  *
648  * @return array
649  */
650 function wp_get_widget_defaults() {
651         global $wp_registered_sidebars;
652
653         $defaults = array();
654
655         foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
656                 $defaults[$index] = array();
657
658         return $defaults;
659 }
660
661 /* Default Widgets */
662
663 /**
664  * Display pages widget.
665  *
666  * @since 2.2.0
667  *
668  * @param array $args Widget arguments.
669  */
670 function wp_widget_pages( $args ) {
671         extract( $args );
672         $options = get_option( 'widget_pages' );
673
674         $title = empty( $options['title'] ) ? __( 'Pages' ) : apply_filters('widget_title', $options['title']);
675         $sortby = empty( $options['sortby'] ) ? 'menu_order' : $options['sortby'];
676         $exclude = empty( $options['exclude'] ) ? '' : $options['exclude'];
677
678         if ( $sortby == 'menu_order' ) {
679                 $sortby = 'menu_order, post_title';
680         }
681
682         $out = wp_list_pages( array('title_li' => '', 'echo' => 0, 'sort_column' => $sortby, 'exclude' => $exclude) );
683
684         if ( !empty( $out ) ) {
685 ?>
686         <?php echo $before_widget; ?>
687                 <?php echo $before_title . $title . $after_title; ?>
688                 <ul>
689                         <?php echo $out; ?>
690                 </ul>
691         <?php echo $after_widget; ?>
692 <?php
693         }
694 }
695
696 /**
697  * Display and process pages widget options form.
698  *
699  * @since 2.2.0
700  */
701 function wp_widget_pages_control() {
702         $options = $newoptions = get_option('widget_pages');
703         if ( isset($_POST['pages-submit']) ) {
704                 $newoptions['title'] = strip_tags(stripslashes($_POST['pages-title']));
705
706                 $sortby = stripslashes( $_POST['pages-sortby'] );
707
708                 if ( in_array( $sortby, array( 'post_title', 'menu_order', 'ID' ) ) ) {
709                         $newoptions['sortby'] = $sortby;
710                 } else {
711                         $newoptions['sortby'] = 'menu_order';
712                 }
713
714                 $newoptions['exclude'] = strip_tags( stripslashes( $_POST['pages-exclude'] ) );
715         }
716         if ( $options != $newoptions ) {
717                 $options = $newoptions;
718                 update_option('widget_pages', $options);
719         }
720         $title = attribute_escape($options['title']);
721         $exclude = attribute_escape( $options['exclude'] );
722 ?>
723                 <p><label for="pages-title"><?php _e('Title:'); ?> <input class="widefat" id="pages-title" name="pages-title" type="text" value="<?php echo $title; ?>" /></label></p>
724                 <p>
725                         <label for="pages-sortby"><?php _e( 'Sort by:' ); ?>
726                                 <select name="pages-sortby" id="pages-sortby" class="widefat">
727                                         <option value="post_title"<?php selected( $options['sortby'], 'post_title' ); ?>><?php _e('Page title'); ?></option>
728                                         <option value="menu_order"<?php selected( $options['sortby'], 'menu_order' ); ?>><?php _e('Page order'); ?></option>
729                                         <option value="ID"<?php selected( $options['sortby'], 'ID' ); ?>><?php _e( 'Page ID' ); ?></option>
730                                 </select>
731                         </label>
732                 </p>
733                 <p>
734                         <label for="pages-exclude"><?php _e( 'Exclude:' ); ?> <input type="text" value="<?php echo $exclude; ?>" name="pages-exclude" id="pages-exclude" class="widefat" /></label>
735                         <br />
736                         <small><?php _e( 'Page IDs, separated by commas.' ); ?></small>
737                 </p>
738                 <input type="hidden" id="pages-submit" name="pages-submit" value="1" />
739 <?php
740 }
741
742 /**
743  * Display links widget.
744  *
745  * @since 2.2.0
746  *
747  * @param array $args Widget arguments.
748  */
749 function wp_widget_links($args) {
750         extract($args, EXTR_SKIP);
751
752         $before_widget = preg_replace('/id="[^"]*"/','id="%id"', $before_widget);
753         wp_list_bookmarks(apply_filters('widget_links_args', array(
754                 'title_before' => $before_title, 'title_after' => $after_title,
755                 'category_before' => $before_widget, 'category_after' => $after_widget,
756                 'show_images' => true, 'class' => 'linkcat widget'
757         )));
758 }
759
760 /**
761  * Display search widget.
762  *
763  * @since 2.2.0
764  *
765  * @param array $args Widget arguments.
766  */
767 function wp_widget_search($args) {
768         extract($args);
769         echo $before_widget;
770
771         // Use current theme search form if it exists
772         get_search_form();
773
774         echo $after_widget;
775 }
776
777 /**
778  * Display archives widget.
779  *
780  * @since 2.2.0
781  *
782  * @param array $args Widget arguments.
783  */
784 function wp_widget_archives($args) {
785         extract($args);
786         $options = get_option('widget_archives');
787         $c = $options['count'] ? '1' : '0';
788         $d = $options['dropdown'] ? '1' : '0';
789         $title = empty($options['title']) ? __('Archives') : apply_filters('widget_title', $options['title']);
790
791         echo $before_widget;
792         echo $before_title . $title . $after_title;
793
794         if($d) {
795 ?>
796                 <select name="archive-dropdown" onchange='document.location.href=this.options[this.selectedIndex].value;'> <option value=""><?php echo attribute_escape(__('Select Month')); ?></option> <?php wp_get_archives("type=monthly&format=option&show_post_count=$c"); ?> </select>
797 <?php
798         } else {
799 ?>
800                 <ul>
801                 <?php wp_get_archives("type=monthly&show_post_count=$c"); ?>
802                 </ul>
803 <?php
804         }
805
806         echo $after_widget;
807 }
808
809 /**
810  * Display and process archives widget options form.
811  *
812  * @since 2.2.0
813  */
814 function wp_widget_archives_control() {
815         $options = $newoptions = get_option('widget_archives');
816         if ( isset($_POST["archives-submit"]) ) {
817                 $newoptions['count'] = isset($_POST['archives-count']);
818                 $newoptions['dropdown'] = isset($_POST['archives-dropdown']);
819                 $newoptions['title'] = strip_tags(stripslashes($_POST["archives-title"]));
820         }
821         if ( $options != $newoptions ) {
822                 $options = $newoptions;
823                 update_option('widget_archives', $options);
824         }
825         $count = $options['count'] ? 'checked="checked"' : '';
826         $dropdown = $options['dropdown'] ? 'checked="checked"' : '';
827         $title = attribute_escape($options['title']);
828 ?>
829                         <p><label for="archives-title"><?php _e('Title:'); ?> <input class="widefat" id="archives-title" name="archives-title" type="text" value="<?php echo $title; ?>" /></label></p>
830                         <p>
831                                 <label for="archives-count"><input class="checkbox" type="checkbox" <?php echo $count; ?> id="archives-count" name="archives-count" /> <?php _e('Show post counts'); ?></label>
832                                 <br />
833                                 <label for="archives-dropdown"><input class="checkbox" type="checkbox" <?php echo $dropdown; ?> id="archives-dropdown" name="archives-dropdown" /> <?php _e('Display as a drop down'); ?></label>
834                         </p>
835                         <input type="hidden" id="archives-submit" name="archives-submit" value="1" />
836 <?php
837 }
838
839 /**
840  * Display meta widget.
841  *
842  * Displays log in/out, RSS feed links, etc.
843  *
844  * @since 2.2.0
845  *
846  * @param array $args Widget arguments.
847  */
848 function wp_widget_meta($args) {
849         extract($args);
850         $options = get_option('widget_meta');
851         $title = empty($options['title']) ? __('Meta') : apply_filters('widget_title', $options['title']);
852 ?>
853                 <?php echo $before_widget; ?>
854                         <?php echo $before_title . $title . $after_title; ?>
855                         <ul>
856                         <?php wp_register(); ?>
857                         <li><?php wp_loginout(); ?></li>
858                         <li><a href="<?php bloginfo('rss2_url'); ?>" title="<?php echo attribute_escape(__('Syndicate this site using RSS 2.0')); ?>"><?php _e('Entries <abbr title="Really Simple Syndication">RSS</abbr>'); ?></a></li>
859                         <li><a href="<?php bloginfo('comments_rss2_url'); ?>" title="<?php echo attribute_escape(__('The latest comments to all posts in RSS')); ?>"><?php _e('Comments <abbr title="Really Simple Syndication">RSS</abbr>'); ?></a></li>
860                         <li><a href="http://wordpress.org/" title="<?php echo attribute_escape(__('Powered by WordPress, state-of-the-art semantic personal publishing platform.')); ?>">WordPress.org</a></li>
861                         <?php wp_meta(); ?>
862                         </ul>
863                 <?php echo $after_widget; ?>
864 <?php
865 }
866
867 /**
868  * Display and process meta widget options form.
869  *
870  * @since 2.2.0
871  */
872 function wp_widget_meta_control() {
873         $options = $newoptions = get_option('widget_meta');
874         if ( isset($_POST["meta-submit"]) ) {
875                 $newoptions['title'] = strip_tags(stripslashes($_POST["meta-title"]));
876         }
877         if ( $options != $newoptions ) {
878                 $options = $newoptions;
879                 update_option('widget_meta', $options);
880         }
881         $title = attribute_escape($options['title']);
882 ?>
883                         <p><label for="meta-title"><?php _e('Title:'); ?> <input class="widefat" id="meta-title" name="meta-title" type="text" value="<?php echo $title; ?>" /></label></p>
884                         <input type="hidden" id="meta-submit" name="meta-submit" value="1" />
885 <?php
886 }
887
888 /**
889  * Display calendar widget.
890  *
891  * @since 2.2.0
892  *
893  * @param array $args Widget arguments.
894  */
895 function wp_widget_calendar($args) {
896         extract($args);
897         $options = get_option('widget_calendar');
898         $title = apply_filters('widget_title', $options['title']);
899         if ( empty($title) )
900                 $title = '&nbsp;';
901         echo $before_widget . $before_title . $title . $after_title;
902         echo '<div id="calendar_wrap">';
903         get_calendar();
904         echo '</div>';
905         echo $after_widget;
906 }
907
908 /**
909  * Display and process calendar widget options form.
910  *
911  * @since 2.2.0
912  */
913 function wp_widget_calendar_control() {
914         $options = $newoptions = get_option('widget_calendar');
915         if ( isset($_POST["calendar-submit"]) ) {
916                 $newoptions['title'] = strip_tags(stripslashes($_POST["calendar-title"]));
917         }
918         if ( $options != $newoptions ) {
919                 $options = $newoptions;
920                 update_option('widget_calendar', $options);
921         }
922         $title = attribute_escape($options['title']);
923 ?>
924                         <p><label for="calendar-title"><?php _e('Title:'); ?> <input class="widefat" id="calendar-title" name="calendar-title" type="text" value="<?php echo $title; ?>" /></label></p>
925                         <input type="hidden" id="calendar-submit" name="calendar-submit" value="1" />
926 <?php
927 }
928
929 /**
930  * Display the Text widget, depending on the widget number.
931  *
932  * Supports multiple text widgets and keeps track of the widget number by using
933  * the $widget_args parameter. The option 'widget_text' is used to store the
934  * content for the widgets. The content and title are passed through the
935  * 'widget_text' and 'widget_title' filters respectively.
936  *
937  * @since 2.2.0
938  *
939  * @param array $args Widget arguments.
940  * @param int $number Widget number.
941  */
942 function wp_widget_text($args, $widget_args = 1) {
943         extract( $args, EXTR_SKIP );
944         if ( is_numeric($widget_args) )
945                 $widget_args = array( 'number' => $widget_args );
946         $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
947         extract( $widget_args, EXTR_SKIP );
948
949         $options = get_option('widget_text');
950         if ( !isset($options[$number]) )
951                 return;
952
953         $title = apply_filters('widget_title', $options[$number]['title']);
954         $text = apply_filters( 'widget_text', $options[$number]['text'] );
955 ?>
956                 <?php echo $before_widget; ?>
957                         <?php if ( !empty( $title ) ) { echo $before_title . $title . $after_title; } ?>
958                         <div class="textwidget"><?php echo $text; ?></div>
959                 <?php echo $after_widget; ?>
960 <?php
961 }
962
963 /**
964  * Display and process text widget options form.
965  *
966  * @since 2.2.0
967  *
968  * @param int $widget_args Widget number.
969  */
970 function wp_widget_text_control($widget_args) {
971         global $wp_registered_widgets;
972         static $updated = false;
973
974         if ( is_numeric($widget_args) )
975                 $widget_args = array( 'number' => $widget_args );
976         $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
977         extract( $widget_args, EXTR_SKIP );
978
979         $options = get_option('widget_text');
980         if ( !is_array($options) )
981                 $options = array();
982
983         if ( !$updated && !empty($_POST['sidebar']) ) {
984                 $sidebar = (string) $_POST['sidebar'];
985
986                 $sidebars_widgets = wp_get_sidebars_widgets();
987                 if ( isset($sidebars_widgets[$sidebar]) )
988                         $this_sidebar =& $sidebars_widgets[$sidebar];
989                 else
990                         $this_sidebar = array();
991
992                 foreach ( (array) $this_sidebar as $_widget_id ) {
993                         if ( 'wp_widget_text' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
994                                 $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
995                                 if ( !in_array( "text-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed.
996                                         unset($options[$widget_number]);
997                         }
998                 }
999
1000                 foreach ( (array) $_POST['widget-text'] as $widget_number => $widget_text ) {
1001                         if ( !isset($widget_text['text']) && isset($options[$widget_number]) ) // user clicked cancel
1002                                 continue;
1003                         $title = strip_tags(stripslashes($widget_text['title']));
1004                         if ( current_user_can('unfiltered_html') )
1005                                 $text = stripslashes( $widget_text['text'] );
1006                         else
1007                                 $text = stripslashes(wp_filter_post_kses( $widget_text['text'] ));
1008                         $options[$widget_number] = compact( 'title', 'text' );
1009                 }
1010
1011                 update_option('widget_text', $options);
1012                 $updated = true;
1013         }
1014
1015         if ( -1 == $number ) {
1016                 $title = '';
1017                 $text = '';
1018                 $number = '%i%';
1019         } else {
1020                 $title = attribute_escape($options[$number]['title']);
1021                 $text = format_to_edit($options[$number]['text']);
1022         }
1023 ?>
1024                 <p>
1025                         <input class="widefat" id="text-title-<?php echo $number; ?>" name="widget-text[<?php echo $number; ?>][title]" type="text" value="<?php echo $title; ?>" />
1026                         <textarea class="widefat" rows="16" cols="20" id="text-text-<?php echo $number; ?>" name="widget-text[<?php echo $number; ?>][text]"><?php echo $text; ?></textarea>
1027                         <input type="hidden" name="widget-text[<?php echo $number; ?>][submit]" value="1" />
1028                 </p>
1029 <?php
1030 }
1031
1032 /**
1033  * Register text widget on startup.
1034  *
1035  * @since 2.2.0
1036  */
1037 function wp_widget_text_register() {
1038         if ( !$options = get_option('widget_text') )
1039                 $options = array();
1040         $widget_ops = array('classname' => 'widget_text', 'description' => __('Arbitrary text or HTML'));
1041         $control_ops = array('width' => 400, 'height' => 350, 'id_base' => 'text');
1042         $name = __('Text');
1043
1044         $id = false;
1045         foreach ( (array) array_keys($options) as $o ) {
1046                 // Old widgets can have null values for some reason
1047                 if ( !isset($options[$o]['title']) || !isset($options[$o]['text']) )
1048                         continue;
1049                 $id = "text-$o"; // Never never never translate an id
1050                 wp_register_sidebar_widget($id, $name, 'wp_widget_text', $widget_ops, array( 'number' => $o ));
1051                 wp_register_widget_control($id, $name, 'wp_widget_text_control', $control_ops, array( 'number' => $o ));
1052         }
1053
1054         // If there are none, we register the widget's existance with a generic template
1055         if ( !$id ) {
1056                 wp_register_sidebar_widget( 'text-1', $name, 'wp_widget_text', $widget_ops, array( 'number' => -1 ) );
1057                 wp_register_widget_control( 'text-1', $name, 'wp_widget_text_control', $control_ops, array( 'number' => -1 ) );
1058         }
1059 }
1060
1061 /**
1062  * Display categories widget.
1063  *
1064  * Allows multiple category widgets.
1065  *
1066  * @since 2.2.0
1067  *
1068  * @param array $args Widget arguments.
1069  * @param int $number Widget number.
1070  */
1071 function wp_widget_categories($args, $widget_args = 1) {
1072         extract($args, EXTR_SKIP);
1073         if ( is_numeric($widget_args) )
1074                 $widget_args = array( 'number' => $widget_args );
1075         $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
1076         extract($widget_args, EXTR_SKIP);
1077
1078         $options = get_option('widget_categories');
1079         if ( !isset($options[$number]) )
1080                 return;
1081
1082         $c = $options[$number]['count'] ? '1' : '0';
1083         $h = $options[$number]['hierarchical'] ? '1' : '0';
1084         $d = $options[$number]['dropdown'] ? '1' : '0';
1085
1086         $title = empty($options[$number]['title']) ? __('Categories') : apply_filters('widget_title', $options[$number]['title']);
1087
1088         echo $before_widget;
1089         echo $before_title . $title . $after_title;
1090
1091         $cat_args = array('orderby' => 'name', 'show_count' => $c, 'hierarchical' => $h);
1092
1093         if ( $d ) {
1094                 $cat_args['show_option_none'] = __('Select Category');
1095                 wp_dropdown_categories($cat_args);
1096 ?>
1097
1098 <script type='text/javascript'>
1099 /* <![CDATA[ */
1100         var dropdown = document.getElementById("cat");
1101         function onCatChange() {
1102                 if ( dropdown.options[dropdown.selectedIndex].value > 0 ) {
1103                         location.href = "<?php echo get_option('home'); ?>/?cat="+dropdown.options[dropdown.selectedIndex].value;
1104                 }
1105         }
1106         dropdown.onchange = onCatChange;
1107 /* ]]> */
1108 </script>
1109
1110 <?php
1111         } else {
1112 ?>
1113                 <ul>
1114                 <?php
1115                         $cat_args['title_li'] = '';
1116                         wp_list_categories($cat_args);
1117                 ?>
1118                 </ul>
1119 <?php
1120         }
1121
1122         echo $after_widget;
1123 }
1124
1125 /**
1126  * Display and process categories widget options form.
1127  *
1128  * @since 2.2.0
1129  *
1130  * @param int $widget_args Widget number.
1131  */
1132 function wp_widget_categories_control( $widget_args ) {
1133         global $wp_registered_widgets;
1134         static $updated = false;
1135
1136         if ( is_numeric($widget_args) )
1137                 $widget_args = array( 'number' => $widget_args );
1138         $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
1139         extract($widget_args, EXTR_SKIP);
1140
1141         $options = get_option('widget_categories');
1142
1143         if ( !is_array( $options ) )
1144                 $options = array();
1145
1146         if ( !$updated && !empty($_POST['sidebar']) ) {
1147                 $sidebar = (string) $_POST['sidebar'];
1148
1149                 $sidebars_widgets = wp_get_sidebars_widgets();
1150                 if ( isset($sidebars_widgets[$sidebar]) )
1151                         $this_sidebar =& $sidebars_widgets[$sidebar];
1152                 else
1153                         $this_sidebar = array();
1154
1155                 foreach ( (array) $this_sidebar as $_widget_id ) {
1156                         if ( 'wp_widget_categories' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
1157                                 $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
1158                                 if ( !in_array( "categories-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed.
1159                                         unset($options[$widget_number]);
1160                         }
1161                 }
1162
1163                 foreach ( (array) $_POST['widget-categories'] as $widget_number => $widget_cat ) {
1164                         if ( !isset($widget_cat['title']) && isset($options[$widget_number]) ) // user clicked cancel
1165                                 continue;
1166                         $title = trim(strip_tags(stripslashes($widget_cat['title'])));
1167                         $count = isset($widget_cat['count']);
1168                         $hierarchical = isset($widget_cat['hierarchical']);
1169                         $dropdown = isset($widget_cat['dropdown']);
1170                         $options[$widget_number] = compact( 'title', 'count', 'hierarchical', 'dropdown' );
1171                 }
1172
1173                 update_option('widget_categories', $options);
1174                 $updated = true;
1175         }
1176
1177         if ( -1 == $number ) {
1178                 $title = '';
1179                 $count = false;
1180                 $hierarchical = false;
1181                 $dropdown = false;
1182                 $number = '%i%';
1183         } else {
1184                 $title = attribute_escape( $options[$number]['title'] );
1185                 $count = (bool) $options[$number]['count'];
1186                 $hierarchical = (bool) $options[$number]['hierarchical'];
1187                 $dropdown = (bool) $options[$number]['dropdown'];
1188         }
1189 ?>
1190                         <p>
1191                                 <label for="categories-title-<?php echo $number; ?>">
1192                                         <?php _e( 'Title:' ); ?>
1193                                         <input class="widefat" id="categories-title-<?php echo $number; ?>" name="widget-categories[<?php echo $number; ?>][title]" type="text" value="<?php echo $title; ?>" />
1194                                 </label>
1195                         </p>
1196
1197                         <p>
1198                                 <label for="categories-dropdown-<?php echo $number; ?>">
1199                                         <input type="checkbox" class="checkbox" id="categories-dropdown-<?php echo $number; ?>" name="widget-categories[<?php echo $number; ?>][dropdown]"<?php checked( $dropdown, true ); ?> />
1200                                         <?php _e( 'Show as dropdown' ); ?>
1201                                 </label>
1202                                 <br />
1203                                 <label for="categories-count-<?php echo $number; ?>">
1204                                         <input type="checkbox" class="checkbox" id="categories-count-<?php echo $number; ?>" name="widget-categories[<?php echo $number; ?>][count]"<?php checked( $count, true ); ?> />
1205                                         <?php _e( 'Show post counts' ); ?>
1206                                 </label>
1207                                 <br />
1208                                 <label for="categories-hierarchical-<?php echo $number; ?>">
1209                                         <input type="checkbox" class="checkbox" id="categories-hierarchical-<?php echo $number; ?>" name="widget-categories[<?php echo $number; ?>][hierarchical]"<?php checked( $hierarchical, true ); ?> />
1210                                         <?php _e( 'Show hierarchy' ); ?>
1211                                 </label>
1212                         </p>
1213
1214                         <input type="hidden" name="widget-categories[<?php echo $number; ?>][submit]" value="1" />
1215 <?php
1216 }
1217
1218 /**
1219  * Register categories widget on startup.
1220  *
1221  * @since 2.3.0
1222  */
1223 function wp_widget_categories_register() {
1224         if ( !$options = get_option( 'widget_categories' ) )
1225                 $options = array();
1226
1227         if ( isset($options['title']) )
1228                 $options = wp_widget_categories_upgrade();
1229
1230         $widget_ops = array( 'classname' => 'widget_categories', 'description' => __( "A list or dropdown of categories" ) );
1231
1232         $name = __( 'Categories' );
1233
1234         $id = false;
1235         foreach ( (array) array_keys($options) as $o ) {
1236                 // Old widgets can have null values for some reason
1237                 if ( !isset($options[$o]['title']) )
1238                         continue;
1239                 $id = "categories-$o";
1240                 wp_register_sidebar_widget( $id, $name, 'wp_widget_categories', $widget_ops, array( 'number' => $o ) );
1241                 wp_register_widget_control( $id, $name, 'wp_widget_categories_control', array( 'id_base' => 'categories' ), array( 'number' => $o ) );
1242         }
1243
1244         // If there are none, we register the widget's existance with a generic template
1245         if ( !$id ) {
1246                 wp_register_sidebar_widget( 'categories-1', $name, 'wp_widget_categories', $widget_ops, array( 'number' => -1 ) );
1247                 wp_register_widget_control( 'categories-1', $name, 'wp_widget_categories_control', array( 'id_base' => 'categories' ), array( 'number' => -1 ) );
1248         }
1249 }
1250
1251 /**
1252  * Upgrade previous category widget to current version.
1253  *
1254  * @since 2.3.0
1255  *
1256  * @return array
1257  */
1258 function wp_widget_categories_upgrade() {
1259         $options = get_option( 'widget_categories' );
1260
1261         if ( !isset( $options['title'] ) )
1262                 return $options;
1263
1264         $newoptions = array( 1 => $options );
1265
1266         update_option( 'widget_categories', $newoptions );
1267
1268         $sidebars_widgets = get_option( 'sidebars_widgets' );
1269         if ( is_array( $sidebars_widgets ) ) {
1270                 foreach ( $sidebars_widgets as $sidebar => $widgets ) {
1271                         if ( is_array( $widgets ) ) {
1272                                 foreach ( $widgets as $widget )
1273                                         $new_widgets[$sidebar][] = ( $widget == 'categories' ) ? 'categories-1' : $widget;
1274                         } else {
1275                                 $new_widgets[$sidebar] = $widgets;
1276                         }
1277                 }
1278                 if ( $new_widgets != $sidebars_widgets )
1279                         update_option( 'sidebars_widgets', $new_widgets );
1280         }
1281
1282         return $newoptions;
1283 }
1284
1285 /**
1286  * Display recent entries widget.
1287  *
1288  * @since 2.2.0
1289  *
1290  * @param array $args Widget arguments.
1291  * @return int Displayed cache.
1292  */
1293 function wp_widget_recent_entries($args) {
1294         if ( '%BEG_OF_TITLE%' != $args['before_title'] ) {
1295                 if ( $output = wp_cache_get('widget_recent_entries', 'widget') )
1296                         return print($output);
1297                 ob_start();
1298         }
1299
1300         extract($args);
1301         $options = get_option('widget_recent_entries');
1302         $title = empty($options['title']) ? __('Recent Posts') : apply_filters('widget_title', $options['title']);
1303         if ( !$number = (int) $options['number'] )
1304                 $number = 10;
1305         else if ( $number < 1 )
1306                 $number = 1;
1307         else if ( $number > 15 )
1308                 $number = 15;
1309
1310         $r = new WP_Query(array('showposts' => $number, 'what_to_show' => 'posts', 'nopaging' => 0, 'post_status' => 'publish', 'caller_get_posts' => 1));
1311         if ($r->have_posts()) :
1312 ?>
1313                 <?php echo $before_widget; ?>
1314                         <?php echo $before_title . $title . $after_title; ?>
1315                         <ul>
1316                         <?php  while ($r->have_posts()) : $r->the_post(); ?>
1317                         <li><a href="<?php the_permalink() ?>"><?php if ( get_the_title() ) the_title(); else the_ID(); ?> </a></li>
1318                         <?php endwhile; ?>
1319                         </ul>
1320                 <?php echo $after_widget; ?>
1321 <?php
1322                 wp_reset_query();  // Restore global post data stomped by the_post().
1323         endif;
1324
1325         if ( '%BEG_OF_TITLE%' != $args['before_title'] )
1326                 wp_cache_add('widget_recent_entries', ob_get_flush(), 'widget');
1327 }
1328
1329 /**
1330  * Remove recent entries widget items cache.
1331  *
1332  * @since 2.2.0
1333  */
1334 function wp_flush_widget_recent_entries() {
1335         wp_cache_delete('widget_recent_entries', 'widget');
1336 }
1337
1338 add_action('save_post', 'wp_flush_widget_recent_entries');
1339 add_action('deleted_post', 'wp_flush_widget_recent_entries');
1340 add_action('switch_theme', 'wp_flush_widget_recent_entries');
1341
1342 /**
1343  * Display and process recent entries widget options form.
1344  *
1345  * @since 2.2.0
1346  */
1347 function wp_widget_recent_entries_control() {
1348         $options = $newoptions = get_option('widget_recent_entries');
1349         if ( isset($_POST["recent-entries-submit"]) ) {
1350                 $newoptions['title'] = strip_tags(stripslashes($_POST["recent-entries-title"]));
1351                 $newoptions['number'] = (int) $_POST["recent-entries-number"];
1352         }
1353         if ( $options != $newoptions ) {
1354                 $options = $newoptions;
1355                 update_option('widget_recent_entries', $options);
1356                 wp_flush_widget_recent_entries();
1357         }
1358         $title = attribute_escape($options['title']);
1359         if ( !$number = (int) $options['number'] )
1360                 $number = 5;
1361 ?>
1362
1363                         <p><label for="recent-entries-title"><?php _e('Title:'); ?> <input class="widefat" id="recent-entries-title" name="recent-entries-title" type="text" value="<?php echo $title; ?>" /></label></p>
1364                         <p>
1365                                 <label for="recent-entries-number"><?php _e('Number of posts to show:'); ?> <input style="width: 25px; text-align: center;" id="recent-entries-number" name="recent-entries-number" type="text" value="<?php echo $number; ?>" /></label>
1366                                 <br />
1367                                 <small><?php _e('(at most 15)'); ?></small>
1368                         </p>
1369                         <input type="hidden" id="recent-entries-submit" name="recent-entries-submit" value="1" />
1370 <?php
1371 }
1372
1373 /**
1374  * Display recent comments widget.
1375  *
1376  * @since 2.2.0
1377  *
1378  * @param array $args Widget arguments.
1379  */
1380 function wp_widget_recent_comments($args) {
1381         global $wpdb, $comments, $comment;
1382         extract($args, EXTR_SKIP);
1383         $options = get_option('widget_recent_comments');
1384         $title = empty($options['title']) ? __('Recent Comments') : apply_filters('widget_title', $options['title']);
1385         if ( !$number = (int) $options['number'] )
1386                 $number = 5;
1387         else if ( $number < 1 )
1388                 $number = 1;
1389         else if ( $number > 15 )
1390                 $number = 15;
1391
1392         if ( !$comments = wp_cache_get( 'recent_comments', 'widget' ) ) {
1393                 $comments = $wpdb->get_results("SELECT * FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT $number");
1394                 wp_cache_add( 'recent_comments', $comments, 'widget' );
1395         }
1396 ?>
1397
1398                 <?php echo $before_widget; ?>
1399                         <?php echo $before_title . $title . $after_title; ?>
1400                         <ul id="recentcomments"><?php
1401                         if ( $comments ) : foreach ( (array) $comments as $comment) :
1402                         echo  '<li class="recentcomments">' . sprintf(__('%1$s on %2$s'), get_comment_author_link(), '<a href="' . clean_url( get_comment_link($comment->comment_ID) ) . '">' . get_the_title($comment->comment_post_ID) . '</a>') . '</li>';
1403                         endforeach; endif;?></ul>
1404                 <?php echo $after_widget; ?>
1405 <?php
1406 }
1407
1408 /**
1409  * Remove the cache for recent comments widget.
1410  *
1411  * @since 2.2.0
1412  */
1413 function wp_delete_recent_comments_cache() {
1414         wp_cache_delete( 'recent_comments', 'widget' );
1415 }
1416 add_action( 'comment_post', 'wp_delete_recent_comments_cache' );
1417 add_action( 'wp_set_comment_status', 'wp_delete_recent_comments_cache' );
1418
1419 /**
1420  * Display and process recent comments widget options form.
1421  *
1422  * @since 2.2.0
1423  */
1424 function wp_widget_recent_comments_control() {
1425         $options = $newoptions = get_option('widget_recent_comments');
1426         if ( isset($_POST["recent-comments-submit"]) ) {
1427                 $newoptions['title'] = strip_tags(stripslashes($_POST["recent-comments-title"]));
1428                 $newoptions['number'] = (int) $_POST["recent-comments-number"];
1429         }
1430         if ( $options != $newoptions ) {
1431                 $options = $newoptions;
1432                 update_option('widget_recent_comments', $options);
1433                 wp_delete_recent_comments_cache();
1434         }
1435         $title = attribute_escape($options['title']);
1436         if ( !$number = (int) $options['number'] )
1437                 $number = 5;
1438 ?>
1439                         <p><label for="recent-comments-title"><?php _e('Title:'); ?> <input class="widefat" id="recent-comments-title" name="recent-comments-title" type="text" value="<?php echo $title; ?>" /></label></p>
1440                         <p>
1441                                 <label for="recent-comments-number"><?php _e('Number of comments to show:'); ?> <input style="width: 25px; text-align: center;" id="recent-comments-number" name="recent-comments-number" type="text" value="<?php echo $number; ?>" /></label>
1442                                 <br />
1443                                 <small><?php _e('(at most 15)'); ?></small>
1444                         </p>
1445                         <input type="hidden" id="recent-comments-submit" name="recent-comments-submit" value="1" />
1446 <?php
1447 }
1448
1449 /**
1450  * Display the style for recent comments widget.
1451  *
1452  * @since 2.2.0
1453  */
1454 function wp_widget_recent_comments_style() {
1455 ?>
1456 <style type="text/css">.recentcomments a{display:inline !important;padding: 0 !important;margin: 0 !important;}</style>
1457 <?php
1458 }
1459
1460 /**
1461  * Register recent comments with control and hook for 'wp_head' action.
1462  *
1463  * @since 2.2.0
1464  */
1465 function wp_widget_recent_comments_register() {
1466         $widget_ops = array('classname' => 'widget_recent_comments', 'description' => __( 'The most recent comments' ) );
1467         wp_register_sidebar_widget('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments', $widget_ops);
1468         wp_register_widget_control('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments_control');
1469
1470         if ( is_active_widget('wp_widget_recent_comments') )
1471                 add_action('wp_head', 'wp_widget_recent_comments_style');
1472 }
1473
1474 /**
1475  * Display RSS widget.
1476  *
1477  * Allows for multiple widgets to be displayed.
1478  *
1479  * @since 2.2.0
1480  *
1481  * @param array $args Widget arguments.
1482  * @param int $number Widget number.
1483  */
1484 function wp_widget_rss($args, $widget_args = 1) {
1485         extract($args, EXTR_SKIP);
1486         if ( is_numeric($widget_args) )
1487                 $widget_args = array( 'number' => $widget_args );
1488         $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
1489         extract($widget_args, EXTR_SKIP);
1490
1491         $options = get_option('widget_rss');
1492
1493         if ( !isset($options[$number]) )
1494                 return;
1495
1496         if ( isset($options[$number]['error']) && $options[$number]['error'] )
1497                 return;
1498
1499         $url = $options[$number]['url'];
1500         while ( strstr($url, 'http') != $url )
1501                 $url = substr($url, 1);
1502         if ( empty($url) )
1503                 return;
1504
1505         require_once(ABSPATH . WPINC . '/rss.php');
1506
1507         $rss = fetch_rss($url);
1508         $link = clean_url(strip_tags($rss->channel['link']));
1509         while ( strstr($link, 'http') != $link )
1510                 $link = substr($link, 1);
1511         $desc = attribute_escape(strip_tags(html_entity_decode($rss->channel['description'], ENT_QUOTES)));
1512         $title = $options[$number]['title'];
1513         if ( empty($title) )
1514                 $title = htmlentities(strip_tags($rss->channel['title']));
1515         if ( empty($title) )
1516                 $title = $desc;
1517         if ( empty($title) )
1518                 $title = __('Unknown Feed');
1519         $title = apply_filters('widget_title', $title );
1520         $url = clean_url(strip_tags($url));
1521         if ( file_exists(dirname(__FILE__) . '/rss.png') )
1522                 $icon = str_replace(ABSPATH, site_url() . '/', dirname(__FILE__)) . '/rss.png';
1523         else
1524                 $icon = includes_url('images/rss.png');
1525         $title = "<a class='rsswidget' href='$url' title='" . attribute_escape(__('Syndicate this content')) ."'><img style='background:orange;color:white;border:none;' width='14' height='14' src='$icon' alt='RSS' /></a> <a class='rsswidget' href='$link' title='$desc'>$title</a>";
1526
1527         echo $before_widget;
1528         echo $before_title . $title . $after_title;
1529
1530         wp_widget_rss_output( $rss, $options[$number] );
1531
1532         echo $after_widget;
1533 }
1534
1535 /**
1536  * Display the RSS entries in a list.
1537  *
1538  * @since 2.5.0
1539  *
1540  * @param string|array|object $rss RSS url.
1541  * @param array $args Widget arguments.
1542  */
1543 function wp_widget_rss_output( $rss, $args = array() ) {
1544         if ( is_string( $rss ) ) {
1545                 require_once(ABSPATH . WPINC . '/rss.php');
1546                 if ( !$rss = fetch_rss($rss) )
1547                         return;
1548         } elseif ( is_array($rss) && isset($rss['url']) ) {
1549                 require_once(ABSPATH . WPINC . '/rss.php');
1550                 $args = $rss;
1551                 if ( !$rss = fetch_rss($rss['url']) )
1552                         return;
1553         } elseif ( !is_object($rss) ) {
1554                 return;
1555         }
1556
1557         $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0 );
1558         $args = wp_parse_args( $args, $default_args );
1559         extract( $args, EXTR_SKIP );
1560
1561         $items = (int) $items;
1562         if ( $items < 1 || 20 < $items )
1563                 $items = 10;
1564         $show_summary  = (int) $show_summary;
1565         $show_author   = (int) $show_author;
1566         $show_date     = (int) $show_date;
1567
1568         if ( is_array( $rss->items ) && !empty( $rss->items ) ) {
1569                 $rss->items = array_slice($rss->items, 0, $items);
1570                 echo '<ul>';
1571                 foreach ( (array) $rss->items as $item ) {
1572                         while ( strstr($item['link'], 'http') != $item['link'] )
1573                                 $item['link'] = substr($item['link'], 1);
1574                         $link = clean_url(strip_tags($item['link']));
1575                         $title = attribute_escape(strip_tags($item['title']));
1576                         if ( empty($title) )
1577                                 $title = __('Untitled');
1578                         $desc = '';
1579                         if ( isset( $item['description'] ) && is_string( $item['description'] ) )
1580                                 $desc = str_replace(array("\n", "\r"), ' ', attribute_escape(strip_tags(html_entity_decode($item['description'], ENT_QUOTES))));
1581                         elseif ( isset( $item['summary'] ) && is_string( $item['summary'] ) )
1582                                 $desc = str_replace(array("\n", "\r"), ' ', attribute_escape(strip_tags(html_entity_decode($item['summary'], ENT_QUOTES))));
1583                         if ( 360 < strlen( $desc ) )
1584                                 $desc = wp_html_excerpt( $desc, 360 ) . ' [&hellip;]';
1585                         $summary = $desc;
1586
1587                         if ( $show_summary ) {
1588                                 $desc = '';
1589                                 $summary = wp_specialchars( $summary );
1590                                 $summary = "<div class='rssSummary'>$summary</div>";
1591                         } else {
1592                                 $summary = '';
1593                         }
1594
1595                         $date = '';
1596                         if ( $show_date ) {
1597                                 if ( isset($item['pubdate']) )
1598                                         $date = $item['pubdate'];
1599                                 elseif ( isset($item['published']) )
1600                                         $date = $item['published'];
1601
1602                                 if ( $date ) {
1603                                         if ( $date_stamp = strtotime( $date ) )
1604                                                 $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date_stamp ) . '</span>';
1605                                         else
1606                                                 $date = '';
1607                                 }
1608                         }
1609
1610                         $author = '';
1611                         if ( $show_author ) {
1612                                 if ( isset($item['dc']['creator']) )
1613                                         $author = ' <cite>' . wp_specialchars( strip_tags( $item['dc']['creator'] ) ) . '</cite>';
1614                                 elseif ( isset($item['author_name']) )
1615                                         $author = ' <cite>' . wp_specialchars( strip_tags( $item['author_name'] ) ) . '</cite>';
1616                         }
1617
1618                         if ( $link == '' ) {
1619                                 echo "<li>$title{$date}{$summary}{$author}</li>";
1620                         } else {
1621                                 echo "<li><a class='rsswidget' href='$link' title='$desc'>$title</a>{$date}{$summary}{$author}</li>";
1622                         }
1623 }
1624                 echo '</ul>';
1625         } else {
1626                 echo '<ul><li>' . __( 'An error has occurred; the feed is probably down. Try again later.' ) . '</li></ul>';
1627         }
1628 }
1629
1630 /**
1631  * Display and process RSS widget control form.
1632  *
1633  * @since 2.2.0
1634  *
1635  * @param int $widget_args Widget number.
1636  */
1637 function wp_widget_rss_control($widget_args) {
1638         global $wp_registered_widgets;
1639         static $updated = false;
1640
1641         if ( is_numeric($widget_args) )
1642                 $widget_args = array( 'number' => $widget_args );
1643         $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
1644         extract($widget_args, EXTR_SKIP);
1645
1646         $options = get_option('widget_rss');
1647         if ( !is_array($options) )
1648                 $options = array();
1649
1650         $urls = array();
1651         foreach ( (array) $options as $option )
1652                 if ( isset($option['url']) )
1653                         $urls[$option['url']] = true;
1654
1655         if ( !$updated && 'POST' == $_SERVER['REQUEST_METHOD'] && !empty($_POST['sidebar']) ) {
1656                 $sidebar = (string) $_POST['sidebar'];
1657
1658                 $sidebars_widgets = wp_get_sidebars_widgets();
1659                 if ( isset($sidebars_widgets[$sidebar]) )
1660                         $this_sidebar =& $sidebars_widgets[$sidebar];
1661                 else
1662                         $this_sidebar = array();
1663
1664                 foreach ( (array) $this_sidebar as $_widget_id ) {
1665                         if ( 'wp_widget_rss' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
1666                                 $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
1667                                 if ( !in_array( "rss-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed.
1668                                         unset($options[$widget_number]);
1669                         }
1670                 }
1671
1672                 foreach( (array) $_POST['widget-rss'] as $widget_number => $widget_rss ) {
1673                         if ( !isset($widget_rss['url']) && isset($options[$widget_number]) ) // user clicked cancel
1674                                 continue;
1675                         $widget_rss = stripslashes_deep( $widget_rss );
1676                         $url = sanitize_url(strip_tags($widget_rss['url']));
1677                         $options[$widget_number] = wp_widget_rss_process( $widget_rss, !isset($urls[$url]) );
1678                 }
1679
1680                 update_option('widget_rss', $options);
1681                 $updated = true;
1682         }
1683
1684         if ( -1 == $number ) {
1685                 $title = '';
1686                 $url = '';
1687                 $items = 10;
1688                 $error = false;
1689                 $number = '%i%';
1690                 $show_summary = 0;
1691                 $show_author = 0;
1692                 $show_date = 0;
1693         } else {
1694                 extract( (array) $options[$number] );
1695         }
1696
1697         wp_widget_rss_form( compact( 'number', 'title', 'url', 'items', 'error', 'show_summary', 'show_author', 'show_date' ) );
1698 }
1699
1700 /**
1701  * Display RSS widget options form.
1702  *
1703  * The options for what fields are displayed for the RSS form are all booleans
1704  * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
1705  * 'show_date'.
1706  *
1707  * @since 2.5.0
1708  *
1709  * @param array|string $args Values for input fields.
1710  * @param array $inputs Override default display options.
1711  */
1712 function wp_widget_rss_form( $args, $inputs = null ) {
1713
1714         $default_inputs = array( 'url' => true, 'title' => true, 'items' => true, 'show_summary' => true, 'show_author' => true, 'show_date' => true );
1715         $inputs = wp_parse_args( $inputs, $default_inputs );
1716         extract( $args );
1717         extract( $inputs, EXTR_SKIP);
1718
1719         $number = attribute_escape( $number );
1720         $title  = attribute_escape( $title );
1721         $url    = attribute_escape( $url );
1722         $items  = (int) $items;
1723         if ( $items < 1 || 20 < $items )
1724                 $items  = 10;
1725         $show_summary   = (int) $show_summary;
1726         $show_author    = (int) $show_author;
1727         $show_date      = (int) $show_date;
1728
1729         if ( $inputs['url'] ) :
1730 ?>
1731         <p>
1732                 <label for="rss-url-<?php echo $number; ?>"><?php _e('Enter the RSS feed URL here:'); ?>
1733                         <input class="widefat" id="rss-url-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][url]" type="text" value="<?php echo $url; ?>" />
1734                 </label>
1735         </p>
1736 <?php endif; if ( $inputs['title'] ) : ?>
1737         <p>
1738                 <label for="rss-title-<?php echo $number; ?>"><?php _e('Give the feed a title (optional):'); ?>
1739                         <input class="widefat" id="rss-title-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][title]" type="text" value="<?php echo $title; ?>" />
1740                 </label>
1741         </p>
1742 <?php endif; if ( $inputs['items'] ) : ?>
1743         <p>
1744                 <label for="rss-items-<?php echo $number; ?>"><?php _e('How many items would you like to display?'); ?>
1745                         <select id="rss-items-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][items]">
1746                                 <?php
1747                                         for ( $i = 1; $i <= 20; ++$i )
1748                                                 echo "<option value='$i' " . ( $items == $i ? "selected='selected'" : '' ) . ">$i</option>";
1749                                 ?>
1750                         </select>
1751                 </label>
1752         </p>
1753 <?php endif; if ( $inputs['show_summary'] ) : ?>
1754         <p>
1755                 <label for="rss-show-summary-<?php echo $number; ?>">
1756                         <input id="rss-show-summary-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][show_summary]" type="checkbox" value="1" <?php if ( $show_summary ) echo 'checked="checked"'; ?>/>
1757                         <?php _e('Display item content?'); ?>
1758                 </label>
1759         </p>
1760 <?php endif; if ( $inputs['show_author'] ) : ?>
1761         <p>
1762                 <label for="rss-show-author-<?php echo $number; ?>">
1763                         <input id="rss-show-author-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][show_author]" type="checkbox" value="1" <?php if ( $show_author ) echo 'checked="checked"'; ?>/>
1764                         <?php _e('Display item author if available?'); ?>
1765                 </label>
1766         </p>
1767 <?php endif; if ( $inputs['show_date'] ) : ?>
1768         <p>
1769                 <label for="rss-show-date-<?php echo $number; ?>">
1770                         <input id="rss-show-date-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][show_date]" type="checkbox" value="1" <?php if ( $show_date ) echo 'checked="checked"'; ?>/>
1771                         <?php _e('Display item date?'); ?>
1772                 </label>
1773         </p>
1774         <input type="hidden" name="widget-rss[<?php echo $number; ?>][submit]" value="1" />
1775 <?php
1776         endif;
1777         foreach ( array_keys($default_inputs) as $input ) :
1778                 if ( 'hidden' === $inputs[$input] ) :
1779                         $id = str_replace( '_', '-', $input );
1780 ?>
1781         <input type="hidden" id="rss-<?php echo $id; ?>-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][<?php echo $input; ?>]" value="<?php echo $$input; ?>" />
1782 <?php
1783                 endif;
1784         endforeach;
1785 }
1786
1787 /**
1788  * Process RSS feed widget data and optionally retrieve feed items.
1789  *
1790  * The feed widget can not have more than 20 items or it will reset back to the
1791  * default, which is 10.
1792  *
1793  * The resulting array has the feed title, feed url, feed link (from channel),
1794  * feed items, error (if any), and whether to show summary, author, and date.
1795  * All respectively in the order of the array elements.
1796  *
1797  * @since 2.5.0
1798  *
1799  * @param array $widget_rss RSS widget feed data. Expects unescaped data.
1800  * @param bool $check_feed Optional, default is true. Whether to check feed for errors.
1801  * @return array
1802  */
1803 function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
1804         $items = (int) $widget_rss['items'];
1805         if ( $items < 1 || 20 < $items )
1806                 $items = 10;
1807         $url           = sanitize_url(strip_tags( $widget_rss['url'] ));
1808         $title         = trim(strip_tags( $widget_rss['title'] ));
1809         $show_summary  = (int) $widget_rss['show_summary'];
1810         $show_author   = (int) $widget_rss['show_author'];
1811         $show_date     = (int) $widget_rss['show_date'];
1812
1813         if ( $check_feed ) {
1814                 require_once(ABSPATH . WPINC . '/rss.php');
1815                 $rss = fetch_rss($url);
1816                 $error = false;
1817                 $link = '';
1818                 if ( !is_object($rss) ) {
1819                         $url = wp_specialchars(__('Error: could not find an RSS or ATOM feed at that URL.'), 1);
1820                         $error = sprintf(__('Error in RSS %1$d'), $widget_number );
1821                 } else {
1822                         $link = clean_url(strip_tags($rss->channel['link']));
1823                         while ( strstr($link, 'http') != $link )
1824                                 $link = substr($link, 1);
1825                 }
1826         }
1827
1828         return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
1829 }
1830
1831 /**
1832  * Register RSS widget to allow multiple RSS widgets on startup.
1833  *
1834  * @since 2.2.0
1835  */
1836 function wp_widget_rss_register() {
1837         if ( !$options = get_option('widget_rss') )
1838                 $options = array();
1839         $widget_ops = array('classname' => 'widget_rss', 'description' => __( 'Entries from any RSS or Atom feed' ));
1840         $control_ops = array('width' => 400, 'height' => 200, 'id_base' => 'rss');
1841         $name = __('RSS');
1842
1843         $id = false;
1844         foreach ( (array) array_keys($options) as $o ) {
1845                 // Old widgets can have null values for some reason
1846                 if ( !isset($options[$o]['url']) || !isset($options[$o]['title']) || !isset($options[$o]['items']) )
1847                         continue;
1848                 $id = "rss-$o"; // Never never never translate an id
1849                 wp_register_sidebar_widget($id, $name, 'wp_widget_rss', $widget_ops, array( 'number' => $o ));
1850                 wp_register_widget_control($id, $name, 'wp_widget_rss_control', $control_ops, array( 'number' => $o ));
1851         }
1852
1853         // If there are none, we register the widget's existance with a generic template
1854         if ( !$id ) {
1855                 wp_register_sidebar_widget( 'rss-1', $name, 'wp_widget_rss', $widget_ops, array( 'number' => -1 ) );
1856                 wp_register_widget_control( 'rss-1', $name, 'wp_widget_rss_control', $control_ops, array( 'number' => -1 ) );
1857         }
1858 }
1859
1860 /**
1861  * Display tag cloud widget.
1862  *
1863  * @since 2.3.0
1864  *
1865  * @param array $args Widget arguments.
1866  */
1867 function wp_widget_tag_cloud($args) {
1868         extract($args);
1869         $options = get_option('widget_tag_cloud');
1870         $title = empty($options['title']) ? __('Tags') : apply_filters('widget_title', $options['title']);
1871
1872         echo $before_widget;
1873         echo $before_title . $title . $after_title;
1874         wp_tag_cloud();
1875         echo $after_widget;
1876 }
1877
1878 /**
1879  * Manage WordPress Tag Cloud widget options.
1880  *
1881  * Displays management form for changing the tag cloud widget title.
1882  *
1883  * @since 2.3.0
1884  */
1885 function wp_widget_tag_cloud_control() {
1886         $options = $newoptions = get_option('widget_tag_cloud');
1887
1888         if ( isset($_POST['tag-cloud-submit']) ) {
1889                 $newoptions['title'] = strip_tags(stripslashes($_POST['tag-cloud-title']));
1890         }
1891
1892         if ( $options != $newoptions ) {
1893                 $options = $newoptions;
1894                 update_option('widget_tag_cloud', $options);
1895         }
1896
1897         $title = attribute_escape( $options['title'] );
1898 ?>
1899         <p><label for="tag-cloud-title">
1900         <?php _e('Title:') ?> <input type="text" class="widefat" id="tag-cloud-title" name="tag-cloud-title" value="<?php echo $title ?>" /></label>
1901         </p>
1902         <input type="hidden" name="tag-cloud-submit" id="tag-cloud-submit" value="1" />
1903 <?php
1904 }
1905
1906 /**
1907  * Register all of the default WordPress widgets on startup.
1908  *
1909  * Calls 'widgets_init' action after all of the WordPress widgets have been
1910  * registered.
1911  *
1912  * @since 2.2.0
1913  */
1914 function wp_widgets_init() {
1915         if ( !is_blog_installed() )
1916                 return;
1917
1918         $widget_ops = array('classname' => 'widget_pages', 'description' => __( "Your blog's WordPress Pages") );
1919         wp_register_sidebar_widget('pages', __('Pages'), 'wp_widget_pages', $widget_ops);
1920         wp_register_widget_control('pages', __('Pages'), 'wp_widget_pages_control' );
1921
1922         $widget_ops = array('classname' => 'widget_calendar', 'description' => __( "A calendar of your blog's posts") );
1923         wp_register_sidebar_widget('calendar', __('Calendar'), 'wp_widget_calendar', $widget_ops);
1924         wp_register_widget_control('calendar', __('Calendar'), 'wp_widget_calendar_control' );
1925
1926         $widget_ops = array('classname' => 'widget_archive', 'description' => __( "A monthly archive of your blog's posts") );
1927         wp_register_sidebar_widget('archives', __('Archives'), 'wp_widget_archives', $widget_ops);
1928         wp_register_widget_control('archives', __('Archives'), 'wp_widget_archives_control' );
1929
1930         $widget_ops = array('classname' => 'widget_links', 'description' => __( "Your blogroll") );
1931         wp_register_sidebar_widget('links', __('Links'), 'wp_widget_links', $widget_ops);
1932
1933         $widget_ops = array('classname' => 'widget_meta', 'description' => __( "Log in/out, admin, feed and WordPress links") );
1934         wp_register_sidebar_widget('meta', __('Meta'), 'wp_widget_meta', $widget_ops);
1935         wp_register_widget_control('meta', __('Meta'), 'wp_widget_meta_control' );
1936
1937         $widget_ops = array('classname' => 'widget_search', 'description' => __( "A search form for your blog") );
1938         wp_register_sidebar_widget('search', __('Search'), 'wp_widget_search', $widget_ops);
1939
1940         $widget_ops = array('classname' => 'widget_recent_entries', 'description' => __( "The most recent posts on your blog") );
1941         wp_register_sidebar_widget('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries', $widget_ops);
1942         wp_register_widget_control('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries_control' );
1943
1944         $widget_ops = array('classname' => 'widget_tag_cloud', 'description' => __( "Your most used tags in cloud format") );
1945         wp_register_sidebar_widget('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud', $widget_ops);
1946         wp_register_widget_control('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud_control' );
1947
1948         wp_widget_categories_register();
1949         wp_widget_text_register();
1950         wp_widget_rss_register();
1951         wp_widget_recent_comments_register();
1952
1953         do_action('widgets_init');
1954 }
1955
1956 add_action('init', 'wp_widgets_init', 1);
1957
1958 /*
1959  * Pattern for multi-widget (allows multiple instances such as the text widget).
1960  *
1961  * Make sure to close the comments after copying.
1962
1963 /**
1964  * Displays widget.
1965  *
1966  * Supports multiple widgets.
1967  *
1968  * @param array $args Widget arguments.
1969  * @param array|int $widget_args Widget number. Which of the several widgets of this type do we mean.
1970  * /
1971 function widget_many( $args, $widget_args = 1 ) {
1972         extract( $args, EXTR_SKIP );
1973         if ( is_numeric($widget_args) )
1974                 $widget_args = array( 'number' => $widget_args );
1975         $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
1976         extract( $widget_args, EXTR_SKIP );
1977
1978         // Data should be stored as array:  array( number => data for that instance of the widget, ... )
1979         $options = get_option('widget_many');
1980         if ( !isset($options[$number]) )
1981                 return;
1982
1983         echo $before_widget;
1984
1985         // Do stuff for this widget, drawing data from $options[$number]
1986
1987         echo $after_widget;
1988 }
1989
1990 /**
1991  * Displays form for a particular instance of the widget.
1992  *
1993  * Also updates the data after a POST submit.
1994  *
1995  * @param array|int $widget_args Widget number. Which of the several widgets of this type do we mean.
1996  * /
1997 function widget_many_control( $widget_args = 1 ) {
1998         global $wp_registered_widgets;
1999         static $updated = false; // Whether or not we have already updated the data after a POST submit
2000
2001         if ( is_numeric($widget_args) )
2002                 $widget_args = array( 'number' => $widget_args );
2003         $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
2004         extract( $widget_args, EXTR_SKIP );
2005
2006         // Data should be stored as array:  array( number => data for that instance of the widget, ... )
2007         $options = get_option('widget_many');
2008         if ( !is_array($options) )
2009                 $options = array();
2010
2011         // We need to update the data
2012         if ( !$updated && !empty($_POST['sidebar']) ) {
2013                 // Tells us what sidebar to put the data in
2014                 $sidebar = (string) $_POST['sidebar'];
2015
2016                 $sidebars_widgets = wp_get_sidebars_widgets();
2017                 if ( isset($sidebars_widgets[$sidebar]) )
2018                         $this_sidebar =& $sidebars_widgets[$sidebar];
2019                 else
2020                         $this_sidebar = array();
2021
2022                 foreach ( $this_sidebar as $_widget_id ) {
2023                         // 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
2024                         // since widget ids aren't necessarily persistent across multiple updates
2025                         if ( 'widget_many' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
2026                                 $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
2027                                 if ( !in_array( "many-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed. "many-$widget_number" is "{id_base}-{widget_number}
2028                                         unset($options[$widget_number]);
2029                         }
2030                 }
2031
2032                 foreach ( (array) $_POST['widget-many'] as $widget_number => $widget_many_instance ) {
2033                         // compile data from $widget_many_instance
2034                         if ( !isset($widget_many_instance['something']) && isset($options[$widget_number]) ) // user clicked cancel
2035                                 continue;
2036                         $something = wp_specialchars( $widget_many_instance['something'] );
2037                         $options[$widget_number] = array( 'something' => $something );  // Even simple widgets should store stuff in array, rather than in scalar
2038                 }
2039
2040                 update_option('widget_many', $options);
2041
2042                 $updated = true; // So that we don't go through this more than once
2043         }
2044
2045
2046         // Here we echo out the form
2047         if ( -1 == $number ) { // We echo out a template for a form which can be converted to a specific form later via JS
2048                 $something = '';
2049                 $number = '%i%';
2050         } else {
2051                 $something = attribute_escape($options[$number]['something']);
2052         }
2053
2054         // The form has inputs with names like widget-many[$number][something] so that all data for that instance of
2055         // the widget are stored in one $_POST variable: $_POST['widget-many'][$number]
2056 ?>
2057                 <p>
2058                         <input class="widefat" id="widget-many-something-<?php echo $number; ?>" name="widget-many[<?php echo $number; ?>][something]" type="text" value="<?php echo $data; ?>" />
2059                         <input type="hidden" id="widget-many-submit-<?php echo $number; ?>" name="widget-many[<?php echo $number; ?>][submit]" value="1" />
2060                 </p>
2061 <?php
2062 }
2063
2064 /**
2065  * Registers each instance of our widget on startup.
2066  * /
2067 function widget_many_register() {
2068         if ( !$options = get_option('widget_many') )
2069                 $options = array();
2070
2071         $widget_ops = array('classname' => 'widget_many', 'description' => __('Widget which allows multiple instances'));
2072         $control_ops = array('width' => 400, 'height' => 350, 'id_base' => 'many');
2073         $name = __('Many');
2074
2075         $registered = false;
2076         foreach ( array_keys($options) as $o ) {
2077                 // Old widgets can have null values for some reason
2078                 if ( !isset($options[$o]['something']) ) // we used 'something' above in our exampple.  Replace with with whatever your real data are.
2079                         continue;
2080
2081                 // $id should look like {$id_base}-{$o}
2082                 $id = "many-$o"; // Never never never translate an id
2083                 $registered = true;
2084                 wp_register_sidebar_widget( $id, $name, 'widget_many', $widget_ops, array( 'number' => $o ) );
2085                 wp_register_widget_control( $id, $name, 'widget_many_control', $control_ops, array( 'number' => $o ) );
2086         }
2087
2088         // If there are none, we register the widget's existance with a generic template
2089         if ( !$registered ) {
2090                 wp_register_sidebar_widget( 'many-1', $name, 'widget_many', $widget_ops, array( 'number' => -1 ) );
2091                 wp_register_widget_control( 'many-1', $name, 'widget_many_control', $control_ops, array( 'number' => -1 ) );
2092         }
2093 }
2094
2095 // This is important
2096 add_action( 'widgets_init', 'widget_many_register' );
2097
2098 */
2099
2100 ?>