WordPress 4.4.1
[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  * Unregister a widget
118  *
119  * Unregisters a WP_Widget widget. Useful for unregistering default widgets.
120  * Run within a function hooked to the 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  * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
449  * option is never used. The 'width' option is the width of the fully expanded
450  * control form, but try hard to use the default width. The 'id_base' is for
451  * multi-widgets (widgets which allow multiple instances such as the text
452  * widget), an id_base must be provided. The widget id will end up looking like
453  * `{$id_base}-{$unique_number}`.
454  *
455  * @since 2.2.0
456  *
457  * @todo Document `$options` as a hash notation, re: WP_Widget::__construct() cross-reference.
458  * @todo `$params` parameter?
459  *
460  * @global array $wp_registered_widget_controls
461  * @global array $wp_registered_widget_updates
462  * @global array $wp_registered_widgets
463  * @global array $_wp_deprecated_widgets_callbacks
464  *
465  * @param int|string   $id               Sidebar ID.
466  * @param string       $name             Sidebar display name.
467  * @param callable     $control_callback Run when sidebar is displayed.
468  * @param array|string $options          Optional. Widget options. See description above. Default empty array.
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  * @global array $wp_registered_widget_updates
517  *
518  * @param string   $id_base
519  * @param callable $update_callback
520  * @param array    $options
521  */
522 function _register_widget_update_callback($id_base, $update_callback, $options = array()) {
523         global $wp_registered_widget_updates;
524
525         if ( isset($wp_registered_widget_updates[$id_base]) ) {
526                 if ( empty($update_callback) )
527                         unset($wp_registered_widget_updates[$id_base]);
528                 return;
529         }
530
531         $widget = array(
532                 'callback' => $update_callback,
533                 'params' => array_slice(func_get_args(), 3)
534         );
535
536         $widget = array_merge($widget, $options);
537         $wp_registered_widget_updates[$id_base] = $widget;
538 }
539
540 /**
541  *
542  * @global array $wp_registered_widget_controls
543  *
544  * @param int|string $id
545  * @param string     $name
546  * @param callable   $form_callback
547  * @param array      $options
548  */
549 function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
550         global $wp_registered_widget_controls;
551
552         $id = strtolower($id);
553
554         if ( empty($form_callback) ) {
555                 unset($wp_registered_widget_controls[$id]);
556                 return;
557         }
558
559         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
560                 return;
561
562         $defaults = array('width' => 250, 'height' => 200 );
563         $options = wp_parse_args($options, $defaults);
564         $options['width'] = (int) $options['width'];
565         $options['height'] = (int) $options['height'];
566
567         $widget = array(
568                 'name' => $name,
569                 'id' => $id,
570                 'callback' => $form_callback,
571                 'params' => array_slice(func_get_args(), 4)
572         );
573         $widget = array_merge($widget, $options);
574
575         $wp_registered_widget_controls[$id] = $widget;
576 }
577
578 /**
579  * Remove control callback for widget.
580  *
581  * @since 2.2.0
582  *
583  * @param int|string $id Widget ID.
584  */
585 function wp_unregister_widget_control($id) {
586         wp_register_widget_control( $id, '', '' );
587 }
588
589 /**
590  * Display dynamic sidebar.
591  *
592  * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
593  * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
594  * Otherwise, you can pass in a numerical index to display the sidebar at that index.
595  *
596  * @since 2.2.0
597  *
598  * @global array $wp_registered_sidebars
599  * @global array $wp_registered_widgets
600  *
601  * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
602  * @return bool True, if widget sidebar was found and called. False if not found or not called.
603  */
604 function dynamic_sidebar( $index = 1 ) {
605         global $wp_registered_sidebars, $wp_registered_widgets;
606
607         if ( is_int( $index ) ) {
608                 $index = "sidebar-$index";
609         } else {
610                 $index = sanitize_title( $index );
611                 foreach ( (array) $wp_registered_sidebars as $key => $value ) {
612                         if ( sanitize_title( $value['name'] ) == $index ) {
613                                 $index = $key;
614                                 break;
615                         }
616                 }
617         }
618
619         $sidebars_widgets = wp_get_sidebars_widgets();
620         if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
621                 /** This action is documented in wp-includes/widget.php */
622                 do_action( 'dynamic_sidebar_before', $index, false );
623                 /** This action is documented in wp-includes/widget.php */
624                 do_action( 'dynamic_sidebar_after',  $index, false );
625                 /** This filter is documented in wp-includes/widget.php */
626                 return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
627         }
628
629         /**
630          * Fires before widgets are rendered in a dynamic sidebar.
631          *
632          * Note: The action also fires for empty sidebars, and on both the front-end
633          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
634          *
635          * @since 3.9.0
636          *
637          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
638          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
639          *                                Default true.
640          */
641         do_action( 'dynamic_sidebar_before', $index, true );
642         $sidebar = $wp_registered_sidebars[$index];
643
644         $did_one = false;
645         foreach ( (array) $sidebars_widgets[$index] as $id ) {
646
647                 if ( !isset($wp_registered_widgets[$id]) ) continue;
648
649                 $params = array_merge(
650                         array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
651                         (array) $wp_registered_widgets[$id]['params']
652                 );
653
654                 // Substitute HTML id and class attributes into before_widget
655                 $classname_ = '';
656                 foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
657                         if ( is_string($cn) )
658                                 $classname_ .= '_' . $cn;
659                         elseif ( is_object($cn) )
660                                 $classname_ .= '_' . get_class($cn);
661                 }
662                 $classname_ = ltrim($classname_, '_');
663                 $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
664
665                 /**
666                  * Filter the parameters passed to a widget's display callback.
667                  *
668                  * Note: The filter is evaluated on both the front-end and back-end,
669                  * including for the Inactive Widgets sidebar on the Widgets screen.
670                  *
671                  * @since 2.5.0
672                  *
673                  * @see register_sidebar()
674                  *
675                  * @param array $params {
676                  *     @type array $args  {
677                  *         An array of widget display arguments.
678                  *
679                  *         @type string $name          Name of the sidebar the widget is assigned to.
680                  *         @type string $id            ID of the sidebar the widget is assigned to.
681                  *         @type string $description   The sidebar description.
682                  *         @type string $class         CSS class applied to the sidebar container.
683                  *         @type string $before_widget HTML markup to prepend to each widget in the sidebar.
684                  *         @type string $after_widget  HTML markup to append to each widget in the sidebar.
685                  *         @type string $before_title  HTML markup to prepend to the widget title when displayed.
686                  *         @type string $after_title   HTML markup to append to the widget title when displayed.
687                  *         @type string $widget_id     ID of the widget.
688                  *         @type string $widget_name   Name of the widget.
689                  *     }
690                  *     @type array $widget_args {
691                  *         An array of multi-widget arguments.
692                  *
693                  *         @type int $number Number increment used for multiples of the same widget.
694                  *     }
695                  * }
696                  */
697                 $params = apply_filters( 'dynamic_sidebar_params', $params );
698
699                 $callback = $wp_registered_widgets[$id]['callback'];
700
701                 /**
702                  * Fires before a widget's display callback is called.
703                  *
704                  * Note: The action fires on both the front-end and back-end, including
705                  * for widgets in the Inactive Widgets sidebar on the Widgets screen.
706                  *
707                  * The action is not fired for empty sidebars.
708                  *
709                  * @since 3.0.0
710                  *
711                  * @param array $widget_id {
712                  *     An associative array of widget arguments.
713                  *
714                  *     @type string $name                Name of the widget.
715                  *     @type string $id                  Widget ID.
716                  *     @type array|callable $callback    When the hook is fired on the front-end, $callback is an array
717                  *                                       containing the widget object. Fired on the back-end, $callback
718                  *                                       is 'wp_widget_control', see $_callback.
719                  *     @type array          $params      An associative array of multi-widget arguments.
720                  *     @type string         $classname   CSS class applied to the widget container.
721                  *     @type string         $description The widget description.
722                  *     @type array          $_callback   When the hook is fired on the back-end, $_callback is populated
723                  *                                       with an array containing the widget object, see $callback.
724                  * }
725                  */
726                 do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
727
728                 if ( is_callable($callback) ) {
729                         call_user_func_array($callback, $params);
730                         $did_one = true;
731                 }
732         }
733
734         /**
735          * Fires after widgets are rendered in a dynamic sidebar.
736          *
737          * Note: The action also fires for empty sidebars, and on both the front-end
738          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
739          *
740          * @since 3.9.0
741          *
742          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
743          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
744          *                                Default true.
745          */
746         do_action( 'dynamic_sidebar_after', $index, true );
747
748         /**
749          * Filter whether a sidebar has widgets.
750          *
751          * Note: The filter is also evaluated for empty sidebars, and on both the front-end
752          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
753          *
754          * @since 3.9.0
755          *
756          * @param bool       $did_one Whether at least one widget was rendered in the sidebar.
757          *                            Default false.
758          * @param int|string $index   Index, name, or ID of the dynamic sidebar.
759          */
760         return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
761 }
762
763 /**
764  * Whether widget is displayed on the front-end.
765  *
766  * Either $callback or $id_base can be used
767  * $id_base is the first argument when extending WP_Widget class
768  * Without the optional $widget_id parameter, returns the ID of the first sidebar
769  * in which the first instance of the widget with the given callback or $id_base is found.
770  * With the $widget_id parameter, returns the ID of the sidebar where
771  * the widget with that callback/$id_base AND that ID is found.
772  *
773  * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
774  * this function has to run after widgets have initialized, at action 'init' or later.
775  *
776  * @since 2.2.0
777  *
778  * @global array $wp_registered_widgets
779  *
780  * @param string $callback      Optional, Widget callback to check.
781  * @param int    $widget_id     Optional, but needed for checking. Widget ID.
782  * @param string $id_base       Optional, the base ID of a widget created by extending WP_Widget.
783  * @param bool   $skip_inactive Optional, whether to check in 'wp_inactive_widgets'.
784  * @return string|false False if widget is not active or id of sidebar in which the widget is active.
785  */
786 function is_active_widget($callback = false, $widget_id = false, $id_base = false, $skip_inactive = true) {
787         global $wp_registered_widgets;
788
789         $sidebars_widgets = wp_get_sidebars_widgets();
790
791         if ( is_array($sidebars_widgets) ) {
792                 foreach ( $sidebars_widgets as $sidebar => $widgets ) {
793                         if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) ) {
794                                 continue;
795                         }
796
797                         if ( is_array($widgets) ) {
798                                 foreach ( $widgets as $widget ) {
799                                         if ( ( $callback && isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback ) || ( $id_base && _get_widget_id_base($widget) == $id_base ) ) {
800                                                 if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
801                                                         return $sidebar;
802                                         }
803                                 }
804                         }
805                 }
806         }
807         return false;
808 }
809
810 /**
811  * Whether the dynamic sidebar is enabled and used by theme.
812  *
813  * @since 2.2.0
814  *
815  * @global array $wp_registered_widgets
816  * @global array $wp_registered_sidebars
817  *
818  * @return bool True, if using widgets. False, if not using widgets.
819  */
820 function is_dynamic_sidebar() {
821         global $wp_registered_widgets, $wp_registered_sidebars;
822         $sidebars_widgets = get_option('sidebars_widgets');
823         foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
824                 if ( count($sidebars_widgets[$index]) ) {
825                         foreach ( (array) $sidebars_widgets[$index] as $widget )
826                                 if ( array_key_exists($widget, $wp_registered_widgets) )
827                                         return true;
828                 }
829         }
830         return false;
831 }
832
833 /**
834  * Whether a sidebar is in use.
835  *
836  * @since 2.8.0
837  *
838  * @param string|int $index Sidebar name, id or number to check.
839  * @return bool true if the sidebar is in use, false otherwise.
840  */
841 function is_active_sidebar( $index ) {
842         $index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
843         $sidebars_widgets = wp_get_sidebars_widgets();
844         $is_active_sidebar = ! empty( $sidebars_widgets[$index] );
845
846         /**
847          * Filter whether a dynamic sidebar is considered "active".
848          *
849          * @since 3.9.0
850          *
851          * @param bool       $is_active_sidebar Whether or not the sidebar should be considered "active".
852          *                                      In other words, whether the sidebar contains any widgets.
853          * @param int|string $index             Index, name, or ID of the dynamic sidebar.
854          */
855         return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
856 }
857
858 //
859 // Internal Functions
860 //
861
862 /**
863  * Retrieve full list of sidebars and their widget instance IDs.
864  *
865  * Will upgrade sidebar widget list, if needed. Will also save updated list, if
866  * needed.
867  *
868  * @since 2.2.0
869  * @access private
870  *
871  * @global array $_wp_sidebars_widgets
872  * @global array $sidebars_widgets
873  *
874  * @param bool $deprecated Not used (argument deprecated).
875  * @return array Upgraded list of widgets to version 3 array format when called from the admin.
876  */
877 function wp_get_sidebars_widgets( $deprecated = true ) {
878         if ( $deprecated !== true )
879                 _deprecated_argument( __FUNCTION__, '2.8.1' );
880
881         global $_wp_sidebars_widgets, $sidebars_widgets;
882
883         // If loading from front page, consult $_wp_sidebars_widgets rather than options
884         // to see if wp_convert_widget_settings() has made manipulations in memory.
885         if ( !is_admin() ) {
886                 if ( empty($_wp_sidebars_widgets) )
887                         $_wp_sidebars_widgets = get_option('sidebars_widgets', array());
888
889                 $sidebars_widgets = $_wp_sidebars_widgets;
890         } else {
891                 $sidebars_widgets = get_option('sidebars_widgets', array());
892         }
893
894         if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
895                 unset($sidebars_widgets['array_version']);
896
897         /**
898          * Filter the list of sidebars and their widgets.
899          *
900          * @since 2.7.0
901          *
902          * @param array $sidebars_widgets An associative array of sidebars and their widgets.
903          */
904         return apply_filters( 'sidebars_widgets', $sidebars_widgets );
905 }
906
907 /**
908  * Set the sidebar widget option to update sidebars.
909  *
910  * @since 2.2.0
911  * @access private
912  *
913  * @param array $sidebars_widgets Sidebar widgets and their settings.
914  */
915 function wp_set_sidebars_widgets( $sidebars_widgets ) {
916         if ( !isset( $sidebars_widgets['array_version'] ) )
917                 $sidebars_widgets['array_version'] = 3;
918         update_option( 'sidebars_widgets', $sidebars_widgets );
919 }
920
921 /**
922  * Retrieve default registered sidebars list.
923  *
924  * @since 2.2.0
925  * @access private
926  *
927  * @global array $wp_registered_sidebars
928  *
929  * @return array
930  */
931 function wp_get_widget_defaults() {
932         global $wp_registered_sidebars;
933
934         $defaults = array();
935
936         foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
937                 $defaults[$index] = array();
938
939         return $defaults;
940 }
941
942 /**
943  * Convert the widget settings from single to multi-widget format.
944  *
945  * @since 2.8.0
946  *
947  * @global array $_wp_sidebars_widgets
948  *
949  * @param string $base_name
950  * @param string $option_name
951  * @param array  $settings
952  * @return array
953  */
954 function wp_convert_widget_settings($base_name, $option_name, $settings) {
955         // This test may need expanding.
956         $single = $changed = false;
957         if ( empty($settings) ) {
958                 $single = true;
959         } else {
960                 foreach ( array_keys($settings) as $number ) {
961                         if ( 'number' == $number )
962                                 continue;
963                         if ( !is_numeric($number) ) {
964                                 $single = true;
965                                 break;
966                         }
967                 }
968         }
969
970         if ( $single ) {
971                 $settings = array( 2 => $settings );
972
973                 // If loading from the front page, update sidebar in memory but don't save to options
974                 if ( is_admin() ) {
975                         $sidebars_widgets = get_option('sidebars_widgets');
976                 } else {
977                         if ( empty($GLOBALS['_wp_sidebars_widgets']) )
978                                 $GLOBALS['_wp_sidebars_widgets'] = get_option('sidebars_widgets', array());
979                         $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
980                 }
981
982                 foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
983                         if ( is_array($sidebar) ) {
984                                 foreach ( $sidebar as $i => $name ) {
985                                         if ( $base_name == $name ) {
986                                                 $sidebars_widgets[$index][$i] = "$name-2";
987                                                 $changed = true;
988                                                 break 2;
989                                         }
990                                 }
991                         }
992                 }
993
994                 if ( is_admin() && $changed )
995                         update_option('sidebars_widgets', $sidebars_widgets);
996         }
997
998         $settings['_multiwidget'] = 1;
999         if ( is_admin() )
1000                 update_option( $option_name, $settings );
1001
1002         return $settings;
1003 }
1004
1005 /**
1006  * Output an arbitrary widget as a template tag.
1007  *
1008  * @since 2.8.0
1009  *
1010  * @global WP_Widget_Factory $wp_widget_factory
1011  *
1012  * @param string $widget   The widget's PHP class name (see class-wp-widget.php).
1013  * @param array  $instance Optional. The widget's instance settings. Default empty array.
1014  * @param array  $args {
1015  *     Optional. Array of arguments to configure the display of the widget.
1016  *
1017  *     @type string $before_widget HTML content that will be prepended to the widget's HTML output.
1018  *                                 Default `<div class="widget %s">`, where `%s` is the widget's class name.
1019  *     @type string $after_widget  HTML content that will be appended to the widget's HTML output.
1020  *                                 Default `</div>`.
1021  *     @type string $before_title  HTML content that will be prepended to the widget's title when displayed.
1022  *                                 Default `<h2 class="widgettitle">`.
1023  *     @type string $after_title   HTML content that will be appended to the widget's title when displayed.
1024  *                                 Default `</h2>`.
1025  * }
1026  */
1027 function the_widget( $widget, $instance = array(), $args = array() ) {
1028         global $wp_widget_factory;
1029
1030         $widget_obj = $wp_widget_factory->widgets[$widget];
1031         if ( ! ( $widget_obj instanceof WP_Widget ) ) {
1032                 return;
1033         }
1034
1035         $default_args = array(
1036                 'before_widget' => '<div class="widget %s">',
1037                 'after_widget'  => "</div>",
1038                 'before_title'  => '<h2 class="widgettitle">',
1039                 'after_title'   => '</h2>',
1040         );
1041         $args = wp_parse_args( $args, $default_args );
1042         $args['before_widget'] = sprintf( $args['before_widget'], $widget_obj->widget_options['classname'] );
1043
1044         $instance = wp_parse_args($instance);
1045
1046         /**
1047          * Fires before rendering the requested widget.
1048          *
1049          * @since 3.0.0
1050          *
1051          * @param string $widget   The widget's class name.
1052          * @param array  $instance The current widget instance's settings.
1053          * @param array  $args     An array of the widget's sidebar arguments.
1054          */
1055         do_action( 'the_widget', $widget, $instance, $args );
1056
1057         $widget_obj->_set(-1);
1058         $widget_obj->widget($args, $instance);
1059 }
1060
1061 /**
1062  * Private
1063  *
1064  * @return string
1065  */
1066 function _get_widget_id_base($id) {
1067         return preg_replace( '/-[0-9]+$/', '', $id );
1068 }
1069
1070 /**
1071  * Handle sidebars config after theme change
1072  *
1073  * @access private
1074  * @since 3.3.0
1075  *
1076  * @global array $sidebars_widgets
1077  */
1078 function _wp_sidebars_changed() {
1079         global $sidebars_widgets;
1080
1081         if ( ! is_array( $sidebars_widgets ) )
1082                 $sidebars_widgets = wp_get_sidebars_widgets();
1083
1084         retrieve_widgets(true);
1085 }
1086
1087 /**
1088  * Look for "lost" widgets, this has to run at least on each theme change.
1089  *
1090  * @since 2.8.0
1091  *
1092  * @global array $wp_registered_sidebars
1093  * @global array $sidebars_widgets
1094  * @global array $wp_registered_widgets
1095  *
1096  * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
1097  *                                   of 'customize' defers updates for the Customizer.
1098  * @return array|void
1099  */
1100 function retrieve_widgets( $theme_changed = false ) {
1101         global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
1102
1103         $registered_sidebar_keys = array_keys( $wp_registered_sidebars );
1104         $orphaned = 0;
1105
1106         $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
1107         if ( is_array( $old_sidebars_widgets ) ) {
1108                 // time() that sidebars were stored is in $old_sidebars_widgets['time']
1109                 $_sidebars_widgets = $old_sidebars_widgets['data'];
1110
1111                 if ( 'customize' !== $theme_changed ) {
1112                         remove_theme_mod( 'sidebars_widgets' );
1113                 }
1114
1115                 foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
1116                         if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
1117                                 continue;
1118                         }
1119
1120                         if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {
1121                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;
1122                                 unset( $_sidebars_widgets[$sidebar] );
1123                         }
1124                 }
1125         } else {
1126                 if ( empty( $sidebars_widgets ) )
1127                         return;
1128
1129                 unset( $sidebars_widgets['array_version'] );
1130
1131                 $old = array_keys($sidebars_widgets);
1132                 sort($old);
1133                 sort($registered_sidebar_keys);
1134
1135                 if ( $old == $registered_sidebar_keys )
1136                         return;
1137
1138                 $_sidebars_widgets = array(
1139                         'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()
1140                 );
1141
1142                 unset( $sidebars_widgets['wp_inactive_widgets'] );
1143
1144                 foreach ( $wp_registered_sidebars as $id => $settings ) {
1145                         if ( $theme_changed ) {
1146                                 $_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
1147                         } else {
1148                                 // no theme change, grab only sidebars that are currently registered
1149                                 if ( isset( $sidebars_widgets[$id] ) ) {
1150                                         $_sidebars_widgets[$id] = $sidebars_widgets[$id];
1151                                         unset( $sidebars_widgets[$id] );
1152                                 }
1153                         }
1154                 }
1155
1156                 foreach ( $sidebars_widgets as $val ) {
1157                         if ( is_array($val) && ! empty( $val ) )
1158                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
1159                 }
1160         }
1161
1162         // discard invalid, theme-specific widgets from sidebars
1163         $shown_widgets = array();
1164
1165         foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
1166                 if ( !is_array($widgets) )
1167                         continue;
1168
1169                 $_widgets = array();
1170                 foreach ( $widgets as $widget ) {
1171                         if ( isset($wp_registered_widgets[$widget]) )
1172                                 $_widgets[] = $widget;
1173                 }
1174
1175                 $_sidebars_widgets[$sidebar] = $_widgets;
1176                 $shown_widgets = array_merge($shown_widgets, $_widgets);
1177         }
1178
1179         $sidebars_widgets = $_sidebars_widgets;
1180         unset($_sidebars_widgets, $_widgets);
1181
1182         // find hidden/lost multi-widget instances
1183         $lost_widgets = array();
1184         foreach ( $wp_registered_widgets as $key => $val ) {
1185                 if ( in_array($key, $shown_widgets, true) )
1186                         continue;
1187
1188                 $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
1189
1190                 if ( 2 > (int) $number )
1191                         continue;
1192
1193                 $lost_widgets[] = $key;
1194         }
1195
1196         $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
1197         if ( 'customize' !== $theme_changed ) {
1198                 wp_set_sidebars_widgets( $sidebars_widgets );
1199         }
1200
1201         return $sidebars_widgets;
1202 }
1203
1204 /**
1205  * Display the RSS entries in a list.
1206  *
1207  * @since 2.5.0
1208  *
1209  * @param string|array|object $rss RSS url.
1210  * @param array $args Widget arguments.
1211  */
1212 function wp_widget_rss_output( $rss, $args = array() ) {
1213         if ( is_string( $rss ) ) {
1214                 $rss = fetch_feed($rss);
1215         } elseif ( is_array($rss) && isset($rss['url']) ) {
1216                 $args = $rss;
1217                 $rss = fetch_feed($rss['url']);
1218         } elseif ( !is_object($rss) ) {
1219                 return;
1220         }
1221
1222         if ( is_wp_error($rss) ) {
1223                 if ( is_admin() || current_user_can('manage_options') )
1224                         echo '<p>' . sprintf( __('<strong>RSS Error</strong>: %s'), $rss->get_error_message() ) . '</p>';
1225                 return;
1226         }
1227
1228         $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0, 'items' => 0 );
1229         $args = wp_parse_args( $args, $default_args );
1230
1231         $items = (int) $args['items'];
1232         if ( $items < 1 || 20 < $items )
1233                 $items = 10;
1234         $show_summary  = (int) $args['show_summary'];
1235         $show_author   = (int) $args['show_author'];
1236         $show_date     = (int) $args['show_date'];
1237
1238         if ( !$rss->get_item_quantity() ) {
1239                 echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
1240                 $rss->__destruct();
1241                 unset($rss);
1242                 return;
1243         }
1244
1245         echo '<ul>';
1246         foreach ( $rss->get_items( 0, $items ) as $item ) {
1247                 $link = $item->get_link();
1248                 while ( stristr( $link, 'http' ) != $link ) {
1249                         $link = substr( $link, 1 );
1250                 }
1251                 $link = esc_url( strip_tags( $link ) );
1252
1253                 $title = esc_html( trim( strip_tags( $item->get_title() ) ) );
1254                 if ( empty( $title ) ) {
1255                         $title = __( 'Untitled' );
1256                 }
1257
1258                 $desc = @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option( 'blog_charset' ) );
1259                 $desc = esc_attr( wp_trim_words( $desc, 55, ' [&hellip;]' ) );
1260
1261                 $summary = '';
1262                 if ( $show_summary ) {
1263                         $summary = $desc;
1264
1265                         // Change existing [...] to [&hellip;].
1266                         if ( '[...]' == substr( $summary, -5 ) ) {
1267                                 $summary = substr( $summary, 0, -5 ) . '[&hellip;]';
1268                         }
1269
1270                         $summary = '<div class="rssSummary">' . esc_html( $summary ) . '</div>';
1271                 }
1272
1273                 $date = '';
1274                 if ( $show_date ) {
1275                         $date = $item->get_date( 'U' );
1276
1277                         if ( $date ) {
1278                                 $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
1279                         }
1280                 }
1281
1282                 $author = '';
1283                 if ( $show_author ) {
1284                         $author = $item->get_author();
1285                         if ( is_object($author) ) {
1286                                 $author = $author->get_name();
1287                                 $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
1288                         }
1289                 }
1290
1291                 if ( $link == '' ) {
1292                         echo "<li>$title{$date}{$summary}{$author}</li>";
1293                 } elseif ( $show_summary ) {
1294                         echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$summary}{$author}</li>";
1295                 } else {
1296                         echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$author}</li>";
1297                 }
1298         }
1299         echo '</ul>';
1300         $rss->__destruct();
1301         unset($rss);
1302 }
1303
1304 /**
1305  * Display RSS widget options form.
1306  *
1307  * The options for what fields are displayed for the RSS form are all booleans
1308  * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
1309  * 'show_date'.
1310  *
1311  * @since 2.5.0
1312  *
1313  * @param array|string $args Values for input fields.
1314  * @param array $inputs Override default display options.
1315  */
1316 function wp_widget_rss_form( $args, $inputs = null ) {
1317         $default_inputs = array( 'url' => true, 'title' => true, 'items' => true, 'show_summary' => true, 'show_author' => true, 'show_date' => true );
1318         $inputs = wp_parse_args( $inputs, $default_inputs );
1319
1320         $args['title'] = isset( $args['title'] ) ? $args['title'] : '';
1321         $args['url'] = isset( $args['url'] ) ? $args['url'] : '';
1322         $args['items'] = isset( $args['items'] ) ? (int) $args['items'] : 0;
1323
1324         if ( $args['items'] < 1 || 20 < $args['items'] ) {
1325                 $args['items'] = 10;
1326         }
1327
1328         $args['show_summary']   = isset( $args['show_summary'] ) ? (int) $args['show_summary'] : (int) $inputs['show_summary'];
1329         $args['show_author']    = isset( $args['show_author'] ) ? (int) $args['show_author'] : (int) $inputs['show_author'];
1330         $args['show_date']      = isset( $args['show_date'] ) ? (int) $args['show_date'] : (int) $inputs['show_date'];
1331
1332         if ( ! empty( $args['error'] ) ) {
1333                 echo '<p class="widget-error"><strong>' . sprintf( __( 'RSS Error: %s' ), $args['error'] ) . '</strong></p>';
1334         }
1335
1336         $esc_number = esc_attr( $args['number'] );
1337         if ( $inputs['url'] ) :
1338 ?>
1339         <p><label for="rss-url-<?php echo $esc_number; ?>"><?php _e( 'Enter the RSS feed URL here:' ); ?></label>
1340         <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>
1341 <?php endif; if ( $inputs['title'] ) : ?>
1342         <p><label for="rss-title-<?php echo $esc_number; ?>"><?php _e( 'Give the feed a title (optional):' ); ?></label>
1343         <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>
1344 <?php endif; if ( $inputs['items'] ) : ?>
1345         <p><label for="rss-items-<?php echo $esc_number; ?>"><?php _e( 'How many items would you like to display?' ); ?></label>
1346         <select id="rss-items-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][items]">
1347         <?php
1348         for ( $i = 1; $i <= 20; ++$i ) {
1349                 echo "<option value='$i' " . selected( $args['items'], $i, false ) . ">$i</option>";
1350         }
1351         ?>
1352         </select></p>
1353 <?php endif; if ( $inputs['show_summary'] ) : ?>
1354         <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'] ); ?> />
1355         <label for="rss-show-summary-<?php echo $esc_number; ?>"><?php _e( 'Display item content?' ); ?></label></p>
1356 <?php endif; if ( $inputs['show_author'] ) : ?>
1357         <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'] ); ?> />
1358         <label for="rss-show-author-<?php echo $esc_number; ?>"><?php _e( 'Display item author if available?' ); ?></label></p>
1359 <?php endif; if ( $inputs['show_date'] ) : ?>
1360         <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'] ); ?>/>
1361         <label for="rss-show-date-<?php echo $esc_number; ?>"><?php _e( 'Display item date?' ); ?></label></p>
1362 <?php
1363         endif;
1364         foreach ( array_keys($default_inputs) as $input ) :
1365                 if ( 'hidden' === $inputs[$input] ) :
1366                         $id = str_replace( '_', '-', $input );
1367 ?>
1368         <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 ] ); ?>" />
1369 <?php
1370                 endif;
1371         endforeach;
1372 }
1373
1374 /**
1375  * Process RSS feed widget data and optionally retrieve feed items.
1376  *
1377  * The feed widget can not have more than 20 items or it will reset back to the
1378  * default, which is 10.
1379  *
1380  * The resulting array has the feed title, feed url, feed link (from channel),
1381  * feed items, error (if any), and whether to show summary, author, and date.
1382  * All respectively in the order of the array elements.
1383  *
1384  * @since 2.5.0
1385  *
1386  * @param array $widget_rss RSS widget feed data. Expects unescaped data.
1387  * @param bool $check_feed Optional, default is true. Whether to check feed for errors.
1388  * @return array
1389  */
1390 function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
1391         $items = (int) $widget_rss['items'];
1392         if ( $items < 1 || 20 < $items )
1393                 $items = 10;
1394         $url           = esc_url_raw( strip_tags( $widget_rss['url'] ) );
1395         $title         = isset( $widget_rss['title'] ) ? trim( strip_tags( $widget_rss['title'] ) ) : '';
1396         $show_summary  = isset( $widget_rss['show_summary'] ) ? (int) $widget_rss['show_summary'] : 0;
1397         $show_author   = isset( $widget_rss['show_author'] ) ? (int) $widget_rss['show_author'] :0;
1398         $show_date     = isset( $widget_rss['show_date'] ) ? (int) $widget_rss['show_date'] : 0;
1399
1400         if ( $check_feed ) {
1401                 $rss = fetch_feed($url);
1402                 $error = false;
1403                 $link = '';
1404                 if ( is_wp_error($rss) ) {
1405                         $error = $rss->get_error_message();
1406                 } else {
1407                         $link = esc_url(strip_tags($rss->get_permalink()));
1408                         while ( stristr($link, 'http') != $link )
1409                                 $link = substr($link, 1);
1410
1411                         $rss->__destruct();
1412                         unset($rss);
1413                 }
1414         }
1415
1416         return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
1417 }
1418
1419 /**
1420  * Register all of the default WordPress widgets on startup.
1421  *
1422  * Calls 'widgets_init' action after all of the WordPress widgets have been
1423  * registered.
1424  *
1425  * @since 2.2.0
1426  */
1427 function wp_widgets_init() {
1428         if ( !is_blog_installed() )
1429                 return;
1430
1431         register_widget('WP_Widget_Pages');
1432
1433         register_widget('WP_Widget_Calendar');
1434
1435         register_widget('WP_Widget_Archives');
1436
1437         if ( get_option( 'link_manager_enabled' ) )
1438                 register_widget('WP_Widget_Links');
1439
1440         register_widget('WP_Widget_Meta');
1441
1442         register_widget('WP_Widget_Search');
1443
1444         register_widget('WP_Widget_Text');
1445
1446         register_widget('WP_Widget_Categories');
1447
1448         register_widget('WP_Widget_Recent_Posts');
1449
1450         register_widget('WP_Widget_Recent_Comments');
1451
1452         register_widget('WP_Widget_RSS');
1453
1454         register_widget('WP_Widget_Tag_Cloud');
1455
1456         register_widget('WP_Nav_Menu_Widget');
1457
1458         /**
1459          * Fires after all default WordPress widgets have been registered.
1460          *
1461          * @since 2.2.0
1462          */
1463         do_action( 'widgets_init' );
1464 }