wp/wp-includes/widgets.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     1 <?php
     1 <?php
     2 /**
     2 /**
     3  * API for creating dynamic sidebar without hardcoding functionality into
     3  * Core Widgets API
     4  * themes. Includes both internal WordPress routines and theme use routines.
     4  *
     5  *
     5  * This API is used for creating dynamic sidebar without hardcoding functionality into
     6  * This functionality was found in a plugin before WordPress 2.2 release which
     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
     7  * included it in the core from that point on.
    11  * included it in the core from that point on.
     8  *
    12  *
     9  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
    13  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
    10  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
    14  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
    11  *
    15  *
    12  * @package WordPress
    16  * @package WordPress
    13  * @subpackage Widgets
    17  * @subpackage Widgets
    14  */
    18  * @since 2.2.0
    15 
    19  */
    16 /**
    20 
    17  * This class must be extended for each widget and WP_Widget::widget(), WP_Widget::update()
    21 //
    18  * and WP_Widget::form() need to be over-ridden.
    22 // Global Variables
    19  *
    23 //
    20  * @package WordPress
       
    21  * @subpackage Widgets
       
    22  * @since 2.8.0
       
    23  */
       
    24 class WP_Widget {
       
    25 
       
    26 	/**
       
    27 	 * Root ID for all widgets of this type.
       
    28 	 *
       
    29 	 * @since 2.8.0
       
    30 	 * @access public
       
    31 	 * @var mixed|string
       
    32 	 */
       
    33 	public $id_base;
       
    34 
       
    35 	/**
       
    36 	 * Name for this widget type.
       
    37 	 *
       
    38 	 * @since 2.8.0
       
    39 	 * @access public
       
    40 	 * @var string
       
    41 	 */
       
    42 	public $name;
       
    43 
       
    44 	/**
       
    45 	 * Option array passed to {@see wp_register_sidebar_widget()}.
       
    46 	 *
       
    47 	 * @since 2.8.0
       
    48 	 * @access public
       
    49 	 * @var array
       
    50 	 */
       
    51 	public $widget_options;
       
    52 
       
    53 	/**
       
    54 	 * Option array passed to {@see wp_register_widget_control()}.
       
    55 	 *
       
    56 	 * @since 2.8.0
       
    57 	 * @access public
       
    58 	 * @var array
       
    59 	 */
       
    60 	public $control_options;
       
    61 
       
    62 	/**
       
    63 	 * Unique ID number of the current instance.
       
    64 	 *
       
    65 	 * @since 2.8.0
       
    66 	 * @access public
       
    67 	 * @var bool|int
       
    68 	 */
       
    69 	public $number = false;
       
    70 
       
    71 	/**
       
    72 	 * Unique ID string of the current instance (id_base-number).
       
    73 	 *
       
    74 	 * @since 2.8.0
       
    75 	 * @access public
       
    76 	 * @var bool|string
       
    77 	 */
       
    78 	public $id = false;
       
    79 
       
    80 	/**
       
    81 	 * Whether the widget data has been updated.
       
    82 	 *
       
    83 	 * Set to true when the data is updated after a POST submit - ensures it does
       
    84 	 * not happen twice.
       
    85 	 *
       
    86 	 * @since 2.8.0
       
    87 	 * @access public
       
    88 	 * @var bool
       
    89 	 */
       
    90 	public $updated = false;
       
    91 
       
    92 	// Member functions that you must over-ride.
       
    93 
       
    94 	/**
       
    95 	 * Echo the widget content.
       
    96 	 *
       
    97 	 * Subclasses should over-ride this function to generate their widget code.
       
    98 	 *
       
    99 	 * @since 2.8.0
       
   100 	 * @access public
       
   101 	 *
       
   102 	 * @param array $args     Display arguments including before_title, after_title,
       
   103 	 *                        before_widget, and after_widget.
       
   104 	 * @param array $instance The settings for the particular instance of the widget.
       
   105 	 */
       
   106 	public function widget( $args, $instance ) {
       
   107 		die('function WP_Widget::widget() must be over-ridden in a sub-class.');
       
   108 	}
       
   109 
       
   110 	/**
       
   111 	 * Update a particular instance.
       
   112 	 *
       
   113 	 * This function should check that $new_instance is set correctly. The newly-calculated
       
   114 	 * value of `$instance` should be returned. If false is returned, the instance won't be
       
   115 	 * saved/updated.
       
   116 	 *
       
   117 	 * @since 2.8.0
       
   118 	 * @access public
       
   119 	 *
       
   120 	 * @param array $new_instance New settings for this instance as input by the user via
       
   121 	 *                            {@see WP_Widget::form()}.
       
   122 	 * @param array $old_instance Old settings for this instance.
       
   123 	 * @return array Settings to save or bool false to cancel saving.
       
   124 	 */
       
   125 	public function update( $new_instance, $old_instance ) {
       
   126 		return $new_instance;
       
   127 	}
       
   128 
       
   129 	/**
       
   130 	 * Output the settings update form.
       
   131 	 *
       
   132 	 * @since 2.8.0
       
   133 	 * @access public
       
   134 	 *
       
   135 	 * @param array $instance Current settings.
       
   136 	 * @return string Default return is 'noform'.
       
   137 	 */
       
   138 	public function form($instance) {
       
   139 		echo '<p class="no-options-widget">' . __('There are no options for this widget.') . '</p>';
       
   140 		return 'noform';
       
   141 	}
       
   142 
       
   143 	// Functions you'll need to call.
       
   144 
       
   145 	/**
       
   146 	 * PHP5 constructor.
       
   147 	 *
       
   148 	 * @since 2.8.0
       
   149 	 * @access public
       
   150 	 *
       
   151 	 * @param string $id_base         Optional Base ID for the widget, lowercase and unique. If left empty,
       
   152 	 *                                a portion of the widget's class name will be used Has to be unique.
       
   153 	 * @param string $name            Name for the widget displayed on the configuration page.
       
   154 	 * @param array  $widget_options  Optional. Widget options. See {@see wp_register_sidebar_widget()} for
       
   155 	 *                                information on accepted arguments. Default empty array.
       
   156 	 * @param array  $control_options Optional. Widget control options. See {@see wp_register_widget_control()}
       
   157 	 *                                for information on accepted arguments. Default empty array.
       
   158 	 */
       
   159 	public function __construct( $id_base, $name, $widget_options = array(), $control_options = array() ) {
       
   160 		$this->id_base = empty($id_base) ? preg_replace( '/(wp_)?widget_/', '', strtolower(get_class($this)) ) : strtolower($id_base);
       
   161 		$this->name = $name;
       
   162 		$this->option_name = 'widget_' . $this->id_base;
       
   163 		$this->widget_options = wp_parse_args( $widget_options, array('classname' => $this->option_name) );
       
   164 		$this->control_options = wp_parse_args( $control_options, array('id_base' => $this->id_base) );
       
   165 	}
       
   166 
       
   167 	/**
       
   168 	 * PHP4 constructor
       
   169 	 *
       
   170 	 * @param string $id_base
       
   171 	 * @param string $name
       
   172 	 * @param array  $widget_options
       
   173 	 * @param array  $control_options
       
   174 	 */
       
   175 	public function WP_Widget( $id_base, $name, $widget_options = array(), $control_options = array() ) {
       
   176 		WP_Widget::__construct( $id_base, $name, $widget_options, $control_options );
       
   177 	}
       
   178 
       
   179 	/**
       
   180 	 * Constructs name attributes for use in form() fields
       
   181 	 *
       
   182 	 * This function should be used in form() methods to create name attributes for fields to be saved by update()
       
   183 	 *
       
   184 	 * @param string $field_name Field name
       
   185 	 * @return string Name attribute for $field_name
       
   186 	 */
       
   187 	public function get_field_name($field_name) {
       
   188 		return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']';
       
   189 	}
       
   190 
       
   191 	/**
       
   192 	 * Constructs id attributes for use in {@see WP_Widget::form()} fields.
       
   193 	 *
       
   194 	 * This function should be used in form() methods to create id attributes
       
   195 	 * for fields to be saved by {@see WP_Widget::update()}.
       
   196 	 *
       
   197 	 * @since 2.8.0
       
   198 	 * @access public
       
   199 	 *
       
   200 	 * @param string $field_name Field name.
       
   201 	 * @return string ID attribute for `$field_name`.
       
   202 	 */
       
   203 	public function get_field_id( $field_name ) {
       
   204 		return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field_name;
       
   205 	}
       
   206 
       
   207 	/**
       
   208 	 * Register all widget instances of this widget class.
       
   209 	 *
       
   210 	 * @since 2.8.0
       
   211 	 * @access private
       
   212 	 */
       
   213 	public function _register() {
       
   214 		$settings = $this->get_settings();
       
   215 		$empty = true;
       
   216 
       
   217 		if ( is_array($settings) ) {
       
   218 			foreach ( array_keys($settings) as $number ) {
       
   219 				if ( is_numeric($number) ) {
       
   220 					$this->_set($number);
       
   221 					$this->_register_one($number);
       
   222 					$empty = false;
       
   223 				}
       
   224 			}
       
   225 		}
       
   226 
       
   227 		if ( $empty ) {
       
   228 			// If there are none, we register the widget's existence with a
       
   229 			// generic template
       
   230 			$this->_set(1);
       
   231 			$this->_register_one();
       
   232 		}
       
   233 	}
       
   234 
       
   235 	/**
       
   236 	 * Set the internal order number for the widget instance.
       
   237 	 *
       
   238 	 * @since 2.8.0
       
   239 	 * @access private
       
   240 	 *
       
   241 	 * @param int $number The unique order number of this widget instance compared to other
       
   242 	 *                    instances of the same class.
       
   243 	 */
       
   244 	public function _set($number) {
       
   245 		$this->number = $number;
       
   246 		$this->id = $this->id_base . '-' . $number;
       
   247 	}
       
   248 
       
   249 	public function _get_display_callback() {
       
   250 		return array($this, 'display_callback');
       
   251 	}
       
   252 
       
   253 	public function _get_update_callback() {
       
   254 		return array($this, 'update_callback');
       
   255 	}
       
   256 
       
   257 	public function _get_form_callback() {
       
   258 		return array($this, 'form_callback');
       
   259 	}
       
   260 
       
   261 	/**
       
   262 	 * Determine whether the current request is inside the Customizer preview.
       
   263 	 *
       
   264 	 * If true -- the current request is inside the Customizer preview, then
       
   265 	 * the object cache gets suspended and widgets should check this to decide
       
   266 	 * whether they should store anything persistently to the object cache,
       
   267 	 * to transients, or anywhere else.
       
   268 	 *
       
   269 	 * @since 3.9.0
       
   270 	 * @access public
       
   271 	 *
       
   272 	 * @return bool True if within the Customizer preview, false if not.
       
   273 	 */
       
   274 	public function is_preview() {
       
   275 		global $wp_customize;
       
   276 		return ( isset( $wp_customize ) && $wp_customize->is_preview() ) ;
       
   277 	}
       
   278 
       
   279 	/**
       
   280 	 * Generate the actual widget content (Do NOT override).
       
   281 	 *
       
   282 	 * Finds the instance and calls {@see WP_Widget::widget()}.
       
   283 	 *
       
   284 	 * @since 2.8.0
       
   285 	 * @access public
       
   286 	 *
       
   287 	 * @param array     $args        Display arguments. See {@see WP_Widget::widget()} for information
       
   288 	 *                               on accepted arguments.
       
   289 	 * @param int|array $widget_args {
       
   290 	 *     Optional. Internal order number of the widget instance, or array of multi-widget arguments.
       
   291 	 *     Default 1.
       
   292 	 *
       
   293 	 *     @type int $number Number increment used for multiples of the same widget.
       
   294 	 * }
       
   295 	 */
       
   296 	public function display_callback( $args, $widget_args = 1 ) {
       
   297 		if ( is_numeric($widget_args) )
       
   298 			$widget_args = array( 'number' => $widget_args );
       
   299 
       
   300 		$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
       
   301 		$this->_set( $widget_args['number'] );
       
   302 		$instance = $this->get_settings();
       
   303 
       
   304 		if ( array_key_exists( $this->number, $instance ) ) {
       
   305 			$instance = $instance[$this->number];
       
   306 
       
   307 			/**
       
   308 			 * Filter the settings for a particular widget instance.
       
   309 			 *
       
   310 			 * Returning false will effectively short-circuit display of the widget.
       
   311 			 *
       
   312 			 * @since 2.8.0
       
   313 			 *
       
   314 			 * @param array     $instance The current widget instance's settings.
       
   315 			 * @param WP_Widget $this     The current widget instance.
       
   316 			 * @param array     $args     An array of default widget arguments.
       
   317 			 */
       
   318 			$instance = apply_filters( 'widget_display_callback', $instance, $this, $args );
       
   319 
       
   320 			if ( false === $instance ) {
       
   321 				return;
       
   322 			}
       
   323 
       
   324 			$was_cache_addition_suspended = wp_suspend_cache_addition();
       
   325 			if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
       
   326 				wp_suspend_cache_addition( true );
       
   327 			}
       
   328 
       
   329 			$this->widget( $args, $instance );
       
   330 
       
   331 			if ( $this->is_preview() ) {
       
   332 				wp_suspend_cache_addition( $was_cache_addition_suspended );
       
   333 			}
       
   334 		}
       
   335 	}
       
   336 
       
   337 	/**
       
   338 	 * Deal with changed settings (Do NOT override).
       
   339 	 *
       
   340 	 * @since 2.8.0
       
   341 	 * @access public
       
   342 	 *
       
   343 	 * @param int $deprecated Not used.
       
   344 	 */
       
   345 	public function update_callback( $deprecated = 1 ) {
       
   346 		global $wp_registered_widgets;
       
   347 
       
   348 		$all_instances = $this->get_settings();
       
   349 
       
   350 		// We need to update the data
       
   351 		if ( $this->updated )
       
   352 			return;
       
   353 
       
   354 		if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
       
   355 			// Delete the settings for this instance of the widget
       
   356 			if ( isset($_POST['the-widget-id']) )
       
   357 				$del_id = $_POST['the-widget-id'];
       
   358 			else
       
   359 				return;
       
   360 
       
   361 			if ( isset($wp_registered_widgets[$del_id]['params'][0]['number']) ) {
       
   362 				$number = $wp_registered_widgets[$del_id]['params'][0]['number'];
       
   363 
       
   364 				if ( $this->id_base . '-' . $number == $del_id )
       
   365 					unset($all_instances[$number]);
       
   366 			}
       
   367 		} else {
       
   368 			if ( isset($_POST['widget-' . $this->id_base]) && is_array($_POST['widget-' . $this->id_base]) ) {
       
   369 				$settings = $_POST['widget-' . $this->id_base];
       
   370 			} elseif ( isset($_POST['id_base']) && $_POST['id_base'] == $this->id_base ) {
       
   371 				$num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number'];
       
   372 				$settings = array( $num => array() );
       
   373 			} else {
       
   374 				return;
       
   375 			}
       
   376 
       
   377 			foreach ( $settings as $number => $new_instance ) {
       
   378 				$new_instance = stripslashes_deep($new_instance);
       
   379 				$this->_set($number);
       
   380 
       
   381 				$old_instance = isset($all_instances[$number]) ? $all_instances[$number] : array();
       
   382 
       
   383 				$was_cache_addition_suspended = wp_suspend_cache_addition();
       
   384 				if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
       
   385 					wp_suspend_cache_addition( true );
       
   386 				}
       
   387 
       
   388 				$instance = $this->update( $new_instance, $old_instance );
       
   389 
       
   390 				if ( $this->is_preview() ) {
       
   391 					wp_suspend_cache_addition( $was_cache_addition_suspended );
       
   392 				}
       
   393 
       
   394 				/**
       
   395 				 * Filter a widget's settings before saving.
       
   396 				 *
       
   397 				 * Returning false will effectively short-circuit the widget's ability
       
   398 				 * to update settings.
       
   399 				 *
       
   400 				 * @since 2.8.0
       
   401 				 *
       
   402 				 * @param array     $instance     The current widget instance's settings.
       
   403 				 * @param array     $new_instance Array of new widget settings.
       
   404 				 * @param array     $old_instance Array of old widget settings.
       
   405 				 * @param WP_Widget $this         The current widget instance.
       
   406 				 */
       
   407 				$instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this );
       
   408 				if ( false !== $instance ) {
       
   409 					$all_instances[$number] = $instance;
       
   410 				}
       
   411 
       
   412 				break; // run only once
       
   413 			}
       
   414 		}
       
   415 
       
   416 		$this->save_settings($all_instances);
       
   417 		$this->updated = true;
       
   418 	}
       
   419 
       
   420 	/**
       
   421 	 * Generate the widget control form (Do NOT override).
       
   422 	 *
       
   423 	 * @since 2.8.0
       
   424 	 * @access public
       
   425 	 *
       
   426 	 * @param int|array $widget_args Widget instance number or array of widget arguments.
       
   427 	 */
       
   428 	public function form_callback( $widget_args = 1 ) {
       
   429 		if ( is_numeric($widget_args) )
       
   430 			$widget_args = array( 'number' => $widget_args );
       
   431 
       
   432 		$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
       
   433 		$all_instances = $this->get_settings();
       
   434 
       
   435 		if ( -1 == $widget_args['number'] ) {
       
   436 			// We echo out a form where 'number' can be set later
       
   437 			$this->_set('__i__');
       
   438 			$instance = array();
       
   439 		} else {
       
   440 			$this->_set($widget_args['number']);
       
   441 			$instance = $all_instances[ $widget_args['number'] ];
       
   442 		}
       
   443 
       
   444 		/**
       
   445 		 * Filter the widget instance's settings before displaying the control form.
       
   446 		 *
       
   447 		 * Returning false effectively short-circuits display of the control form.
       
   448 		 *
       
   449 		 * @since 2.8.0
       
   450 		 *
       
   451 		 * @param array     $instance The current widget instance's settings.
       
   452 		 * @param WP_Widget $this     The current widget instance.
       
   453 		 */
       
   454 		$instance = apply_filters( 'widget_form_callback', $instance, $this );
       
   455 
       
   456 		$return = null;
       
   457 		if ( false !== $instance ) {
       
   458 			$return = $this->form($instance);
       
   459 
       
   460 			/**
       
   461 			 * Fires at the end of the widget control form.
       
   462 			 *
       
   463 			 * Use this hook to add extra fields to the widget form. The hook
       
   464 			 * is only fired if the value passed to the 'widget_form_callback'
       
   465 			 * hook is not false.
       
   466 			 *
       
   467 			 * Note: If the widget has no form, the text echoed from the default
       
   468 			 * form method can be hidden using CSS.
       
   469 			 *
       
   470 			 * @since 2.8.0
       
   471 			 *
       
   472 			 * @param WP_Widget $this     The widget instance, passed by reference.
       
   473 			 * @param null      $return   Return null if new fields are added.
       
   474 			 * @param array     $instance An array of the widget's settings.
       
   475 			 */
       
   476 			do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) );
       
   477 		}
       
   478 		return $return;
       
   479 	}
       
   480 
       
   481 	/**
       
   482 	 * Register an instance of the widget class.
       
   483 	 *
       
   484 	 * @since 2.8.0
       
   485 	 * @access private
       
   486 	 *
       
   487 	 * @param integer $number Optional. The unique order number of this widget instance
       
   488 	 *                        compared to other instances of the same class. Default -1.
       
   489 	 */
       
   490 	public function _register_one( $number = -1 ) {
       
   491 		wp_register_sidebar_widget(	$this->id, $this->name,	$this->_get_display_callback(), $this->widget_options, array( 'number' => $number ) );
       
   492 		_register_widget_update_callback( $this->id_base, $this->_get_update_callback(), $this->control_options, array( 'number' => -1 ) );
       
   493 		_register_widget_form_callback(	$this->id, $this->name,	$this->_get_form_callback(), $this->control_options, array( 'number' => $number ) );
       
   494 	}
       
   495 
       
   496 	/**
       
   497 	 * Save the settings for all instances of the widget class.
       
   498 	 *
       
   499 	 * @since 2.8.0
       
   500 	 * @access public
       
   501 	 *
       
   502 	 * @param array $settings Multi-dimensional array of widget instance settings.
       
   503 	 */
       
   504 	public function save_settings( $settings ) {
       
   505 		$settings['_multiwidget'] = 1;
       
   506 		update_option( $this->option_name, $settings );
       
   507 	}
       
   508 
       
   509 	/**
       
   510 	 * Get the settings for all instances of the widget class.
       
   511 	 *
       
   512 	 * @since 2.8.0
       
   513 	 * @access public
       
   514 	 *
       
   515 	 * @return array Multi-dimensional array of widget instance settings.
       
   516 	 */
       
   517 	public function get_settings() {
       
   518 
       
   519 		$settings = get_option($this->option_name);
       
   520 
       
   521 		if ( false === $settings && isset($this->alt_option_name) )
       
   522 			$settings = get_option($this->alt_option_name);
       
   523 
       
   524 		if ( !is_array($settings) )
       
   525 			$settings = array();
       
   526 
       
   527 		if ( !empty($settings) && !array_key_exists('_multiwidget', $settings) ) {
       
   528 			// old format, convert if single widget
       
   529 			$settings = wp_convert_widget_settings($this->id_base, $this->option_name, $settings);
       
   530 		}
       
   531 
       
   532 		unset($settings['_multiwidget'], $settings['__i__']);
       
   533 		return $settings;
       
   534 	}
       
   535 }
       
   536 
       
   537 /**
       
   538  * Singleton that registers and instantiates WP_Widget classes.
       
   539  *
       
   540  * @package WordPress
       
   541  * @subpackage Widgets
       
   542  * @since 2.8.0
       
   543  */
       
   544 class WP_Widget_Factory {
       
   545 	public $widgets = array();
       
   546 
       
   547 	public function WP_Widget_Factory() {
       
   548 		add_action( 'widgets_init', array( $this, '_register_widgets' ), 100 );
       
   549 	}
       
   550 
       
   551 	/**
       
   552 	 * Register a widget subclass.
       
   553 	 *
       
   554 	 * @since 2.8.0
       
   555 	 * @access public
       
   556 	 *
       
   557 	 * @param string $widget_class The name of a {@see WP_Widget} subclass.
       
   558 	 */
       
   559 	public function register( $widget_class ) {
       
   560 		$this->widgets[$widget_class] = new $widget_class();
       
   561 	}
       
   562 
       
   563 	/**
       
   564 	 * Un-register a widget subclass.
       
   565 	 *
       
   566 	 * @since 2.8.0
       
   567 	 * @access public
       
   568 	 *
       
   569 	 * @param string $widget_class The name of a {@see WP_Widget} subclass.
       
   570 	 */
       
   571 	public function unregister( $widget_class ) {
       
   572 		if ( isset($this->widgets[$widget_class]) )
       
   573 			unset($this->widgets[$widget_class]);
       
   574 	}
       
   575 
       
   576 	/**
       
   577 	 * Utility method for adding widgets to the registered widgets global.
       
   578 	 *
       
   579 	 * @since 2.8.0
       
   580 	 * @access public
       
   581 	 */
       
   582 	public function _register_widgets() {
       
   583 		global $wp_registered_widgets;
       
   584 		$keys = array_keys($this->widgets);
       
   585 		$registered = array_keys($wp_registered_widgets);
       
   586 		$registered = array_map('_get_widget_id_base', $registered);
       
   587 
       
   588 		foreach ( $keys as $key ) {
       
   589 			// don't register new widget if old widget with the same id is already registered
       
   590 			if ( in_array($this->widgets[$key]->id_base, $registered, true) ) {
       
   591 				unset($this->widgets[$key]);
       
   592 				continue;
       
   593 			}
       
   594 
       
   595 			$this->widgets[$key]->_register();
       
   596 		}
       
   597 	}
       
   598 }
       
   599 
       
   600 /* Global Variables */
       
   601 
    24 
   602 /** @ignore */
    25 /** @ignore */
   603 global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
    26 global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
   604 
    27 
   605 /**
    28 /**
   623  *
    46  *
   624  * @global array $wp_registered_widget_controls
    47  * @global array $wp_registered_widget_controls
   625  * @since 2.2.0
    48  * @since 2.2.0
   626  */
    49  */
   627 $wp_registered_widget_controls = array();
    50 $wp_registered_widget_controls = array();
       
    51 /**
       
    52  * @global array $wp_registered_widget_updates
       
    53  */
   628 $wp_registered_widget_updates = array();
    54 $wp_registered_widget_updates = array();
   629 
    55 
   630 /**
    56 /**
   631  * Private
    57  * Private
       
    58  *
       
    59  * @global array $_wp_sidebars_widgets
   632  */
    60  */
   633 $_wp_sidebars_widgets = array();
    61 $_wp_sidebars_widgets = array();
   634 
    62 
   635 /**
    63 /**
   636  * Private
    64  * Private
       
    65  *
       
    66  * @global array $_wp_deprecated_widgets_callbacks
   637  */
    67  */
   638 $GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
    68 $GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
   639 	'wp_widget_pages',
    69 	'wp_widget_pages',
   640 	'wp_widget_pages_control',
    70 	'wp_widget_pages_control',
   641 	'wp_widget_calendar',
    71 	'wp_widget_calendar',
   658 	'wp_widget_rss_control',
    88 	'wp_widget_rss_control',
   659 	'wp_widget_recent_comments',
    89 	'wp_widget_recent_comments',
   660 	'wp_widget_recent_comments_control'
    90 	'wp_widget_recent_comments_control'
   661 );
    91 );
   662 
    92 
   663 /* Template tags & API functions */
    93 //
       
    94 // Template tags & API functions
       
    95 //
   664 
    96 
   665 /**
    97 /**
   666  * Register a widget
    98  * Register a widget
   667  *
    99  *
   668  * Registers a WP_Widget widget
   100  * Registers a WP_Widget widget
   669  *
   101  *
   670  * @since 2.8.0
   102  * @since 2.8.0
       
   103  * @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
       
   104  *              instead of simply a `WP_Widget` subclass name.
   671  *
   105  *
   672  * @see WP_Widget
   106  * @see WP_Widget
   673  * @see WP_Widget_Factory
   107  *
   674  * @uses WP_Widget_Factory
   108  * @global WP_Widget_Factory $wp_widget_factory
   675  *
   109  *
   676  * @param string $widget_class The name of a class that extends WP_Widget
   110  * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
   677  */
   111  */
   678 function register_widget($widget_class) {
   112 function register_widget( $widget ) {
   679 	global $wp_widget_factory;
   113 	global $wp_widget_factory;
   680 
   114 
   681 	$wp_widget_factory->register($widget_class);
   115 	$wp_widget_factory->register( $widget );
   682 }
   116 }
   683 
   117 
   684 /**
   118 /**
   685  * Unregister a widget
   119  * Unregisters a widget.
   686  *
   120  *
   687  * Unregisters a WP_Widget widget. Useful for unregistering default widgets.
   121  * Unregisters a WP_Widget widget. Useful for un-registering default widgets.
   688  * Run within a function hooked to the widgets_init action.
   122  * Run within a function hooked to the {@see 'widgets_init'} action.
   689  *
   123  *
   690  * @since 2.8.0
   124  * @since 2.8.0
       
   125  * @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
       
   126  *              instead of simply a `WP_Widget` subclass name.
   691  *
   127  *
   692  * @see WP_Widget
   128  * @see WP_Widget
   693  * @see WP_Widget_Factory
   129  *
   694  * @uses WP_Widget_Factory
   130  * @global WP_Widget_Factory $wp_widget_factory
   695  *
   131  *
   696  * @param string $widget_class The name of a class that extends WP_Widget
   132  * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
   697  */
   133  */
   698 function unregister_widget($widget_class) {
   134 function unregister_widget( $widget ) {
   699 	global $wp_widget_factory;
   135 	global $wp_widget_factory;
   700 
   136 
   701 	$wp_widget_factory->unregister($widget_class);
   137 	$wp_widget_factory->unregister( $widget );
   702 }
   138 }
   703 
   139 
   704 /**
   140 /**
   705  * Creates multiple sidebars.
   141  * Creates multiple sidebars.
   706  *
   142  *
   709  * 'id' in `$args`, then they will be built for you.
   145  * 'id' in `$args`, then they will be built for you.
   710  *
   146  *
   711  * @since 2.2.0
   147  * @since 2.2.0
   712  *
   148  *
   713  * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
   149  * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
       
   150  *
       
   151  * @global array $wp_registered_sidebars
   714  *
   152  *
   715  * @param int          $number Optional. Number of sidebars to create. Default 1.
   153  * @param int          $number Optional. Number of sidebars to create. Default 1.
   716  * @param array|string $args {
   154  * @param array|string $args {
   717  *     Optional. Array or string of arguments for building a sidebar.
   155  *     Optional. Array or string of arguments for building a sidebar.
   718  *
   156  *
   743 		// Custom specified ID's are suffixed if they exist already.
   181 		// Custom specified ID's are suffixed if they exist already.
   744 		// Automatically generated sidebar names need to be suffixed regardless starting at -0
   182 		// Automatically generated sidebar names need to be suffixed regardless starting at -0
   745 		if ( isset($args['id']) ) {
   183 		if ( isset($args['id']) ) {
   746 			$_args['id'] = $args['id'];
   184 			$_args['id'] = $args['id'];
   747 			$n = 2; // Start at -2 for conflicting custom ID's
   185 			$n = 2; // Start at -2 for conflicting custom ID's
   748 			while ( isset($wp_registered_sidebars[$_args['id']]) )
   186 			while ( is_registered_sidebar( $_args['id'] ) ) {
   749 				$_args['id'] = $args['id'] . '-' . $n++;
   187 				$_args['id'] = $args['id'] . '-' . $n++;
       
   188 			}
   750 		} else {
   189 		} else {
   751 			$n = count($wp_registered_sidebars);
   190 			$n = count( $wp_registered_sidebars );
   752 			do {
   191 			do {
   753 				$_args['id'] = 'sidebar-' . ++$n;
   192 				$_args['id'] = 'sidebar-' . ++$n;
   754 			} while ( isset($wp_registered_sidebars[$_args['id']]) );
   193 			} while ( is_registered_sidebar( $_args['id'] ) );
   755 		}
   194 		}
   756 		register_sidebar($_args);
   195 		register_sidebar($_args);
   757 	}
   196 	}
   758 }
   197 }
   759 
   198 
   842 /**
   281 /**
   843  * Removes a sidebar from the list.
   282  * Removes a sidebar from the list.
   844  *
   283  *
   845  * @since 2.2.0
   284  * @since 2.2.0
   846  *
   285  *
   847  * @uses $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
   286  * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
   848  *
   287  *
   849  * @param string $name The ID of the sidebar when it was added.
   288  * @param string|int $sidebar_id The ID of the sidebar when it was registered.
   850  */
   289  */
   851 function unregister_sidebar( $name ) {
   290 function unregister_sidebar( $sidebar_id ) {
   852 	global $wp_registered_sidebars;
   291 	global $wp_registered_sidebars;
   853 
   292 
   854 	if ( isset( $wp_registered_sidebars[$name] ) )
   293 	unset( $wp_registered_sidebars[ $sidebar_id ] );
   855 		unset( $wp_registered_sidebars[$name] );
   294 }
       
   295 
       
   296 /**
       
   297  * Checks if a sidebar is registered.
       
   298  *
       
   299  * @since 4.4.0
       
   300  *
       
   301  * @global array $wp_registered_sidebars Registered sidebars.
       
   302  *
       
   303  * @param string|int $sidebar_id The ID of the sidebar when it was registered.
       
   304  * @return bool True if the sidebar is registered, false otherwise.
       
   305  */
       
   306 function is_registered_sidebar( $sidebar_id ) {
       
   307 	global $wp_registered_sidebars;
       
   308 
       
   309 	return isset( $wp_registered_sidebars[ $sidebar_id ] );
   856 }
   310 }
   857 
   311 
   858 /**
   312 /**
   859  * Register an instance of a widget.
   313  * Register an instance of a widget.
   860  *
   314  *
   863  * The function can also be used to un-register widgets when `$output_callback`
   317  * The function can also be used to un-register widgets when `$output_callback`
   864  * parameter is an empty string.
   318  * parameter is an empty string.
   865  *
   319  *
   866  * @since 2.2.0
   320  * @since 2.2.0
   867  *
   321  *
   868  * @global array $wp_registered_widgets       Uses stored registered widgets.
   322  * @global array $wp_registered_widgets            Uses stored registered widgets.
   869  * @global array $wp_register_widget_defaults Retrieves widget defaults.
   323  * @global array $wp_registered_widget_controls    Stores the registered widget controls (options).
       
   324  * @global array $wp_registered_widget_updates
       
   325  * @global array $_wp_deprecated_widgets_callbacks
   870  *
   326  *
   871  * @param int|string $id              Widget ID.
   327  * @param int|string $id              Widget ID.
   872  * @param string     $name            Widget display title.
   328  * @param string     $name            Widget display title.
   873  * @param callback   $output_callback Run when widget is called.
   329  * @param callable   $output_callback Run when widget is called.
   874  * @param array      $options {
   330  * @param array      $options {
   875  *     Optional. An array of supplementary widget options for the instance.
   331  *     Optional. An array of supplementary widget options for the instance.
   876  *
   332  *
   877  *     @type string $classname   Class name for the widget's HTML container. Default is a shortened
   333  *     @type string $classname   Class name for the widget's HTML container. Default is a shortened
   878  *                               version of the output callback name.
   334  *                               version of the output callback name.
   879  *     @type string $description Widget description for display in the widget administration
   335  *     @type string $description Widget description for display in the widget administration
   880  *                               panel and/or theme.
   336  *                               panel and/or theme.
   881  * }
   337  * }
   882  * @return null Will return if `$output_callback` is empty after removing widget.
       
   883  */
   338  */
   884 function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array() ) {
   339 function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array() ) {
   885 	global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
   340 	global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
   886 
   341 
   887 	$id = strtolower($id);
   342 	$id = strtolower($id);
   891 		return;
   346 		return;
   892 	}
   347 	}
   893 
   348 
   894 	$id_base = _get_widget_id_base($id);
   349 	$id_base = _get_widget_id_base($id);
   895 	if ( in_array($output_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($output_callback) ) {
   350 	if ( in_array($output_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($output_callback) ) {
   896 		if ( isset($wp_registered_widget_controls[$id]) )
   351 		unset( $wp_registered_widget_controls[ $id ] );
   897 			unset($wp_registered_widget_controls[$id]);
   352 		unset( $wp_registered_widget_updates[ $id_base ] );
   898 
       
   899 		if ( isset($wp_registered_widget_updates[$id_base]) )
       
   900 			unset($wp_registered_widget_updates[$id_base]);
       
   901 
       
   902 		return;
   353 		return;
   903 	}
   354 	}
   904 
   355 
   905 	$defaults = array('classname' => $output_callback);
   356 	$defaults = array('classname' => $output_callback);
   906 	$options = wp_parse_args($options, $defaults);
   357 	$options = wp_parse_args($options, $defaults);
   933  * describes the widget for display on the widget administration panel or
   384  * describes the widget for display on the widget administration panel or
   934  * in the theme.
   385  * in the theme.
   935  *
   386  *
   936  * @since 2.5.0
   387  * @since 2.5.0
   937  *
   388  *
       
   389  * @global array $wp_registered_widgets
       
   390  *
   938  * @param int|string $id Widget ID.
   391  * @param int|string $id Widget ID.
   939  * @return string Widget description, if available. Null on failure to retrieve description.
   392  * @return string|void Widget description, if available.
   940  */
   393  */
   941 function wp_widget_description( $id ) {
   394 function wp_widget_description( $id ) {
   942 	if ( !is_scalar($id) )
   395 	if ( !is_scalar($id) )
   943 		return;
   396 		return;
   944 
   397 
   954  * When registering sidebars a 'description' parameter can be included that
   407  * When registering sidebars a 'description' parameter can be included that
   955  * describes the sidebar for display on the widget administration panel.
   408  * describes the sidebar for display on the widget administration panel.
   956  *
   409  *
   957  * @since 2.9.0
   410  * @since 2.9.0
   958  *
   411  *
       
   412  * @global array $wp_registered_sidebars
       
   413  *
   959  * @param string $id sidebar ID.
   414  * @param string $id sidebar ID.
   960  * @return string Sidebar description, if available. Null on failure to retrieve description.
   415  * @return string|void Sidebar description, if available.
   961  */
   416  */
   962 function wp_sidebar_description( $id ) {
   417 function wp_sidebar_description( $id ) {
   963 	if ( !is_scalar($id) )
   418 	if ( !is_scalar($id) )
   964 		return;
   419 		return;
   965 
   420 
   966 	global $wp_registered_sidebars;
   421 	global $wp_registered_sidebars;
   967 
   422 
   968 	if ( isset($wp_registered_sidebars[$id]['description']) )
   423 	if ( isset( $wp_registered_sidebars[ $id ]['description'] ) ) {
   969 		return esc_html( $wp_registered_sidebars[$id]['description'] );
   424 		return wp_kses( $wp_registered_sidebars[ $id ]['description'], 'sidebar_description' );
       
   425 	}
   970 }
   426 }
   971 
   427 
   972 /**
   428 /**
   973  * Remove widget from sidebar.
   429  * Remove widget from sidebar.
   974  *
   430  *
   992 }
   448 }
   993 
   449 
   994 /**
   450 /**
   995  * Registers widget control callback for customizing options.
   451  * Registers widget control callback for customizing options.
   996  *
   452  *
   997  * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
   453  * @since 2.2.0
   998  * option is never used. The 'width' option is the width of the fully expanded
   454  *
   999  * control form, but try hard to use the default width. The 'id_base' is for
       
  1000  * multi-widgets (widgets which allow multiple instances such as the text
       
  1001  * widget), an id_base must be provided. The widget id will end up looking like
       
  1002  * `{$id_base}-{$unique_number}`.
       
  1003  *
       
  1004  * @since 2.2.0
       
  1005  *
       
  1006  * @todo Document `$options` as a hash notation, re: WP_Widget::__construct() cross-reference.
       
  1007  * @todo `$params` parameter?
   455  * @todo `$params` parameter?
       
   456  *
       
   457  * @global array $wp_registered_widget_controls
       
   458  * @global array $wp_registered_widget_updates
       
   459  * @global array $wp_registered_widgets
       
   460  * @global array $_wp_deprecated_widgets_callbacks
  1008  *
   461  *
  1009  * @param int|string   $id               Sidebar ID.
   462  * @param int|string   $id               Sidebar ID.
  1010  * @param string       $name             Sidebar display name.
   463  * @param string       $name             Sidebar display name.
  1011  * @param callback     $control_callback Run when sidebar is displayed.
   464  * @param callable     $control_callback Run when sidebar is displayed.
  1012  * @param array|string $options          Optional. Widget options. See description above. Default empty array.
   465  * @param array $options {
       
   466  *     Optional. Array or string of control options. Default empty array.
       
   467  *
       
   468  *     @type int        $height  Never used. Default 200.
       
   469  *     @type int        $width   Width of the fully expanded control form (but try hard to use the default width).
       
   470  *                               Default 250.
       
   471  *     @type int|string $id_base Required for multi-widgets, i.e widgets that allow multiple instances such as the
       
   472  *                               text widget. The widget id will end up looking like `{$id_base}-{$unique_number}`.
       
   473  * }
  1013  */
   474  */
  1014 function wp_register_widget_control( $id, $name, $control_callback, $options = array() ) {
   475 function wp_register_widget_control( $id, $name, $control_callback, $options = array() ) {
  1015 	global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
   476 	global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
  1016 
   477 
  1017 	$id = strtolower($id);
   478 	$id = strtolower($id);
  1022 		unset($wp_registered_widget_updates[$id_base]);
   483 		unset($wp_registered_widget_updates[$id_base]);
  1023 		return;
   484 		return;
  1024 	}
   485 	}
  1025 
   486 
  1026 	if ( in_array($control_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($control_callback) ) {
   487 	if ( in_array($control_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($control_callback) ) {
  1027 		if ( isset($wp_registered_widgets[$id]) )
   488 		unset( $wp_registered_widgets[ $id ] );
  1028 			unset($wp_registered_widgets[$id]);
       
  1029 
       
  1030 		return;
   489 		return;
  1031 	}
   490 	}
  1032 
   491 
  1033 	if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
   492 	if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
  1034 		return;
   493 		return;
  1057 	unset($widget['width'], $widget['height'], $widget['name'], $widget['id']);
   516 	unset($widget['width'], $widget['height'], $widget['name'], $widget['id']);
  1058 	$wp_registered_widget_updates[$id_base] = $widget;
   517 	$wp_registered_widget_updates[$id_base] = $widget;
  1059 }
   518 }
  1060 
   519 
  1061 /**
   520 /**
       
   521  * Registers the update callback for a widget.
       
   522  *
       
   523  * @since 2.8.0
  1062  *
   524  *
  1063  * @global array $wp_registered_widget_updates
   525  * @global array $wp_registered_widget_updates
  1064  * @param string   $id_base
   526  *
  1065  * @param callable $update_callback
   527  * @param string   $id_base         The base ID of a widget created by extending WP_Widget.
  1066  * @param array    $options
   528  * @param callable $update_callback Update callback method for the widget.
  1067  */
   529  * @param array    $options         Optional. Widget control options. See wp_register_widget_control().
  1068 function _register_widget_update_callback($id_base, $update_callback, $options = array()) {
   530  *                                  Default empty array.
       
   531  */
       
   532 function _register_widget_update_callback( $id_base, $update_callback, $options = array() ) {
  1069 	global $wp_registered_widget_updates;
   533 	global $wp_registered_widget_updates;
  1070 
   534 
  1071 	if ( isset($wp_registered_widget_updates[$id_base]) ) {
   535 	if ( isset($wp_registered_widget_updates[$id_base]) ) {
  1072 		if ( empty($update_callback) )
   536 		if ( empty($update_callback) )
  1073 			unset($wp_registered_widget_updates[$id_base]);
   537 			unset($wp_registered_widget_updates[$id_base]);
  1082 	$widget = array_merge($widget, $options);
   546 	$widget = array_merge($widget, $options);
  1083 	$wp_registered_widget_updates[$id_base] = $widget;
   547 	$wp_registered_widget_updates[$id_base] = $widget;
  1084 }
   548 }
  1085 
   549 
  1086 /**
   550 /**
       
   551  * Registers the form callback for a widget.
       
   552  *
       
   553  * @since 2.8.0
  1087  *
   554  *
  1088  * @global array $wp_registered_widget_controls
   555  * @global array $wp_registered_widget_controls
  1089  * @param int|string $id
   556  *
  1090  * @param string     $name
   557  * @param int|string $id            Widget ID.
  1091  * @param callable   $form_callback
   558  * @param string     $name          Name attribute for the widget.
  1092  * @param array      $options
   559  * @param callable   $form_callback Form callback.
  1093  * @return null
   560  * @param array      $options       Optional. Widget control options. See wp_register_widget_control().
       
   561  *                                  Default empty array.
  1094  */
   562  */
  1095 function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
   563 function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
  1096 	global $wp_registered_widget_controls;
   564 	global $wp_registered_widget_controls;
  1097 
   565 
  1098 	$id = strtolower($id);
   566 	$id = strtolower($id);
  1127  * @since 2.2.0
   595  * @since 2.2.0
  1128  *
   596  *
  1129  * @param int|string $id Widget ID.
   597  * @param int|string $id Widget ID.
  1130  */
   598  */
  1131 function wp_unregister_widget_control($id) {
   599 function wp_unregister_widget_control($id) {
  1132 	return wp_register_widget_control($id, '', '');
   600 	wp_register_widget_control( $id, '', '' );
  1133 }
   601 }
  1134 
   602 
  1135 /**
   603 /**
  1136  * Display dynamic sidebar.
   604  * Display dynamic sidebar.
  1137  *
   605  *
  1139  * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
   607  * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
  1140  * Otherwise, you can pass in a numerical index to display the sidebar at that index.
   608  * Otherwise, you can pass in a numerical index to display the sidebar at that index.
  1141  *
   609  *
  1142  * @since 2.2.0
   610  * @since 2.2.0
  1143  *
   611  *
       
   612  * @global array $wp_registered_sidebars
       
   613  * @global array $wp_registered_widgets
       
   614  *
  1144  * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
   615  * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
  1145  * @return bool True, if widget sidebar was found and called. False if not found or not called.
   616  * @return bool True, if widget sidebar was found and called. False if not found or not called.
  1146  */
   617  */
  1147 function dynamic_sidebar($index = 1) {
   618 function dynamic_sidebar( $index = 1 ) {
  1148 	global $wp_registered_sidebars, $wp_registered_widgets;
   619 	global $wp_registered_sidebars, $wp_registered_widgets;
  1149 
   620 
  1150 	if ( is_int($index) ) {
   621 	if ( is_int( $index ) ) {
  1151 		$index = "sidebar-$index";
   622 		$index = "sidebar-$index";
  1152 	} else {
   623 	} else {
  1153 		$index = sanitize_title($index);
   624 		$index = sanitize_title( $index );
  1154 		foreach ( (array) $wp_registered_sidebars as $key => $value ) {
   625 		foreach ( (array) $wp_registered_sidebars as $key => $value ) {
  1155 			if ( sanitize_title($value['name']) == $index ) {
   626 			if ( sanitize_title( $value['name'] ) == $index ) {
  1156 				$index = $key;
   627 				$index = $key;
  1157 				break;
   628 				break;
  1158 			}
   629 			}
  1159 		}
   630 		}
  1160 	}
   631 	}
  1161 
   632 
  1162 	$sidebars_widgets = wp_get_sidebars_widgets();
   633 	$sidebars_widgets = wp_get_sidebars_widgets();
  1163 	if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
   634 	if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
  1164 		/** This action is documented in wp-includes/widgets.php */
   635 		/** This action is documented in wp-includes/widget.php */
  1165 		do_action( 'dynamic_sidebar_before', $index, false );
   636 		do_action( 'dynamic_sidebar_before', $index, false );
  1166 		/** This action is documented in wp-includes/widgets.php */
   637 		/** This action is documented in wp-includes/widget.php */
  1167 		do_action( 'dynamic_sidebar_after',  $index, false );
   638 		do_action( 'dynamic_sidebar_after',  $index, false );
  1168 		/** This filter is documented in wp-includes/widgets.php */
   639 		/** This filter is documented in wp-includes/widget.php */
  1169 		return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
   640 		return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
  1170 	}
   641 	}
  1171 
   642 
  1172 	/**
   643 	/**
  1173 	 * Fires before widgets are rendered in a dynamic sidebar.
   644 	 * Fires before widgets are rendered in a dynamic sidebar.
  1174 	 *
   645 	 *
  1175 	 * Note: The action also fires for empty sidebars, and on both the front-end
   646 	 * Note: The action also fires for empty sidebars, and on both the front end
  1176 	 * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
   647 	 * and back end, including the Inactive Widgets sidebar on the Widgets screen.
  1177 	 *
   648 	 *
  1178 	 * @since 3.9.0
   649 	 * @since 3.9.0
  1179 	 *
   650 	 *
  1180 	 * @param int|string $index       Index, name, or ID of the dynamic sidebar.
   651 	 * @param int|string $index       Index, name, or ID of the dynamic sidebar.
  1181 	 * @param bool       $has_widgets Whether the sidebar is populated with widgets.
   652 	 * @param bool       $has_widgets Whether the sidebar is populated with widgets.
  1204 		}
   675 		}
  1205 		$classname_ = ltrim($classname_, '_');
   676 		$classname_ = ltrim($classname_, '_');
  1206 		$params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
   677 		$params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
  1207 
   678 
  1208 		/**
   679 		/**
  1209 		 * Filter the parameters passed to a widget's display callback.
   680 		 * Filters the parameters passed to a widget's display callback.
  1210 		 *
   681 		 *
  1211 		 * Note: The filter is evaluated on both the front-end and back-end,
   682 		 * Note: The filter is evaluated on both the front end and back end,
  1212 		 * including for the Inactive Widgets sidebar on the Widgets screen.
   683 		 * including for the Inactive Widgets sidebar on the Widgets screen.
  1213 		 *
   684 		 *
  1214 		 * @since 2.5.0
   685 		 * @since 2.5.0
  1215 		 *
   686 		 *
  1216 		 * @see register_sidebar()
   687 		 * @see register_sidebar()
  1242 		$callback = $wp_registered_widgets[$id]['callback'];
   713 		$callback = $wp_registered_widgets[$id]['callback'];
  1243 
   714 
  1244 		/**
   715 		/**
  1245 		 * Fires before a widget's display callback is called.
   716 		 * Fires before a widget's display callback is called.
  1246 		 *
   717 		 *
  1247 		 * Note: The action fires on both the front-end and back-end, including
   718 		 * Note: The action fires on both the front end and back end, including
  1248 		 * for widgets in the Inactive Widgets sidebar on the Widgets screen.
   719 		 * for widgets in the Inactive Widgets sidebar on the Widgets screen.
  1249 		 *
   720 		 *
  1250 		 * The action is not fired for empty sidebars.
   721 		 * The action is not fired for empty sidebars.
  1251 		 *
   722 		 *
  1252 		 * @since 3.0.0
   723 		 * @since 3.0.0
  1254 		 * @param array $widget_id {
   725 		 * @param array $widget_id {
  1255 		 *     An associative array of widget arguments.
   726 		 *     An associative array of widget arguments.
  1256 		 *
   727 		 *
  1257 		 *     @type string $name                Name of the widget.
   728 		 *     @type string $name                Name of the widget.
  1258 		 *     @type string $id                  Widget ID.
   729 		 *     @type string $id                  Widget ID.
  1259 		 *     @type array|callback $callback    When the hook is fired on the front-end, $callback is an array
   730 		 *     @type array|callable $callback    When the hook is fired on the front end, $callback is an array
  1260 		 *                                       containing the widget object. Fired on the back-end, $callback
   731 		 *                                       containing the widget object. Fired on the back end, $callback
  1261 		 *                                       is 'wp_widget_control', see $_callback.
   732 		 *                                       is 'wp_widget_control', see $_callback.
  1262 		 *     @type array          $params      An associative array of multi-widget arguments.
   733 		 *     @type array          $params      An associative array of multi-widget arguments.
  1263 		 *     @type string         $classname   CSS class applied to the widget container.
   734 		 *     @type string         $classname   CSS class applied to the widget container.
  1264 		 *     @type string         $description The widget description.
   735 		 *     @type string         $description The widget description.
  1265 		 *     @type array          $_callback   When the hook is fired on the back-end, $_callback is populated
   736 		 *     @type array          $_callback   When the hook is fired on the back end, $_callback is populated
  1266 		 *                                       with an array containing the widget object, see $callback.
   737 		 *                                       with an array containing the widget object, see $callback.
  1267 		 * }
   738 		 * }
  1268 		 */
   739 		 */
  1269 		do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
   740 		do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
  1270 
   741 
  1275 	}
   746 	}
  1276 
   747 
  1277 	/**
   748 	/**
  1278 	 * Fires after widgets are rendered in a dynamic sidebar.
   749 	 * Fires after widgets are rendered in a dynamic sidebar.
  1279 	 *
   750 	 *
  1280 	 * Note: The action also fires for empty sidebars, and on both the front-end
   751 	 * Note: The action also fires for empty sidebars, and on both the front end
  1281 	 * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
   752 	 * and back end, including the Inactive Widgets sidebar on the Widgets screen.
  1282 	 *
   753 	 *
  1283 	 * @since 3.9.0
   754 	 * @since 3.9.0
  1284 	 *
   755 	 *
  1285 	 * @param int|string $index       Index, name, or ID of the dynamic sidebar.
   756 	 * @param int|string $index       Index, name, or ID of the dynamic sidebar.
  1286 	 * @param bool       $has_widgets Whether the sidebar is populated with widgets.
   757 	 * @param bool       $has_widgets Whether the sidebar is populated with widgets.
  1287 	 *                                Default true.
   758 	 *                                Default true.
  1288 	 */
   759 	 */
  1289 	do_action( 'dynamic_sidebar_after', $index, true );
   760 	do_action( 'dynamic_sidebar_after', $index, true );
  1290 
   761 
  1291 	/**
   762 	/**
  1292 	 * Filter whether a sidebar has widgets.
   763 	 * Filters whether a sidebar has widgets.
  1293 	 *
   764 	 *
  1294 	 * Note: The filter is also evaluated for empty sidebars, and on both the front-end
   765 	 * Note: The filter is also evaluated for empty sidebars, and on both the front end
  1295 	 * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
   766 	 * and back end, including the Inactive Widgets sidebar on the Widgets screen.
  1296 	 *
   767 	 *
  1297 	 * @since 3.9.0
   768 	 * @since 3.9.0
  1298 	 *
   769 	 *
  1299 	 * @param bool       $did_one Whether at least one widget was rendered in the sidebar.
   770 	 * @param bool       $did_one Whether at least one widget was rendered in the sidebar.
  1300 	 *                            Default false.
   771 	 *                            Default false.
  1301 	 * @param int|string $index   Index, name, or ID of the dynamic sidebar.
   772 	 * @param int|string $index   Index, name, or ID of the dynamic sidebar.
  1302 	 */
   773 	 */
  1303 
   774 	return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
  1304 	$did_one = apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
   775 }
  1305 
   776 
  1306 	return $did_one;
   777 /**
  1307 }
   778  * Whether widget is displayed on the front end.
  1308 
       
  1309 /**
       
  1310  * Whether widget is displayed on the front-end.
       
  1311  *
   779  *
  1312  * Either $callback or $id_base can be used
   780  * Either $callback or $id_base can be used
  1313  * $id_base is the first argument when extending WP_Widget class
   781  * $id_base is the first argument when extending WP_Widget class
  1314  * Without the optional $widget_id parameter, returns the ID of the first sidebar
   782  * Without the optional $widget_id parameter, returns the ID of the first sidebar
  1315  * in which the first instance of the widget with the given callback or $id_base is found.
   783  * in which the first instance of the widget with the given callback or $id_base is found.
  1316  * With the $widget_id parameter, returns the ID of the sidebar where
   784  * With the $widget_id parameter, returns the ID of the sidebar where
  1317  * the widget with that callback/$id_base AND that ID is found.
   785  * the widget with that callback/$id_base AND that ID is found.
  1318  *
   786  *
  1319  * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
   787  * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
  1320  * this function has to run after widgets have initialized, at action 'init' or later.
   788  * this function has to run after widgets have initialized, at action {@see 'init'} or later.
  1321  *
   789  *
  1322  * @since 2.2.0
   790  * @since 2.2.0
  1323  *
   791  *
  1324  * @param string $callback Optional, Widget callback to check.
   792  * @global array $wp_registered_widgets
  1325  * @param int $widget_id Optional, but needed for checking. Widget ID.
   793  *
  1326  * @param string $id_base Optional, the base ID of a widget created by extending WP_Widget.
   794  * @param string|false $callback      Optional, Widget callback to check. Default false.
  1327  * @param bool $skip_inactive Optional, whether to check in 'wp_inactive_widgets'.
   795  * @param int|false    $widget_id     Optional. Widget ID. Optional, but needed for checking. Default false.
  1328  * @return mixed false if widget is not active or id of sidebar in which the widget is active.
   796  * @param string|false $id_base       Optional. The base ID of a widget created by extending WP_Widget. Default false.
  1329  */
   797  * @param bool         $skip_inactive Optional. Whether to check in 'wp_inactive_widgets'. Default true.
  1330 function is_active_widget($callback = false, $widget_id = false, $id_base = false, $skip_inactive = true) {
   798  * @return string|false False if widget is not active or id of sidebar in which the widget is active.
       
   799  */
       
   800 function is_active_widget( $callback = false, $widget_id = false, $id_base = false, $skip_inactive = true ) {
  1331 	global $wp_registered_widgets;
   801 	global $wp_registered_widgets;
  1332 
   802 
  1333 	$sidebars_widgets = wp_get_sidebars_widgets();
   803 	$sidebars_widgets = wp_get_sidebars_widgets();
  1334 
   804 
  1335 	if ( is_array($sidebars_widgets) ) {
   805 	if ( is_array($sidebars_widgets) ) {
  1354 /**
   824 /**
  1355  * Whether the dynamic sidebar is enabled and used by theme.
   825  * Whether the dynamic sidebar is enabled and used by theme.
  1356  *
   826  *
  1357  * @since 2.2.0
   827  * @since 2.2.0
  1358  *
   828  *
       
   829  * @global array $wp_registered_widgets
       
   830  * @global array $wp_registered_sidebars
       
   831  *
  1359  * @return bool True, if using widgets. False, if not using widgets.
   832  * @return bool True, if using widgets. False, if not using widgets.
  1360  */
   833  */
  1361 function is_dynamic_sidebar() {
   834 function is_dynamic_sidebar() {
  1362 	global $wp_registered_widgets, $wp_registered_sidebars;
   835 	global $wp_registered_widgets, $wp_registered_sidebars;
  1363 	$sidebars_widgets = get_option('sidebars_widgets');
   836 	$sidebars_widgets = get_option('sidebars_widgets');
  1364 	foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
   837 	foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
  1365 		if ( count($sidebars_widgets[$index]) ) {
   838 		if ( ! empty( $sidebars_widgets[ $index ] ) ) {
  1366 			foreach ( (array) $sidebars_widgets[$index] as $widget )
   839 			foreach ( (array) $sidebars_widgets[$index] as $widget )
  1367 				if ( array_key_exists($widget, $wp_registered_widgets) )
   840 				if ( array_key_exists($widget, $wp_registered_widgets) )
  1368 					return true;
   841 					return true;
  1369 		}
   842 		}
  1370 	}
   843 	}
  1383 	$index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
   856 	$index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
  1384 	$sidebars_widgets = wp_get_sidebars_widgets();
   857 	$sidebars_widgets = wp_get_sidebars_widgets();
  1385 	$is_active_sidebar = ! empty( $sidebars_widgets[$index] );
   858 	$is_active_sidebar = ! empty( $sidebars_widgets[$index] );
  1386 
   859 
  1387 	/**
   860 	/**
  1388 	 * Filter whether a dynamic sidebar is considered "active".
   861 	 * Filters whether a dynamic sidebar is considered "active".
  1389 	 *
   862 	 *
  1390 	 * @since 3.9.0
   863 	 * @since 3.9.0
  1391 	 *
   864 	 *
  1392 	 * @param bool       $is_active_sidebar Whether or not the sidebar should be considered "active".
   865 	 * @param bool       $is_active_sidebar Whether or not the sidebar should be considered "active".
  1393 	 *                                      In other words, whether the sidebar contains any widgets.
   866 	 *                                      In other words, whether the sidebar contains any widgets.
  1394 	 * @param int|string $index             Index, name, or ID of the dynamic sidebar.
   867 	 * @param int|string $index             Index, name, or ID of the dynamic sidebar.
  1395 	 */
   868 	 */
  1396 	return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
   869 	return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
  1397 }
   870 }
  1398 
   871 
  1399 /* Internal Functions */
   872 //
       
   873 // Internal Functions
       
   874 //
  1400 
   875 
  1401 /**
   876 /**
  1402  * Retrieve full list of sidebars and their widget instance IDs.
   877  * Retrieve full list of sidebars and their widget instance IDs.
  1403  *
   878  *
  1404  * Will upgrade sidebar widget list, if needed. Will also save updated list, if
   879  * Will upgrade sidebar widget list, if needed. Will also save updated list, if
  1405  * needed.
   880  * needed.
  1406  *
   881  *
  1407  * @since 2.2.0
   882  * @since 2.2.0
  1408  * @access private
   883  * @access private
       
   884  *
       
   885  * @global array $_wp_sidebars_widgets
       
   886  * @global array $sidebars_widgets
  1409  *
   887  *
  1410  * @param bool $deprecated Not used (argument deprecated).
   888  * @param bool $deprecated Not used (argument deprecated).
  1411  * @return array Upgraded list of widgets to version 3 array format when called from the admin.
   889  * @return array Upgraded list of widgets to version 3 array format when called from the admin.
  1412  */
   890  */
  1413 function wp_get_sidebars_widgets( $deprecated = true ) {
   891 function wp_get_sidebars_widgets( $deprecated = true ) {
  1429 
   907 
  1430 	if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
   908 	if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
  1431 		unset($sidebars_widgets['array_version']);
   909 		unset($sidebars_widgets['array_version']);
  1432 
   910 
  1433 	/**
   911 	/**
  1434 	 * Filter the list of sidebars and their widgets.
   912 	 * Filters the list of sidebars and their widgets.
  1435 	 *
   913 	 *
  1436 	 * @since 2.7.0
   914 	 * @since 2.7.0
  1437 	 *
   915 	 *
  1438 	 * @param array $sidebars_widgets An associative array of sidebars and their widgets.
   916 	 * @param array $sidebars_widgets An associative array of sidebars and their widgets.
  1439 	 */
   917 	 */
  1440 	$sidebars_widgets = apply_filters( 'sidebars_widgets', $sidebars_widgets );
   918 	return apply_filters( 'sidebars_widgets', $sidebars_widgets );
  1441 	return $sidebars_widgets;
       
  1442 }
   919 }
  1443 
   920 
  1444 /**
   921 /**
  1445  * Set the sidebar widget option to update sidebars.
   922  * Set the sidebar widget option to update sidebars.
  1446  *
   923  *
  1447  * @since 2.2.0
   924  * @since 2.2.0
  1448  * @access private
   925  * @access private
  1449  *
   926  *
       
   927  * @global array $_wp_sidebars_widgets
  1450  * @param array $sidebars_widgets Sidebar widgets and their settings.
   928  * @param array $sidebars_widgets Sidebar widgets and their settings.
  1451  */
   929  */
  1452 function wp_set_sidebars_widgets( $sidebars_widgets ) {
   930 function wp_set_sidebars_widgets( $sidebars_widgets ) {
  1453 	if ( !isset( $sidebars_widgets['array_version'] ) )
   931 	global $_wp_sidebars_widgets;
       
   932 
       
   933 	// Clear cached value used in wp_get_sidebars_widgets().
       
   934 	$_wp_sidebars_widgets = null;
       
   935 
       
   936 	if ( ! isset( $sidebars_widgets['array_version'] ) ) {
  1454 		$sidebars_widgets['array_version'] = 3;
   937 		$sidebars_widgets['array_version'] = 3;
       
   938 	}
       
   939 
  1455 	update_option( 'sidebars_widgets', $sidebars_widgets );
   940 	update_option( 'sidebars_widgets', $sidebars_widgets );
  1456 }
   941 }
  1457 
   942 
  1458 /**
   943 /**
  1459  * Retrieve default registered sidebars list.
   944  * Retrieve default registered sidebars list.
  1460  *
   945  *
  1461  * @since 2.2.0
   946  * @since 2.2.0
  1462  * @access private
   947  * @access private
       
   948  *
       
   949  * @global array $wp_registered_sidebars
  1463  *
   950  *
  1464  * @return array
   951  * @return array
  1465  */
   952  */
  1466 function wp_get_widget_defaults() {
   953 function wp_get_widget_defaults() {
  1467 	global $wp_registered_sidebars;
   954 	global $wp_registered_sidebars;
  1476 
   963 
  1477 /**
   964 /**
  1478  * Convert the widget settings from single to multi-widget format.
   965  * Convert the widget settings from single to multi-widget format.
  1479  *
   966  *
  1480  * @since 2.8.0
   967  * @since 2.8.0
       
   968  *
       
   969  * @global array $_wp_sidebars_widgets
  1481  *
   970  *
  1482  * @param string $base_name
   971  * @param string $base_name
  1483  * @param string $option_name
   972  * @param string $option_name
  1484  * @param array  $settings
   973  * @param array  $settings
  1485  * @return array
   974  * @return array
  1538 /**
  1027 /**
  1539  * Output an arbitrary widget as a template tag.
  1028  * Output an arbitrary widget as a template tag.
  1540  *
  1029  *
  1541  * @since 2.8.0
  1030  * @since 2.8.0
  1542  *
  1031  *
  1543  * @param string $widget   The widget's PHP class name (see default-widgets.php).
  1032  * @global WP_Widget_Factory $wp_widget_factory
       
  1033  *
       
  1034  * @param string $widget   The widget's PHP class name (see class-wp-widget.php).
  1544  * @param array  $instance Optional. The widget's instance settings. Default empty array.
  1035  * @param array  $instance Optional. The widget's instance settings. Default empty array.
  1545  * @param array  $args {
  1036  * @param array  $args {
  1546  *     Optional. Array of arguments to configure the display of the widget.
  1037  *     Optional. Array of arguments to configure the display of the widget.
  1547  *
  1038  *
  1548  *     @type string $before_widget HTML content that will be prepended to the widget's HTML output.
  1039  *     @type string $before_widget HTML content that will be prepended to the widget's HTML output.
  1556  * }
  1047  * }
  1557  */
  1048  */
  1558 function the_widget( $widget, $instance = array(), $args = array() ) {
  1049 function the_widget( $widget, $instance = array(), $args = array() ) {
  1559 	global $wp_widget_factory;
  1050 	global $wp_widget_factory;
  1560 
  1051 
       
  1052 	if ( ! isset( $wp_widget_factory->widgets[ $widget ] ) ) {
       
  1053 		/* translators: %s: register_widget() */
       
  1054 		_doing_it_wrong( __FUNCTION__, sprintf( __( 'Widgets need to be registered using %s, before they can be displayed.' ), '<code>register_widget()</code>' ), '4.9.0' );
       
  1055 		return;
       
  1056 	}
       
  1057 
  1561 	$widget_obj = $wp_widget_factory->widgets[$widget];
  1058 	$widget_obj = $wp_widget_factory->widgets[$widget];
  1562 	if ( ! ( $widget_obj instanceof WP_Widget ) ) {
  1059 	if ( ! ( $widget_obj instanceof WP_Widget ) ) {
  1563 		return;
  1060 		return;
  1564 	}
  1061 	}
  1565 
  1062 
  1566 	$before_widget = sprintf('<div class="widget %s">', $widget_obj->widget_options['classname'] );
  1063 	$default_args = array(
  1567 	$default_args = array( 'before_widget' => $before_widget, 'after_widget' => "</div>", 'before_title' => '<h2 class="widgettitle">', 'after_title' => '</h2>' );
  1064 		'before_widget' => '<div class="widget %s">',
  1568 
  1065 		'after_widget'  => "</div>",
  1569 	$args = wp_parse_args($args, $default_args);
  1066 		'before_title'  => '<h2 class="widgettitle">',
       
  1067 		'after_title'   => '</h2>',
       
  1068 	);
       
  1069 	$args = wp_parse_args( $args, $default_args );
       
  1070 	$args['before_widget'] = sprintf( $args['before_widget'], $widget_obj->widget_options['classname'] );
       
  1071 
  1570 	$instance = wp_parse_args($instance);
  1072 	$instance = wp_parse_args($instance);
  1571 
  1073 
  1572 	/**
  1074 	/**
  1573 	 * Fires before rendering the requested widget.
  1075 	 * Fires before rendering the requested widget.
  1574 	 *
  1076 	 *
  1583 	$widget_obj->_set(-1);
  1085 	$widget_obj->_set(-1);
  1584 	$widget_obj->widget($args, $instance);
  1086 	$widget_obj->widget($args, $instance);
  1585 }
  1087 }
  1586 
  1088 
  1587 /**
  1089 /**
  1588  * Private
  1090  * Retrieves the widget ID base value.
  1589  */
  1091  *
  1590 function _get_widget_id_base($id) {
  1092  * @since 2.8.0
       
  1093  *
       
  1094  * @param string $id Widget ID.
       
  1095  * @return string Widget ID base.
       
  1096  */
       
  1097 function _get_widget_id_base( $id ) {
  1591 	return preg_replace( '/-[0-9]+$/', '', $id );
  1098 	return preg_replace( '/-[0-9]+$/', '', $id );
  1592 }
  1099 }
  1593 
  1100 
  1594 /**
  1101 /**
  1595  * Handle sidebars config after theme change
  1102  * Handle sidebars config after theme change
  1596  *
  1103  *
  1597  * @access private
  1104  * @access private
  1598  * @since 3.3.0
  1105  * @since 3.3.0
       
  1106  *
       
  1107  * @global array $sidebars_widgets
  1599  */
  1108  */
  1600 function _wp_sidebars_changed() {
  1109 function _wp_sidebars_changed() {
  1601 	global $sidebars_widgets;
  1110 	global $sidebars_widgets;
  1602 
  1111 
  1603 	if ( ! is_array( $sidebars_widgets ) )
  1112 	if ( ! is_array( $sidebars_widgets ) )
  1609 /**
  1118 /**
  1610  * Look for "lost" widgets, this has to run at least on each theme change.
  1119  * Look for "lost" widgets, this has to run at least on each theme change.
  1611  *
  1120  *
  1612  * @since 2.8.0
  1121  * @since 2.8.0
  1613  *
  1122  *
       
  1123  * @global array $wp_registered_sidebars
       
  1124  * @global array $sidebars_widgets
       
  1125  * @global array $wp_registered_widgets
       
  1126  *
  1614  * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
  1127  * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
  1615  *                                   of 'customize' defers updates for the Customizer.
  1128  *                                   of 'customize' defers updates for the Customizer.
  1616  * @return array
  1129  * @return array Updated sidebars widgets.
  1617  */
  1130  */
  1618 function retrieve_widgets( $theme_changed = false ) {
  1131 function retrieve_widgets( $theme_changed = false ) {
  1619 	global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
  1132 	global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
  1620 
  1133 
  1621 	$registered_sidebar_keys = array_keys( $wp_registered_sidebars );
  1134 	$registered_sidebars_keys = array_keys( $wp_registered_sidebars );
  1622 	$orphaned = 0;
  1135 	$registered_widgets_ids   = array_keys( $wp_registered_widgets );
  1623 
  1136 
  1624 	$old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
  1137 	if ( ! is_array( get_theme_mod( 'sidebars_widgets' ) ) )  {
  1625 	if ( is_array( $old_sidebars_widgets ) ) {
  1138 		if ( empty( $sidebars_widgets ) ) {
  1626 		// time() that sidebars were stored is in $old_sidebars_widgets['time']
  1139 			return array();
  1627 		$_sidebars_widgets = $old_sidebars_widgets['data'];
  1140 		}
  1628 
       
  1629 		if ( 'customize' !== $theme_changed ) {
       
  1630 			remove_theme_mod( 'sidebars_widgets' );
       
  1631 		}
       
  1632 
       
  1633 		foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
       
  1634 			if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
       
  1635 				continue;
       
  1636 			}
       
  1637 
       
  1638 			if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {
       
  1639 				$_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;
       
  1640 				unset( $_sidebars_widgets[$sidebar] );
       
  1641 			}
       
  1642 		}
       
  1643 	} else {
       
  1644 		if ( empty( $sidebars_widgets ) )
       
  1645 			return;
       
  1646 
  1141 
  1647 		unset( $sidebars_widgets['array_version'] );
  1142 		unset( $sidebars_widgets['array_version'] );
  1648 
  1143 
  1649 		$old = array_keys($sidebars_widgets);
  1144 		$sidebars_widgets_keys = array_keys( $sidebars_widgets );
  1650 		sort($old);
  1145 		sort( $sidebars_widgets_keys );
  1651 		sort($registered_sidebar_keys);
  1146 		sort( $registered_sidebars_keys );
  1652 
  1147 
  1653 		if ( $old == $registered_sidebar_keys )
  1148 		if ( $sidebars_widgets_keys === $registered_sidebars_keys ) {
  1654 			return;
  1149 			$sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids );
  1655 
  1150 
  1656 		$_sidebars_widgets = array(
  1151 			return $sidebars_widgets;
  1657 			'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()
  1152 		}
  1658 		);
  1153 	}
  1659 
  1154 
  1660 		unset( $sidebars_widgets['wp_inactive_widgets'] );
  1155 	// Discard invalid, theme-specific widgets from sidebars.
  1661 
  1156 	$sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids );
  1662 		foreach ( $wp_registered_sidebars as $id => $settings ) {
  1157 	$sidebars_widgets = wp_map_sidebars_widgets( $sidebars_widgets );
  1663 			if ( $theme_changed ) {
  1158 
  1664 				$_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
  1159 	// Find hidden/lost multi-widget instances.
  1665 			} else {
  1160 	$shown_widgets = call_user_func_array( 'array_merge', $sidebars_widgets );
  1666 				// no theme change, grab only sidebars that are currently registered
  1161 	$lost_widgets  = array_diff( $registered_widgets_ids, $shown_widgets );
  1667 				if ( isset( $sidebars_widgets[$id] ) ) {
  1162 
  1668 					$_sidebars_widgets[$id] = $sidebars_widgets[$id];
  1163 	foreach ( $lost_widgets as $key => $widget_id ) {
  1669 					unset( $sidebars_widgets[$id] );
  1164 		$number = preg_replace( '/.+?-([0-9]+)$/', '$1', $widget_id );
  1670 				}
  1165 
  1671 			}
  1166 		// Only keep active and default widgets.
  1672 		}
  1167 		if ( is_numeric( $number ) && (int) $number < 2 ) {
  1673 
  1168 			unset( $lost_widgets[ $key ] );
  1674 		foreach ( $sidebars_widgets as $val ) {
  1169 		}
  1675 			if ( is_array($val) && ! empty( $val ) )
  1170 	}
  1676 				$_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
  1171 	$sidebars_widgets['wp_inactive_widgets'] = array_merge( $lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets'] );
  1677 		}
  1172 
  1678 	}
       
  1679 
       
  1680 	// discard invalid, theme-specific widgets from sidebars
       
  1681 	$shown_widgets = array();
       
  1682 
       
  1683 	foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
       
  1684 		if ( !is_array($widgets) )
       
  1685 			continue;
       
  1686 
       
  1687 		$_widgets = array();
       
  1688 		foreach ( $widgets as $widget ) {
       
  1689 			if ( isset($wp_registered_widgets[$widget]) )
       
  1690 				$_widgets[] = $widget;
       
  1691 		}
       
  1692 
       
  1693 		$_sidebars_widgets[$sidebar] = $_widgets;
       
  1694 		$shown_widgets = array_merge($shown_widgets, $_widgets);
       
  1695 	}
       
  1696 
       
  1697 	$sidebars_widgets = $_sidebars_widgets;
       
  1698 	unset($_sidebars_widgets, $_widgets);
       
  1699 
       
  1700 	// find hidden/lost multi-widget instances
       
  1701 	$lost_widgets = array();
       
  1702 	foreach ( $wp_registered_widgets as $key => $val ) {
       
  1703 		if ( in_array($key, $shown_widgets, true) )
       
  1704 			continue;
       
  1705 
       
  1706 		$number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
       
  1707 
       
  1708 		if ( 2 > (int) $number )
       
  1709 			continue;
       
  1710 
       
  1711 		$lost_widgets[] = $key;
       
  1712 	}
       
  1713 
       
  1714 	$sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
       
  1715 	if ( 'customize' !== $theme_changed ) {
  1173 	if ( 'customize' !== $theme_changed ) {
  1716 		wp_set_sidebars_widgets( $sidebars_widgets );
  1174 		wp_set_sidebars_widgets( $sidebars_widgets );
  1717 	}
  1175 	}
  1718 
  1176 
  1719 	return $sidebars_widgets;
  1177 	return $sidebars_widgets;
  1720 }
  1178 }
       
  1179 
       
  1180 /**
       
  1181  * Compares a list of sidebars with their widgets against a whitelist.
       
  1182  *
       
  1183  * @since 4.9.0
       
  1184  * @since 4.9.2 Always tries to restore widget assignments from previous data, not just if sidebars needed mapping.
       
  1185  *
       
  1186  * @param array $existing_sidebars_widgets List of sidebars and their widget instance IDs.
       
  1187  * @return array Mapped sidebars widgets.
       
  1188  */
       
  1189 function wp_map_sidebars_widgets( $existing_sidebars_widgets ) {
       
  1190 	global $wp_registered_sidebars;
       
  1191 
       
  1192 	$new_sidebars_widgets = array(
       
  1193 		'wp_inactive_widgets' => array(),
       
  1194 	);
       
  1195 
       
  1196 	// Short-circuit if there are no sidebars to map.
       
  1197 	if ( ! is_array( $existing_sidebars_widgets ) || empty( $existing_sidebars_widgets ) ) {
       
  1198 		return $new_sidebars_widgets;
       
  1199 	}
       
  1200 
       
  1201 	foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) {
       
  1202 		if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
       
  1203 			$new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], (array) $widgets );
       
  1204 			unset( $existing_sidebars_widgets[ $sidebar ] );
       
  1205 		}
       
  1206 	}
       
  1207 
       
  1208 	// If old and new theme have just one sidebar, map it and we're done.
       
  1209 	if ( 1 === count( $existing_sidebars_widgets ) && 1 === count( $wp_registered_sidebars ) ) {
       
  1210 		$new_sidebars_widgets[ key( $wp_registered_sidebars ) ] = array_pop( $existing_sidebars_widgets );
       
  1211 
       
  1212 		return $new_sidebars_widgets;
       
  1213 	}
       
  1214 
       
  1215 	// Map locations with the same slug.
       
  1216 	$existing_sidebars = array_keys( $existing_sidebars_widgets );
       
  1217 
       
  1218 	foreach ( $wp_registered_sidebars as $sidebar => $name ) {
       
  1219 		if ( in_array( $sidebar, $existing_sidebars, true ) ) {
       
  1220 			$new_sidebars_widgets[ $sidebar ] = $existing_sidebars_widgets[ $sidebar ];
       
  1221 			unset( $existing_sidebars_widgets[ $sidebar ] );
       
  1222 		} else if ( ! array_key_exists( $sidebar, $new_sidebars_widgets ) ) {
       
  1223 			$new_sidebars_widgets[ $sidebar ] = array();
       
  1224 		}
       
  1225 	}
       
  1226 
       
  1227 	// If there are more sidebars, try to map them.
       
  1228 	if ( ! empty( $existing_sidebars_widgets ) ) {
       
  1229 
       
  1230 		/*
       
  1231 		 * If old and new theme both have sidebars that contain phrases
       
  1232 		 * from within the same group, make an educated guess and map it.
       
  1233 		 */
       
  1234 		$common_slug_groups = array(
       
  1235 			array( 'sidebar', 'primary', 'main', 'right' ),
       
  1236 			array( 'second', 'left' ),
       
  1237 			array( 'sidebar-2', 'footer', 'bottom' ),
       
  1238 			array( 'header', 'top' ),
       
  1239 		);
       
  1240 
       
  1241 		// Go through each group...
       
  1242 		foreach ( $common_slug_groups as $slug_group ) {
       
  1243 
       
  1244 			// ...and see if any of these slugs...
       
  1245 			foreach ( $slug_group as $slug ) {
       
  1246 
       
  1247 				// ...and any of the new sidebars...
       
  1248 				foreach ( $wp_registered_sidebars as $new_sidebar => $args ) {
       
  1249 
       
  1250 					// ...actually match!
       
  1251 					if ( false === stripos( $new_sidebar, $slug ) && false === stripos( $slug, $new_sidebar ) ) {
       
  1252 						continue;
       
  1253 					}
       
  1254 
       
  1255 					// Then see if any of the existing sidebars...
       
  1256 					foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) {
       
  1257 
       
  1258 						// ...and any slug in the same group...
       
  1259 						foreach ( $slug_group as $slug ) {
       
  1260 
       
  1261 							// ... have a match as well.
       
  1262 							if ( false === stripos( $sidebar, $slug ) && false === stripos( $slug, $sidebar ) ) {
       
  1263 								continue;
       
  1264 							}
       
  1265 
       
  1266 							// Make sure this sidebar wasn't mapped and removed previously.
       
  1267 							if ( ! empty( $existing_sidebars_widgets[ $sidebar ] ) ) {
       
  1268 
       
  1269 								// We have a match that can be mapped!
       
  1270 								$new_sidebars_widgets[ $new_sidebar ] = array_merge( $new_sidebars_widgets[ $new_sidebar ], $existing_sidebars_widgets[ $sidebar ] );
       
  1271 
       
  1272 								// Remove the mapped sidebar so it can't be mapped again.
       
  1273 								unset( $existing_sidebars_widgets[ $sidebar ] );
       
  1274 
       
  1275 								// Go back and check the next new sidebar.
       
  1276 								continue 3;
       
  1277 							}
       
  1278 						} // endforeach ( $slug_group as $slug )
       
  1279 					} // endforeach ( $existing_sidebars_widgets as $sidebar => $widgets )
       
  1280 				} // endforeach foreach ( $wp_registered_sidebars as $new_sidebar => $args )
       
  1281 			} // endforeach ( $slug_group as $slug )
       
  1282 		} // endforeach ( $common_slug_groups as $slug_group )
       
  1283 	}
       
  1284 
       
  1285 	// Move any left over widgets to inactive sidebar.
       
  1286 	foreach ( $existing_sidebars_widgets as $widgets ) {
       
  1287 		if ( is_array( $widgets ) && ! empty( $widgets ) ) {
       
  1288 			$new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], $widgets );
       
  1289 		}
       
  1290 	}
       
  1291 
       
  1292 	// Sidebars_widgets settings from when this theme was previously active.
       
  1293 	$old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
       
  1294 	$old_sidebars_widgets = isset( $old_sidebars_widgets['data'] ) ? $old_sidebars_widgets['data'] : false;
       
  1295 
       
  1296 	if ( is_array( $old_sidebars_widgets ) ) {
       
  1297 
       
  1298 		// Remove empty sidebars, no need to map those.
       
  1299 		$old_sidebars_widgets = array_filter( $old_sidebars_widgets );
       
  1300 
       
  1301 		// Only check sidebars that are empty or have not been mapped to yet.
       
  1302 		foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ) {
       
  1303 			if ( array_key_exists( $new_sidebar, $old_sidebars_widgets ) && ! empty( $new_widgets ) ) {
       
  1304 				unset( $old_sidebars_widgets[ $new_sidebar ] );
       
  1305 			}
       
  1306 		}
       
  1307 
       
  1308 		// Remove orphaned widgets, we're only interested in previously active sidebars.
       
  1309 		foreach ( $old_sidebars_widgets as $sidebar => $widgets ) {
       
  1310 			if ( 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
       
  1311 				unset( $old_sidebars_widgets[ $sidebar ] );
       
  1312 			}
       
  1313 		}
       
  1314 
       
  1315 		$old_sidebars_widgets = _wp_remove_unregistered_widgets( $old_sidebars_widgets );
       
  1316 
       
  1317 		if ( ! empty( $old_sidebars_widgets ) ) {
       
  1318 
       
  1319 			// Go through each remaining sidebar...
       
  1320 			foreach ( $old_sidebars_widgets as $old_sidebar => $old_widgets ) {
       
  1321 
       
  1322 				// ...and check every new sidebar...
       
  1323 				foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ) {
       
  1324 
       
  1325 					// ...for every widget we're trying to revive.
       
  1326 					foreach ( $old_widgets as $key => $widget_id ) {
       
  1327 						$active_key = array_search( $widget_id, $new_widgets, true );
       
  1328 
       
  1329 						// If the widget is used elsewhere...
       
  1330 						if ( false !== $active_key ) {
       
  1331 
       
  1332 							// ...and that elsewhere is inactive widgets...
       
  1333 							if ( 'wp_inactive_widgets' === $new_sidebar ) {
       
  1334 
       
  1335 								// ...remove it from there and keep the active version...
       
  1336 								unset( $new_sidebars_widgets['wp_inactive_widgets'][ $active_key ] );
       
  1337 							} else {
       
  1338 
       
  1339 								// ...otherwise remove it from the old sidebar and keep it in the new one.
       
  1340 								unset( $old_sidebars_widgets[ $old_sidebar ][ $key ] );
       
  1341 							}
       
  1342 						} // endif ( $active_key )
       
  1343 					} // endforeach ( $old_widgets as $key => $widget_id )
       
  1344 				} // endforeach ( $new_sidebars_widgets as $new_sidebar => $new_widgets )
       
  1345 			} // endforeach ( $old_sidebars_widgets as $old_sidebar => $old_widgets )
       
  1346 		} // endif ( ! empty( $old_sidebars_widgets ) )
       
  1347 
       
  1348 
       
  1349 		// Restore widget settings from when theme was previously active.
       
  1350 		$new_sidebars_widgets = array_merge( $new_sidebars_widgets, $old_sidebars_widgets );
       
  1351 	}
       
  1352 
       
  1353 	return $new_sidebars_widgets;
       
  1354 }
       
  1355 
       
  1356 /**
       
  1357  * Compares a list of sidebars with their widgets against a whitelist.
       
  1358  *
       
  1359  * @since 4.9.0
       
  1360  *
       
  1361  * @param array $sidebars_widgets List of sidebars and their widget instance IDs.
       
  1362  * @param array $whitelist        Optional. List of widget IDs to compare against. Default: Registered widgets.
       
  1363  * @return array Sidebars with whitelisted widgets.
       
  1364  */
       
  1365 function _wp_remove_unregistered_widgets( $sidebars_widgets, $whitelist = array() ) {
       
  1366 	if ( empty( $whitelist ) ) {
       
  1367 		$whitelist = array_keys( $GLOBALS['wp_registered_widgets'] );
       
  1368 	}
       
  1369 
       
  1370 	foreach ( $sidebars_widgets as $sidebar => $widgets ) {
       
  1371 		if ( is_array( $widgets ) ) {
       
  1372 			$sidebars_widgets[ $sidebar ] = array_intersect( $widgets, $whitelist );
       
  1373 		}
       
  1374 	}
       
  1375 
       
  1376 	return $sidebars_widgets;
       
  1377 }
       
  1378 
       
  1379 /**
       
  1380  * Display the RSS entries in a list.
       
  1381  *
       
  1382  * @since 2.5.0
       
  1383  *
       
  1384  * @param string|array|object $rss RSS url.
       
  1385  * @param array $args Widget arguments.
       
  1386  */
       
  1387 function wp_widget_rss_output( $rss, $args = array() ) {
       
  1388 	if ( is_string( $rss ) ) {
       
  1389 		$rss = fetch_feed($rss);
       
  1390 	} elseif ( is_array($rss) && isset($rss['url']) ) {
       
  1391 		$args = $rss;
       
  1392 		$rss = fetch_feed($rss['url']);
       
  1393 	} elseif ( !is_object($rss) ) {
       
  1394 		return;
       
  1395 	}
       
  1396 
       
  1397 	if ( is_wp_error($rss) ) {
       
  1398 		if ( is_admin() || current_user_can('manage_options') )
       
  1399 			echo '<p><strong>' . __( 'RSS Error:' ) . '</strong> ' . $rss->get_error_message() . '</p>';
       
  1400 		return;
       
  1401 	}
       
  1402 
       
  1403 	$default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0, 'items' => 0 );
       
  1404 	$args = wp_parse_args( $args, $default_args );
       
  1405 
       
  1406 	$items = (int) $args['items'];
       
  1407 	if ( $items < 1 || 20 < $items )
       
  1408 		$items = 10;
       
  1409 	$show_summary  = (int) $args['show_summary'];
       
  1410 	$show_author   = (int) $args['show_author'];
       
  1411 	$show_date     = (int) $args['show_date'];
       
  1412 
       
  1413 	if ( !$rss->get_item_quantity() ) {
       
  1414 		echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
       
  1415 		$rss->__destruct();
       
  1416 		unset($rss);
       
  1417 		return;
       
  1418 	}
       
  1419 
       
  1420 	echo '<ul>';
       
  1421 	foreach ( $rss->get_items( 0, $items ) as $item ) {
       
  1422 		$link = $item->get_link();
       
  1423 		while ( stristr( $link, 'http' ) != $link ) {
       
  1424 			$link = substr( $link, 1 );
       
  1425 		}
       
  1426 		$link = esc_url( strip_tags( $link ) );
       
  1427 
       
  1428 		$title = esc_html( trim( strip_tags( $item->get_title() ) ) );
       
  1429 		if ( empty( $title ) ) {
       
  1430 			$title = __( 'Untitled' );
       
  1431 		}
       
  1432 
       
  1433 		$desc = @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option( 'blog_charset' ) );
       
  1434 		$desc = esc_attr( wp_trim_words( $desc, 55, ' [&hellip;]' ) );
       
  1435 
       
  1436 		$summary = '';
       
  1437 		if ( $show_summary ) {
       
  1438 			$summary = $desc;
       
  1439 
       
  1440 			// Change existing [...] to [&hellip;].
       
  1441 			if ( '[...]' == substr( $summary, -5 ) ) {
       
  1442 				$summary = substr( $summary, 0, -5 ) . '[&hellip;]';
       
  1443 			}
       
  1444 
       
  1445 			$summary = '<div class="rssSummary">' . esc_html( $summary ) . '</div>';
       
  1446 		}
       
  1447 
       
  1448 		$date = '';
       
  1449 		if ( $show_date ) {
       
  1450 			$date = $item->get_date( 'U' );
       
  1451 
       
  1452 			if ( $date ) {
       
  1453 				$date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
       
  1454 			}
       
  1455 		}
       
  1456 
       
  1457 		$author = '';
       
  1458 		if ( $show_author ) {
       
  1459 			$author = $item->get_author();
       
  1460 			if ( is_object($author) ) {
       
  1461 				$author = $author->get_name();
       
  1462 				$author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
       
  1463 			}
       
  1464 		}
       
  1465 
       
  1466 		if ( $link == '' ) {
       
  1467 			echo "<li>$title{$date}{$summary}{$author}</li>";
       
  1468 		} elseif ( $show_summary ) {
       
  1469 			echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$summary}{$author}</li>";
       
  1470 		} else {
       
  1471 			echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$author}</li>";
       
  1472 		}
       
  1473 	}
       
  1474 	echo '</ul>';
       
  1475 	$rss->__destruct();
       
  1476 	unset($rss);
       
  1477 }
       
  1478 
       
  1479 /**
       
  1480  * Display RSS widget options form.
       
  1481  *
       
  1482  * The options for what fields are displayed for the RSS form are all booleans
       
  1483  * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
       
  1484  * 'show_date'.
       
  1485  *
       
  1486  * @since 2.5.0
       
  1487  *
       
  1488  * @param array|string $args Values for input fields.
       
  1489  * @param array $inputs Override default display options.
       
  1490  */
       
  1491 function wp_widget_rss_form( $args, $inputs = null ) {
       
  1492 	$default_inputs = array( 'url' => true, 'title' => true, 'items' => true, 'show_summary' => true, 'show_author' => true, 'show_date' => true );
       
  1493 	$inputs = wp_parse_args( $inputs, $default_inputs );
       
  1494 
       
  1495 	$args['title'] = isset( $args['title'] ) ? $args['title'] : '';
       
  1496 	$args['url'] = isset( $args['url'] ) ? $args['url'] : '';
       
  1497 	$args['items'] = isset( $args['items'] ) ? (int) $args['items'] : 0;
       
  1498 
       
  1499 	if ( $args['items'] < 1 || 20 < $args['items'] ) {
       
  1500 		$args['items'] = 10;
       
  1501 	}
       
  1502 
       
  1503 	$args['show_summary']   = isset( $args['show_summary'] ) ? (int) $args['show_summary'] : (int) $inputs['show_summary'];
       
  1504 	$args['show_author']    = isset( $args['show_author'] ) ? (int) $args['show_author'] : (int) $inputs['show_author'];
       
  1505 	$args['show_date']      = isset( $args['show_date'] ) ? (int) $args['show_date'] : (int) $inputs['show_date'];
       
  1506 
       
  1507 	if ( ! empty( $args['error'] ) ) {
       
  1508 		echo '<p class="widget-error"><strong>' . __( 'RSS Error:' ) . '</strong> ' . $args['error'] . '</p>';
       
  1509 	}
       
  1510 
       
  1511 	$esc_number = esc_attr( $args['number'] );
       
  1512 	if ( $inputs['url'] ) :
       
  1513 ?>
       
  1514 	<p><label for="rss-url-<?php echo $esc_number; ?>"><?php _e( 'Enter the RSS feed URL here:' ); ?></label>
       
  1515 	<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>
       
  1516 <?php endif; if ( $inputs['title'] ) : ?>
       
  1517 	<p><label for="rss-title-<?php echo $esc_number; ?>"><?php _e( 'Give the feed a title (optional):' ); ?></label>
       
  1518 	<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>
       
  1519 <?php endif; if ( $inputs['items'] ) : ?>
       
  1520 	<p><label for="rss-items-<?php echo $esc_number; ?>"><?php _e( 'How many items would you like to display?' ); ?></label>
       
  1521 	<select id="rss-items-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][items]">
       
  1522 	<?php
       
  1523 	for ( $i = 1; $i <= 20; ++$i ) {
       
  1524 		echo "<option value='$i' " . selected( $args['items'], $i, false ) . ">$i</option>";
       
  1525 	}
       
  1526 	?>
       
  1527 	</select></p>
       
  1528 <?php endif; if ( $inputs['show_summary'] ) : ?>
       
  1529 	<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'] ); ?> />
       
  1530 	<label for="rss-show-summary-<?php echo $esc_number; ?>"><?php _e( 'Display item content?' ); ?></label></p>
       
  1531 <?php endif; if ( $inputs['show_author'] ) : ?>
       
  1532 	<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'] ); ?> />
       
  1533 	<label for="rss-show-author-<?php echo $esc_number; ?>"><?php _e( 'Display item author if available?' ); ?></label></p>
       
  1534 <?php endif; if ( $inputs['show_date'] ) : ?>
       
  1535 	<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'] ); ?>/>
       
  1536 	<label for="rss-show-date-<?php echo $esc_number; ?>"><?php _e( 'Display item date?' ); ?></label></p>
       
  1537 <?php
       
  1538 	endif;
       
  1539 	foreach ( array_keys($default_inputs) as $input ) :
       
  1540 		if ( 'hidden' === $inputs[$input] ) :
       
  1541 			$id = str_replace( '_', '-', $input );
       
  1542 ?>
       
  1543 	<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 ] ); ?>" />
       
  1544 <?php
       
  1545 		endif;
       
  1546 	endforeach;
       
  1547 }
       
  1548 
       
  1549 /**
       
  1550  * Process RSS feed widget data and optionally retrieve feed items.
       
  1551  *
       
  1552  * The feed widget can not have more than 20 items or it will reset back to the
       
  1553  * default, which is 10.
       
  1554  *
       
  1555  * The resulting array has the feed title, feed url, feed link (from channel),
       
  1556  * feed items, error (if any), and whether to show summary, author, and date.
       
  1557  * All respectively in the order of the array elements.
       
  1558  *
       
  1559  * @since 2.5.0
       
  1560  *
       
  1561  * @param array $widget_rss RSS widget feed data. Expects unescaped data.
       
  1562  * @param bool $check_feed Optional, default is true. Whether to check feed for errors.
       
  1563  * @return array
       
  1564  */
       
  1565 function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
       
  1566 	$items = (int) $widget_rss['items'];
       
  1567 	if ( $items < 1 || 20 < $items )
       
  1568 		$items = 10;
       
  1569 	$url           = esc_url_raw( strip_tags( $widget_rss['url'] ) );
       
  1570 	$title         = isset( $widget_rss['title'] ) ? trim( strip_tags( $widget_rss['title'] ) ) : '';
       
  1571 	$show_summary  = isset( $widget_rss['show_summary'] ) ? (int) $widget_rss['show_summary'] : 0;
       
  1572 	$show_author   = isset( $widget_rss['show_author'] ) ? (int) $widget_rss['show_author'] :0;
       
  1573 	$show_date     = isset( $widget_rss['show_date'] ) ? (int) $widget_rss['show_date'] : 0;
       
  1574 
       
  1575 	if ( $check_feed ) {
       
  1576 		$rss = fetch_feed($url);
       
  1577 		$error = false;
       
  1578 		$link = '';
       
  1579 		if ( is_wp_error($rss) ) {
       
  1580 			$error = $rss->get_error_message();
       
  1581 		} else {
       
  1582 			$link = esc_url(strip_tags($rss->get_permalink()));
       
  1583 			while ( stristr($link, 'http') != $link )
       
  1584 				$link = substr($link, 1);
       
  1585 
       
  1586 			$rss->__destruct();
       
  1587 			unset($rss);
       
  1588 		}
       
  1589 	}
       
  1590 
       
  1591 	return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
       
  1592 }
       
  1593 
       
  1594 /**
       
  1595  * Registers all of the default WordPress widgets on startup.
       
  1596  *
       
  1597  * Calls {@see 'widgets_init'} action after all of the WordPress widgets have been registered.
       
  1598  *
       
  1599  * @since 2.2.0
       
  1600  */
       
  1601 function wp_widgets_init() {
       
  1602 	if ( ! is_blog_installed() ) {
       
  1603 		return;
       
  1604 	}
       
  1605 
       
  1606 	register_widget( 'WP_Widget_Pages' );
       
  1607 
       
  1608 	register_widget( 'WP_Widget_Calendar' );
       
  1609 
       
  1610 	register_widget( 'WP_Widget_Archives' );
       
  1611 
       
  1612 	if ( get_option( 'link_manager_enabled' ) ) {
       
  1613 		register_widget( 'WP_Widget_Links' );
       
  1614 	}
       
  1615 
       
  1616 	register_widget( 'WP_Widget_Media_Audio' );
       
  1617 
       
  1618 	register_widget( 'WP_Widget_Media_Image' );
       
  1619 
       
  1620 	register_widget( 'WP_Widget_Media_Gallery' );
       
  1621 
       
  1622 	register_widget( 'WP_Widget_Media_Video' );
       
  1623 
       
  1624 	register_widget( 'WP_Widget_Meta' );
       
  1625 
       
  1626 	register_widget( 'WP_Widget_Search' );
       
  1627 
       
  1628 	register_widget( 'WP_Widget_Text' );
       
  1629 
       
  1630 	register_widget( 'WP_Widget_Categories' );
       
  1631 
       
  1632 	register_widget( 'WP_Widget_Recent_Posts' );
       
  1633 
       
  1634 	register_widget( 'WP_Widget_Recent_Comments' );
       
  1635 
       
  1636 	register_widget( 'WP_Widget_RSS' );
       
  1637 
       
  1638 	register_widget( 'WP_Widget_Tag_Cloud' );
       
  1639 
       
  1640 	register_widget( 'WP_Nav_Menu_Widget' );
       
  1641 
       
  1642 	register_widget( 'WP_Widget_Custom_HTML' );
       
  1643 
       
  1644 	/**
       
  1645 	 * Fires after all default WordPress widgets have been registered.
       
  1646 	 *
       
  1647 	 * @since 2.2.0
       
  1648 	 */
       
  1649 	do_action( 'widgets_init' );
       
  1650 }