WordPress 4.7
[autoinstalls/wordpress.git] / wp-includes / widgets.php
1 <?php
2 /**
3  * Core Widgets API
4  *
5  * This API is used for creating dynamic sidebar without hardcoding functionality into
6  * themes
7  *
8  * Includes both internal WordPress routines and theme-use routines.
9  *
10  * This functionality was found in a plugin before the WordPress 2.2 release, which
11  * included it in the core from that point on.
12  *
13  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
14  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
15  *
16  * @package WordPress
17  * @subpackage Widgets
18  * @since 2.2.0
19  */
20
21 //
22 // Global Variables
23 //
24
25 /** @ignore */
26 global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
27
28 /**
29  * Stores the sidebars, since many themes can have more than one.
30  *
31  * @global array $wp_registered_sidebars
32  * @since 2.2.0
33  */
34 $wp_registered_sidebars = array();
35
36 /**
37  * Stores the registered widgets.
38  *
39  * @global array $wp_registered_widgets
40  * @since 2.2.0
41  */
42 $wp_registered_widgets = array();
43
44 /**
45  * Stores the registered widget control (options).
46  *
47  * @global array $wp_registered_widget_controls
48  * @since 2.2.0
49  */
50 $wp_registered_widget_controls = array();
51 /**
52  * @global array $wp_registered_widget_updates
53  */
54 $wp_registered_widget_updates = array();
55
56 /**
57  * Private
58  *
59  * @global array $_wp_sidebars_widgets
60  */
61 $_wp_sidebars_widgets = array();
62
63 /**
64  * Private
65  *
66  * @global array $_wp_deprecated_widgets_callbacks
67  */
68 $GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
69         'wp_widget_pages',
70         'wp_widget_pages_control',
71         'wp_widget_calendar',
72         'wp_widget_calendar_control',
73         'wp_widget_archives',
74         'wp_widget_archives_control',
75         'wp_widget_links',
76         'wp_widget_meta',
77         'wp_widget_meta_control',
78         'wp_widget_search',
79         'wp_widget_recent_entries',
80         'wp_widget_recent_entries_control',
81         'wp_widget_tag_cloud',
82         'wp_widget_tag_cloud_control',
83         'wp_widget_categories',
84         'wp_widget_categories_control',
85         'wp_widget_text',
86         'wp_widget_text_control',
87         'wp_widget_rss',
88         'wp_widget_rss_control',
89         'wp_widget_recent_comments',
90         'wp_widget_recent_comments_control'
91 );
92
93 //
94 // Template tags & API functions
95 //
96
97 /**
98  * Register a widget
99  *
100  * Registers a WP_Widget widget
101  *
102  * @since 2.8.0
103  *
104  * @see WP_Widget
105  *
106  * @global WP_Widget_Factory $wp_widget_factory
107  *
108  * @param string $widget_class The name of a class that extends WP_Widget
109  */
110 function register_widget($widget_class) {
111         global $wp_widget_factory;
112
113         $wp_widget_factory->register($widget_class);
114 }
115
116 /**
117  * Unregisters a widget.
118  *
119  * Unregisters a WP_Widget widget. Useful for un-registering default widgets.
120  * Run within a function hooked to the {@see 'widgets_init'} action.
121  *
122  * @since 2.8.0
123  *
124  * @see WP_Widget
125  *
126  * @global WP_Widget_Factory $wp_widget_factory
127  *
128  * @param string $widget_class The name of a class that extends WP_Widget.
129  */
130 function unregister_widget($widget_class) {
131         global $wp_widget_factory;
132
133         $wp_widget_factory->unregister($widget_class);
134 }
135
136 /**
137  * Creates multiple sidebars.
138  *
139  * If you wanted to quickly create multiple sidebars for a theme or internally.
140  * This function will allow you to do so. If you don't pass the 'name' and/or
141  * 'id' in `$args`, then they will be built for you.
142  *
143  * @since 2.2.0
144  *
145  * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
146  *
147  * @global array $wp_registered_sidebars
148  *
149  * @param int          $number Optional. Number of sidebars to create. Default 1.
150  * @param array|string $args {
151  *     Optional. Array or string of arguments for building a sidebar.
152  *
153  *     @type string $id   The base string of the unique identifier for each sidebar. If provided, and multiple
154  *                        sidebars are being defined, the id will have "-2" appended, and so on.
155  *                        Default 'sidebar-' followed by the number the sidebar creation is currently at.
156  *     @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering
157  *                        more than one sidebar, include '%d' in the string as a placeholder for the uniquely
158  *                        assigned number for each sidebar.
159  *                        Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'.
160  * }
161  */
162 function register_sidebars( $number = 1, $args = array() ) {
163         global $wp_registered_sidebars;
164         $number = (int) $number;
165
166         if ( is_string($args) )
167                 parse_str($args, $args);
168
169         for ( $i = 1; $i <= $number; $i++ ) {
170                 $_args = $args;
171
172                 if ( $number > 1 )
173                         $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i);
174                 else
175                         $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar');
176
177                 // Custom specified ID's are suffixed if they exist already.
178                 // Automatically generated sidebar names need to be suffixed regardless starting at -0
179                 if ( isset($args['id']) ) {
180                         $_args['id'] = $args['id'];
181                         $n = 2; // Start at -2 for conflicting custom ID's
182                         while ( is_registered_sidebar( $_args['id'] ) ) {
183                                 $_args['id'] = $args['id'] . '-' . $n++;
184                         }
185                 } else {
186                         $n = count( $wp_registered_sidebars );
187                         do {
188                                 $_args['id'] = 'sidebar-' . ++$n;
189                         } while ( is_registered_sidebar( $_args['id'] ) );
190                 }
191                 register_sidebar($_args);
192         }
193 }
194
195 /**
196  * Builds the definition for a single sidebar and returns the ID.
197  *
198  * Accepts either a string or an array and then parses that against a set
199  * of default arguments for the new sidebar. WordPress will automatically
200  * generate a sidebar ID and name based on the current number of registered
201  * sidebars if those arguments are not included.
202  *
203  * When allowing for automatic generation of the name and ID parameters, keep
204  * in mind that the incrementor for your sidebar can change over time depending
205  * on what other plugins and themes are installed.
206  *
207  * If theme support for 'widgets' has not yet been added when this function is
208  * called, it will be automatically enabled through the use of add_theme_support()
209  *
210  * @since 2.2.0
211  *
212  * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
213  *
214  * @param array|string $args {
215  *     Optional. Array or string of arguments for the sidebar being registered.
216  *
217  *     @type string $name          The name or title of the sidebar displayed in the Widgets
218  *                                 interface. Default 'Sidebar $instance'.
219  *     @type string $id            The unique identifier by which the sidebar will be called.
220  *                                 Default 'sidebar-$instance'.
221  *     @type string $description   Description of the sidebar, displayed in the Widgets interface.
222  *                                 Default empty string.
223  *     @type string $class         Extra CSS class to assign to the sidebar in the Widgets interface.
224  *                                 Default empty.
225  *     @type string $before_widget HTML content to prepend to each widget's HTML output when
226  *                                 assigned to this sidebar. Default is an opening list item element.
227  *     @type string $after_widget  HTML content to append to each widget's HTML output when
228  *                                 assigned to this sidebar. Default is a closing list item element.
229  *     @type string $before_title  HTML content to prepend to the sidebar title when displayed.
230  *                                 Default is an opening h2 element.
231  *     @type string $after_title   HTML content to append to the sidebar title when displayed.
232  *                                 Default is a closing h2 element.
233  * }
234  * @return string Sidebar ID added to $wp_registered_sidebars global.
235  */
236 function register_sidebar($args = array()) {
237         global $wp_registered_sidebars;
238
239         $i = count($wp_registered_sidebars) + 1;
240
241         $id_is_empty = empty( $args['id'] );
242
243         $defaults = array(
244                 'name' => sprintf(__('Sidebar %d'), $i ),
245                 'id' => "sidebar-$i",
246                 'description' => '',
247                 'class' => '',
248                 'before_widget' => '<li id="%1$s" class="widget %2$s">',
249                 'after_widget' => "</li>\n",
250                 'before_title' => '<h2 class="widgettitle">',
251                 'after_title' => "</h2>\n",
252         );
253
254         $sidebar = wp_parse_args( $args, $defaults );
255
256         if ( $id_is_empty ) {
257                 /* translators: 1: the id argument, 2: sidebar name, 3: recommended id value */
258                 _doing_it_wrong( __FUNCTION__, sprintf( __( 'No %1$s was set in the arguments array for the "%2$s" sidebar. Defaulting to "%3$s". Manually set the %1$s to "%3$s" to silence this notice and keep existing sidebar content.' ), '<code>id</code>', $sidebar['name'], $sidebar['id'] ), '4.2.0' );
259         }
260
261         $wp_registered_sidebars[$sidebar['id']] = $sidebar;
262
263         add_theme_support('widgets');
264
265         /**
266          * Fires once a sidebar has been registered.
267          *
268          * @since 3.0.0
269          *
270          * @param array $sidebar Parsed arguments for the registered sidebar.
271          */
272         do_action( 'register_sidebar', $sidebar );
273
274         return $sidebar['id'];
275 }
276
277 /**
278  * Removes a sidebar from the list.
279  *
280  * @since 2.2.0
281  *
282  * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
283  *
284  * @param string $name The ID of the sidebar when it was added.
285  */
286 function unregister_sidebar( $name ) {
287         global $wp_registered_sidebars;
288
289         unset( $wp_registered_sidebars[ $name ] );
290 }
291
292 /**
293  * Checks if a sidebar is registered.
294  *
295  * @since 4.4.0
296  *
297  * @global array $wp_registered_sidebars Registered sidebars.
298  *
299  * @param string|int $sidebar_id The ID of the sidebar when it was registered.
300  * @return bool True if the sidebar is registered, false otherwise.
301  */
302 function is_registered_sidebar( $sidebar_id ) {
303         global $wp_registered_sidebars;
304
305         return isset( $wp_registered_sidebars[ $sidebar_id ] );
306 }
307
308 /**
309  * Register an instance of a widget.
310  *
311  * The default widget option is 'classname' that can be overridden.
312  *
313  * The function can also be used to un-register widgets when `$output_callback`
314  * parameter is an empty string.
315  *
316  * @since 2.2.0
317  *
318  * @global array $wp_registered_widgets       Uses stored registered widgets.
319  * @global array $wp_register_widget_defaults Retrieves widget defaults.
320  * @global array $wp_registered_widget_updates
321  * @global array $_wp_deprecated_widgets_callbacks
322  *
323  * @param int|string $id              Widget ID.
324  * @param string     $name            Widget display title.
325  * @param callable   $output_callback Run when widget is called.
326  * @param array      $options {
327  *     Optional. An array of supplementary widget options for the instance.
328  *
329  *     @type string $classname   Class name for the widget's HTML container. Default is a shortened
330  *                               version of the output callback name.
331  *     @type string $description Widget description for display in the widget administration
332  *                               panel and/or theme.
333  * }
334  */
335 function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array() ) {
336         global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
337
338         $id = strtolower($id);
339
340         if ( empty($output_callback) ) {
341                 unset($wp_registered_widgets[$id]);
342                 return;
343         }
344
345         $id_base = _get_widget_id_base($id);
346         if ( in_array($output_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($output_callback) ) {
347                 unset( $wp_registered_widget_controls[ $id ] );
348                 unset( $wp_registered_widget_updates[ $id_base ] );
349                 return;
350         }
351
352         $defaults = array('classname' => $output_callback);
353         $options = wp_parse_args($options, $defaults);
354         $widget = array(
355                 'name' => $name,
356                 'id' => $id,
357                 'callback' => $output_callback,
358                 'params' => array_slice(func_get_args(), 4)
359         );
360         $widget = array_merge($widget, $options);
361
362         if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) ) {
363
364                 /**
365                  * Fires once for each registered widget.
366                  *
367                  * @since 3.0.0
368                  *
369                  * @param array $widget An array of default widget arguments.
370                  */
371                 do_action( 'wp_register_sidebar_widget', $widget );
372                 $wp_registered_widgets[$id] = $widget;
373         }
374 }
375
376 /**
377  * Retrieve description for widget.
378  *
379  * When registering widgets, the options can also include 'description' that
380  * describes the widget for display on the widget administration panel or
381  * in the theme.
382  *
383  * @since 2.5.0
384  *
385  * @global array $wp_registered_widgets
386  *
387  * @param int|string $id Widget ID.
388  * @return string|void Widget description, if available.
389  */
390 function wp_widget_description( $id ) {
391         if ( !is_scalar($id) )
392                 return;
393
394         global $wp_registered_widgets;
395
396         if ( isset($wp_registered_widgets[$id]['description']) )
397                 return esc_html( $wp_registered_widgets[$id]['description'] );
398 }
399
400 /**
401  * Retrieve description for a sidebar.
402  *
403  * When registering sidebars a 'description' parameter can be included that
404  * describes the sidebar for display on the widget administration panel.
405  *
406  * @since 2.9.0
407  *
408  * @global array $wp_registered_sidebars
409  *
410  * @param string $id sidebar ID.
411  * @return string|void Sidebar description, if available.
412  */
413 function wp_sidebar_description( $id ) {
414         if ( !is_scalar($id) )
415                 return;
416
417         global $wp_registered_sidebars;
418
419         if ( isset($wp_registered_sidebars[$id]['description']) )
420                 return esc_html( $wp_registered_sidebars[$id]['description'] );
421 }
422
423 /**
424  * Remove widget from sidebar.
425  *
426  * @since 2.2.0
427  *
428  * @param int|string $id Widget ID.
429  */
430 function wp_unregister_sidebar_widget($id) {
431
432         /**
433          * Fires just before a widget is removed from a sidebar.
434          *
435          * @since 3.0.0
436          *
437          * @param int $id The widget ID.
438          */
439         do_action( 'wp_unregister_sidebar_widget', $id );
440
441         wp_register_sidebar_widget($id, '', '');
442         wp_unregister_widget_control($id);
443 }
444
445 /**
446  * Registers widget control callback for customizing options.
447  *
448  * @since 2.2.0
449  *
450  * @todo `$params` parameter?
451  *
452  * @global array $wp_registered_widget_controls
453  * @global array $wp_registered_widget_updates
454  * @global array $wp_registered_widgets
455  * @global array $_wp_deprecated_widgets_callbacks
456  *
457  * @param int|string   $id               Sidebar ID.
458  * @param string       $name             Sidebar display name.
459  * @param callable     $control_callback Run when sidebar is displayed.
460  * @param array $options {
461  *     Optional. Array or string of control options. Default empty array.
462  *
463  *     @type int        $height  Never used. Default 200.
464  *     @type int        $width   Width of the fully expanded control form (but try hard to use the default width).
465  *                               Default 250.
466  *     @type int|string $id_base Required for multi-widgets, i.e widgets that allow multiple instances such as the
467  *                               text widget. The widget id will end up looking like `{$id_base}-{$unique_number}`.
468  * }
469  */
470 function wp_register_widget_control( $id, $name, $control_callback, $options = array() ) {
471         global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
472
473         $id = strtolower($id);
474         $id_base = _get_widget_id_base($id);
475
476         if ( empty($control_callback) ) {
477                 unset($wp_registered_widget_controls[$id]);
478                 unset($wp_registered_widget_updates[$id_base]);
479                 return;
480         }
481
482         if ( in_array($control_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($control_callback) ) {
483                 unset( $wp_registered_widgets[ $id ] );
484                 return;
485         }
486
487         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
488                 return;
489
490         $defaults = array('width' => 250, 'height' => 200 ); // height is never used
491         $options = wp_parse_args($options, $defaults);
492         $options['width'] = (int) $options['width'];
493         $options['height'] = (int) $options['height'];
494
495         $widget = array(
496                 'name' => $name,
497                 'id' => $id,
498                 'callback' => $control_callback,
499                 'params' => array_slice(func_get_args(), 4)
500         );
501         $widget = array_merge($widget, $options);
502
503         $wp_registered_widget_controls[$id] = $widget;
504
505         if ( isset($wp_registered_widget_updates[$id_base]) )
506                 return;
507
508         if ( isset($widget['params'][0]['number']) )
509                 $widget['params'][0]['number'] = -1;
510
511         unset($widget['width'], $widget['height'], $widget['name'], $widget['id']);
512         $wp_registered_widget_updates[$id_base] = $widget;
513 }
514
515 /**
516  * Registers the update callback for a widget.
517  *
518  * @since 2.8.0
519  *
520  * @global array $wp_registered_widget_updates
521  *
522  * @param string   $id_base         The base ID of a widget created by extending WP_Widget.
523  * @param callable $update_callback Update callback method for the widget.
524  * @param array    $options         Optional. Widget control options. See wp_register_widget_control().
525  *                                  Default empty array.
526  */
527 function _register_widget_update_callback( $id_base, $update_callback, $options = array() ) {
528         global $wp_registered_widget_updates;
529
530         if ( isset($wp_registered_widget_updates[$id_base]) ) {
531                 if ( empty($update_callback) )
532                         unset($wp_registered_widget_updates[$id_base]);
533                 return;
534         }
535
536         $widget = array(
537                 'callback' => $update_callback,
538                 'params' => array_slice(func_get_args(), 3)
539         );
540
541         $widget = array_merge($widget, $options);
542         $wp_registered_widget_updates[$id_base] = $widget;
543 }
544
545 /**
546  * Registers the form callback for a widget.
547  *
548  * @since 2.8.0
549  *
550  * @global array $wp_registered_widget_controls
551  *
552  * @param int|string $id            Widget ID.
553  * @param string     $name          Name attribute for the widget.
554  * @param callable   $form_callback Form callback.
555  * @param array      $options       Optional. Widget control options. See wp_register_widget_control().
556  *                                  Default empty array.
557  */
558 function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
559         global $wp_registered_widget_controls;
560
561         $id = strtolower($id);
562
563         if ( empty($form_callback) ) {
564                 unset($wp_registered_widget_controls[$id]);
565                 return;
566         }
567
568         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
569                 return;
570
571         $defaults = array('width' => 250, 'height' => 200 );
572         $options = wp_parse_args($options, $defaults);
573         $options['width'] = (int) $options['width'];
574         $options['height'] = (int) $options['height'];
575
576         $widget = array(
577                 'name' => $name,
578                 'id' => $id,
579                 'callback' => $form_callback,
580                 'params' => array_slice(func_get_args(), 4)
581         );
582         $widget = array_merge($widget, $options);
583
584         $wp_registered_widget_controls[$id] = $widget;
585 }
586
587 /**
588  * Remove control callback for widget.
589  *
590  * @since 2.2.0
591  *
592  * @param int|string $id Widget ID.
593  */
594 function wp_unregister_widget_control($id) {
595         wp_register_widget_control( $id, '', '' );
596 }
597
598 /**
599  * Display dynamic sidebar.
600  *
601  * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
602  * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
603  * Otherwise, you can pass in a numerical index to display the sidebar at that index.
604  *
605  * @since 2.2.0
606  *
607  * @global array $wp_registered_sidebars
608  * @global array $wp_registered_widgets
609  *
610  * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
611  * @return bool True, if widget sidebar was found and called. False if not found or not called.
612  */
613 function dynamic_sidebar( $index = 1 ) {
614         global $wp_registered_sidebars, $wp_registered_widgets;
615
616         if ( is_int( $index ) ) {
617                 $index = "sidebar-$index";
618         } else {
619                 $index = sanitize_title( $index );
620                 foreach ( (array) $wp_registered_sidebars as $key => $value ) {
621                         if ( sanitize_title( $value['name'] ) == $index ) {
622                                 $index = $key;
623                                 break;
624                         }
625                 }
626         }
627
628         $sidebars_widgets = wp_get_sidebars_widgets();
629         if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
630                 /** This action is documented in wp-includes/widget.php */
631                 do_action( 'dynamic_sidebar_before', $index, false );
632                 /** This action is documented in wp-includes/widget.php */
633                 do_action( 'dynamic_sidebar_after',  $index, false );
634                 /** This filter is documented in wp-includes/widget.php */
635                 return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
636         }
637
638         /**
639          * Fires before widgets are rendered in a dynamic sidebar.
640          *
641          * Note: The action also fires for empty sidebars, and on both the front end
642          * and back end, including the Inactive Widgets sidebar on the Widgets screen.
643          *
644          * @since 3.9.0
645          *
646          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
647          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
648          *                                Default true.
649          */
650         do_action( 'dynamic_sidebar_before', $index, true );
651         $sidebar = $wp_registered_sidebars[$index];
652
653         $did_one = false;
654         foreach ( (array) $sidebars_widgets[$index] as $id ) {
655
656                 if ( !isset($wp_registered_widgets[$id]) ) continue;
657
658                 $params = array_merge(
659                         array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
660                         (array) $wp_registered_widgets[$id]['params']
661                 );
662
663                 // Substitute HTML id and class attributes into before_widget
664                 $classname_ = '';
665                 foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
666                         if ( is_string($cn) )
667                                 $classname_ .= '_' . $cn;
668                         elseif ( is_object($cn) )
669                                 $classname_ .= '_' . get_class($cn);
670                 }
671                 $classname_ = ltrim($classname_, '_');
672                 $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
673
674                 /**
675                  * Filters the parameters passed to a widget's display callback.
676                  *
677                  * Note: The filter is evaluated on both the front end and back end,
678                  * including for the Inactive Widgets sidebar on the Widgets screen.
679                  *
680                  * @since 2.5.0
681                  *
682                  * @see register_sidebar()
683                  *
684                  * @param array $params {
685                  *     @type array $args  {
686                  *         An array of widget display arguments.
687                  *
688                  *         @type string $name          Name of the sidebar the widget is assigned to.
689                  *         @type string $id            ID of the sidebar the widget is assigned to.
690                  *         @type string $description   The sidebar description.
691                  *         @type string $class         CSS class applied to the sidebar container.
692                  *         @type string $before_widget HTML markup to prepend to each widget in the sidebar.
693                  *         @type string $after_widget  HTML markup to append to each widget in the sidebar.
694                  *         @type string $before_title  HTML markup to prepend to the widget title when displayed.
695                  *         @type string $after_title   HTML markup to append to the widget title when displayed.
696                  *         @type string $widget_id     ID of the widget.
697                  *         @type string $widget_name   Name of the widget.
698                  *     }
699                  *     @type array $widget_args {
700                  *         An array of multi-widget arguments.
701                  *
702                  *         @type int $number Number increment used for multiples of the same widget.
703                  *     }
704                  * }
705                  */
706                 $params = apply_filters( 'dynamic_sidebar_params', $params );
707
708                 $callback = $wp_registered_widgets[$id]['callback'];
709
710                 /**
711                  * Fires before a widget's display callback is called.
712                  *
713                  * Note: The action fires on both the front end and back end, including
714                  * for widgets in the Inactive Widgets sidebar on the Widgets screen.
715                  *
716                  * The action is not fired for empty sidebars.
717                  *
718                  * @since 3.0.0
719                  *
720                  * @param array $widget_id {
721                  *     An associative array of widget arguments.
722                  *
723                  *     @type string $name                Name of the widget.
724                  *     @type string $id                  Widget ID.
725                  *     @type array|callable $callback    When the hook is fired on the front end, $callback is an array
726                  *                                       containing the widget object. Fired on the back end, $callback
727                  *                                       is 'wp_widget_control', see $_callback.
728                  *     @type array          $params      An associative array of multi-widget arguments.
729                  *     @type string         $classname   CSS class applied to the widget container.
730                  *     @type string         $description The widget description.
731                  *     @type array          $_callback   When the hook is fired on the back end, $_callback is populated
732                  *                                       with an array containing the widget object, see $callback.
733                  * }
734                  */
735                 do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
736
737                 if ( is_callable($callback) ) {
738                         call_user_func_array($callback, $params);
739                         $did_one = true;
740                 }
741         }
742
743         /**
744          * Fires after widgets are rendered in a dynamic sidebar.
745          *
746          * Note: The action also fires for empty sidebars, and on both the front end
747          * and back end, including the Inactive Widgets sidebar on the Widgets screen.
748          *
749          * @since 3.9.0
750          *
751          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
752          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
753          *                                Default true.
754          */
755         do_action( 'dynamic_sidebar_after', $index, true );
756
757         /**
758          * Filters whether a sidebar has widgets.
759          *
760          * Note: The filter is also evaluated for empty sidebars, and on both the front end
761          * and back end, including the Inactive Widgets sidebar on the Widgets screen.
762          *
763          * @since 3.9.0
764          *
765          * @param bool       $did_one Whether at least one widget was rendered in the sidebar.
766          *                            Default false.
767          * @param int|string $index   Index, name, or ID of the dynamic sidebar.
768          */
769         return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
770 }
771
772 /**
773  * Whether widget is displayed on the front end.
774  *
775  * Either $callback or $id_base can be used
776  * $id_base is the first argument when extending WP_Widget class
777  * Without the optional $widget_id parameter, returns the ID of the first sidebar
778  * in which the first instance of the widget with the given callback or $id_base is found.
779  * With the $widget_id parameter, returns the ID of the sidebar where
780  * the widget with that callback/$id_base AND that ID is found.
781  *
782  * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
783  * this function has to run after widgets have initialized, at action {@see 'init'} or later.
784  *
785  * @since 2.2.0
786  *
787  * @global array $wp_registered_widgets
788  *
789  * @param string|false $callback      Optional, Widget callback to check. Default false.
790  * @param int|false    $widget_id     Optional. Widget ID. Optional, but needed for checking. Default false.
791  * @param string|false $id_base       Optional. The base ID of a widget created by extending WP_Widget. Default false.
792  * @param bool         $skip_inactive Optional. Whether to check in 'wp_inactive_widgets'. Default true.
793  * @return string|false False if widget is not active or id of sidebar in which the widget is active.
794  */
795 function is_active_widget( $callback = false, $widget_id = false, $id_base = false, $skip_inactive = true ) {
796         global $wp_registered_widgets;
797
798         $sidebars_widgets = wp_get_sidebars_widgets();
799
800         if ( is_array($sidebars_widgets) ) {
801                 foreach ( $sidebars_widgets as $sidebar => $widgets ) {
802                         if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) ) {
803                                 continue;
804                         }
805
806                         if ( is_array($widgets) ) {
807                                 foreach ( $widgets as $widget ) {
808                                         if ( ( $callback && isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback ) || ( $id_base && _get_widget_id_base($widget) == $id_base ) ) {
809                                                 if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
810                                                         return $sidebar;
811                                         }
812                                 }
813                         }
814                 }
815         }
816         return false;
817 }
818
819 /**
820  * Whether the dynamic sidebar is enabled and used by theme.
821  *
822  * @since 2.2.0
823  *
824  * @global array $wp_registered_widgets
825  * @global array $wp_registered_sidebars
826  *
827  * @return bool True, if using widgets. False, if not using widgets.
828  */
829 function is_dynamic_sidebar() {
830         global $wp_registered_widgets, $wp_registered_sidebars;
831         $sidebars_widgets = get_option('sidebars_widgets');
832         foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
833                 if ( ! empty( $sidebars_widgets[ $index ] ) ) {
834                         foreach ( (array) $sidebars_widgets[$index] as $widget )
835                                 if ( array_key_exists($widget, $wp_registered_widgets) )
836                                         return true;
837                 }
838         }
839         return false;
840 }
841
842 /**
843  * Whether a sidebar is in use.
844  *
845  * @since 2.8.0
846  *
847  * @param string|int $index Sidebar name, id or number to check.
848  * @return bool true if the sidebar is in use, false otherwise.
849  */
850 function is_active_sidebar( $index ) {
851         $index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
852         $sidebars_widgets = wp_get_sidebars_widgets();
853         $is_active_sidebar = ! empty( $sidebars_widgets[$index] );
854
855         /**
856          * Filters whether a dynamic sidebar is considered "active".
857          *
858          * @since 3.9.0
859          *
860          * @param bool       $is_active_sidebar Whether or not the sidebar should be considered "active".
861          *                                      In other words, whether the sidebar contains any widgets.
862          * @param int|string $index             Index, name, or ID of the dynamic sidebar.
863          */
864         return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
865 }
866
867 //
868 // Internal Functions
869 //
870
871 /**
872  * Retrieve full list of sidebars and their widget instance IDs.
873  *
874  * Will upgrade sidebar widget list, if needed. Will also save updated list, if
875  * needed.
876  *
877  * @since 2.2.0
878  * @access private
879  *
880  * @global array $_wp_sidebars_widgets
881  * @global array $sidebars_widgets
882  *
883  * @param bool $deprecated Not used (argument deprecated).
884  * @return array Upgraded list of widgets to version 3 array format when called from the admin.
885  */
886 function wp_get_sidebars_widgets( $deprecated = true ) {
887         if ( $deprecated !== true )
888                 _deprecated_argument( __FUNCTION__, '2.8.1' );
889
890         global $_wp_sidebars_widgets, $sidebars_widgets;
891
892         // If loading from front page, consult $_wp_sidebars_widgets rather than options
893         // to see if wp_convert_widget_settings() has made manipulations in memory.
894         if ( !is_admin() ) {
895                 if ( empty($_wp_sidebars_widgets) )
896                         $_wp_sidebars_widgets = get_option('sidebars_widgets', array());
897
898                 $sidebars_widgets = $_wp_sidebars_widgets;
899         } else {
900                 $sidebars_widgets = get_option('sidebars_widgets', array());
901         }
902
903         if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
904                 unset($sidebars_widgets['array_version']);
905
906         /**
907          * Filters the list of sidebars and their widgets.
908          *
909          * @since 2.7.0
910          *
911          * @param array $sidebars_widgets An associative array of sidebars and their widgets.
912          */
913         return apply_filters( 'sidebars_widgets', $sidebars_widgets );
914 }
915
916 /**
917  * Set the sidebar widget option to update sidebars.
918  *
919  * @since 2.2.0
920  * @access private
921  *
922  * @param array $sidebars_widgets Sidebar widgets and their settings.
923  */
924 function wp_set_sidebars_widgets( $sidebars_widgets ) {
925         if ( !isset( $sidebars_widgets['array_version'] ) )
926                 $sidebars_widgets['array_version'] = 3;
927         update_option( 'sidebars_widgets', $sidebars_widgets );
928 }
929
930 /**
931  * Retrieve default registered sidebars list.
932  *
933  * @since 2.2.0
934  * @access private
935  *
936  * @global array $wp_registered_sidebars
937  *
938  * @return array
939  */
940 function wp_get_widget_defaults() {
941         global $wp_registered_sidebars;
942
943         $defaults = array();
944
945         foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
946                 $defaults[$index] = array();
947
948         return $defaults;
949 }
950
951 /**
952  * Convert the widget settings from single to multi-widget format.
953  *
954  * @since 2.8.0
955  *
956  * @global array $_wp_sidebars_widgets
957  *
958  * @param string $base_name
959  * @param string $option_name
960  * @param array  $settings
961  * @return array
962  */
963 function wp_convert_widget_settings($base_name, $option_name, $settings) {
964         // This test may need expanding.
965         $single = $changed = false;
966         if ( empty($settings) ) {
967                 $single = true;
968         } else {
969                 foreach ( array_keys($settings) as $number ) {
970                         if ( 'number' == $number )
971                                 continue;
972                         if ( !is_numeric($number) ) {
973                                 $single = true;
974                                 break;
975                         }
976                 }
977         }
978
979         if ( $single ) {
980                 $settings = array( 2 => $settings );
981
982                 // If loading from the front page, update sidebar in memory but don't save to options
983                 if ( is_admin() ) {
984                         $sidebars_widgets = get_option('sidebars_widgets');
985                 } else {
986                         if ( empty($GLOBALS['_wp_sidebars_widgets']) )
987                                 $GLOBALS['_wp_sidebars_widgets'] = get_option('sidebars_widgets', array());
988                         $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
989                 }
990
991                 foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
992                         if ( is_array($sidebar) ) {
993                                 foreach ( $sidebar as $i => $name ) {
994                                         if ( $base_name == $name ) {
995                                                 $sidebars_widgets[$index][$i] = "$name-2";
996                                                 $changed = true;
997                                                 break 2;
998                                         }
999                                 }
1000                         }
1001                 }
1002
1003                 if ( is_admin() && $changed )
1004                         update_option('sidebars_widgets', $sidebars_widgets);
1005         }
1006
1007         $settings['_multiwidget'] = 1;
1008         if ( is_admin() )
1009                 update_option( $option_name, $settings );
1010
1011         return $settings;
1012 }
1013
1014 /**
1015  * Output an arbitrary widget as a template tag.
1016  *
1017  * @since 2.8.0
1018  *
1019  * @global WP_Widget_Factory $wp_widget_factory
1020  *
1021  * @param string $widget   The widget's PHP class name (see class-wp-widget.php).
1022  * @param array  $instance Optional. The widget's instance settings. Default empty array.
1023  * @param array  $args {
1024  *     Optional. Array of arguments to configure the display of the widget.
1025  *
1026  *     @type string $before_widget HTML content that will be prepended to the widget's HTML output.
1027  *                                 Default `<div class="widget %s">`, where `%s` is the widget's class name.
1028  *     @type string $after_widget  HTML content that will be appended to the widget's HTML output.
1029  *                                 Default `</div>`.
1030  *     @type string $before_title  HTML content that will be prepended to the widget's title when displayed.
1031  *                                 Default `<h2 class="widgettitle">`.
1032  *     @type string $after_title   HTML content that will be appended to the widget's title when displayed.
1033  *                                 Default `</h2>`.
1034  * }
1035  */
1036 function the_widget( $widget, $instance = array(), $args = array() ) {
1037         global $wp_widget_factory;
1038
1039         $widget_obj = $wp_widget_factory->widgets[$widget];
1040         if ( ! ( $widget_obj instanceof WP_Widget ) ) {
1041                 return;
1042         }
1043
1044         $default_args = array(
1045                 'before_widget' => '<div class="widget %s">',
1046                 'after_widget'  => "</div>",
1047                 'before_title'  => '<h2 class="widgettitle">',
1048                 'after_title'   => '</h2>',
1049         );
1050         $args = wp_parse_args( $args, $default_args );
1051         $args['before_widget'] = sprintf( $args['before_widget'], $widget_obj->widget_options['classname'] );
1052
1053         $instance = wp_parse_args($instance);
1054
1055         /**
1056          * Fires before rendering the requested widget.
1057          *
1058          * @since 3.0.0
1059          *
1060          * @param string $widget   The widget's class name.
1061          * @param array  $instance The current widget instance's settings.
1062          * @param array  $args     An array of the widget's sidebar arguments.
1063          */
1064         do_action( 'the_widget', $widget, $instance, $args );
1065
1066         $widget_obj->_set(-1);
1067         $widget_obj->widget($args, $instance);
1068 }
1069
1070 /**
1071  * Retrieves the widget ID base value.
1072  *
1073  * @since 2.8.0
1074  *
1075  * @param string $id Widget ID.
1076  * @return string Widget ID base.
1077  */
1078 function _get_widget_id_base( $id ) {
1079         return preg_replace( '/-[0-9]+$/', '', $id );
1080 }
1081
1082 /**
1083  * Handle sidebars config after theme change
1084  *
1085  * @access private
1086  * @since 3.3.0
1087  *
1088  * @global array $sidebars_widgets
1089  */
1090 function _wp_sidebars_changed() {
1091         global $sidebars_widgets;
1092
1093         if ( ! is_array( $sidebars_widgets ) )
1094                 $sidebars_widgets = wp_get_sidebars_widgets();
1095
1096         retrieve_widgets(true);
1097 }
1098
1099 /**
1100  * Look for "lost" widgets, this has to run at least on each theme change.
1101  *
1102  * @since 2.8.0
1103  *
1104  * @global array $wp_registered_sidebars
1105  * @global array $sidebars_widgets
1106  * @global array $wp_registered_widgets
1107  *
1108  * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
1109  *                                   of 'customize' defers updates for the Customizer.
1110  * @return array|void
1111  */
1112 function retrieve_widgets( $theme_changed = false ) {
1113         global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
1114
1115         $registered_sidebar_keys = array_keys( $wp_registered_sidebars );
1116         $orphaned = 0;
1117
1118         $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
1119         if ( is_array( $old_sidebars_widgets ) ) {
1120                 // time() that sidebars were stored is in $old_sidebars_widgets['time']
1121                 $_sidebars_widgets = $old_sidebars_widgets['data'];
1122
1123                 if ( 'customize' !== $theme_changed ) {
1124                         remove_theme_mod( 'sidebars_widgets' );
1125                 }
1126
1127                 foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
1128                         if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
1129                                 continue;
1130                         }
1131
1132                         if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {
1133                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;
1134                                 unset( $_sidebars_widgets[$sidebar] );
1135                         }
1136                 }
1137         } else {
1138                 if ( empty( $sidebars_widgets ) )
1139                         return;
1140
1141                 unset( $sidebars_widgets['array_version'] );
1142
1143                 $old = array_keys($sidebars_widgets);
1144                 sort($old);
1145                 sort($registered_sidebar_keys);
1146
1147                 if ( $old == $registered_sidebar_keys )
1148                         return;
1149
1150                 $_sidebars_widgets = array(
1151                         'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()
1152                 );
1153
1154                 unset( $sidebars_widgets['wp_inactive_widgets'] );
1155
1156                 foreach ( $wp_registered_sidebars as $id => $settings ) {
1157                         if ( $theme_changed ) {
1158                                 $_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
1159                         } else {
1160                                 // no theme change, grab only sidebars that are currently registered
1161                                 if ( isset( $sidebars_widgets[$id] ) ) {
1162                                         $_sidebars_widgets[$id] = $sidebars_widgets[$id];
1163                                         unset( $sidebars_widgets[$id] );
1164                                 }
1165                         }
1166                 }
1167
1168                 foreach ( $sidebars_widgets as $val ) {
1169                         if ( is_array($val) && ! empty( $val ) )
1170                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
1171                 }
1172         }
1173
1174         // discard invalid, theme-specific widgets from sidebars
1175         $shown_widgets = array();
1176
1177         foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
1178                 if ( !is_array($widgets) )
1179                         continue;
1180
1181                 $_widgets = array();
1182                 foreach ( $widgets as $widget ) {
1183                         if ( isset($wp_registered_widgets[$widget]) )
1184                                 $_widgets[] = $widget;
1185                 }
1186
1187                 $_sidebars_widgets[$sidebar] = $_widgets;
1188                 $shown_widgets = array_merge($shown_widgets, $_widgets);
1189         }
1190
1191         $sidebars_widgets = $_sidebars_widgets;
1192         unset($_sidebars_widgets, $_widgets);
1193
1194         // find hidden/lost multi-widget instances
1195         $lost_widgets = array();
1196         foreach ( $wp_registered_widgets as $key => $val ) {
1197                 if ( in_array($key, $shown_widgets, true) )
1198                         continue;
1199
1200                 $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
1201
1202                 if ( 2 > (int) $number )
1203                         continue;
1204
1205                 $lost_widgets[] = $key;
1206         }
1207
1208         $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
1209         if ( 'customize' !== $theme_changed ) {
1210                 wp_set_sidebars_widgets( $sidebars_widgets );
1211         }
1212
1213         return $sidebars_widgets;
1214 }
1215
1216 /**
1217  * Display the RSS entries in a list.
1218  *
1219  * @since 2.5.0
1220  *
1221  * @param string|array|object $rss RSS url.
1222  * @param array $args Widget arguments.
1223  */
1224 function wp_widget_rss_output( $rss, $args = array() ) {
1225         if ( is_string( $rss ) ) {
1226                 $rss = fetch_feed($rss);
1227         } elseif ( is_array($rss) && isset($rss['url']) ) {
1228                 $args = $rss;
1229                 $rss = fetch_feed($rss['url']);
1230         } elseif ( !is_object($rss) ) {
1231                 return;
1232         }
1233
1234         if ( is_wp_error($rss) ) {
1235                 if ( is_admin() || current_user_can('manage_options') )
1236                         echo '<p><strong>' . __( 'RSS Error:' ) . '</strong> ' . $rss->get_error_message() . '</p>';
1237                 return;
1238         }
1239
1240         $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0, 'items' => 0 );
1241         $args = wp_parse_args( $args, $default_args );
1242
1243         $items = (int) $args['items'];
1244         if ( $items < 1 || 20 < $items )
1245                 $items = 10;
1246         $show_summary  = (int) $args['show_summary'];
1247         $show_author   = (int) $args['show_author'];
1248         $show_date     = (int) $args['show_date'];
1249
1250         if ( !$rss->get_item_quantity() ) {
1251                 echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
1252                 $rss->__destruct();
1253                 unset($rss);
1254                 return;
1255         }
1256
1257         echo '<ul>';
1258         foreach ( $rss->get_items( 0, $items ) as $item ) {
1259                 $link = $item->get_link();
1260                 while ( stristr( $link, 'http' ) != $link ) {
1261                         $link = substr( $link, 1 );
1262                 }
1263                 $link = esc_url( strip_tags( $link ) );
1264
1265                 $title = esc_html( trim( strip_tags( $item->get_title() ) ) );
1266                 if ( empty( $title ) ) {
1267                         $title = __( 'Untitled' );
1268                 }
1269
1270                 $desc = @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option( 'blog_charset' ) );
1271                 $desc = esc_attr( wp_trim_words( $desc, 55, ' [&hellip;]' ) );
1272
1273                 $summary = '';
1274                 if ( $show_summary ) {
1275                         $summary = $desc;
1276
1277                         // Change existing [...] to [&hellip;].
1278                         if ( '[...]' == substr( $summary, -5 ) ) {
1279                                 $summary = substr( $summary, 0, -5 ) . '[&hellip;]';
1280                         }
1281
1282                         $summary = '<div class="rssSummary">' . esc_html( $summary ) . '</div>';
1283                 }
1284
1285                 $date = '';
1286                 if ( $show_date ) {
1287                         $date = $item->get_date( 'U' );
1288
1289                         if ( $date ) {
1290                                 $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
1291                         }
1292                 }
1293
1294                 $author = '';
1295                 if ( $show_author ) {
1296                         $author = $item->get_author();
1297                         if ( is_object($author) ) {
1298                                 $author = $author->get_name();
1299                                 $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
1300                         }
1301                 }
1302
1303                 if ( $link == '' ) {
1304                         echo "<li>$title{$date}{$summary}{$author}</li>";
1305                 } elseif ( $show_summary ) {
1306                         echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$summary}{$author}</li>";
1307                 } else {
1308                         echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$author}</li>";
1309                 }
1310         }
1311         echo '</ul>';
1312         $rss->__destruct();
1313         unset($rss);
1314 }
1315
1316 /**
1317  * Display RSS widget options form.
1318  *
1319  * The options for what fields are displayed for the RSS form are all booleans
1320  * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
1321  * 'show_date'.
1322  *
1323  * @since 2.5.0
1324  *
1325  * @param array|string $args Values for input fields.
1326  * @param array $inputs Override default display options.
1327  */
1328 function wp_widget_rss_form( $args, $inputs = null ) {
1329         $default_inputs = array( 'url' => true, 'title' => true, 'items' => true, 'show_summary' => true, 'show_author' => true, 'show_date' => true );
1330         $inputs = wp_parse_args( $inputs, $default_inputs );
1331
1332         $args['title'] = isset( $args['title'] ) ? $args['title'] : '';
1333         $args['url'] = isset( $args['url'] ) ? $args['url'] : '';
1334         $args['items'] = isset( $args['items'] ) ? (int) $args['items'] : 0;
1335
1336         if ( $args['items'] < 1 || 20 < $args['items'] ) {
1337                 $args['items'] = 10;
1338         }
1339
1340         $args['show_summary']   = isset( $args['show_summary'] ) ? (int) $args['show_summary'] : (int) $inputs['show_summary'];
1341         $args['show_author']    = isset( $args['show_author'] ) ? (int) $args['show_author'] : (int) $inputs['show_author'];
1342         $args['show_date']      = isset( $args['show_date'] ) ? (int) $args['show_date'] : (int) $inputs['show_date'];
1343
1344         if ( ! empty( $args['error'] ) ) {
1345                 echo '<p class="widget-error"><strong>' . __( 'RSS Error:' ) . '</strong> ' . $args['error'] . '</p>';
1346         }
1347
1348         $esc_number = esc_attr( $args['number'] );
1349         if ( $inputs['url'] ) :
1350 ?>
1351         <p><label for="rss-url-<?php echo $esc_number; ?>"><?php _e( 'Enter the RSS feed URL here:' ); ?></label>
1352         <input class="widefat" id="rss-url-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][url]" type="text" value="<?php echo esc_url( $args['url'] ); ?>" /></p>
1353 <?php endif; if ( $inputs['title'] ) : ?>
1354         <p><label for="rss-title-<?php echo $esc_number; ?>"><?php _e( 'Give the feed a title (optional):' ); ?></label>
1355         <input class="widefat" id="rss-title-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][title]" type="text" value="<?php echo esc_attr( $args['title'] ); ?>" /></p>
1356 <?php endif; if ( $inputs['items'] ) : ?>
1357         <p><label for="rss-items-<?php echo $esc_number; ?>"><?php _e( 'How many items would you like to display?' ); ?></label>
1358         <select id="rss-items-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][items]">
1359         <?php
1360         for ( $i = 1; $i <= 20; ++$i ) {
1361                 echo "<option value='$i' " . selected( $args['items'], $i, false ) . ">$i</option>";
1362         }
1363         ?>
1364         </select></p>
1365 <?php endif; if ( $inputs['show_summary'] ) : ?>
1366         <p><input id="rss-show-summary-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_summary]" type="checkbox" value="1" <?php checked( $args['show_summary'] ); ?> />
1367         <label for="rss-show-summary-<?php echo $esc_number; ?>"><?php _e( 'Display item content?' ); ?></label></p>
1368 <?php endif; if ( $inputs['show_author'] ) : ?>
1369         <p><input id="rss-show-author-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_author]" type="checkbox" value="1" <?php checked( $args['show_author'] ); ?> />
1370         <label for="rss-show-author-<?php echo $esc_number; ?>"><?php _e( 'Display item author if available?' ); ?></label></p>
1371 <?php endif; if ( $inputs['show_date'] ) : ?>
1372         <p><input id="rss-show-date-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_date]" type="checkbox" value="1" <?php checked( $args['show_date'] ); ?>/>
1373         <label for="rss-show-date-<?php echo $esc_number; ?>"><?php _e( 'Display item date?' ); ?></label></p>
1374 <?php
1375         endif;
1376         foreach ( array_keys($default_inputs) as $input ) :
1377                 if ( 'hidden' === $inputs[$input] ) :
1378                         $id = str_replace( '_', '-', $input );
1379 ?>
1380         <input type="hidden" id="rss-<?php echo esc_attr( $id ); ?>-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][<?php echo esc_attr( $input ); ?>]" value="<?php echo esc_attr( $args[ $input ] ); ?>" />
1381 <?php
1382                 endif;
1383         endforeach;
1384 }
1385
1386 /**
1387  * Process RSS feed widget data and optionally retrieve feed items.
1388  *
1389  * The feed widget can not have more than 20 items or it will reset back to the
1390  * default, which is 10.
1391  *
1392  * The resulting array has the feed title, feed url, feed link (from channel),
1393  * feed items, error (if any), and whether to show summary, author, and date.
1394  * All respectively in the order of the array elements.
1395  *
1396  * @since 2.5.0
1397  *
1398  * @param array $widget_rss RSS widget feed data. Expects unescaped data.
1399  * @param bool $check_feed Optional, default is true. Whether to check feed for errors.
1400  * @return array
1401  */
1402 function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
1403         $items = (int) $widget_rss['items'];
1404         if ( $items < 1 || 20 < $items )
1405                 $items = 10;
1406         $url           = esc_url_raw( strip_tags( $widget_rss['url'] ) );
1407         $title         = isset( $widget_rss['title'] ) ? trim( strip_tags( $widget_rss['title'] ) ) : '';
1408         $show_summary  = isset( $widget_rss['show_summary'] ) ? (int) $widget_rss['show_summary'] : 0;
1409         $show_author   = isset( $widget_rss['show_author'] ) ? (int) $widget_rss['show_author'] :0;
1410         $show_date     = isset( $widget_rss['show_date'] ) ? (int) $widget_rss['show_date'] : 0;
1411
1412         if ( $check_feed ) {
1413                 $rss = fetch_feed($url);
1414                 $error = false;
1415                 $link = '';
1416                 if ( is_wp_error($rss) ) {
1417                         $error = $rss->get_error_message();
1418                 } else {
1419                         $link = esc_url(strip_tags($rss->get_permalink()));
1420                         while ( stristr($link, 'http') != $link )
1421                                 $link = substr($link, 1);
1422
1423                         $rss->__destruct();
1424                         unset($rss);
1425                 }
1426         }
1427
1428         return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
1429 }
1430
1431 /**
1432  * Registers all of the default WordPress widgets on startup.
1433  *
1434  * Calls {@see 'widgets_init'} action after all of the WordPress widgets have been registered.
1435  *
1436  * @since 2.2.0
1437  */
1438 function wp_widgets_init() {
1439         if ( !is_blog_installed() )
1440                 return;
1441
1442         register_widget('WP_Widget_Pages');
1443
1444         register_widget('WP_Widget_Calendar');
1445
1446         register_widget('WP_Widget_Archives');
1447
1448         if ( get_option( 'link_manager_enabled' ) )
1449                 register_widget('WP_Widget_Links');
1450
1451         register_widget('WP_Widget_Meta');
1452
1453         register_widget('WP_Widget_Search');
1454
1455         register_widget('WP_Widget_Text');
1456
1457         register_widget('WP_Widget_Categories');
1458
1459         register_widget('WP_Widget_Recent_Posts');
1460
1461         register_widget('WP_Widget_Recent_Comments');
1462
1463         register_widget('WP_Widget_RSS');
1464
1465         register_widget('WP_Widget_Tag_Cloud');
1466
1467         register_widget('WP_Nav_Menu_Widget');
1468
1469         /**
1470          * Fires after all default WordPress widgets have been registered.
1471          *
1472          * @since 2.2.0
1473          */
1474         do_action( 'widgets_init' );
1475 }