Make WordPress Core

Changeset 33746


Ignore:
Timestamp:
08/26/2015 02:39:50 AM (11 years ago)
Author:
wonderboymusic
Message:

Widgets: move classes into their own files, widgets.php loads the new files, so this is 100% BC if someone is loading widgets.php directly. New files created using svn cp.

Creates:
class-wp-widget.php
class-wp-widget-factory.php
widget-functions.php

widgets.php contains only top-level code. Class files only contain classes. Functions file only contains functions.

See #33413.

Location:
trunk/src/wp-includes
Files:
1 edited
3 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-widget-factory.php

    r33745 r33746  
    11<?php
    2 /**
    3  * API for creating dynamic sidebar without hardcoding functionality into
    4  * themes. Includes both internal WordPress routines and theme use routines.
    5  *
    6  * This functionality was found in a plugin before WordPress 2.2 release which
    7  * included it in the core from that point on.
    8  *
    9  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
    10  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
    11  *
    12  * @package WordPress
    13  * @subpackage Widgets
    14  */
    15 
    16 /**
    17  * This class must be extended for each widget and WP_Widget::widget(), WP_Widget::update()
    18  * and WP_Widget::form() need to be over-ridden.
    19  *
    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                 _deprecated_constructor( 'WP_Widget', '4.3.0' );
    177                 WP_Widget::__construct( $id_base, $name, $widget_options, $control_options );
    178         }
    179 
    180         /**
    181          * Constructs name attributes for use in form() fields
    182          *
    183          * This function should be used in form() methods to create name attributes for fields to be saved by update()
    184          *
    185          * @param string $field_name Field name
    186          * @return string Name attribute for $field_name
    187          */
    188         public function get_field_name($field_name) {
    189                 return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']';
    190         }
    191 
    192         /**
    193          * Constructs id attributes for use in {@see WP_Widget::form()} fields.
    194          *
    195          * This function should be used in form() methods to create id attributes
    196          * for fields to be saved by {@see WP_Widget::update()}.
    197          *
    198          * @since 2.8.0
    199          * @access public
    200          *
    201          * @param string $field_name Field name.
    202          * @return string ID attribute for `$field_name`.
    203          */
    204         public function get_field_id( $field_name ) {
    205                 return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field_name;
    206         }
    207 
    208         /**
    209          * Register all widget instances of this widget class.
    210          *
    211          * @since 2.8.0
    212          * @access private
    213          */
    214         public function _register() {
    215                 $settings = $this->get_settings();
    216                 $empty = true;
    217 
    218                 // When $settings is an array-like object, get an intrinsic array for use with array_keys().
    219                 if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) {
    220                         $settings = $settings->getArrayCopy();
    221                 }
    222 
    223                 if ( is_array( $settings ) ) {
    224                         foreach ( array_keys( $settings ) as $number ) {
    225                                 if ( is_numeric( $number ) ) {
    226                                         $this->_set( $number );
    227                                         $this->_register_one( $number );
    228                                         $empty = false;
    229                                 }
    230                         }
    231                 }
    232 
    233                 if ( $empty ) {
    234                         // If there are none, we register the widget's existence with a generic template.
    235                         $this->_set( 1 );
    236                         $this->_register_one();
    237                 }
    238         }
    239 
    240         /**
    241          * Set the internal order number for the widget instance.
    242          *
    243          * @since 2.8.0
    244          * @access private
    245          *
    246          * @param int $number The unique order number of this widget instance compared to other
    247          *                    instances of the same class.
    248          */
    249         public function _set($number) {
    250                 $this->number = $number;
    251                 $this->id = $this->id_base . '-' . $number;
    252         }
    253 
    254         /**
    255          * @return callback
    256          */
    257         public function _get_display_callback() {
    258                 return array($this, 'display_callback');
    259         }
    260         /**
    261          * @return callback
    262          */
    263         public function _get_update_callback() {
    264                 return array($this, 'update_callback');
    265         }
    266         /**
    267          * @return callback
    268          */
    269         public function _get_form_callback() {
    270                 return array($this, 'form_callback');
    271         }
    272 
    273         /**
    274          * Determine whether the current request is inside the Customizer preview.
    275          *
    276          * If true -- the current request is inside the Customizer preview, then
    277          * the object cache gets suspended and widgets should check this to decide
    278          * whether they should store anything persistently to the object cache,
    279          * to transients, or anywhere else.
    280          *
    281          * @since 3.9.0
    282          * @access public
    283          *
    284          * @global WP_Customize_Manager $wp_customize
    285          *
    286          * @return bool True if within the Customizer preview, false if not.
    287          */
    288         public function is_preview() {
    289                 global $wp_customize;
    290                 return ( isset( $wp_customize ) && $wp_customize->is_preview() ) ;
    291         }
    292 
    293         /**
    294          * Generate the actual widget content (Do NOT override).
    295          *
    296          * Finds the instance and calls {@see WP_Widget::widget()}.
    297          *
    298          * @since 2.8.0
    299          * @access public
    300          *
    301          * @param array     $args        Display arguments. See {@see WP_Widget::widget()} for information
    302          *                               on accepted arguments.
    303          * @param int|array $widget_args {
    304          *     Optional. Internal order number of the widget instance, or array of multi-widget arguments.
    305          *     Default 1.
    306          *
    307          *     @type int $number Number increment used for multiples of the same widget.
    308          * }
    309          */
    310         public function display_callback( $args, $widget_args = 1 ) {
    311                 if ( is_numeric( $widget_args ) ) {
    312                         $widget_args = array( 'number' => $widget_args );
    313                 }
    314 
    315                 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
    316                 $this->_set( $widget_args['number'] );
    317                 $instances = $this->get_settings();
    318 
    319                 if ( array_key_exists( $this->number, $instances ) ) {
    320                         $instance = $instances[ $this->number ];
    321 
    322                         /**
    323                          * Filter the settings for a particular widget instance.
    324                          *
    325                          * Returning false will effectively short-circuit display of the widget.
    326                          *
    327                          * @since 2.8.0
    328                          *
    329                          * @param array     $instance The current widget instance's settings.
    330                          * @param WP_Widget $this     The current widget instance.
    331                          * @param array     $args     An array of default widget arguments.
    332                          */
    333                         $instance = apply_filters( 'widget_display_callback', $instance, $this, $args );
    334 
    335                         if ( false === $instance ) {
    336                                 return;
    337                         }
    338 
    339                         $was_cache_addition_suspended = wp_suspend_cache_addition();
    340                         if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
    341                                 wp_suspend_cache_addition( true );
    342                         }
    343 
    344                         $this->widget( $args, $instance );
    345 
    346                         if ( $this->is_preview() ) {
    347                                 wp_suspend_cache_addition( $was_cache_addition_suspended );
    348                         }
    349                 }
    350         }
    351 
    352         /**
    353          * Deal with changed settings (Do NOT override).
    354          *
    355          * @since 2.8.0
    356          * @access public
    357          *
    358          * @global array $wp_registered_widgets
    359          *
    360          * @param int $deprecated Not used.
    361          */
    362         public function update_callback( $deprecated = 1 ) {
    363                 global $wp_registered_widgets;
    364 
    365                 $all_instances = $this->get_settings();
    366 
    367                 // We need to update the data
    368                 if ( $this->updated )
    369                         return;
    370 
    371                 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
    372                         // Delete the settings for this instance of the widget
    373                         if ( isset($_POST['the-widget-id']) )
    374                                 $del_id = $_POST['the-widget-id'];
    375                         else
    376                                 return;
    377 
    378                         if ( isset($wp_registered_widgets[$del_id]['params'][0]['number']) ) {
    379                                 $number = $wp_registered_widgets[$del_id]['params'][0]['number'];
    380 
    381                                 if ( $this->id_base . '-' . $number == $del_id )
    382                                         unset($all_instances[$number]);
    383                         }
    384                 } else {
    385                         if ( isset($_POST['widget-' . $this->id_base]) && is_array($_POST['widget-' . $this->id_base]) ) {
    386                                 $settings = $_POST['widget-' . $this->id_base];
    387                         } elseif ( isset($_POST['id_base']) && $_POST['id_base'] == $this->id_base ) {
    388                                 $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number'];
    389                                 $settings = array( $num => array() );
    390                         } else {
    391                                 return;
    392                         }
    393 
    394                         foreach ( $settings as $number => $new_instance ) {
    395                                 $new_instance = stripslashes_deep($new_instance);
    396                                 $this->_set($number);
    397 
    398                                 $old_instance = isset($all_instances[$number]) ? $all_instances[$number] : array();
    399 
    400                                 $was_cache_addition_suspended = wp_suspend_cache_addition();
    401                                 if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
    402                                         wp_suspend_cache_addition( true );
    403                                 }
    404 
    405                                 $instance = $this->update( $new_instance, $old_instance );
    406 
    407                                 if ( $this->is_preview() ) {
    408                                         wp_suspend_cache_addition( $was_cache_addition_suspended );
    409                                 }
    410 
    411                                 /**
    412                                  * Filter a widget's settings before saving.
    413                                  *
    414                                  * Returning false will effectively short-circuit the widget's ability
    415                                  * to update settings.
    416                                  *
    417                                  * @since 2.8.0
    418                                  *
    419                                  * @param array     $instance     The current widget instance's settings.
    420                                  * @param array     $new_instance Array of new widget settings.
    421                                  * @param array     $old_instance Array of old widget settings.
    422                                  * @param WP_Widget $this         The current widget instance.
    423                                  */
    424                                 $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this );
    425                                 if ( false !== $instance ) {
    426                                         $all_instances[$number] = $instance;
    427                                 }
    428 
    429                                 break; // run only once
    430                         }
    431                 }
    432 
    433                 $this->save_settings($all_instances);
    434                 $this->updated = true;
    435         }
    436 
    437         /**
    438          * Generate the widget control form (Do NOT override).
    439          *
    440          * @since 2.8.0
    441          * @access public
    442          *
    443          * @param int|array $widget_args Widget instance number or array of widget arguments.
    444          * @return string|null
    445          */
    446         public function form_callback( $widget_args = 1 ) {
    447                 if ( is_numeric($widget_args) )
    448                         $widget_args = array( 'number' => $widget_args );
    449 
    450                 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
    451                 $all_instances = $this->get_settings();
    452 
    453                 if ( -1 == $widget_args['number'] ) {
    454                         // We echo out a form where 'number' can be set later
    455                         $this->_set('__i__');
    456                         $instance = array();
    457                 } else {
    458                         $this->_set($widget_args['number']);
    459                         $instance = $all_instances[ $widget_args['number'] ];
    460                 }
    461 
    462                 /**
    463                  * Filter the widget instance's settings before displaying the control form.
    464                  *
    465                  * Returning false effectively short-circuits display of the control form.
    466                  *
    467                  * @since 2.8.0
    468                  *
    469                  * @param array     $instance The current widget instance's settings.
    470                  * @param WP_Widget $this     The current widget instance.
    471                  */
    472                 $instance = apply_filters( 'widget_form_callback', $instance, $this );
    473 
    474                 $return = null;
    475                 if ( false !== $instance ) {
    476                         $return = $this->form($instance);
    477 
    478                         /**
    479                          * Fires at the end of the widget control form.
    480                          *
    481                          * Use this hook to add extra fields to the widget form. The hook
    482                          * is only fired if the value passed to the 'widget_form_callback'
    483                          * hook is not false.
    484                          *
    485                          * Note: If the widget has no form, the text echoed from the default
    486                          * form method can be hidden using CSS.
    487                          *
    488                          * @since 2.8.0
    489                          *
    490                          * @param WP_Widget $this     The widget instance, passed by reference.
    491                          * @param null      $return   Return null if new fields are added.
    492                          * @param array     $instance An array of the widget's settings.
    493                          */
    494                         do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) );
    495                 }
    496                 return $return;
    497         }
    498 
    499         /**
    500          * Register an instance of the widget class.
    501          *
    502          * @since 2.8.0
    503          * @access private
    504          *
    505          * @param integer $number Optional. The unique order number of this widget instance
    506          *                        compared to other instances of the same class. Default -1.
    507          */
    508         public function _register_one( $number = -1 ) {
    509                 wp_register_sidebar_widget(     $this->id, $this->name, $this->_get_display_callback(), $this->widget_options, array( 'number' => $number ) );
    510                 _register_widget_update_callback( $this->id_base, $this->_get_update_callback(), $this->control_options, array( 'number' => -1 ) );
    511                 _register_widget_form_callback( $this->id, $this->name, $this->_get_form_callback(), $this->control_options, array( 'number' => $number ) );
    512         }
    513 
    514         /**
    515          * Save the settings for all instances of the widget class.
    516          *
    517          * @since 2.8.0
    518          * @access public
    519          *
    520          * @param array $settings Multi-dimensional array of widget instance settings.
    521          */
    522         public function save_settings( $settings ) {
    523                 $settings['_multiwidget'] = 1;
    524                 update_option( $this->option_name, $settings );
    525         }
    526 
    527         /**
    528          * Get the settings for all instances of the widget class.
    529          *
    530          * @since 2.8.0
    531          * @access public
    532          *
    533          * @return array Multi-dimensional array of widget instance settings.
    534          */
    535         public function get_settings() {
    536 
    537                 $settings = get_option( $this->option_name );
    538 
    539                 if ( false === $settings && isset( $this->alt_option_name ) ) {
    540                         $settings = get_option( $this->alt_option_name );
    541                 }
    542 
    543                 if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) {
    544                         $settings = array();
    545                 }
    546 
    547                 if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) {
    548                         // Old format, convert if single widget.
    549                         $settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings );
    550                 }
    551 
    552                 unset( $settings['_multiwidget'], $settings['__i__'] );
    553                 return $settings;
    554         }
    555 }
    556 
    5572/**
    5583 * Singleton that registers and instantiates WP_Widget classes.
    … …  
    62974        }
    63075}
    631 
    632 /* Global Variables */
    633 
    634 /** @ignore */
    635 global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
    636 
    637 /**
    638  * Stores the sidebars, since many themes can have more than one.
    639  *
    640  * @global array $wp_registered_sidebars
    641  * @since 2.2.0
    642  */
    643 $wp_registered_sidebars = array();
    644 
    645 /**
    646  * Stores the registered widgets.
    647  *
    648  * @global array $wp_registered_widgets
    649  * @since 2.2.0
    650  */
    651 $wp_registered_widgets = array();
    652 
    653 /**
    654  * Stores the registered widget control (options).
    655  *
    656  * @global array $wp_registered_widget_controls
    657  * @since 2.2.0
    658  */
    659 $wp_registered_widget_controls = array();
    660 /**
    661  * @global array $wp_registered_widget_updates
    662  */
    663 $wp_registered_widget_updates = array();
    664 
    665 /**
    666  * Private
    667  *
    668  * @global array $_wp_sidebars_widgets
    669  */
    670 $_wp_sidebars_widgets = array();
    671 
    672 /**
    673  * Private
    674  *
    675  * @global array $_wp_deprecated_widgets_callbacks
    676  */
    677 $GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
    678         'wp_widget_pages',
    679         'wp_widget_pages_control',
    680         'wp_widget_calendar',
    681         'wp_widget_calendar_control',
    682         'wp_widget_archives',
    683         'wp_widget_archives_control',
    684         'wp_widget_links',
    685         'wp_widget_meta',
    686         'wp_widget_meta_control',
    687         'wp_widget_search',
    688         'wp_widget_recent_entries',
    689         'wp_widget_recent_entries_control',
    690         'wp_widget_tag_cloud',
    691         'wp_widget_tag_cloud_control',
    692         'wp_widget_categories',
    693         'wp_widget_categories_control',
    694         'wp_widget_text',
    695         'wp_widget_text_control',
    696         'wp_widget_rss',
    697         'wp_widget_rss_control',
    698         'wp_widget_recent_comments',
    699         'wp_widget_recent_comments_control'
    700 );
    701 
    702 /* Template tags & API functions */
    703 
    704 /**
    705  * Register a widget
    706  *
    707  * Registers a WP_Widget widget
    708  *
    709  * @since 2.8.0
    710  *
    711  * @see WP_Widget
    712  *
    713  * @global WP_Widget_Factory $wp_widget_factory
    714  *
    715  * @param string $widget_class The name of a class that extends WP_Widget
    716  */
    717 function register_widget($widget_class) {
    718         global $wp_widget_factory;
    719 
    720         $wp_widget_factory->register($widget_class);
    721 }
    722 
    723 /**
    724  * Unregister a widget
    725  *
    726  * Unregisters a WP_Widget widget. Useful for unregistering default widgets.
    727  * Run within a function hooked to the widgets_init action.
    728  *
    729  * @since 2.8.0
    730  *
    731  * @see WP_Widget
    732  *
    733  * @global WP_Widget_Factory $wp_widget_factory
    734  *
    735  * @param string $widget_class The name of a class that extends WP_Widget
    736  */
    737 function unregister_widget($widget_class) {
    738         global $wp_widget_factory;
    739 
    740         $wp_widget_factory->unregister($widget_class);
    741 }
    742 
    743 /**
    744  * Creates multiple sidebars.
    745  *
    746  * If you wanted to quickly create multiple sidebars for a theme or internally.
    747  * This function will allow you to do so. If you don't pass the 'name' and/or
    748  * 'id' in `$args`, then they will be built for you.
    749  *
    750  * @since 2.2.0
    751  *
    752  * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
    753  *
    754  * @global array $wp_registered_sidebars
    755  *
    756  * @param int          $number Optional. Number of sidebars to create. Default 1.
    757  * @param array|string $args {
    758  *     Optional. Array or string of arguments for building a sidebar.
    759  *
    760  *     @type string $id   The base string of the unique identifier for each sidebar. If provided, and multiple
    761  *                        sidebars are being defined, the id will have "-2" appended, and so on.
    762  *                        Default 'sidebar-' followed by the number the sidebar creation is currently at.
    763  *     @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering
    764  *                        more than one sidebar, include '%d' in the string as a placeholder for the uniquely
    765  *                        assigned number for each sidebar.
    766  *                        Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'.
    767  * }
    768  */
    769 function register_sidebars( $number = 1, $args = array() ) {
    770         global $wp_registered_sidebars;
    771         $number = (int) $number;
    772 
    773         if ( is_string($args) )
    774                 parse_str($args, $args);
    775 
    776         for ( $i = 1; $i <= $number; $i++ ) {
    777                 $_args = $args;
    778 
    779                 if ( $number > 1 )
    780                         $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i);
    781                 else
    782                         $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar');
    783 
    784                 // Custom specified ID's are suffixed if they exist already.
    785                 // Automatically generated sidebar names need to be suffixed regardless starting at -0
    786                 if ( isset($args['id']) ) {
    787                         $_args['id'] = $args['id'];
    788                         $n = 2; // Start at -2 for conflicting custom ID's
    789                         while ( isset($wp_registered_sidebars[$_args['id']]) )
    790                                 $_args['id'] = $args['id'] . '-' . $n++;
    791                 } else {
    792                         $n = count($wp_registered_sidebars);
    793                         do {
    794                                 $_args['id'] = 'sidebar-' . ++$n;
    795                         } while ( isset($wp_registered_sidebars[$_args['id']]) );
    796                 }
    797                 register_sidebar($_args);
    798         }
    799 }
    800 
    801 /**
    802  * Builds the definition for a single sidebar and returns the ID.
    803  *
    804  * Accepts either a string or an array and then parses that against a set
    805  * of default arguments for the new sidebar. WordPress will automatically
    806  * generate a sidebar ID and name based on the current number of registered
    807  * sidebars if those arguments are not included.
    808  *
    809  * When allowing for automatic generation of the name and ID parameters, keep
    810  * in mind that the incrementor for your sidebar can change over time depending
    811  * on what other plugins and themes are installed.
    812  *
    813  * If theme support for 'widgets' has not yet been added when this function is
    814  * called, it will be automatically enabled through the use of add_theme_support()
    815  *
    816  * @since 2.2.0
    817  *
    818  * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
    819  *
    820  * @param array|string $args {
    821  *     Optional. Array or string of arguments for the sidebar being registered.
    822  *
    823  *     @type string $name          The name or title of the sidebar displayed in the Widgets
    824  *                                 interface. Default 'Sidebar $instance'.
    825  *     @type string $id            The unique identifier by which the sidebar will be called.
    826  *                                 Default 'sidebar-$instance'.
    827  *     @type string $description   Description of the sidebar, displayed in the Widgets interface.
    828  *                                 Default empty string.
    829  *     @type string $class         Extra CSS class to assign to the sidebar in the Widgets interface.
    830  *                                 Default empty.
    831  *     @type string $before_widget HTML content to prepend to each widget's HTML output when
    832  *                                 assigned to this sidebar. Default is an opening list item element.
    833  *     @type string $after_widget  HTML content to append to each widget's HTML output when
    834  *                                 assigned to this sidebar. Default is a closing list item element.
    835  *     @type string $before_title  HTML content to prepend to the sidebar title when displayed.
    836  *                                 Default is an opening h2 element.
    837  *     @type string $after_title   HTML content to append to the sidebar title when displayed.
    838  *                                 Default is a closing h2 element.
    839  * }
    840  * @return string Sidebar ID added to $wp_registered_sidebars global.
    841  */
    842 function register_sidebar($args = array()) {
    843         global $wp_registered_sidebars;
    844 
    845         $i = count($wp_registered_sidebars) + 1;
    846 
    847         $id_is_empty = empty( $args['id'] );
    848 
    849         $defaults = array(
    850                 'name' => sprintf(__('Sidebar %d'), $i ),
    851                 'id' => "sidebar-$i",
    852                 'description' => '',
    853                 'class' => '',
    854                 'before_widget' => '<li id="%1$s" class="widget %2$s">',
    855                 'after_widget' => "</li>\n",
    856                 'before_title' => '<h2 class="widgettitle">',
    857                 'after_title' => "</h2>\n",
    858         );
    859 
    860         $sidebar = wp_parse_args( $args, $defaults );
    861 
    862         if ( $id_is_empty ) {
    863                 /* translators: 1: the id argument, 2: sidebar name, 3: recommended id value */
    864                 _doing_it_wrong( __FUNCTION__, sprintf( __( 'No %1$s was set in the arguments array for the "%2$s" sidebar. Defaulting to "%3$s". Manually set the %1$s to "%3$s" to silence this notice and keep existing sidebar content.' ), '<code>id</code>', $sidebar['name'], $sidebar['id'] ), '4.2.0' );
    865         }
    866 
    867         $wp_registered_sidebars[$sidebar['id']] = $sidebar;
    868 
    869         add_theme_support('widgets');
    870 
    871         /**
    872          * Fires once a sidebar has been registered.
    873          *
    874          * @since 3.0.0
    875          *
    876          * @param array $sidebar Parsed arguments for the registered sidebar.
    877          */
    878         do_action( 'register_sidebar', $sidebar );
    879 
    880         return $sidebar['id'];
    881 }
    882 
    883 /**
    884  * Removes a sidebar from the list.
    885  *
    886  * @since 2.2.0
    887  *
    888  * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
    889  *
    890  * @param string $name The ID of the sidebar when it was added.
    891  */
    892 function unregister_sidebar( $name ) {
    893         global $wp_registered_sidebars;
    894 
    895         unset( $wp_registered_sidebars[ $name ] );
    896 }
    897 
    898 /**
    899  * Register an instance of a widget.
    900  *
    901  * The default widget option is 'classname' that can be overridden.
    902  *
    903  * The function can also be used to un-register widgets when `$output_callback`
    904  * parameter is an empty string.
    905  *
    906  * @since 2.2.0
    907  *
    908  * @global array $wp_registered_widgets       Uses stored registered widgets.
    909  * @global array $wp_register_widget_defaults Retrieves widget defaults.
    910  * @global array $wp_registered_widget_updates
    911  * @global array $_wp_deprecated_widgets_callbacks
    912  *
    913  * @param int|string $id              Widget ID.
    914  * @param string     $name            Widget display title.
    915  * @param callback   $output_callback Run when widget is called.
    916  * @param array      $options {
    917  *     Optional. An array of supplementary widget options for the instance.
    918  *
    919  *     @type string $classname   Class name for the widget's HTML container. Default is a shortened
    920  *                               version of the output callback name.
    921  *     @type string $description Widget description for display in the widget administration
    922  *                               panel and/or theme.
    923  * }
    924  */
    925 function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array() ) {
    926         global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
    927 
    928         $id = strtolower($id);
    929 
    930         if ( empty($output_callback) ) {
    931                 unset($wp_registered_widgets[$id]);
    932                 return;
    933         }
    934 
    935         $id_base = _get_widget_id_base($id);
    936         if ( in_array($output_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($output_callback) ) {
    937                 unset( $wp_registered_widget_controls[ $id ] );
    938                 unset( $wp_registered_widget_updates[ $id_base ] );
    939                 return;
    940         }
    941 
    942         $defaults = array('classname' => $output_callback);
    943         $options = wp_parse_args($options, $defaults);
    944         $widget = array(
    945                 'name' => $name,
    946                 'id' => $id,
    947                 'callback' => $output_callback,
    948                 'params' => array_slice(func_get_args(), 4)
    949         );
    950         $widget = array_merge($widget, $options);
    951 
    952         if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) ) {
    953 
    954                 /**
    955                  * Fires once for each registered widget.
    956                  *
    957                  * @since 3.0.0
    958                  *
    959                  * @param array $widget An array of default widget arguments.
    960                  */
    961                 do_action( 'wp_register_sidebar_widget', $widget );
    962                 $wp_registered_widgets[$id] = $widget;
    963         }
    964 }
    965 
    966 /**
    967  * Retrieve description for widget.
    968  *
    969  * When registering widgets, the options can also include 'description' that
    970  * describes the widget for display on the widget administration panel or
    971  * in the theme.
    972  *
    973  * @since 2.5.0
    974  *
    975  * @global array $wp_registered_widgets
    976  *
    977  * @param int|string $id Widget ID.
    978  * @return string|void Widget description, if available.
    979  */
    980 function wp_widget_description( $id ) {
    981         if ( !is_scalar($id) )
    982                 return;
    983 
    984         global $wp_registered_widgets;
    985 
    986         if ( isset($wp_registered_widgets[$id]['description']) )
    987                 return esc_html( $wp_registered_widgets[$id]['description'] );
    988 }
    989 
    990 /**
    991  * Retrieve description for a sidebar.
    992  *
    993  * When registering sidebars a 'description' parameter can be included that
    994  * describes the sidebar for display on the widget administration panel.
    995  *
    996  * @since 2.9.0
    997  *
    998  * @global array $wp_registered_sidebars
    999  *
    1000  * @param string $id sidebar ID.
    1001  * @return string|void Sidebar description, if available.
    1002  */
    1003 function wp_sidebar_description( $id ) {
    1004         if ( !is_scalar($id) )
    1005                 return;
    1006 
    1007         global $wp_registered_sidebars;
    1008 
    1009         if ( isset($wp_registered_sidebars[$id]['description']) )
    1010                 return esc_html( $wp_registered_sidebars[$id]['description'] );
    1011 }
    1012 
    1013 /**
    1014  * Remove widget from sidebar.
    1015  *
    1016  * @since 2.2.0
    1017  *
    1018  * @param int|string $id Widget ID.
    1019  */
    1020 function wp_unregister_sidebar_widget($id) {
    1021 
    1022         /**
    1023          * Fires just before a widget is removed from a sidebar.
    1024          *
    1025          * @since 3.0.0
    1026          *
    1027          * @param int $id The widget ID.
    1028          */
    1029         do_action( 'wp_unregister_sidebar_widget', $id );
    1030 
    1031         wp_register_sidebar_widget($id, '', '');
    1032         wp_unregister_widget_control($id);
    1033 }
    1034 
    1035 /**
    1036  * Registers widget control callback for customizing options.
    1037  *
    1038  * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
    1039  * option is never used. The 'width' option is the width of the fully expanded
    1040  * control form, but try hard to use the default width. The 'id_base' is for
    1041  * multi-widgets (widgets which allow multiple instances such as the text
    1042  * widget), an id_base must be provided. The widget id will end up looking like
    1043  * `{$id_base}-{$unique_number}`.
    1044  *
    1045  * @since 2.2.0
    1046  *
    1047  * @todo Document `$options` as a hash notation, re: WP_Widget::__construct() cross-reference.
    1048  * @todo `$params` parameter?
    1049  *
    1050  * @global array $wp_registered_widget_controls
    1051  * @global array $wp_registered_widget_updates
    1052  * @global array $wp_registered_widgets
    1053  * @global array $_wp_deprecated_widgets_callbacks
    1054  *
    1055  * @param int|string   $id               Sidebar ID.
    1056  * @param string       $name             Sidebar display name.
    1057  * @param callback     $control_callback Run when sidebar is displayed.
    1058  * @param array|string $options          Optional. Widget options. See description above. Default empty array.
    1059  */
    1060 function wp_register_widget_control( $id, $name, $control_callback, $options = array() ) {
    1061         global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
    1062 
    1063         $id = strtolower($id);
    1064         $id_base = _get_widget_id_base($id);
    1065 
    1066         if ( empty($control_callback) ) {
    1067                 unset($wp_registered_widget_controls[$id]);
    1068                 unset($wp_registered_widget_updates[$id_base]);
    1069                 return;
    1070         }
    1071 
    1072         if ( in_array($control_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($control_callback) ) {
    1073                 unset( $wp_registered_widgets[ $id ] );
    1074                 return;
    1075         }
    1076 
    1077         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
    1078                 return;
    1079 
    1080         $defaults = array('width' => 250, 'height' => 200 ); // height is never used
    1081         $options = wp_parse_args($options, $defaults);
    1082         $options['width'] = (int) $options['width'];
    1083         $options['height'] = (int) $options['height'];
    1084 
    1085         $widget = array(
    1086                 'name' => $name,
    1087                 'id' => $id,
    1088                 'callback' => $control_callback,
    1089                 'params' => array_slice(func_get_args(), 4)
    1090         );
    1091         $widget = array_merge($widget, $options);
    1092 
    1093         $wp_registered_widget_controls[$id] = $widget;
    1094 
    1095         if ( isset($wp_registered_widget_updates[$id_base]) )
    1096                 return;
    1097 
    1098         if ( isset($widget['params'][0]['number']) )
    1099                 $widget['params'][0]['number'] = -1;
    1100 
    1101         unset($widget['width'], $widget['height'], $widget['name'], $widget['id']);
    1102         $wp_registered_widget_updates[$id_base] = $widget;
    1103 }
    1104 
    1105 /**
    1106  * @global array $wp_registered_widget_updates
    1107  *
    1108  * @param string   $id_base
    1109  * @param callable $update_callback
    1110  * @param array    $options
    1111  */
    1112 function _register_widget_update_callback($id_base, $update_callback, $options = array()) {
    1113         global $wp_registered_widget_updates;
    1114 
    1115         if ( isset($wp_registered_widget_updates[$id_base]) ) {
    1116                 if ( empty($update_callback) )
    1117                         unset($wp_registered_widget_updates[$id_base]);
    1118                 return;
    1119         }
    1120 
    1121         $widget = array(
    1122                 'callback' => $update_callback,
    1123                 'params' => array_slice(func_get_args(), 3)
    1124         );
    1125 
    1126         $widget = array_merge($widget, $options);
    1127         $wp_registered_widget_updates[$id_base] = $widget;
    1128 }
    1129 
    1130 /**
    1131  *
    1132  * @global array $wp_registered_widget_controls
    1133  *
    1134  * @param int|string $id
    1135  * @param string     $name
    1136  * @param callable   $form_callback
    1137  * @param array      $options
    1138  */
    1139 function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
    1140         global $wp_registered_widget_controls;
    1141 
    1142         $id = strtolower($id);
    1143 
    1144         if ( empty($form_callback) ) {
    1145                 unset($wp_registered_widget_controls[$id]);
    1146                 return;
    1147         }
    1148 
    1149         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
    1150                 return;
    1151 
    1152         $defaults = array('width' => 250, 'height' => 200 );
    1153         $options = wp_parse_args($options, $defaults);
    1154         $options['width'] = (int) $options['width'];
    1155         $options['height'] = (int) $options['height'];
    1156 
    1157         $widget = array(
    1158                 'name' => $name,
    1159                 'id' => $id,
    1160                 'callback' => $form_callback,
    1161                 'params' => array_slice(func_get_args(), 4)
    1162         );
    1163         $widget = array_merge($widget, $options);
    1164 
    1165         $wp_registered_widget_controls[$id] = $widget;
    1166 }
    1167 
    1168 /**
    1169  * Remove control callback for widget.
    1170  *
    1171  * @since 2.2.0
    1172  *
    1173  * @param int|string $id Widget ID.
    1174  */
    1175 function wp_unregister_widget_control($id) {
    1176         wp_register_widget_control( $id, '', '' );
    1177 }
    1178 
    1179 /**
    1180  * Display dynamic sidebar.
    1181  *
    1182  * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
    1183  * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
    1184  * Otherwise, you can pass in a numerical index to display the sidebar at that index.
    1185  *
    1186  * @since 2.2.0
    1187  *
    1188  * @global array $wp_registered_sidebars
    1189  * @global array $wp_registered_widgets
    1190  *
    1191  * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
    1192  * @return bool True, if widget sidebar was found and called. False if not found or not called.
    1193  */
    1194 function dynamic_sidebar($index = 1) {
    1195         global $wp_registered_sidebars, $wp_registered_widgets;
    1196 
    1197         if ( is_int($index) ) {
    1198                 $index = "sidebar-$index";
    1199         } else {
    1200                 $index = sanitize_title($index);
    1201                 foreach ( (array) $wp_registered_sidebars as $key => $value ) {
    1202                         if ( sanitize_title($value['name']) == $index ) {
    1203                                 $index = $key;
    1204                                 break;
    1205                         }
    1206                 }
    1207         }
    1208 
    1209         $sidebars_widgets = wp_get_sidebars_widgets();
    1210         if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
    1211                 /** This action is documented in wp-includes/widgets.php */
    1212                 do_action( 'dynamic_sidebar_before', $index, false );
    1213                 /** This action is documented in wp-includes/widgets.php */
    1214                 do_action( 'dynamic_sidebar_after',  $index, false );
    1215                 /** This filter is documented in wp-includes/widgets.php */
    1216                 return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
    1217         }
    1218 
    1219         /**
    1220          * Fires before widgets are rendered in a dynamic sidebar.
    1221          *
    1222          * Note: The action also fires for empty sidebars, and on both the front-end
    1223          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
    1224          *
    1225          * @since 3.9.0
    1226          *
    1227          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
    1228          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
    1229          *                                Default true.
    1230          */
    1231         do_action( 'dynamic_sidebar_before', $index, true );
    1232         $sidebar = $wp_registered_sidebars[$index];
    1233 
    1234         $did_one = false;
    1235         foreach ( (array) $sidebars_widgets[$index] as $id ) {
    1236 
    1237                 if ( !isset($wp_registered_widgets[$id]) ) continue;
    1238 
    1239                 $params = array_merge(
    1240                         array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
    1241                         (array) $wp_registered_widgets[$id]['params']
    1242                 );
    1243 
    1244                 // Substitute HTML id and class attributes into before_widget
    1245                 $classname_ = '';
    1246                 foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
    1247                         if ( is_string($cn) )
    1248                                 $classname_ .= '_' . $cn;
    1249                         elseif ( is_object($cn) )
    1250                                 $classname_ .= '_' . get_class($cn);
    1251                 }
    1252                 $classname_ = ltrim($classname_, '_');
    1253                 $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
    1254 
    1255                 /**
    1256                  * Filter the parameters passed to a widget's display callback.
    1257                  *
    1258                  * Note: The filter is evaluated on both the front-end and back-end,
    1259                  * including for the Inactive Widgets sidebar on the Widgets screen.
    1260                  *
    1261                  * @since 2.5.0
    1262                  *
    1263                  * @see register_sidebar()
    1264                  *
    1265                  * @param array $params {
    1266                  *     @type array $args  {
    1267                  *         An array of widget display arguments.
    1268                  *
    1269                  *         @type string $name          Name of the sidebar the widget is assigned to.
    1270                  *         @type string $id            ID of the sidebar the widget is assigned to.
    1271                  *         @type string $description   The sidebar description.
    1272                  *         @type string $class         CSS class applied to the sidebar container.
    1273                  *         @type string $before_widget HTML markup to prepend to each widget in the sidebar.
    1274                  *         @type string $after_widget  HTML markup to append to each widget in the sidebar.
    1275                  *         @type string $before_title  HTML markup to prepend to the widget title when displayed.
    1276                  *         @type string $after_title   HTML markup to append to the widget title when displayed.
    1277                  *         @type string $widget_id     ID of the widget.
    1278                  *         @type string $widget_name   Name of the widget.
    1279                  *     }
    1280                  *     @type array $widget_args {
    1281                  *         An array of multi-widget arguments.
    1282                  *
    1283                  *         @type int $number Number increment used for multiples of the same widget.
    1284                  *     }
    1285                  * }
    1286                  */
    1287                 $params = apply_filters( 'dynamic_sidebar_params', $params );
    1288 
    1289                 $callback = $wp_registered_widgets[$id]['callback'];
    1290 
    1291                 /**
    1292                  * Fires before a widget's display callback is called.
    1293                  *
    1294                  * Note: The action fires on both the front-end and back-end, including
    1295                  * for widgets in the Inactive Widgets sidebar on the Widgets screen.
    1296                  *
    1297                  * The action is not fired for empty sidebars.
    1298                  *
    1299                  * @since 3.0.0
    1300                  *
    1301                  * @param array $widget_id {
    1302                  *     An associative array of widget arguments.
    1303                  *
    1304                  *     @type string $name                Name of the widget.
    1305                  *     @type string $id                  Widget ID.
    1306                  *     @type array|callback $callback    When the hook is fired on the front-end, $callback is an array
    1307                  *                                       containing the widget object. Fired on the back-end, $callback
    1308                  *                                       is 'wp_widget_control', see $_callback.
    1309                  *     @type array          $params      An associative array of multi-widget arguments.
    1310                  *     @type string         $classname   CSS class applied to the widget container.
    1311                  *     @type string         $description The widget description.
    1312                  *     @type array          $_callback   When the hook is fired on the back-end, $_callback is populated
    1313                  *                                       with an array containing the widget object, see $callback.
    1314                  * }
    1315                  */
    1316                 do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
    1317 
    1318                 if ( is_callable($callback) ) {
    1319                         call_user_func_array($callback, $params);
    1320                         $did_one = true;
    1321                 }
    1322         }
    1323 
    1324         /**
    1325          * Fires after widgets are rendered in a dynamic sidebar.
    1326          *
    1327          * Note: The action also fires for empty sidebars, and on both the front-end
    1328          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
    1329          *
    1330          * @since 3.9.0
    1331          *
    1332          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
    1333          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
    1334          *                                Default true.
    1335          */
    1336         do_action( 'dynamic_sidebar_after', $index, true );
    1337 
    1338         /**
    1339          * Filter whether a sidebar has widgets.
    1340          *
    1341          * Note: The filter is also evaluated for empty sidebars, and on both the front-end
    1342          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
    1343          *
    1344          * @since 3.9.0
    1345          *
    1346          * @param bool       $did_one Whether at least one widget was rendered in the sidebar.
    1347          *                            Default false.
    1348          * @param int|string $index   Index, name, or ID of the dynamic sidebar.
    1349          */
    1350         return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
    1351 }
    1352 
    1353 /**
    1354  * Whether widget is displayed on the front-end.
    1355  *
    1356  * Either $callback or $id_base can be used
    1357  * $id_base is the first argument when extending WP_Widget class
    1358  * Without the optional $widget_id parameter, returns the ID of the first sidebar
    1359  * in which the first instance of the widget with the given callback or $id_base is found.
    1360  * With the $widget_id parameter, returns the ID of the sidebar where
    1361  * the widget with that callback/$id_base AND that ID is found.
    1362  *
    1363  * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
    1364  * this function has to run after widgets have initialized, at action 'init' or later.
    1365  *
    1366  * @since 2.2.0
    1367  *
    1368  * @global array $wp_registered_widgets
    1369  *
    1370  * @param string $callback      Optional, Widget callback to check.
    1371  * @param int    $widget_id     Optional, but needed for checking. Widget ID.
    1372  * @param string $id_base       Optional, the base ID of a widget created by extending WP_Widget.
    1373  * @param bool   $skip_inactive Optional, whether to check in 'wp_inactive_widgets'.
    1374  * @return string|false False if widget is not active or id of sidebar in which the widget is active.
    1375  */
    1376 function is_active_widget($callback = false, $widget_id = false, $id_base = false, $skip_inactive = true) {
    1377         global $wp_registered_widgets;
    1378 
    1379         $sidebars_widgets = wp_get_sidebars_widgets();
    1380 
    1381         if ( is_array($sidebars_widgets) ) {
    1382                 foreach ( $sidebars_widgets as $sidebar => $widgets ) {
    1383                         if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) ) {
    1384                                 continue;
    1385                         }
    1386 
    1387                         if ( is_array($widgets) ) {
    1388                                 foreach ( $widgets as $widget ) {
    1389                                         if ( ( $callback && isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback ) || ( $id_base && _get_widget_id_base($widget) == $id_base ) ) {
    1390                                                 if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
    1391                                                         return $sidebar;
    1392                                         }
    1393                                 }
    1394                         }
    1395                 }
    1396         }
    1397         return false;
    1398 }
    1399 
    1400 /**
    1401  * Whether the dynamic sidebar is enabled and used by theme.
    1402  *
    1403  * @since 2.2.0
    1404  *
    1405  * @global array $wp_registered_widgets
    1406  * @global array $wp_registered_sidebars
    1407  *
    1408  * @return bool True, if using widgets. False, if not using widgets.
    1409  */
    1410 function is_dynamic_sidebar() {
    1411         global $wp_registered_widgets, $wp_registered_sidebars;
    1412         $sidebars_widgets = get_option('sidebars_widgets');
    1413         foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
    1414                 if ( count($sidebars_widgets[$index]) ) {
    1415                         foreach ( (array) $sidebars_widgets[$index] as $widget )
    1416                                 if ( array_key_exists($widget, $wp_registered_widgets) )
    1417                                         return true;
    1418                 }
    1419         }
    1420         return false;
    1421 }
    1422 
    1423 /**
    1424  * Whether a sidebar is in use.
    1425  *
    1426  * @since 2.8.0
    1427  *
    1428  * @param string|int $index Sidebar name, id or number to check.
    1429  * @return bool true if the sidebar is in use, false otherwise.
    1430  */
    1431 function is_active_sidebar( $index ) {
    1432         $index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
    1433         $sidebars_widgets = wp_get_sidebars_widgets();
    1434         $is_active_sidebar = ! empty( $sidebars_widgets[$index] );
    1435 
    1436         /**
    1437          * Filter whether a dynamic sidebar is considered "active".
    1438          *
    1439          * @since 3.9.0
    1440          *
    1441          * @param bool       $is_active_sidebar Whether or not the sidebar should be considered "active".
    1442          *                                      In other words, whether the sidebar contains any widgets.
    1443          * @param int|string $index             Index, name, or ID of the dynamic sidebar.
    1444          */
    1445         return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
    1446 }
    1447 
    1448 /* Internal Functions */
    1449 
    1450 /**
    1451  * Retrieve full list of sidebars and their widget instance IDs.
    1452  *
    1453  * Will upgrade sidebar widget list, if needed. Will also save updated list, if
    1454  * needed.
    1455  *
    1456  * @since 2.2.0
    1457  * @access private
    1458  *
    1459  * @global array $_wp_sidebars_widgets
    1460  * @global array $sidebars_widgets
    1461  *
    1462  * @param bool $deprecated Not used (argument deprecated).
    1463  * @return array Upgraded list of widgets to version 3 array format when called from the admin.
    1464  */
    1465 function wp_get_sidebars_widgets( $deprecated = true ) {
    1466         if ( $deprecated !== true )
    1467                 _deprecated_argument( __FUNCTION__, '2.8.1' );
    1468 
    1469         global $_wp_sidebars_widgets, $sidebars_widgets;
    1470 
    1471         // If loading from front page, consult $_wp_sidebars_widgets rather than options
    1472         // to see if wp_convert_widget_settings() has made manipulations in memory.
    1473         if ( !is_admin() ) {
    1474                 if ( empty($_wp_sidebars_widgets) )
    1475                         $_wp_sidebars_widgets = get_option('sidebars_widgets', array());
    1476 
    1477                 $sidebars_widgets = $_wp_sidebars_widgets;
    1478         } else {
    1479                 $sidebars_widgets = get_option('sidebars_widgets', array());
    1480         }
    1481 
    1482         if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
    1483                 unset($sidebars_widgets['array_version']);
    1484 
    1485         /**
    1486          * Filter the list of sidebars and their widgets.
    1487          *
    1488          * @since 2.7.0
    1489          *
    1490          * @param array $sidebars_widgets An associative array of sidebars and their widgets.
    1491          */
    1492         return apply_filters( 'sidebars_widgets', $sidebars_widgets );
    1493 }
    1494 
    1495 /**
    1496  * Set the sidebar widget option to update sidebars.
    1497  *
    1498  * @since 2.2.0
    1499  * @access private
    1500  *
    1501  * @param array $sidebars_widgets Sidebar widgets and their settings.
    1502  */
    1503 function wp_set_sidebars_widgets( $sidebars_widgets ) {
    1504         if ( !isset( $sidebars_widgets['array_version'] ) )
    1505                 $sidebars_widgets['array_version'] = 3;
    1506         update_option( 'sidebars_widgets', $sidebars_widgets );
    1507 }
    1508 
    1509 /**
    1510  * Retrieve default registered sidebars list.
    1511  *
    1512  * @since 2.2.0
    1513  * @access private
    1514  *
    1515  * @global array $wp_registered_sidebars
    1516  *
    1517  * @return array
    1518  */
    1519 function wp_get_widget_defaults() {
    1520         global $wp_registered_sidebars;
    1521 
    1522         $defaults = array();
    1523 
    1524         foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
    1525                 $defaults[$index] = array();
    1526 
    1527         return $defaults;
    1528 }
    1529 
    1530 /**
    1531  * Convert the widget settings from single to multi-widget format.
    1532  *
    1533  * @since 2.8.0
    1534  *
    1535  * @global array $_wp_sidebars_widgets
    1536  *
    1537  * @param string $base_name
    1538  * @param string $option_name
    1539  * @param array  $settings
    1540  * @return array
    1541  */
    1542 function wp_convert_widget_settings($base_name, $option_name, $settings) {
    1543         // This test may need expanding.
    1544         $single = $changed = false;
    1545         if ( empty($settings) ) {
    1546                 $single = true;
    1547         } else {
    1548                 foreach ( array_keys($settings) as $number ) {
    1549                         if ( 'number' == $number )
    1550                                 continue;
    1551                         if ( !is_numeric($number) ) {
    1552                                 $single = true;
    1553                                 break;
    1554                         }
    1555                 }
    1556         }
    1557 
    1558         if ( $single ) {
    1559                 $settings = array( 2 => $settings );
    1560 
    1561                 // If loading from the front page, update sidebar in memory but don't save to options
    1562                 if ( is_admin() ) {
    1563                         $sidebars_widgets = get_option('sidebars_widgets');
    1564                 } else {
    1565                         if ( empty($GLOBALS['_wp_sidebars_widgets']) )
    1566                                 $GLOBALS['_wp_sidebars_widgets'] = get_option('sidebars_widgets', array());
    1567                         $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
    1568                 }
    1569 
    1570                 foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
    1571                         if ( is_array($sidebar) ) {
    1572                                 foreach ( $sidebar as $i => $name ) {
    1573                                         if ( $base_name == $name ) {
    1574                                                 $sidebars_widgets[$index][$i] = "$name-2";
    1575                                                 $changed = true;
    1576                                                 break 2;
    1577                                         }
    1578                                 }
    1579                         }
    1580                 }
    1581 
    1582                 if ( is_admin() && $changed )
    1583                         update_option('sidebars_widgets', $sidebars_widgets);
    1584         }
    1585 
    1586         $settings['_multiwidget'] = 1;
    1587         if ( is_admin() )
    1588                 update_option( $option_name, $settings );
    1589 
    1590         return $settings;
    1591 }
    1592 
    1593 /**
    1594  * Output an arbitrary widget as a template tag.
    1595  *
    1596  * @since 2.8.0
    1597  *
    1598  * @global WP_Widget_Factory $wp_widget_factory
    1599  *
    1600  * @param string $widget   The widget's PHP class name (see default-widgets.php).
    1601  * @param array  $instance Optional. The widget's instance settings. Default empty array.
    1602  * @param array  $args {
    1603  *     Optional. Array of arguments to configure the display of the widget.
    1604  *
    1605  *     @type string $before_widget HTML content that will be prepended to the widget's HTML output.
    1606  *                                 Default `<div class="widget %s">`, where `%s` is the widget's class name.
    1607  *     @type string $after_widget  HTML content that will be appended to the widget's HTML output.
    1608  *                                 Default `</div>`.
    1609  *     @type string $before_title  HTML content that will be prepended to the widget's title when displayed.
    1610  *                                 Default `<h2 class="widgettitle">`.
    1611  *     @type string $after_title   HTML content that will be appended to the widget's title when displayed.
    1612  *                                 Default `</h2>`.
    1613  * }
    1614  */
    1615 function the_widget( $widget, $instance = array(), $args = array() ) {
    1616         global $wp_widget_factory;
    1617 
    1618         $widget_obj = $wp_widget_factory->widgets[$widget];
    1619         if ( ! ( $widget_obj instanceof WP_Widget ) ) {
    1620                 return;
    1621         }
    1622 
    1623         $before_widget = sprintf('<div class="widget %s">', $widget_obj->widget_options['classname'] );
    1624         $default_args = array( 'before_widget' => $before_widget, 'after_widget' => "</div>", 'before_title' => '<h2 class="widgettitle">', 'after_title' => '</h2>' );
    1625 
    1626         $args = wp_parse_args($args, $default_args);
    1627         $instance = wp_parse_args($instance);
    1628 
    1629         /**
    1630          * Fires before rendering the requested widget.
    1631          *
    1632          * @since 3.0.0
    1633          *
    1634          * @param string $widget   The widget's class name.
    1635          * @param array  $instance The current widget instance's settings.
    1636          * @param array  $args     An array of the widget's sidebar arguments.
    1637          */
    1638         do_action( 'the_widget', $widget, $instance, $args );
    1639 
    1640         $widget_obj->_set(-1);
    1641         $widget_obj->widget($args, $instance);
    1642 }
    1643 
    1644 /**
    1645  * Private
    1646  *
    1647  * @return string
    1648  */
    1649 function _get_widget_id_base($id) {
    1650         return preg_replace( '/-[0-9]+$/', '', $id );
    1651 }
    1652 
    1653 /**
    1654  * Handle sidebars config after theme change
    1655  *
    1656  * @access private
    1657  * @since 3.3.0
    1658  *
    1659  * @global array $sidebars_widgets
    1660  */
    1661 function _wp_sidebars_changed() {
    1662         global $sidebars_widgets;
    1663 
    1664         if ( ! is_array( $sidebars_widgets ) )
    1665                 $sidebars_widgets = wp_get_sidebars_widgets();
    1666 
    1667         retrieve_widgets(true);
    1668 }
    1669 
    1670 /**
    1671  * Look for "lost" widgets, this has to run at least on each theme change.
    1672  *
    1673  * @since 2.8.0
    1674  *
    1675  * @global array $wp_registered_sidebars
    1676  * @global array $sidebars_widgets
    1677  * @global array $wp_registered_widgets
    1678  *
    1679  * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
    1680  *                                   of 'customize' defers updates for the Customizer.
    1681  * @return array|void
    1682  */
    1683 function retrieve_widgets( $theme_changed = false ) {
    1684         global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
    1685 
    1686         $registered_sidebar_keys = array_keys( $wp_registered_sidebars );
    1687         $orphaned = 0;
    1688 
    1689         $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
    1690         if ( is_array( $old_sidebars_widgets ) ) {
    1691                 // time() that sidebars were stored is in $old_sidebars_widgets['time']
    1692                 $_sidebars_widgets = $old_sidebars_widgets['data'];
    1693 
    1694                 if ( 'customize' !== $theme_changed ) {
    1695                         remove_theme_mod( 'sidebars_widgets' );
    1696                 }
    1697 
    1698                 foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
    1699                         if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
    1700                                 continue;
    1701                         }
    1702 
    1703                         if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {
    1704                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;
    1705                                 unset( $_sidebars_widgets[$sidebar] );
    1706                         }
    1707                 }
    1708         } else {
    1709                 if ( empty( $sidebars_widgets ) )
    1710                         return;
    1711 
    1712                 unset( $sidebars_widgets['array_version'] );
    1713 
    1714                 $old = array_keys($sidebars_widgets);
    1715                 sort($old);
    1716                 sort($registered_sidebar_keys);
    1717 
    1718                 if ( $old == $registered_sidebar_keys )
    1719                         return;
    1720 
    1721                 $_sidebars_widgets = array(
    1722                         'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()
    1723                 );
    1724 
    1725                 unset( $sidebars_widgets['wp_inactive_widgets'] );
    1726 
    1727                 foreach ( $wp_registered_sidebars as $id => $settings ) {
    1728                         if ( $theme_changed ) {
    1729                                 $_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
    1730                         } else {
    1731                                 // no theme change, grab only sidebars that are currently registered
    1732                                 if ( isset( $sidebars_widgets[$id] ) ) {
    1733                                         $_sidebars_widgets[$id] = $sidebars_widgets[$id];
    1734                                         unset( $sidebars_widgets[$id] );
    1735                                 }
    1736                         }
    1737                 }
    1738 
    1739                 foreach ( $sidebars_widgets as $val ) {
    1740                         if ( is_array($val) && ! empty( $val ) )
    1741                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
    1742                 }
    1743         }
    1744 
    1745         // discard invalid, theme-specific widgets from sidebars
    1746         $shown_widgets = array();
    1747 
    1748         foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
    1749                 if ( !is_array($widgets) )
    1750                         continue;
    1751 
    1752                 $_widgets = array();
    1753                 foreach ( $widgets as $widget ) {
    1754                         if ( isset($wp_registered_widgets[$widget]) )
    1755                                 $_widgets[] = $widget;
    1756                 }
    1757 
    1758                 $_sidebars_widgets[$sidebar] = $_widgets;
    1759                 $shown_widgets = array_merge($shown_widgets, $_widgets);
    1760         }
    1761 
    1762         $sidebars_widgets = $_sidebars_widgets;
    1763         unset($_sidebars_widgets, $_widgets);
    1764 
    1765         // find hidden/lost multi-widget instances
    1766         $lost_widgets = array();
    1767         foreach ( $wp_registered_widgets as $key => $val ) {
    1768                 if ( in_array($key, $shown_widgets, true) )
    1769                         continue;
    1770 
    1771                 $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
    1772 
    1773                 if ( 2 > (int) $number )
    1774                         continue;
    1775 
    1776                 $lost_widgets[] = $key;
    1777         }
    1778 
    1779         $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
    1780         if ( 'customize' !== $theme_changed ) {
    1781                 wp_set_sidebars_widgets( $sidebars_widgets );
    1782         }
    1783 
    1784         return $sidebars_widgets;
    1785 }
  • trunk/src/wp-includes/class-wp-widget.php

    r33745 r33746  
    11<?php
    2 /**
    3  * API for creating dynamic sidebar without hardcoding functionality into
    4  * themes. Includes both internal WordPress routines and theme use routines.
    5  *
    6  * This functionality was found in a plugin before WordPress 2.2 release which
    7  * included it in the core from that point on.
    8  *
    9  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
    10  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
    11  *
    12  * @package WordPress
    13  * @subpackage Widgets
    14  */
    15 
    162/**
    173 * This class must be extended for each widget and WP_Widget::widget(), WP_Widget::update()
    … …  
    554540        }
    555541}
    556 
    557 /**
    558  * Singleton that registers and instantiates WP_Widget classes.
    559  *
    560  * @package WordPress
    561  * @subpackage Widgets
    562  * @since 2.8.0
    563  */
    564 class WP_Widget_Factory {
    565         public $widgets = array();
    566 
    567         /**
    568          * PHP5 constructor.
    569          */
    570         public function __construct() {
    571                 add_action( 'widgets_init', array( $this, '_register_widgets' ), 100 );
    572         }
    573 
    574         /**
    575          * PHP4 constructor.
    576          */
    577         public function WP_Widget_Factory() {
    578                 _deprecated_constructor( 'WP_Widget_Factory', '4.2.0' );
    579                 self::__construct();
    580         }
    581 
    582         /**
    583          * Register a widget subclass.
    584          *
    585          * @since 2.8.0
    586          * @access public
    587          *
    588          * @param string $widget_class The name of a {@see WP_Widget} subclass.
    589          */
    590         public function register( $widget_class ) {
    591                 $this->widgets[$widget_class] = new $widget_class();
    592         }
    593 
    594         /**
    595          * Un-register a widget subclass.
    596          *
    597          * @since 2.8.0
    598          * @access public
    599          *
    600          * @param string $widget_class The name of a {@see WP_Widget} subclass.
    601          */
    602         public function unregister( $widget_class ) {
    603                 unset( $this->widgets[ $widget_class ] );
    604         }
    605 
    606         /**
    607          * Utility method for adding widgets to the registered widgets global.
    608          *
    609          * @since 2.8.0
    610          * @access public
    611          *
    612          * @global array $wp_registered_widgets
    613          */
    614         public function _register_widgets() {
    615                 global $wp_registered_widgets;
    616                 $keys = array_keys($this->widgets);
    617                 $registered = array_keys($wp_registered_widgets);
    618                 $registered = array_map('_get_widget_id_base', $registered);
    619 
    620                 foreach ( $keys as $key ) {
    621                         // don't register new widget if old widget with the same id is already registered
    622                         if ( in_array($this->widgets[$key]->id_base, $registered, true) ) {
    623                                 unset($this->widgets[$key]);
    624                                 continue;
    625                         }
    626 
    627                         $this->widgets[$key]->_register();
    628                 }
    629         }
    630 }
    631 
    632 /* Global Variables */
    633 
    634 /** @ignore */
    635 global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
    636 
    637 /**
    638  * Stores the sidebars, since many themes can have more than one.
    639  *
    640  * @global array $wp_registered_sidebars
    641  * @since 2.2.0
    642  */
    643 $wp_registered_sidebars = array();
    644 
    645 /**
    646  * Stores the registered widgets.
    647  *
    648  * @global array $wp_registered_widgets
    649  * @since 2.2.0
    650  */
    651 $wp_registered_widgets = array();
    652 
    653 /**
    654  * Stores the registered widget control (options).
    655  *
    656  * @global array $wp_registered_widget_controls
    657  * @since 2.2.0
    658  */
    659 $wp_registered_widget_controls = array();
    660 /**
    661  * @global array $wp_registered_widget_updates
    662  */
    663 $wp_registered_widget_updates = array();
    664 
    665 /**
    666  * Private
    667  *
    668  * @global array $_wp_sidebars_widgets
    669  */
    670 $_wp_sidebars_widgets = array();
    671 
    672 /**
    673  * Private
    674  *
    675  * @global array $_wp_deprecated_widgets_callbacks
    676  */
    677 $GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
    678         'wp_widget_pages',
    679         'wp_widget_pages_control',
    680         'wp_widget_calendar',
    681         'wp_widget_calendar_control',
    682         'wp_widget_archives',
    683         'wp_widget_archives_control',
    684         'wp_widget_links',
    685         'wp_widget_meta',
    686         'wp_widget_meta_control',
    687         'wp_widget_search',
    688         'wp_widget_recent_entries',
    689         'wp_widget_recent_entries_control',
    690         'wp_widget_tag_cloud',
    691         'wp_widget_tag_cloud_control',
    692         'wp_widget_categories',
    693         'wp_widget_categories_control',
    694         'wp_widget_text',
    695         'wp_widget_text_control',
    696         'wp_widget_rss',
    697         'wp_widget_rss_control',
    698         'wp_widget_recent_comments',
    699         'wp_widget_recent_comments_control'
    700 );
    701 
    702 /* Template tags & API functions */
    703 
    704 /**
    705  * Register a widget
    706  *
    707  * Registers a WP_Widget widget
    708  *
    709  * @since 2.8.0
    710  *
    711  * @see WP_Widget
    712  *
    713  * @global WP_Widget_Factory $wp_widget_factory
    714  *
    715  * @param string $widget_class The name of a class that extends WP_Widget
    716  */
    717 function register_widget($widget_class) {
    718         global $wp_widget_factory;
    719 
    720         $wp_widget_factory->register($widget_class);
    721 }
    722 
    723 /**
    724  * Unregister a widget
    725  *
    726  * Unregisters a WP_Widget widget. Useful for unregistering default widgets.
    727  * Run within a function hooked to the widgets_init action.
    728  *
    729  * @since 2.8.0
    730  *
    731  * @see WP_Widget
    732  *
    733  * @global WP_Widget_Factory $wp_widget_factory
    734  *
    735  * @param string $widget_class The name of a class that extends WP_Widget
    736  */
    737 function unregister_widget($widget_class) {
    738         global $wp_widget_factory;
    739 
    740         $wp_widget_factory->unregister($widget_class);
    741 }
    742 
    743 /**
    744  * Creates multiple sidebars.
    745  *
    746  * If you wanted to quickly create multiple sidebars for a theme or internally.
    747  * This function will allow you to do so. If you don't pass the 'name' and/or
    748  * 'id' in `$args`, then they will be built for you.
    749  *
    750  * @since 2.2.0
    751  *
    752  * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
    753  *
    754  * @global array $wp_registered_sidebars
    755  *
    756  * @param int          $number Optional. Number of sidebars to create. Default 1.
    757  * @param array|string $args {
    758  *     Optional. Array or string of arguments for building a sidebar.
    759  *
    760  *     @type string $id   The base string of the unique identifier for each sidebar. If provided, and multiple
    761  *                        sidebars are being defined, the id will have "-2" appended, and so on.
    762  *                        Default 'sidebar-' followed by the number the sidebar creation is currently at.
    763  *     @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering
    764  *                        more than one sidebar, include '%d' in the string as a placeholder for the uniquely
    765  *                        assigned number for each sidebar.
    766  *                        Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'.
    767  * }
    768  */
    769 function register_sidebars( $number = 1, $args = array() ) {
    770         global $wp_registered_sidebars;
    771         $number = (int) $number;
    772 
    773         if ( is_string($args) )
    774                 parse_str($args, $args);
    775 
    776         for ( $i = 1; $i <= $number; $i++ ) {
    777                 $_args = $args;
    778 
    779                 if ( $number > 1 )
    780                         $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i);
    781                 else
    782                         $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar');
    783 
    784                 // Custom specified ID's are suffixed if they exist already.
    785                 // Automatically generated sidebar names need to be suffixed regardless starting at -0
    786                 if ( isset($args['id']) ) {
    787                         $_args['id'] = $args['id'];
    788                         $n = 2; // Start at -2 for conflicting custom ID's
    789                         while ( isset($wp_registered_sidebars[$_args['id']]) )
    790                                 $_args['id'] = $args['id'] . '-' . $n++;
    791                 } else {
    792                         $n = count($wp_registered_sidebars);
    793                         do {
    794                                 $_args['id'] = 'sidebar-' . ++$n;
    795                         } while ( isset($wp_registered_sidebars[$_args['id']]) );
    796                 }
    797                 register_sidebar($_args);
    798         }
    799 }
    800 
    801 /**
    802  * Builds the definition for a single sidebar and returns the ID.
    803  *
    804  * Accepts either a string or an array and then parses that against a set
    805  * of default arguments for the new sidebar. WordPress will automatically
    806  * generate a sidebar ID and name based on the current number of registered
    807  * sidebars if those arguments are not included.
    808  *
    809  * When allowing for automatic generation of the name and ID parameters, keep
    810  * in mind that the incrementor for your sidebar can change over time depending
    811  * on what other plugins and themes are installed.
    812  *
    813  * If theme support for 'widgets' has not yet been added when this function is
    814  * called, it will be automatically enabled through the use of add_theme_support()
    815  *
    816  * @since 2.2.0
    817  *
    818  * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
    819  *
    820  * @param array|string $args {
    821  *     Optional. Array or string of arguments for the sidebar being registered.
    822  *
    823  *     @type string $name          The name or title of the sidebar displayed in the Widgets
    824  *                                 interface. Default 'Sidebar $instance'.
    825  *     @type string $id            The unique identifier by which the sidebar will be called.
    826  *                                 Default 'sidebar-$instance'.
    827  *     @type string $description   Description of the sidebar, displayed in the Widgets interface.
    828  *                                 Default empty string.
    829  *     @type string $class         Extra CSS class to assign to the sidebar in the Widgets interface.
    830  *                                 Default empty.
    831  *     @type string $before_widget HTML content to prepend to each widget's HTML output when
    832  *                                 assigned to this sidebar. Default is an opening list item element.
    833  *     @type string $after_widget  HTML content to append to each widget's HTML output when
    834  *                                 assigned to this sidebar. Default is a closing list item element.
    835  *     @type string $before_title  HTML content to prepend to the sidebar title when displayed.
    836  *                                 Default is an opening h2 element.
    837  *     @type string $after_title   HTML content to append to the sidebar title when displayed.
    838  *                                 Default is a closing h2 element.
    839  * }
    840  * @return string Sidebar ID added to $wp_registered_sidebars global.
    841  */
    842 function register_sidebar($args = array()) {
    843         global $wp_registered_sidebars;
    844 
    845         $i = count($wp_registered_sidebars) + 1;
    846 
    847         $id_is_empty = empty( $args['id'] );
    848 
    849         $defaults = array(
    850                 'name' => sprintf(__('Sidebar %d'), $i ),
    851                 'id' => "sidebar-$i",
    852                 'description' => '',
    853                 'class' => '',
    854                 'before_widget' => '<li id="%1$s" class="widget %2$s">',
    855                 'after_widget' => "</li>\n",
    856                 'before_title' => '<h2 class="widgettitle">',
    857                 'after_title' => "</h2>\n",
    858         );
    859 
    860         $sidebar = wp_parse_args( $args, $defaults );
    861 
    862         if ( $id_is_empty ) {
    863                 /* translators: 1: the id argument, 2: sidebar name, 3: recommended id value */
    864                 _doing_it_wrong( __FUNCTION__, sprintf( __( 'No %1$s was set in the arguments array for the "%2$s" sidebar. Defaulting to "%3$s". Manually set the %1$s to "%3$s" to silence this notice and keep existing sidebar content.' ), '<code>id</code>', $sidebar['name'], $sidebar['id'] ), '4.2.0' );
    865         }
    866 
    867         $wp_registered_sidebars[$sidebar['id']] = $sidebar;
    868 
    869         add_theme_support('widgets');
    870 
    871         /**
    872          * Fires once a sidebar has been registered.
    873          *
    874          * @since 3.0.0
    875          *
    876          * @param array $sidebar Parsed arguments for the registered sidebar.
    877          */
    878         do_action( 'register_sidebar', $sidebar );
    879 
    880         return $sidebar['id'];
    881 }
    882 
    883 /**
    884  * Removes a sidebar from the list.
    885  *
    886  * @since 2.2.0
    887  *
    888  * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
    889  *
    890  * @param string $name The ID of the sidebar when it was added.
    891  */
    892 function unregister_sidebar( $name ) {
    893         global $wp_registered_sidebars;
    894 
    895         unset( $wp_registered_sidebars[ $name ] );
    896 }
    897 
    898 /**
    899  * Register an instance of a widget.
    900  *
    901  * The default widget option is 'classname' that can be overridden.
    902  *
    903  * The function can also be used to un-register widgets when `$output_callback`
    904  * parameter is an empty string.
    905  *
    906  * @since 2.2.0
    907  *
    908  * @global array $wp_registered_widgets       Uses stored registered widgets.
    909  * @global array $wp_register_widget_defaults Retrieves widget defaults.
    910  * @global array $wp_registered_widget_updates
    911  * @global array $_wp_deprecated_widgets_callbacks
    912  *
    913  * @param int|string $id              Widget ID.
    914  * @param string     $name            Widget display title.
    915  * @param callback   $output_callback Run when widget is called.
    916  * @param array      $options {
    917  *     Optional. An array of supplementary widget options for the instance.
    918  *
    919  *     @type string $classname   Class name for the widget's HTML container. Default is a shortened
    920  *                               version of the output callback name.
    921  *     @type string $description Widget description for display in the widget administration
    922  *                               panel and/or theme.
    923  * }
    924  */
    925 function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array() ) {
    926         global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
    927 
    928         $id = strtolower($id);
    929 
    930         if ( empty($output_callback) ) {
    931                 unset($wp_registered_widgets[$id]);
    932                 return;
    933         }
    934 
    935         $id_base = _get_widget_id_base($id);
    936         if ( in_array($output_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($output_callback) ) {
    937                 unset( $wp_registered_widget_controls[ $id ] );
    938                 unset( $wp_registered_widget_updates[ $id_base ] );
    939                 return;
    940         }
    941 
    942         $defaults = array('classname' => $output_callback);
    943         $options = wp_parse_args($options, $defaults);
    944         $widget = array(
    945                 'name' => $name,
    946                 'id' => $id,
    947                 'callback' => $output_callback,
    948                 'params' => array_slice(func_get_args(), 4)
    949         );
    950         $widget = array_merge($widget, $options);
    951 
    952         if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) ) {
    953 
    954                 /**
    955                  * Fires once for each registered widget.
    956                  *
    957                  * @since 3.0.0
    958                  *
    959                  * @param array $widget An array of default widget arguments.
    960                  */
    961                 do_action( 'wp_register_sidebar_widget', $widget );
    962                 $wp_registered_widgets[$id] = $widget;
    963         }
    964 }
    965 
    966 /**
    967  * Retrieve description for widget.
    968  *
    969  * When registering widgets, the options can also include 'description' that
    970  * describes the widget for display on the widget administration panel or
    971  * in the theme.
    972  *
    973  * @since 2.5.0
    974  *
    975  * @global array $wp_registered_widgets
    976  *
    977  * @param int|string $id Widget ID.
    978  * @return string|void Widget description, if available.
    979  */
    980 function wp_widget_description( $id ) {
    981         if ( !is_scalar($id) )
    982                 return;
    983 
    984         global $wp_registered_widgets;
    985 
    986         if ( isset($wp_registered_widgets[$id]['description']) )
    987                 return esc_html( $wp_registered_widgets[$id]['description'] );
    988 }
    989 
    990 /**
    991  * Retrieve description for a sidebar.
    992  *
    993  * When registering sidebars a 'description' parameter can be included that
    994  * describes the sidebar for display on the widget administration panel.
    995  *
    996  * @since 2.9.0
    997  *
    998  * @global array $wp_registered_sidebars
    999  *
    1000  * @param string $id sidebar ID.
    1001  * @return string|void Sidebar description, if available.
    1002  */
    1003 function wp_sidebar_description( $id ) {
    1004         if ( !is_scalar($id) )
    1005                 return;
    1006 
    1007         global $wp_registered_sidebars;
    1008 
    1009         if ( isset($wp_registered_sidebars[$id]['description']) )
    1010                 return esc_html( $wp_registered_sidebars[$id]['description'] );
    1011 }
    1012 
    1013 /**
    1014  * Remove widget from sidebar.
    1015  *
    1016  * @since 2.2.0
    1017  *
    1018  * @param int|string $id Widget ID.
    1019  */
    1020 function wp_unregister_sidebar_widget($id) {
    1021 
    1022         /**
    1023          * Fires just before a widget is removed from a sidebar.
    1024          *
    1025          * @since 3.0.0
    1026          *
    1027          * @param int $id The widget ID.
    1028          */
    1029         do_action( 'wp_unregister_sidebar_widget', $id );
    1030 
    1031         wp_register_sidebar_widget($id, '', '');
    1032         wp_unregister_widget_control($id);
    1033 }
    1034 
    1035 /**
    1036  * Registers widget control callback for customizing options.
    1037  *
    1038  * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
    1039  * option is never used. The 'width' option is the width of the fully expanded
    1040  * control form, but try hard to use the default width. The 'id_base' is for
    1041  * multi-widgets (widgets which allow multiple instances such as the text
    1042  * widget), an id_base must be provided. The widget id will end up looking like
    1043  * `{$id_base}-{$unique_number}`.
    1044  *
    1045  * @since 2.2.0
    1046  *
    1047  * @todo Document `$options` as a hash notation, re: WP_Widget::__construct() cross-reference.
    1048  * @todo `$params` parameter?
    1049  *
    1050  * @global array $wp_registered_widget_controls
    1051  * @global array $wp_registered_widget_updates
    1052  * @global array $wp_registered_widgets
    1053  * @global array $_wp_deprecated_widgets_callbacks
    1054  *
    1055  * @param int|string   $id               Sidebar ID.
    1056  * @param string       $name             Sidebar display name.
    1057  * @param callback     $control_callback Run when sidebar is displayed.
    1058  * @param array|string $options          Optional. Widget options. See description above. Default empty array.
    1059  */
    1060 function wp_register_widget_control( $id, $name, $control_callback, $options = array() ) {
    1061         global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
    1062 
    1063         $id = strtolower($id);
    1064         $id_base = _get_widget_id_base($id);
    1065 
    1066         if ( empty($control_callback) ) {
    1067                 unset($wp_registered_widget_controls[$id]);
    1068                 unset($wp_registered_widget_updates[$id_base]);
    1069                 return;
    1070         }
    1071 
    1072         if ( in_array($control_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($control_callback) ) {
    1073                 unset( $wp_registered_widgets[ $id ] );
    1074                 return;
    1075         }
    1076 
    1077         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
    1078                 return;
    1079 
    1080         $defaults = array('width' => 250, 'height' => 200 ); // height is never used
    1081         $options = wp_parse_args($options, $defaults);
    1082         $options['width'] = (int) $options['width'];
    1083         $options['height'] = (int) $options['height'];
    1084 
    1085         $widget = array(
    1086                 'name' => $name,
    1087                 'id' => $id,
    1088                 'callback' => $control_callback,
    1089                 'params' => array_slice(func_get_args(), 4)
    1090         );
    1091         $widget = array_merge($widget, $options);
    1092 
    1093         $wp_registered_widget_controls[$id] = $widget;
    1094 
    1095         if ( isset($wp_registered_widget_updates[$id_base]) )
    1096                 return;
    1097 
    1098         if ( isset($widget['params'][0]['number']) )
    1099                 $widget['params'][0]['number'] = -1;
    1100 
    1101         unset($widget['width'], $widget['height'], $widget['name'], $widget['id']);
    1102         $wp_registered_widget_updates[$id_base] = $widget;
    1103 }
    1104 
    1105 /**
    1106  * @global array $wp_registered_widget_updates
    1107  *
    1108  * @param string   $id_base
    1109  * @param callable $update_callback
    1110  * @param array    $options
    1111  */
    1112 function _register_widget_update_callback($id_base, $update_callback, $options = array()) {
    1113         global $wp_registered_widget_updates;
    1114 
    1115         if ( isset($wp_registered_widget_updates[$id_base]) ) {
    1116                 if ( empty($update_callback) )
    1117                         unset($wp_registered_widget_updates[$id_base]);
    1118                 return;
    1119         }
    1120 
    1121         $widget = array(
    1122                 'callback' => $update_callback,
    1123                 'params' => array_slice(func_get_args(), 3)
    1124         );
    1125 
    1126         $widget = array_merge($widget, $options);
    1127         $wp_registered_widget_updates[$id_base] = $widget;
    1128 }
    1129 
    1130 /**
    1131  *
    1132  * @global array $wp_registered_widget_controls
    1133  *
    1134  * @param int|string $id
    1135  * @param string     $name
    1136  * @param callable   $form_callback
    1137  * @param array      $options
    1138  */
    1139 function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
    1140         global $wp_registered_widget_controls;
    1141 
    1142         $id = strtolower($id);
    1143 
    1144         if ( empty($form_callback) ) {
    1145                 unset($wp_registered_widget_controls[$id]);
    1146                 return;
    1147         }
    1148 
    1149         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
    1150                 return;
    1151 
    1152         $defaults = array('width' => 250, 'height' => 200 );
    1153         $options = wp_parse_args($options, $defaults);
    1154         $options['width'] = (int) $options['width'];
    1155         $options['height'] = (int) $options['height'];
    1156 
    1157         $widget = array(
    1158                 'name' => $name,
    1159                 'id' => $id,
    1160                 'callback' => $form_callback,
    1161                 'params' => array_slice(func_get_args(), 4)
    1162         );
    1163         $widget = array_merge($widget, $options);
    1164 
    1165         $wp_registered_widget_controls[$id] = $widget;
    1166 }
    1167 
    1168 /**
    1169  * Remove control callback for widget.
    1170  *
    1171  * @since 2.2.0
    1172  *
    1173  * @param int|string $id Widget ID.
    1174  */
    1175 function wp_unregister_widget_control($id) {
    1176         wp_register_widget_control( $id, '', '' );
    1177 }
    1178 
    1179 /**
    1180  * Display dynamic sidebar.
    1181  *
    1182  * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
    1183  * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
    1184  * Otherwise, you can pass in a numerical index to display the sidebar at that index.
    1185  *
    1186  * @since 2.2.0
    1187  *
    1188  * @global array $wp_registered_sidebars
    1189  * @global array $wp_registered_widgets
    1190  *
    1191  * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
    1192  * @return bool True, if widget sidebar was found and called. False if not found or not called.
    1193  */
    1194 function dynamic_sidebar($index = 1) {
    1195         global $wp_registered_sidebars, $wp_registered_widgets;
    1196 
    1197         if ( is_int($index) ) {
    1198                 $index = "sidebar-$index";
    1199         } else {
    1200                 $index = sanitize_title($index);
    1201                 foreach ( (array) $wp_registered_sidebars as $key => $value ) {
    1202                         if ( sanitize_title($value['name']) == $index ) {
    1203                                 $index = $key;
    1204                                 break;
    1205                         }
    1206                 }
    1207         }
    1208 
    1209         $sidebars_widgets = wp_get_sidebars_widgets();
    1210         if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
    1211                 /** This action is documented in wp-includes/widgets.php */
    1212                 do_action( 'dynamic_sidebar_before', $index, false );
    1213                 /** This action is documented in wp-includes/widgets.php */
    1214                 do_action( 'dynamic_sidebar_after',  $index, false );
    1215                 /** This filter is documented in wp-includes/widgets.php */
    1216                 return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
    1217         }
    1218 
    1219         /**
    1220          * Fires before widgets are rendered in a dynamic sidebar.
    1221          *
    1222          * Note: The action also fires for empty sidebars, and on both the front-end
    1223          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
    1224          *
    1225          * @since 3.9.0
    1226          *
    1227          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
    1228          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
    1229          *                                Default true.
    1230          */
    1231         do_action( 'dynamic_sidebar_before', $index, true );
    1232         $sidebar = $wp_registered_sidebars[$index];
    1233 
    1234         $did_one = false;
    1235         foreach ( (array) $sidebars_widgets[$index] as $id ) {
    1236 
    1237                 if ( !isset($wp_registered_widgets[$id]) ) continue;
    1238 
    1239                 $params = array_merge(
    1240                         array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
    1241                         (array) $wp_registered_widgets[$id]['params']
    1242                 );
    1243 
    1244                 // Substitute HTML id and class attributes into before_widget
    1245                 $classname_ = '';
    1246                 foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
    1247                         if ( is_string($cn) )
    1248                                 $classname_ .= '_' . $cn;
    1249                         elseif ( is_object($cn) )
    1250                                 $classname_ .= '_' . get_class($cn);
    1251                 }
    1252                 $classname_ = ltrim($classname_, '_');
    1253                 $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
    1254 
    1255                 /**
    1256                  * Filter the parameters passed to a widget's display callback.
    1257                  *
    1258                  * Note: The filter is evaluated on both the front-end and back-end,
    1259                  * including for the Inactive Widgets sidebar on the Widgets screen.
    1260                  *
    1261                  * @since 2.5.0
    1262                  *
    1263                  * @see register_sidebar()
    1264                  *
    1265                  * @param array $params {
    1266                  *     @type array $args  {
    1267                  *         An array of widget display arguments.
    1268                  *
    1269                  *         @type string $name          Name of the sidebar the widget is assigned to.
    1270                  *         @type string $id            ID of the sidebar the widget is assigned to.
    1271                  *         @type string $description   The sidebar description.
    1272                  *         @type string $class         CSS class applied to the sidebar container.
    1273                  *         @type string $before_widget HTML markup to prepend to each widget in the sidebar.
    1274                  *         @type string $after_widget  HTML markup to append to each widget in the sidebar.
    1275                  *         @type string $before_title  HTML markup to prepend to the widget title when displayed.
    1276                  *         @type string $after_title   HTML markup to append to the widget title when displayed.
    1277                  *         @type string $widget_id     ID of the widget.
    1278                  *         @type string $widget_name   Name of the widget.
    1279                  *     }
    1280                  *     @type array $widget_args {
    1281                  *         An array of multi-widget arguments.
    1282                  *
    1283                  *         @type int $number Number increment used for multiples of the same widget.
    1284                  *     }
    1285                  * }
    1286                  */
    1287                 $params = apply_filters( 'dynamic_sidebar_params', $params );
    1288 
    1289                 $callback = $wp_registered_widgets[$id]['callback'];
    1290 
    1291                 /**
    1292                  * Fires before a widget's display callback is called.
    1293                  *
    1294                  * Note: The action fires on both the front-end and back-end, including
    1295                  * for widgets in the Inactive Widgets sidebar on the Widgets screen.
    1296                  *
    1297                  * The action is not fired for empty sidebars.
    1298                  *
    1299                  * @since 3.0.0
    1300                  *
    1301                  * @param array $widget_id {
    1302                  *     An associative array of widget arguments.
    1303                  *
    1304                  *     @type string $name                Name of the widget.
    1305                  *     @type string $id                  Widget ID.
    1306                  *     @type array|callback $callback    When the hook is fired on the front-end, $callback is an array
    1307                  *                                       containing the widget object. Fired on the back-end, $callback
    1308                  *                                       is 'wp_widget_control', see $_callback.
    1309                  *     @type array          $params      An associative array of multi-widget arguments.
    1310                  *     @type string         $classname   CSS class applied to the widget container.
    1311                  *     @type string         $description The widget description.
    1312                  *     @type array          $_callback   When the hook is fired on the back-end, $_callback is populated
    1313                  *                                       with an array containing the widget object, see $callback.
    1314                  * }
    1315                  */
    1316                 do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
    1317 
    1318                 if ( is_callable($callback) ) {
    1319                         call_user_func_array($callback, $params);
    1320                         $did_one = true;
    1321                 }
    1322         }
    1323 
    1324         /**
    1325          * Fires after widgets are rendered in a dynamic sidebar.
    1326          *
    1327          * Note: The action also fires for empty sidebars, and on both the front-end
    1328          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
    1329          *
    1330          * @since 3.9.0
    1331          *
    1332          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
    1333          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
    1334          *                                Default true.
    1335          */
    1336         do_action( 'dynamic_sidebar_after', $index, true );
    1337 
    1338         /**
    1339          * Filter whether a sidebar has widgets.
    1340          *
    1341          * Note: The filter is also evaluated for empty sidebars, and on both the front-end
    1342          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
    1343          *
    1344          * @since 3.9.0
    1345          *
    1346          * @param bool       $did_one Whether at least one widget was rendered in the sidebar.
    1347          *                            Default false.
    1348          * @param int|string $index   Index, name, or ID of the dynamic sidebar.
    1349          */
    1350         return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
    1351 }
    1352 
    1353 /**
    1354  * Whether widget is displayed on the front-end.
    1355  *
    1356  * Either $callback or $id_base can be used
    1357  * $id_base is the first argument when extending WP_Widget class
    1358  * Without the optional $widget_id parameter, returns the ID of the first sidebar
    1359  * in which the first instance of the widget with the given callback or $id_base is found.
    1360  * With the $widget_id parameter, returns the ID of the sidebar where
    1361  * the widget with that callback/$id_base AND that ID is found.
    1362  *
    1363  * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
    1364  * this function has to run after widgets have initialized, at action 'init' or later.
    1365  *
    1366  * @since 2.2.0
    1367  *
    1368  * @global array $wp_registered_widgets
    1369  *
    1370  * @param string $callback      Optional, Widget callback to check.
    1371  * @param int    $widget_id     Optional, but needed for checking. Widget ID.
    1372  * @param string $id_base       Optional, the base ID of a widget created by extending WP_Widget.
    1373  * @param bool   $skip_inactive Optional, whether to check in 'wp_inactive_widgets'.
    1374  * @return string|false False if widget is not active or id of sidebar in which the widget is active.
    1375  */
    1376 function is_active_widget($callback = false, $widget_id = false, $id_base = false, $skip_inactive = true) {
    1377         global $wp_registered_widgets;
    1378 
    1379         $sidebars_widgets = wp_get_sidebars_widgets();
    1380 
    1381         if ( is_array($sidebars_widgets) ) {
    1382                 foreach ( $sidebars_widgets as $sidebar => $widgets ) {
    1383                         if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) ) {
    1384                                 continue;
    1385                         }
    1386 
    1387                         if ( is_array($widgets) ) {
    1388                                 foreach ( $widgets as $widget ) {
    1389                                         if ( ( $callback && isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback ) || ( $id_base && _get_widget_id_base($widget) == $id_base ) ) {
    1390                                                 if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
    1391                                                         return $sidebar;
    1392                                         }
    1393                                 }
    1394                         }
    1395                 }
    1396         }
    1397         return false;
    1398 }
    1399 
    1400 /**
    1401  * Whether the dynamic sidebar is enabled and used by theme.
    1402  *
    1403  * @since 2.2.0
    1404  *
    1405  * @global array $wp_registered_widgets
    1406  * @global array $wp_registered_sidebars
    1407  *
    1408  * @return bool True, if using widgets. False, if not using widgets.
    1409  */
    1410 function is_dynamic_sidebar() {
    1411         global $wp_registered_widgets, $wp_registered_sidebars;
    1412         $sidebars_widgets = get_option('sidebars_widgets');
    1413         foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
    1414                 if ( count($sidebars_widgets[$index]) ) {
    1415                         foreach ( (array) $sidebars_widgets[$index] as $widget )
    1416                                 if ( array_key_exists($widget, $wp_registered_widgets) )
    1417                                         return true;
    1418                 }
    1419         }
    1420         return false;
    1421 }
    1422 
    1423 /**
    1424  * Whether a sidebar is in use.
    1425  *
    1426  * @since 2.8.0
    1427  *
    1428  * @param string|int $index Sidebar name, id or number to check.
    1429  * @return bool true if the sidebar is in use, false otherwise.
    1430  */
    1431 function is_active_sidebar( $index ) {
    1432         $index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
    1433         $sidebars_widgets = wp_get_sidebars_widgets();
    1434         $is_active_sidebar = ! empty( $sidebars_widgets[$index] );
    1435 
    1436         /**
    1437          * Filter whether a dynamic sidebar is considered "active".
    1438          *
    1439          * @since 3.9.0
    1440          *
    1441          * @param bool       $is_active_sidebar Whether or not the sidebar should be considered "active".
    1442          *                                      In other words, whether the sidebar contains any widgets.
    1443          * @param int|string $index             Index, name, or ID of the dynamic sidebar.
    1444          */
    1445         return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
    1446 }
    1447 
    1448 /* Internal Functions */
    1449 
    1450 /**
    1451  * Retrieve full list of sidebars and their widget instance IDs.
    1452  *
    1453  * Will upgrade sidebar widget list, if needed. Will also save updated list, if
    1454  * needed.
    1455  *
    1456  * @since 2.2.0
    1457  * @access private
    1458  *
    1459  * @global array $_wp_sidebars_widgets
    1460  * @global array $sidebars_widgets
    1461  *
    1462  * @param bool $deprecated Not used (argument deprecated).
    1463  * @return array Upgraded list of widgets to version 3 array format when called from the admin.
    1464  */
    1465 function wp_get_sidebars_widgets( $deprecated = true ) {
    1466         if ( $deprecated !== true )
    1467                 _deprecated_argument( __FUNCTION__, '2.8.1' );
    1468 
    1469         global $_wp_sidebars_widgets, $sidebars_widgets;
    1470 
    1471         // If loading from front page, consult $_wp_sidebars_widgets rather than options
    1472         // to see if wp_convert_widget_settings() has made manipulations in memory.
    1473         if ( !is_admin() ) {
    1474                 if ( empty($_wp_sidebars_widgets) )
    1475                         $_wp_sidebars_widgets = get_option('sidebars_widgets', array());
    1476 
    1477                 $sidebars_widgets = $_wp_sidebars_widgets;
    1478         } else {
    1479                 $sidebars_widgets = get_option('sidebars_widgets', array());
    1480         }
    1481 
    1482         if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
    1483                 unset($sidebars_widgets['array_version']);
    1484 
    1485         /**
    1486          * Filter the list of sidebars and their widgets.
    1487          *
    1488          * @since 2.7.0
    1489          *
    1490          * @param array $sidebars_widgets An associative array of sidebars and their widgets.
    1491          */
    1492         return apply_filters( 'sidebars_widgets', $sidebars_widgets );
    1493 }
    1494 
    1495 /**
    1496  * Set the sidebar widget option to update sidebars.
    1497  *
    1498  * @since 2.2.0
    1499  * @access private
    1500  *
    1501  * @param array $sidebars_widgets Sidebar widgets and their settings.
    1502  */
    1503 function wp_set_sidebars_widgets( $sidebars_widgets ) {
    1504         if ( !isset( $sidebars_widgets['array_version'] ) )
    1505                 $sidebars_widgets['array_version'] = 3;
    1506         update_option( 'sidebars_widgets', $sidebars_widgets );
    1507 }
    1508 
    1509 /**
    1510  * Retrieve default registered sidebars list.
    1511  *
    1512  * @since 2.2.0
    1513  * @access private
    1514  *
    1515  * @global array $wp_registered_sidebars
    1516  *
    1517  * @return array
    1518  */
    1519 function wp_get_widget_defaults() {
    1520         global $wp_registered_sidebars;
    1521 
    1522         $defaults = array();
    1523 
    1524         foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
    1525                 $defaults[$index] = array();
    1526 
    1527         return $defaults;
    1528 }
    1529 
    1530 /**
    1531  * Convert the widget settings from single to multi-widget format.
    1532  *
    1533  * @since 2.8.0
    1534  *
    1535  * @global array $_wp_sidebars_widgets
    1536  *
    1537  * @param string $base_name
    1538  * @param string $option_name
    1539  * @param array  $settings
    1540  * @return array
    1541  */
    1542 function wp_convert_widget_settings($base_name, $option_name, $settings) {
    1543         // This test may need expanding.
    1544         $single = $changed = false;
    1545         if ( empty($settings) ) {
    1546                 $single = true;
    1547         } else {
    1548                 foreach ( array_keys($settings) as $number ) {
    1549                         if ( 'number' == $number )
    1550                                 continue;
    1551                         if ( !is_numeric($number) ) {
    1552                                 $single = true;
    1553                                 break;
    1554                         }
    1555                 }
    1556         }
    1557 
    1558         if ( $single ) {
    1559                 $settings = array( 2 => $settings );
    1560 
    1561                 // If loading from the front page, update sidebar in memory but don't save to options
    1562                 if ( is_admin() ) {
    1563                         $sidebars_widgets = get_option('sidebars_widgets');
    1564                 } else {
    1565                         if ( empty($GLOBALS['_wp_sidebars_widgets']) )
    1566                                 $GLOBALS['_wp_sidebars_widgets'] = get_option('sidebars_widgets', array());
    1567                         $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
    1568                 }
    1569 
    1570                 foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
    1571                         if ( is_array($sidebar) ) {
    1572                                 foreach ( $sidebar as $i => $name ) {
    1573                                         if ( $base_name == $name ) {
    1574                                                 $sidebars_widgets[$index][$i] = "$name-2";
    1575                                                 $changed = true;
    1576                                                 break 2;
    1577                                         }
    1578                                 }
    1579                         }
    1580                 }
    1581 
    1582                 if ( is_admin() && $changed )
    1583                         update_option('sidebars_widgets', $sidebars_widgets);
    1584         }
    1585 
    1586         $settings['_multiwidget'] = 1;
    1587         if ( is_admin() )
    1588                 update_option( $option_name, $settings );
    1589 
    1590         return $settings;
    1591 }
    1592 
    1593 /**
    1594  * Output an arbitrary widget as a template tag.
    1595  *
    1596  * @since 2.8.0
    1597  *
    1598  * @global WP_Widget_Factory $wp_widget_factory
    1599  *
    1600  * @param string $widget   The widget's PHP class name (see default-widgets.php).
    1601  * @param array  $instance Optional. The widget's instance settings. Default empty array.
    1602  * @param array  $args {
    1603  *     Optional. Array of arguments to configure the display of the widget.
    1604  *
    1605  *     @type string $before_widget HTML content that will be prepended to the widget's HTML output.
    1606  *                                 Default `<div class="widget %s">`, where `%s` is the widget's class name.
    1607  *     @type string $after_widget  HTML content that will be appended to the widget's HTML output.
    1608  *                                 Default `</div>`.
    1609  *     @type string $before_title  HTML content that will be prepended to the widget's title when displayed.
    1610  *                                 Default `<h2 class="widgettitle">`.
    1611  *     @type string $after_title   HTML content that will be appended to the widget's title when displayed.
    1612  *                                 Default `</h2>`.
    1613  * }
    1614  */
    1615 function the_widget( $widget, $instance = array(), $args = array() ) {
    1616         global $wp_widget_factory;
    1617 
    1618         $widget_obj = $wp_widget_factory->widgets[$widget];
    1619         if ( ! ( $widget_obj instanceof WP_Widget ) ) {
    1620                 return;
    1621         }
    1622 
    1623         $before_widget = sprintf('<div class="widget %s">', $widget_obj->widget_options['classname'] );
    1624         $default_args = array( 'before_widget' => $before_widget, 'after_widget' => "</div>", 'before_title' => '<h2 class="widgettitle">', 'after_title' => '</h2>' );
    1625 
    1626         $args = wp_parse_args($args, $default_args);
    1627         $instance = wp_parse_args($instance);
    1628 
    1629         /**
    1630          * Fires before rendering the requested widget.
    1631          *
    1632          * @since 3.0.0
    1633          *
    1634          * @param string $widget   The widget's class name.
    1635          * @param array  $instance The current widget instance's settings.
    1636          * @param array  $args     An array of the widget's sidebar arguments.
    1637          */
    1638         do_action( 'the_widget', $widget, $instance, $args );
    1639 
    1640         $widget_obj->_set(-1);
    1641         $widget_obj->widget($args, $instance);
    1642 }
    1643 
    1644 /**
    1645  * Private
    1646  *
    1647  * @return string
    1648  */
    1649 function _get_widget_id_base($id) {
    1650         return preg_replace( '/-[0-9]+$/', '', $id );
    1651 }
    1652 
    1653 /**
    1654  * Handle sidebars config after theme change
    1655  *
    1656  * @access private
    1657  * @since 3.3.0
    1658  *
    1659  * @global array $sidebars_widgets
    1660  */
    1661 function _wp_sidebars_changed() {
    1662         global $sidebars_widgets;
    1663 
    1664         if ( ! is_array( $sidebars_widgets ) )
    1665                 $sidebars_widgets = wp_get_sidebars_widgets();
    1666 
    1667         retrieve_widgets(true);
    1668 }
    1669 
    1670 /**
    1671  * Look for "lost" widgets, this has to run at least on each theme change.
    1672  *
    1673  * @since 2.8.0
    1674  *
    1675  * @global array $wp_registered_sidebars
    1676  * @global array $sidebars_widgets
    1677  * @global array $wp_registered_widgets
    1678  *
    1679  * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
    1680  *                                   of 'customize' defers updates for the Customizer.
    1681  * @return array|void
    1682  */
    1683 function retrieve_widgets( $theme_changed = false ) {
    1684         global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
    1685 
    1686         $registered_sidebar_keys = array_keys( $wp_registered_sidebars );
    1687         $orphaned = 0;
    1688 
    1689         $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
    1690         if ( is_array( $old_sidebars_widgets ) ) {
    1691                 // time() that sidebars were stored is in $old_sidebars_widgets['time']
    1692                 $_sidebars_widgets = $old_sidebars_widgets['data'];
    1693 
    1694                 if ( 'customize' !== $theme_changed ) {
    1695                         remove_theme_mod( 'sidebars_widgets' );
    1696                 }
    1697 
    1698                 foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
    1699                         if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
    1700                                 continue;
    1701                         }
    1702 
    1703                         if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {
    1704                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;
    1705                                 unset( $_sidebars_widgets[$sidebar] );
    1706                         }
    1707                 }
    1708         } else {
    1709                 if ( empty( $sidebars_widgets ) )
    1710                         return;
    1711 
    1712                 unset( $sidebars_widgets['array_version'] );
    1713 
    1714                 $old = array_keys($sidebars_widgets);
    1715                 sort($old);
    1716                 sort($registered_sidebar_keys);
    1717 
    1718                 if ( $old == $registered_sidebar_keys )
    1719                         return;
    1720 
    1721                 $_sidebars_widgets = array(
    1722                         'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()
    1723                 );
    1724 
    1725                 unset( $sidebars_widgets['wp_inactive_widgets'] );
    1726 
    1727                 foreach ( $wp_registered_sidebars as $id => $settings ) {
    1728                         if ( $theme_changed ) {
    1729                                 $_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
    1730                         } else {
    1731                                 // no theme change, grab only sidebars that are currently registered
    1732                                 if ( isset( $sidebars_widgets[$id] ) ) {
    1733                                         $_sidebars_widgets[$id] = $sidebars_widgets[$id];
    1734                                         unset( $sidebars_widgets[$id] );
    1735                                 }
    1736                         }
    1737                 }
    1738 
    1739                 foreach ( $sidebars_widgets as $val ) {
    1740                         if ( is_array($val) && ! empty( $val ) )
    1741                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
    1742                 }
    1743         }
    1744 
    1745         // discard invalid, theme-specific widgets from sidebars
    1746         $shown_widgets = array();
    1747 
    1748         foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
    1749                 if ( !is_array($widgets) )
    1750                         continue;
    1751 
    1752                 $_widgets = array();
    1753                 foreach ( $widgets as $widget ) {
    1754                         if ( isset($wp_registered_widgets[$widget]) )
    1755                                 $_widgets[] = $widget;
    1756                 }
    1757 
    1758                 $_sidebars_widgets[$sidebar] = $_widgets;
    1759                 $shown_widgets = array_merge($shown_widgets, $_widgets);
    1760         }
    1761 
    1762         $sidebars_widgets = $_sidebars_widgets;
    1763         unset($_sidebars_widgets, $_widgets);
    1764 
    1765         // find hidden/lost multi-widget instances
    1766         $lost_widgets = array();
    1767         foreach ( $wp_registered_widgets as $key => $val ) {
    1768                 if ( in_array($key, $shown_widgets, true) )
    1769                         continue;
    1770 
    1771                 $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
    1772 
    1773                 if ( 2 > (int) $number )
    1774                         continue;
    1775 
    1776                 $lost_widgets[] = $key;
    1777         }
    1778 
    1779         $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
    1780         if ( 'customize' !== $theme_changed ) {
    1781                 wp_set_sidebars_widgets( $sidebars_widgets );
    1782         }
    1783 
    1784         return $sidebars_widgets;
    1785 }
  • trunk/src/wp-includes/widget-functions.php

    r33745 r33746  
    11<?php
    22/**
    3  * API for creating dynamic sidebar without hardcoding functionality into
    4  * themes. Includes both internal WordPress routines and theme use routines.
    5  *
    6  * This functionality was found in a plugin before WordPress 2.2 release which
    7  * included it in the core from that point on.
    8  *
    9  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
    10  * @link https://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
    11  *
    123 * @package WordPress
    134 * @subpackage Widgets
    145 */
    15 
    16 /**
    17  * This class must be extended for each widget and WP_Widget::widget(), WP_Widget::update()
    18  * and WP_Widget::form() need to be over-ridden.
    19  *
    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                 _deprecated_constructor( 'WP_Widget', '4.3.0' );
    177                 WP_Widget::__construct( $id_base, $name, $widget_options, $control_options );
    178         }
    179 
    180         /**
    181          * Constructs name attributes for use in form() fields
    182          *
    183          * This function should be used in form() methods to create name attributes for fields to be saved by update()
    184          *
    185          * @param string $field_name Field name
    186          * @return string Name attribute for $field_name
    187          */
    188         public function get_field_name($field_name) {
    189                 return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']';
    190         }
    191 
    192         /**
    193          * Constructs id attributes for use in {@see WP_Widget::form()} fields.
    194          *
    195          * This function should be used in form() methods to create id attributes
    196          * for fields to be saved by {@see WP_Widget::update()}.
    197          *
    198          * @since 2.8.0
    199          * @access public
    200          *
    201          * @param string $field_name Field name.
    202          * @return string ID attribute for `$field_name`.
    203          */
    204         public function get_field_id( $field_name ) {
    205                 return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field_name;
    206         }
    207 
    208         /**
    209          * Register all widget instances of this widget class.
    210          *
    211          * @since 2.8.0
    212          * @access private
    213          */
    214         public function _register() {
    215                 $settings = $this->get_settings();
    216                 $empty = true;
    217 
    218                 // When $settings is an array-like object, get an intrinsic array for use with array_keys().
    219                 if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) {
    220                         $settings = $settings->getArrayCopy();
    221                 }
    222 
    223                 if ( is_array( $settings ) ) {
    224                         foreach ( array_keys( $settings ) as $number ) {
    225                                 if ( is_numeric( $number ) ) {
    226                                         $this->_set( $number );
    227                                         $this->_register_one( $number );
    228                                         $empty = false;
    229                                 }
    230                         }
    231                 }
    232 
    233                 if ( $empty ) {
    234                         // If there are none, we register the widget's existence with a generic template.
    235                         $this->_set( 1 );
    236                         $this->_register_one();
    237                 }
    238         }
    239 
    240         /**
    241          * Set the internal order number for the widget instance.
    242          *
    243          * @since 2.8.0
    244          * @access private
    245          *
    246          * @param int $number The unique order number of this widget instance compared to other
    247          *                    instances of the same class.
    248          */
    249         public function _set($number) {
    250                 $this->number = $number;
    251                 $this->id = $this->id_base . '-' . $number;
    252         }
    253 
    254         /**
    255          * @return callback
    256          */
    257         public function _get_display_callback() {
    258                 return array($this, 'display_callback');
    259         }
    260         /**
    261          * @return callback
    262          */
    263         public function _get_update_callback() {
    264                 return array($this, 'update_callback');
    265         }
    266         /**
    267          * @return callback
    268          */
    269         public function _get_form_callback() {
    270                 return array($this, 'form_callback');
    271         }
    272 
    273         /**
    274          * Determine whether the current request is inside the Customizer preview.
    275          *
    276          * If true -- the current request is inside the Customizer preview, then
    277          * the object cache gets suspended and widgets should check this to decide
    278          * whether they should store anything persistently to the object cache,
    279          * to transients, or anywhere else.
    280          *
    281          * @since 3.9.0
    282          * @access public
    283          *
    284          * @global WP_Customize_Manager $wp_customize
    285          *
    286          * @return bool True if within the Customizer preview, false if not.
    287          */
    288         public function is_preview() {
    289                 global $wp_customize;
    290                 return ( isset( $wp_customize ) && $wp_customize->is_preview() ) ;
    291         }
    292 
    293         /**
    294          * Generate the actual widget content (Do NOT override).
    295          *
    296          * Finds the instance and calls {@see WP_Widget::widget()}.
    297          *
    298          * @since 2.8.0
    299          * @access public
    300          *
    301          * @param array     $args        Display arguments. See {@see WP_Widget::widget()} for information
    302          *                               on accepted arguments.
    303          * @param int|array $widget_args {
    304          *     Optional. Internal order number of the widget instance, or array of multi-widget arguments.
    305          *     Default 1.
    306          *
    307          *     @type int $number Number increment used for multiples of the same widget.
    308          * }
    309          */
    310         public function display_callback( $args, $widget_args = 1 ) {
    311                 if ( is_numeric( $widget_args ) ) {
    312                         $widget_args = array( 'number' => $widget_args );
    313                 }
    314 
    315                 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
    316                 $this->_set( $widget_args['number'] );
    317                 $instances = $this->get_settings();
    318 
    319                 if ( array_key_exists( $this->number, $instances ) ) {
    320                         $instance = $instances[ $this->number ];
    321 
    322                         /**
    323                          * Filter the settings for a particular widget instance.
    324                          *
    325                          * Returning false will effectively short-circuit display of the widget.
    326                          *
    327                          * @since 2.8.0
    328                          *
    329                          * @param array     $instance The current widget instance's settings.
    330                          * @param WP_Widget $this     The current widget instance.
    331                          * @param array     $args     An array of default widget arguments.
    332                          */
    333                         $instance = apply_filters( 'widget_display_callback', $instance, $this, $args );
    334 
    335                         if ( false === $instance ) {
    336                                 return;
    337                         }
    338 
    339                         $was_cache_addition_suspended = wp_suspend_cache_addition();
    340                         if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
    341                                 wp_suspend_cache_addition( true );
    342                         }
    343 
    344                         $this->widget( $args, $instance );
    345 
    346                         if ( $this->is_preview() ) {
    347                                 wp_suspend_cache_addition( $was_cache_addition_suspended );
    348                         }
    349                 }
    350         }
    351 
    352         /**
    353          * Deal with changed settings (Do NOT override).
    354          *
    355          * @since 2.8.0
    356          * @access public
    357          *
    358          * @global array $wp_registered_widgets
    359          *
    360          * @param int $deprecated Not used.
    361          */
    362         public function update_callback( $deprecated = 1 ) {
    363                 global $wp_registered_widgets;
    364 
    365                 $all_instances = $this->get_settings();
    366 
    367                 // We need to update the data
    368                 if ( $this->updated )
    369                         return;
    370 
    371                 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
    372                         // Delete the settings for this instance of the widget
    373                         if ( isset($_POST['the-widget-id']) )
    374                                 $del_id = $_POST['the-widget-id'];
    375                         else
    376                                 return;
    377 
    378                         if ( isset($wp_registered_widgets[$del_id]['params'][0]['number']) ) {
    379                                 $number = $wp_registered_widgets[$del_id]['params'][0]['number'];
    380 
    381                                 if ( $this->id_base . '-' . $number == $del_id )
    382                                         unset($all_instances[$number]);
    383                         }
    384                 } else {
    385                         if ( isset($_POST['widget-' . $this->id_base]) && is_array($_POST['widget-' . $this->id_base]) ) {
    386                                 $settings = $_POST['widget-' . $this->id_base];
    387                         } elseif ( isset($_POST['id_base']) && $_POST['id_base'] == $this->id_base ) {
    388                                 $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number'];
    389                                 $settings = array( $num => array() );
    390                         } else {
    391                                 return;
    392                         }
    393 
    394                         foreach ( $settings as $number => $new_instance ) {
    395                                 $new_instance = stripslashes_deep($new_instance);
    396                                 $this->_set($number);
    397 
    398                                 $old_instance = isset($all_instances[$number]) ? $all_instances[$number] : array();
    399 
    400                                 $was_cache_addition_suspended = wp_suspend_cache_addition();
    401                                 if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
    402                                         wp_suspend_cache_addition( true );
    403                                 }
    404 
    405                                 $instance = $this->update( $new_instance, $old_instance );
    406 
    407                                 if ( $this->is_preview() ) {
    408                                         wp_suspend_cache_addition( $was_cache_addition_suspended );
    409                                 }
    410 
    411                                 /**
    412                                  * Filter a widget's settings before saving.
    413                                  *
    414                                  * Returning false will effectively short-circuit the widget's ability
    415                                  * to update settings.
    416                                  *
    417                                  * @since 2.8.0
    418                                  *
    419                                  * @param array     $instance     The current widget instance's settings.
    420                                  * @param array     $new_instance Array of new widget settings.
    421                                  * @param array     $old_instance Array of old widget settings.
    422                                  * @param WP_Widget $this         The current widget instance.
    423                                  */
    424                                 $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this );
    425                                 if ( false !== $instance ) {
    426                                         $all_instances[$number] = $instance;
    427                                 }
    428 
    429                                 break; // run only once
    430                         }
    431                 }
    432 
    433                 $this->save_settings($all_instances);
    434                 $this->updated = true;
    435         }
    436 
    437         /**
    438          * Generate the widget control form (Do NOT override).
    439          *
    440          * @since 2.8.0
    441          * @access public
    442          *
    443          * @param int|array $widget_args Widget instance number or array of widget arguments.
    444          * @return string|null
    445          */
    446         public function form_callback( $widget_args = 1 ) {
    447                 if ( is_numeric($widget_args) )
    448                         $widget_args = array( 'number' => $widget_args );
    449 
    450                 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
    451                 $all_instances = $this->get_settings();
    452 
    453                 if ( -1 == $widget_args['number'] ) {
    454                         // We echo out a form where 'number' can be set later
    455                         $this->_set('__i__');
    456                         $instance = array();
    457                 } else {
    458                         $this->_set($widget_args['number']);
    459                         $instance = $all_instances[ $widget_args['number'] ];
    460                 }
    461 
    462                 /**
    463                  * Filter the widget instance's settings before displaying the control form.
    464                  *
    465                  * Returning false effectively short-circuits display of the control form.
    466                  *
    467                  * @since 2.8.0
    468                  *
    469                  * @param array     $instance The current widget instance's settings.
    470                  * @param WP_Widget $this     The current widget instance.
    471                  */
    472                 $instance = apply_filters( 'widget_form_callback', $instance, $this );
    473 
    474                 $return = null;
    475                 if ( false !== $instance ) {
    476                         $return = $this->form($instance);
    477 
    478                         /**
    479                          * Fires at the end of the widget control form.
    480                          *
    481                          * Use this hook to add extra fields to the widget form. The hook
    482                          * is only fired if the value passed to the 'widget_form_callback'
    483                          * hook is not false.
    484                          *
    485                          * Note: If the widget has no form, the text echoed from the default
    486                          * form method can be hidden using CSS.
    487                          *
    488                          * @since 2.8.0
    489                          *
    490                          * @param WP_Widget $this     The widget instance, passed by reference.
    491                          * @param null      $return   Return null if new fields are added.
    492                          * @param array     $instance An array of the widget's settings.
    493                          */
    494                         do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) );
    495                 }
    496                 return $return;
    497         }
    498 
    499         /**
    500          * Register an instance of the widget class.
    501          *
    502          * @since 2.8.0
    503          * @access private
    504          *
    505          * @param integer $number Optional. The unique order number of this widget instance
    506          *                        compared to other instances of the same class. Default -1.
    507          */
    508         public function _register_one( $number = -1 ) {
    509                 wp_register_sidebar_widget(     $this->id, $this->name, $this->_get_display_callback(), $this->widget_options, array( 'number' => $number ) );
    510                 _register_widget_update_callback( $this->id_base, $this->_get_update_callback(), $this->control_options, array( 'number' => -1 ) );
    511                 _register_widget_form_callback( $this->id, $this->name, $this->_get_form_callback(), $this->control_options, array( 'number' => $number ) );
    512         }
    513 
    514         /**
    515          * Save the settings for all instances of the widget class.
    516          *
    517          * @since 2.8.0
    518          * @access public
    519          *
    520          * @param array $settings Multi-dimensional array of widget instance settings.
    521          */
    522         public function save_settings( $settings ) {
    523                 $settings['_multiwidget'] = 1;
    524                 update_option( $this->option_name, $settings );
    525         }
    526 
    527         /**
    528          * Get the settings for all instances of the widget class.
    529          *
    530          * @since 2.8.0
    531          * @access public
    532          *
    533          * @return array Multi-dimensional array of widget instance settings.
    534          */
    535         public function get_settings() {
    536 
    537                 $settings = get_option( $this->option_name );
    538 
    539                 if ( false === $settings && isset( $this->alt_option_name ) ) {
    540                         $settings = get_option( $this->alt_option_name );
    541                 }
    542 
    543                 if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) {
    544                         $settings = array();
    545                 }
    546 
    547                 if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) {
    548                         // Old format, convert if single widget.
    549                         $settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings );
    550                 }
    551 
    552                 unset( $settings['_multiwidget'], $settings['__i__'] );
    553                 return $settings;
    554         }
    555 }
    556 
    557 /**
    558  * Singleton that registers and instantiates WP_Widget classes.
    559  *
    560  * @package WordPress
    561  * @subpackage Widgets
    562  * @since 2.8.0
    563  */
    564 class WP_Widget_Factory {
    565         public $widgets = array();
    566 
    567         /**
    568          * PHP5 constructor.
    569          */
    570         public function __construct() {
    571                 add_action( 'widgets_init', array( $this, '_register_widgets' ), 100 );
    572         }
    573 
    574         /**
    575          * PHP4 constructor.
    576          */
    577         public function WP_Widget_Factory() {
    578                 _deprecated_constructor( 'WP_Widget_Factory', '4.2.0' );
    579                 self::__construct();
    580         }
    581 
    582         /**
    583          * Register a widget subclass.
    584          *
    585          * @since 2.8.0
    586          * @access public
    587          *
    588          * @param string $widget_class The name of a {@see WP_Widget} subclass.
    589          */
    590         public function register( $widget_class ) {
    591                 $this->widgets[$widget_class] = new $widget_class();
    592         }
    593 
    594         /**
    595          * Un-register a widget subclass.
    596          *
    597          * @since 2.8.0
    598          * @access public
    599          *
    600          * @param string $widget_class The name of a {@see WP_Widget} subclass.
    601          */
    602         public function unregister( $widget_class ) {
    603                 unset( $this->widgets[ $widget_class ] );
    604         }
    605 
    606         /**
    607          * Utility method for adding widgets to the registered widgets global.
    608          *
    609          * @since 2.8.0
    610          * @access public
    611          *
    612          * @global array $wp_registered_widgets
    613          */
    614         public function _register_widgets() {
    615                 global $wp_registered_widgets;
    616                 $keys = array_keys($this->widgets);
    617                 $registered = array_keys($wp_registered_widgets);
    618                 $registered = array_map('_get_widget_id_base', $registered);
    619 
    620                 foreach ( $keys as $key ) {
    621                         // don't register new widget if old widget with the same id is already registered
    622                         if ( in_array($this->widgets[$key]->id_base, $registered, true) ) {
    623                                 unset($this->widgets[$key]);
    624                                 continue;
    625                         }
    626 
    627                         $this->widgets[$key]->_register();
    628                 }
    629         }
    630 }
    631 
    632 /* Global Variables */
    633 
    634 /** @ignore */
    635 global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
    636 
    637 /**
    638  * Stores the sidebars, since many themes can have more than one.
    639  *
    640  * @global array $wp_registered_sidebars
    641  * @since 2.2.0
    642  */
    643 $wp_registered_sidebars = array();
    644 
    645 /**
    646  * Stores the registered widgets.
    647  *
    648  * @global array $wp_registered_widgets
    649  * @since 2.2.0
    650  */
    651 $wp_registered_widgets = array();
    652 
    653 /**
    654  * Stores the registered widget control (options).
    655  *
    656  * @global array $wp_registered_widget_controls
    657  * @since 2.2.0
    658  */
    659 $wp_registered_widget_controls = array();
    660 /**
    661  * @global array $wp_registered_widget_updates
    662  */
    663 $wp_registered_widget_updates = array();
    664 
    665 /**
    666  * Private
    667  *
    668  * @global array $_wp_sidebars_widgets
    669  */
    670 $_wp_sidebars_widgets = array();
    671 
    672 /**
    673  * Private
    674  *
    675  * @global array $_wp_deprecated_widgets_callbacks
    676  */
    677 $GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
    678         'wp_widget_pages',
    679         'wp_widget_pages_control',
    680         'wp_widget_calendar',
    681         'wp_widget_calendar_control',
    682         'wp_widget_archives',
    683         'wp_widget_archives_control',
    684         'wp_widget_links',
    685         'wp_widget_meta',
    686         'wp_widget_meta_control',
    687         'wp_widget_search',
    688         'wp_widget_recent_entries',
    689         'wp_widget_recent_entries_control',
    690         'wp_widget_tag_cloud',
    691         'wp_widget_tag_cloud_control',
    692         'wp_widget_categories',
    693         'wp_widget_categories_control',
    694         'wp_widget_text',
    695         'wp_widget_text_control',
    696         'wp_widget_rss',
    697         'wp_widget_rss_control',
    698         'wp_widget_recent_comments',
    699         'wp_widget_recent_comments_control'
    700 );
    7016
    7027/* Template tags & API functions */
  • trunk/src/wp-includes/widgets.php

    r33696 r33746  
    1313 * @subpackage Widgets
    1414 */
    15 
    16 /**
    17  * This class must be extended for each widget and WP_Widget::widget(), WP_Widget::update()
    18  * and WP_Widget::form() need to be over-ridden.
    19  *
    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                 _deprecated_constructor( 'WP_Widget', '4.3.0' );
    177                 WP_Widget::__construct( $id_base, $name, $widget_options, $control_options );
    178         }
    179 
    180         /**
    181          * Constructs name attributes for use in form() fields
    182          *
    183          * This function should be used in form() methods to create name attributes for fields to be saved by update()
    184          *
    185          * @param string $field_name Field name
    186          * @return string Name attribute for $field_name
    187          */
    188         public function get_field_name($field_name) {
    189                 return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']';
    190         }
    191 
    192         /**
    193          * Constructs id attributes for use in {@see WP_Widget::form()} fields.
    194          *
    195          * This function should be used in form() methods to create id attributes
    196          * for fields to be saved by {@see WP_Widget::update()}.
    197          *
    198          * @since 2.8.0
    199          * @access public
    200          *
    201          * @param string $field_name Field name.
    202          * @return string ID attribute for `$field_name`.
    203          */
    204         public function get_field_id( $field_name ) {
    205                 return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field_name;
    206         }
    207 
    208         /**
    209          * Register all widget instances of this widget class.
    210          *
    211          * @since 2.8.0
    212          * @access private
    213          */
    214         public function _register() {
    215                 $settings = $this->get_settings();
    216                 $empty = true;
    217 
    218                 // When $settings is an array-like object, get an intrinsic array for use with array_keys().
    219                 if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) {
    220                         $settings = $settings->getArrayCopy();
    221                 }
    222 
    223                 if ( is_array( $settings ) ) {
    224                         foreach ( array_keys( $settings ) as $number ) {
    225                                 if ( is_numeric( $number ) ) {
    226                                         $this->_set( $number );
    227                                         $this->_register_one( $number );
    228                                         $empty = false;
    229                                 }
    230                         }
    231                 }
    232 
    233                 if ( $empty ) {
    234                         // If there are none, we register the widget's existence with a generic template.
    235                         $this->_set( 1 );
    236                         $this->_register_one();
    237                 }
    238         }
    239 
    240         /**
    241          * Set the internal order number for the widget instance.
    242          *
    243          * @since 2.8.0
    244          * @access private
    245          *
    246          * @param int $number The unique order number of this widget instance compared to other
    247          *                    instances of the same class.
    248          */
    249         public function _set($number) {
    250                 $this->number = $number;
    251                 $this->id = $this->id_base . '-' . $number;
    252         }
    253 
    254         /**
    255          * @return callback
    256          */
    257         public function _get_display_callback() {
    258                 return array($this, 'display_callback');
    259         }
    260         /**
    261          * @return callback
    262          */
    263         public function _get_update_callback() {
    264                 return array($this, 'update_callback');
    265         }
    266         /**
    267          * @return callback
    268          */
    269         public function _get_form_callback() {
    270                 return array($this, 'form_callback');
    271         }
    272 
    273         /**
    274          * Determine whether the current request is inside the Customizer preview.
    275          *
    276          * If true -- the current request is inside the Customizer preview, then
    277          * the object cache gets suspended and widgets should check this to decide
    278          * whether they should store anything persistently to the object cache,
    279          * to transients, or anywhere else.
    280          *
    281          * @since 3.9.0
    282          * @access public
    283          *
    284          * @global WP_Customize_Manager $wp_customize
    285          *
    286          * @return bool True if within the Customizer preview, false if not.
    287          */
    288         public function is_preview() {
    289                 global $wp_customize;
    290                 return ( isset( $wp_customize ) && $wp_customize->is_preview() ) ;
    291         }
    292 
    293         /**
    294          * Generate the actual widget content (Do NOT override).
    295          *
    296          * Finds the instance and calls {@see WP_Widget::widget()}.
    297          *
    298          * @since 2.8.0
    299          * @access public
    300          *
    301          * @param array     $args        Display arguments. See {@see WP_Widget::widget()} for information
    302          *                               on accepted arguments.
    303          * @param int|array $widget_args {
    304          *     Optional. Internal order number of the widget instance, or array of multi-widget arguments.
    305          *     Default 1.
    306          *
    307          *     @type int $number Number increment used for multiples of the same widget.
    308          * }
    309          */
    310         public function display_callback( $args, $widget_args = 1 ) {
    311                 if ( is_numeric( $widget_args ) ) {
    312                         $widget_args = array( 'number' => $widget_args );
    313                 }
    314 
    315                 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
    316                 $this->_set( $widget_args['number'] );
    317                 $instances = $this->get_settings();
    318 
    319                 if ( array_key_exists( $this->number, $instances ) ) {
    320                         $instance = $instances[ $this->number ];
    321 
    322                         /**
    323                          * Filter the settings for a particular widget instance.
    324                          *
    325                          * Returning false will effectively short-circuit display of the widget.
    326                          *
    327                          * @since 2.8.0
    328                          *
    329                          * @param array     $instance The current widget instance's settings.
    330                          * @param WP_Widget $this     The current widget instance.
    331                          * @param array     $args     An array of default widget arguments.
    332                          */
    333                         $instance = apply_filters( 'widget_display_callback', $instance, $this, $args );
    334 
    335                         if ( false === $instance ) {
    336                                 return;
    337                         }
    338 
    339                         $was_cache_addition_suspended = wp_suspend_cache_addition();
    340                         if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
    341                                 wp_suspend_cache_addition( true );
    342                         }
    343 
    344                         $this->widget( $args, $instance );
    345 
    346                         if ( $this->is_preview() ) {
    347                                 wp_suspend_cache_addition( $was_cache_addition_suspended );
    348                         }
    349                 }
    350         }
    351 
    352         /**
    353          * Deal with changed settings (Do NOT override).
    354          *
    355          * @since 2.8.0
    356          * @access public
    357          *
    358          * @global array $wp_registered_widgets
    359          *
    360          * @param int $deprecated Not used.
    361          */
    362         public function update_callback( $deprecated = 1 ) {
    363                 global $wp_registered_widgets;
    364 
    365                 $all_instances = $this->get_settings();
    366 
    367                 // We need to update the data
    368                 if ( $this->updated )
    369                         return;
    370 
    371                 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
    372                         // Delete the settings for this instance of the widget
    373                         if ( isset($_POST['the-widget-id']) )
    374                                 $del_id = $_POST['the-widget-id'];
    375                         else
    376                                 return;
    377 
    378                         if ( isset($wp_registered_widgets[$del_id]['params'][0]['number']) ) {
    379                                 $number = $wp_registered_widgets[$del_id]['params'][0]['number'];
    380 
    381                                 if ( $this->id_base . '-' . $number == $del_id )
    382                                         unset($all_instances[$number]);
    383                         }
    384                 } else {
    385                         if ( isset($_POST['widget-' . $this->id_base]) && is_array($_POST['widget-' . $this->id_base]) ) {
    386                                 $settings = $_POST['widget-' . $this->id_base];
    387                         } elseif ( isset($_POST['id_base']) && $_POST['id_base'] == $this->id_base ) {
    388                                 $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number'];
    389                                 $settings = array( $num => array() );
    390                         } else {
    391                                 return;
    392                         }
    393 
    394                         foreach ( $settings as $number => $new_instance ) {
    395                                 $new_instance = stripslashes_deep($new_instance);
    396                                 $this->_set($number);
    397 
    398                                 $old_instance = isset($all_instances[$number]) ? $all_instances[$number] : array();
    399 
    400                                 $was_cache_addition_suspended = wp_suspend_cache_addition();
    401                                 if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
    402                                         wp_suspend_cache_addition( true );
    403                                 }
    404 
    405                                 $instance = $this->update( $new_instance, $old_instance );
    406 
    407                                 if ( $this->is_preview() ) {
    408                                         wp_suspend_cache_addition( $was_cache_addition_suspended );
    409                                 }
    410 
    411                                 /**
    412                                  * Filter a widget's settings before saving.
    413                                  *
    414                                  * Returning false will effectively short-circuit the widget's ability
    415                                  * to update settings.
    416                                  *
    417                                  * @since 2.8.0
    418                                  *
    419                                  * @param array     $instance     The current widget instance's settings.
    420                                  * @param array     $new_instance Array of new widget settings.
    421                                  * @param array     $old_instance Array of old widget settings.
    422                                  * @param WP_Widget $this         The current widget instance.
    423                                  */
    424                                 $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this );
    425                                 if ( false !== $instance ) {
    426                                         $all_instances[$number] = $instance;
    427                                 }
    428 
    429                                 break; // run only once
    430                         }
    431                 }
    432 
    433                 $this->save_settings($all_instances);
    434                 $this->updated = true;
    435         }
    436 
    437         /**
    438          * Generate the widget control form (Do NOT override).
    439          *
    440          * @since 2.8.0
    441          * @access public
    442          *
    443          * @param int|array $widget_args Widget instance number or array of widget arguments.
    444          * @return string|null
    445          */
    446         public function form_callback( $widget_args = 1 ) {
    447                 if ( is_numeric($widget_args) )
    448                         $widget_args = array( 'number' => $widget_args );
    449 
    450                 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
    451                 $all_instances = $this->get_settings();
    452 
    453                 if ( -1 == $widget_args['number'] ) {
    454                         // We echo out a form where 'number' can be set later
    455                         $this->_set('__i__');
    456                         $instance = array();
    457                 } else {
    458                         $this->_set($widget_args['number']);
    459                         $instance = $all_instances[ $widget_args['number'] ];
    460                 }
    461 
    462                 /**
    463                  * Filter the widget instance's settings before displaying the control form.
    464                  *
    465                  * Returning false effectively short-circuits display of the control form.
    466                  *
    467                  * @since 2.8.0
    468                  *
    469                  * @param array     $instance The current widget instance's settings.
    470                  * @param WP_Widget $this     The current widget instance.
    471                  */
    472                 $instance = apply_filters( 'widget_form_callback', $instance, $this );
    473 
    474                 $return = null;
    475                 if ( false !== $instance ) {
    476                         $return = $this->form($instance);
    477 
    478                         /**
    479                          * Fires at the end of the widget control form.
    480                          *
    481                          * Use this hook to add extra fields to the widget form. The hook
    482                          * is only fired if the value passed to the 'widget_form_callback'
    483                          * hook is not false.
    484                          *
    485                          * Note: If the widget has no form, the text echoed from the default
    486                          * form method can be hidden using CSS.
    487                          *
    488                          * @since 2.8.0
    489                          *
    490                          * @param WP_Widget $this     The widget instance, passed by reference.
    491                          * @param null      $return   Return null if new fields are added.
    492                          * @param array     $instance An array of the widget's settings.
    493                          */
    494                         do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) );
    495                 }
    496                 return $return;
    497         }
    498 
    499         /**
    500          * Register an instance of the widget class.
    501          *
    502          * @since 2.8.0
    503          * @access private
    504          *
    505          * @param integer $number Optional. The unique order number of this widget instance
    506          *                        compared to other instances of the same class. Default -1.
    507          */
    508         public function _register_one( $number = -1 ) {
    509                 wp_register_sidebar_widget(     $this->id, $this->name, $this->_get_display_callback(), $this->widget_options, array( 'number' => $number ) );
    510                 _register_widget_update_callback( $this->id_base, $this->_get_update_callback(), $this->control_options, array( 'number' => -1 ) );
    511                 _register_widget_form_callback( $this->id, $this->name, $this->_get_form_callback(), $this->control_options, array( 'number' => $number ) );
    512         }
    513 
    514         /**
    515          * Save the settings for all instances of the widget class.
    516          *
    517          * @since 2.8.0
    518          * @access public
    519          *
    520          * @param array $settings Multi-dimensional array of widget instance settings.
    521          */
    522         public function save_settings( $settings ) {
    523                 $settings['_multiwidget'] = 1;
    524                 update_option( $this->option_name, $settings );
    525         }
    526 
    527         /**
    528          * Get the settings for all instances of the widget class.
    529          *
    530          * @since 2.8.0
    531          * @access public
    532          *
    533          * @return array Multi-dimensional array of widget instance settings.
    534          */
    535         public function get_settings() {
    536 
    537                 $settings = get_option( $this->option_name );
    538 
    539                 if ( false === $settings && isset( $this->alt_option_name ) ) {
    540                         $settings = get_option( $this->alt_option_name );
    541                 }
    542 
    543                 if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) {
    544                         $settings = array();
    545                 }
    546 
    547                 if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) {
    548                         // Old format, convert if single widget.
    549                         $settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings );
    550                 }
    551 
    552                 unset( $settings['_multiwidget'], $settings['__i__'] );
    553                 return $settings;
    554         }
    555 }
    556 
    557 /**
    558  * Singleton that registers and instantiates WP_Widget classes.
    559  *
    560  * @package WordPress
    561  * @subpackage Widgets
    562  * @since 2.8.0
    563  */
    564 class WP_Widget_Factory {
    565         public $widgets = array();
    566 
    567         /**
    568          * PHP5 constructor.
    569          */
    570         public function __construct() {
    571                 add_action( 'widgets_init', array( $this, '_register_widgets' ), 100 );
    572         }
    573 
    574         /**
    575          * PHP4 constructor.
    576          */
    577         public function WP_Widget_Factory() {
    578                 _deprecated_constructor( 'WP_Widget_Factory', '4.2.0' );
    579                 self::__construct();
    580         }
    581 
    582         /**
    583          * Register a widget subclass.
    584          *
    585          * @since 2.8.0
    586          * @access public
    587          *
    588          * @param string $widget_class The name of a {@see WP_Widget} subclass.
    589          */
    590         public function register( $widget_class ) {
    591                 $this->widgets[$widget_class] = new $widget_class();
    592         }
    593 
    594         /**
    595          * Un-register a widget subclass.
    596          *
    597          * @since 2.8.0
    598          * @access public
    599          *
    600          * @param string $widget_class The name of a {@see WP_Widget} subclass.
    601          */
    602         public function unregister( $widget_class ) {
    603                 unset( $this->widgets[ $widget_class ] );
    604         }
    605 
    606         /**
    607          * Utility method for adding widgets to the registered widgets global.
    608          *
    609          * @since 2.8.0
    610          * @access public
    611          *
    612          * @global array $wp_registered_widgets
    613          */
    614         public function _register_widgets() {
    615                 global $wp_registered_widgets;
    616                 $keys = array_keys($this->widgets);
    617                 $registered = array_keys($wp_registered_widgets);
    618                 $registered = array_map('_get_widget_id_base', $registered);
    619 
    620                 foreach ( $keys as $key ) {
    621                         // don't register new widget if old widget with the same id is already registered
    622                         if ( in_array($this->widgets[$key]->id_base, $registered, true) ) {
    623                                 unset($this->widgets[$key]);
    624                                 continue;
    625                         }
    626 
    627                         $this->widgets[$key]->_register();
    628                 }
    629         }
    630 }
    63115
    63216/* Global Variables */
    … …  
    70084);
    70185
    702 /* Template tags & API functions */
    703 
    704 /**
    705  * Register a widget
    706  *
    707  * Registers a WP_Widget widget
    708  *
    709  * @since 2.8.0
    710  *
    711  * @see WP_Widget
    712  *
    713  * @global WP_Widget_Factory $wp_widget_factory
    714  *
    715  * @param string $widget_class The name of a class that extends WP_Widget
    716  */
    717 function register_widget($widget_class) {
    718         global $wp_widget_factory;
    719 
    720         $wp_widget_factory->register($widget_class);
    721 }
    722 
    723 /**
    724  * Unregister a widget
    725  *
    726  * Unregisters a WP_Widget widget. Useful for unregistering default widgets.
    727  * Run within a function hooked to the widgets_init action.
    728  *
    729  * @since 2.8.0
    730  *
    731  * @see WP_Widget
    732  *
    733  * @global WP_Widget_Factory $wp_widget_factory
    734  *
    735  * @param string $widget_class The name of a class that extends WP_Widget
    736  */
    737 function unregister_widget($widget_class) {
    738         global $wp_widget_factory;
    739 
    740         $wp_widget_factory->unregister($widget_class);
    741 }
    742 
    743 /**
    744  * Creates multiple sidebars.
    745  *
    746  * If you wanted to quickly create multiple sidebars for a theme or internally.
    747  * This function will allow you to do so. If you don't pass the 'name' and/or
    748  * 'id' in `$args`, then they will be built for you.
    749  *
    750  * @since 2.2.0
    751  *
    752  * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
    753  *
    754  * @global array $wp_registered_sidebars
    755  *
    756  * @param int          $number Optional. Number of sidebars to create. Default 1.
    757  * @param array|string $args {
    758  *     Optional. Array or string of arguments for building a sidebar.
    759  *
    760  *     @type string $id   The base string of the unique identifier for each sidebar. If provided, and multiple
    761  *                        sidebars are being defined, the id will have "-2" appended, and so on.
    762  *                        Default 'sidebar-' followed by the number the sidebar creation is currently at.
    763  *     @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering
    764  *                        more than one sidebar, include '%d' in the string as a placeholder for the uniquely
    765  *                        assigned number for each sidebar.
    766  *                        Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'.
    767  * }
    768  */
    769 function register_sidebars( $number = 1, $args = array() ) {
    770         global $wp_registered_sidebars;
    771         $number = (int) $number;
    772 
    773         if ( is_string($args) )
    774                 parse_str($args, $args);
    775 
    776         for ( $i = 1; $i <= $number; $i++ ) {
    777                 $_args = $args;
    778 
    779                 if ( $number > 1 )
    780                         $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i);
    781                 else
    782                         $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar');
    783 
    784                 // Custom specified ID's are suffixed if they exist already.
    785                 // Automatically generated sidebar names need to be suffixed regardless starting at -0
    786                 if ( isset($args['id']) ) {
    787                         $_args['id'] = $args['id'];
    788                         $n = 2; // Start at -2 for conflicting custom ID's
    789                         while ( isset($wp_registered_sidebars[$_args['id']]) )
    790                                 $_args['id'] = $args['id'] . '-' . $n++;
    791                 } else {
    792                         $n = count($wp_registered_sidebars);
    793                         do {
    794                                 $_args['id'] = 'sidebar-' . ++$n;
    795                         } while ( isset($wp_registered_sidebars[$_args['id']]) );
    796                 }
    797                 register_sidebar($_args);
    798         }
    799 }
    800 
    801 /**
    802  * Builds the definition for a single sidebar and returns the ID.
    803  *
    804  * Accepts either a string or an array and then parses that against a set
    805  * of default arguments for the new sidebar. WordPress will automatically
    806  * generate a sidebar ID and name based on the current number of registered
    807  * sidebars if those arguments are not included.
    808  *
    809  * When allowing for automatic generation of the name and ID parameters, keep
    810  * in mind that the incrementor for your sidebar can change over time depending
    811  * on what other plugins and themes are installed.
    812  *
    813  * If theme support for 'widgets' has not yet been added when this function is
    814  * called, it will be automatically enabled through the use of add_theme_support()
    815  *
    816  * @since 2.2.0
    817  *
    818  * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
    819  *
    820  * @param array|string $args {
    821  *     Optional. Array or string of arguments for the sidebar being registered.
    822  *
    823  *     @type string $name          The name or title of the sidebar displayed in the Widgets
    824  *                                 interface. Default 'Sidebar $instance'.
    825  *     @type string $id            The unique identifier by which the sidebar will be called.
    826  *                                 Default 'sidebar-$instance'.
    827  *     @type string $description   Description of the sidebar, displayed in the Widgets interface.
    828  *                                 Default empty string.
    829  *     @type string $class         Extra CSS class to assign to the sidebar in the Widgets interface.
    830  *                                 Default empty.
    831  *     @type string $before_widget HTML content to prepend to each widget's HTML output when
    832  *                                 assigned to this sidebar. Default is an opening list item element.
    833  *     @type string $after_widget  HTML content to append to each widget's HTML output when
    834  *                                 assigned to this sidebar. Default is a closing list item element.
    835  *     @type string $before_title  HTML content to prepend to the sidebar title when displayed.
    836  *                                 Default is an opening h2 element.
    837  *     @type string $after_title   HTML content to append to the sidebar title when displayed.
    838  *                                 Default is a closing h2 element.
    839  * }
    840  * @return string Sidebar ID added to $wp_registered_sidebars global.
    841  */
    842 function register_sidebar($args = array()) {
    843         global $wp_registered_sidebars;
    844 
    845         $i = count($wp_registered_sidebars) + 1;
    846 
    847         $id_is_empty = empty( $args['id'] );
    848 
    849         $defaults = array(
    850                 'name' => sprintf(__('Sidebar %d'), $i ),
    851                 'id' => "sidebar-$i",
    852                 'description' => '',
    853                 'class' => '',
    854                 'before_widget' => '<li id="%1$s" class="widget %2$s">',
    855                 'after_widget' => "</li>\n",
    856                 'before_title' => '<h2 class="widgettitle">',
    857                 'after_title' => "</h2>\n",
    858         );
    859 
    860         $sidebar = wp_parse_args( $args, $defaults );
    861 
    862         if ( $id_is_empty ) {
    863                 /* translators: 1: the id argument, 2: sidebar name, 3: recommended id value */
    864                 _doing_it_wrong( __FUNCTION__, sprintf( __( 'No %1$s was set in the arguments array for the "%2$s" sidebar. Defaulting to "%3$s". Manually set the %1$s to "%3$s" to silence this notice and keep existing sidebar content.' ), '<code>id</code>', $sidebar['name'], $sidebar['id'] ), '4.2.0' );
    865         }
    866 
    867         $wp_registered_sidebars[$sidebar['id']] = $sidebar;
    868 
    869         add_theme_support('widgets');
    870 
    871         /**
    872          * Fires once a sidebar has been registered.
    873          *
    874          * @since 3.0.0
    875          *
    876          * @param array $sidebar Parsed arguments for the registered sidebar.
    877          */
    878         do_action( 'register_sidebar', $sidebar );
    879 
    880         return $sidebar['id'];
    881 }
    882 
    883 /**
    884  * Removes a sidebar from the list.
    885  *
    886  * @since 2.2.0
    887  *
    888  * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
    889  *
    890  * @param string $name The ID of the sidebar when it was added.
    891  */
    892 function unregister_sidebar( $name ) {
    893         global $wp_registered_sidebars;
    894 
    895         unset( $wp_registered_sidebars[ $name ] );
    896 }
    897 
    898 /**
    899  * Register an instance of a widget.
    900  *
    901  * The default widget option is 'classname' that can be overridden.
    902  *
    903  * The function can also be used to un-register widgets when `$output_callback`
    904  * parameter is an empty string.
    905  *
    906  * @since 2.2.0
    907  *
    908  * @global array $wp_registered_widgets       Uses stored registered widgets.
    909  * @global array $wp_register_widget_defaults Retrieves widget defaults.
    910  * @global array $wp_registered_widget_updates
    911  * @global array $_wp_deprecated_widgets_callbacks
    912  *
    913  * @param int|string $id              Widget ID.
    914  * @param string     $name            Widget display title.
    915  * @param callback   $output_callback Run when widget is called.
    916  * @param array      $options {
    917  *     Optional. An array of supplementary widget options for the instance.
    918  *
    919  *     @type string $classname   Class name for the widget's HTML container. Default is a shortened
    920  *                               version of the output callback name.
    921  *     @type string $description Widget description for display in the widget administration
    922  *                               panel and/or theme.
    923  * }
    924  */
    925 function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array() ) {
    926         global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
    927 
    928         $id = strtolower($id);
    929 
    930         if ( empty($output_callback) ) {
    931                 unset($wp_registered_widgets[$id]);
    932                 return;
    933         }
    934 
    935         $id_base = _get_widget_id_base($id);
    936         if ( in_array($output_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($output_callback) ) {
    937                 unset( $wp_registered_widget_controls[ $id ] );
    938                 unset( $wp_registered_widget_updates[ $id_base ] );
    939                 return;
    940         }
    941 
    942         $defaults = array('classname' => $output_callback);
    943         $options = wp_parse_args($options, $defaults);
    944         $widget = array(
    945                 'name' => $name,
    946                 'id' => $id,
    947                 'callback' => $output_callback,
    948                 'params' => array_slice(func_get_args(), 4)
    949         );
    950         $widget = array_merge($widget, $options);
    951 
    952         if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) ) {
    953 
    954                 /**
    955                  * Fires once for each registered widget.
    956                  *
    957                  * @since 3.0.0
    958                  *
    959                  * @param array $widget An array of default widget arguments.
    960                  */
    961                 do_action( 'wp_register_sidebar_widget', $widget );
    962                 $wp_registered_widgets[$id] = $widget;
    963         }
    964 }
    965 
    966 /**
    967  * Retrieve description for widget.
    968  *
    969  * When registering widgets, the options can also include 'description' that
    970  * describes the widget for display on the widget administration panel or
    971  * in the theme.
    972  *
    973  * @since 2.5.0
    974  *
    975  * @global array $wp_registered_widgets
    976  *
    977  * @param int|string $id Widget ID.
    978  * @return string|void Widget description, if available.
    979  */
    980 function wp_widget_description( $id ) {
    981         if ( !is_scalar($id) )
    982                 return;
    983 
    984         global $wp_registered_widgets;
    985 
    986         if ( isset($wp_registered_widgets[$id]['description']) )
    987                 return esc_html( $wp_registered_widgets[$id]['description'] );
    988 }
    989 
    990 /**
    991  * Retrieve description for a sidebar.
    992  *
    993  * When registering sidebars a 'description' parameter can be included that
    994  * describes the sidebar for display on the widget administration panel.
    995  *
    996  * @since 2.9.0
    997  *
    998  * @global array $wp_registered_sidebars
    999  *
    1000  * @param string $id sidebar ID.
    1001  * @return string|void Sidebar description, if available.
    1002  */
    1003 function wp_sidebar_description( $id ) {
    1004         if ( !is_scalar($id) )
    1005                 return;
    1006 
    1007         global $wp_registered_sidebars;
    1008 
    1009         if ( isset($wp_registered_sidebars[$id]['description']) )
    1010                 return esc_html( $wp_registered_sidebars[$id]['description'] );
    1011 }
    1012 
    1013 /**
    1014  * Remove widget from sidebar.
    1015  *
    1016  * @since 2.2.0
    1017  *
    1018  * @param int|string $id Widget ID.
    1019  */
    1020 function wp_unregister_sidebar_widget($id) {
    1021 
    1022         /**
    1023          * Fires just before a widget is removed from a sidebar.
    1024          *
    1025          * @since 3.0.0
    1026          *
    1027          * @param int $id The widget ID.
    1028          */
    1029         do_action( 'wp_unregister_sidebar_widget', $id );
    1030 
    1031         wp_register_sidebar_widget($id, '', '');
    1032         wp_unregister_widget_control($id);
    1033 }
    1034 
    1035 /**
    1036  * Registers widget control callback for customizing options.
    1037  *
    1038  * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
    1039  * option is never used. The 'width' option is the width of the fully expanded
    1040  * control form, but try hard to use the default width. The 'id_base' is for
    1041  * multi-widgets (widgets which allow multiple instances such as the text
    1042  * widget), an id_base must be provided. The widget id will end up looking like
    1043  * `{$id_base}-{$unique_number}`.
    1044  *
    1045  * @since 2.2.0
    1046  *
    1047  * @todo Document `$options` as a hash notation, re: WP_Widget::__construct() cross-reference.
    1048  * @todo `$params` parameter?
    1049  *
    1050  * @global array $wp_registered_widget_controls
    1051  * @global array $wp_registered_widget_updates
    1052  * @global array $wp_registered_widgets
    1053  * @global array $_wp_deprecated_widgets_callbacks
    1054  *
    1055  * @param int|string   $id               Sidebar ID.
    1056  * @param string       $name             Sidebar display name.
    1057  * @param callback     $control_callback Run when sidebar is displayed.
    1058  * @param array|string $options          Optional. Widget options. See description above. Default empty array.
    1059  */
    1060 function wp_register_widget_control( $id, $name, $control_callback, $options = array() ) {
    1061         global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
    1062 
    1063         $id = strtolower($id);
    1064         $id_base = _get_widget_id_base($id);
    1065 
    1066         if ( empty($control_callback) ) {
    1067                 unset($wp_registered_widget_controls[$id]);
    1068                 unset($wp_registered_widget_updates[$id_base]);
    1069                 return;
    1070         }
    1071 
    1072         if ( in_array($control_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($control_callback) ) {
    1073                 unset( $wp_registered_widgets[ $id ] );
    1074                 return;
    1075         }
    1076 
    1077         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
    1078                 return;
    1079 
    1080         $defaults = array('width' => 250, 'height' => 200 ); // height is never used
    1081         $options = wp_parse_args($options, $defaults);
    1082         $options['width'] = (int) $options['width'];
    1083         $options['height'] = (int) $options['height'];
    1084 
    1085         $widget = array(
    1086                 'name' => $name,
    1087                 'id' => $id,
    1088                 'callback' => $control_callback,
    1089                 'params' => array_slice(func_get_args(), 4)
    1090         );
    1091         $widget = array_merge($widget, $options);
    1092 
    1093         $wp_registered_widget_controls[$id] = $widget;
    1094 
    1095         if ( isset($wp_registered_widget_updates[$id_base]) )
    1096                 return;
    1097 
    1098         if ( isset($widget['params'][0]['number']) )
    1099                 $widget['params'][0]['number'] = -1;
    1100 
    1101         unset($widget['width'], $widget['height'], $widget['name'], $widget['id']);
    1102         $wp_registered_widget_updates[$id_base] = $widget;
    1103 }
    1104 
    1105 /**
    1106  * @global array $wp_registered_widget_updates
    1107  *
    1108  * @param string   $id_base
    1109  * @param callable $update_callback
    1110  * @param array    $options
    1111  */
    1112 function _register_widget_update_callback($id_base, $update_callback, $options = array()) {
    1113         global $wp_registered_widget_updates;
    1114 
    1115         if ( isset($wp_registered_widget_updates[$id_base]) ) {
    1116                 if ( empty($update_callback) )
    1117                         unset($wp_registered_widget_updates[$id_base]);
    1118                 return;
    1119         }
    1120 
    1121         $widget = array(
    1122                 'callback' => $update_callback,
    1123                 'params' => array_slice(func_get_args(), 3)
    1124         );
    1125 
    1126         $widget = array_merge($widget, $options);
    1127         $wp_registered_widget_updates[$id_base] = $widget;
    1128 }
    1129 
    1130 /**
    1131  *
    1132  * @global array $wp_registered_widget_controls
    1133  *
    1134  * @param int|string $id
    1135  * @param string     $name
    1136  * @param callable   $form_callback
    1137  * @param array      $options
    1138  */
    1139 function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
    1140         global $wp_registered_widget_controls;
    1141 
    1142         $id = strtolower($id);
    1143 
    1144         if ( empty($form_callback) ) {
    1145                 unset($wp_registered_widget_controls[$id]);
    1146                 return;
    1147         }
    1148 
    1149         if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
    1150                 return;
    1151 
    1152         $defaults = array('width' => 250, 'height' => 200 );
    1153         $options = wp_parse_args($options, $defaults);
    1154         $options['width'] = (int) $options['width'];
    1155         $options['height'] = (int) $options['height'];
    1156 
    1157         $widget = array(
    1158                 'name' => $name,
    1159                 'id' => $id,
    1160                 'callback' => $form_callback,
    1161                 'params' => array_slice(func_get_args(), 4)
    1162         );
    1163         $widget = array_merge($widget, $options);
    1164 
    1165         $wp_registered_widget_controls[$id] = $widget;
    1166 }
    1167 
    1168 /**
    1169  * Remove control callback for widget.
    1170  *
    1171  * @since 2.2.0
    1172  *
    1173  * @param int|string $id Widget ID.
    1174  */
    1175 function wp_unregister_widget_control($id) {
    1176         wp_register_widget_control( $id, '', '' );
    1177 }
    1178 
    1179 /**
    1180  * Display dynamic sidebar.
    1181  *
    1182  * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
    1183  * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
    1184  * Otherwise, you can pass in a numerical index to display the sidebar at that index.
    1185  *
    1186  * @since 2.2.0
    1187  *
    1188  * @global array $wp_registered_sidebars
    1189  * @global array $wp_registered_widgets
    1190  *
    1191  * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
    1192  * @return bool True, if widget sidebar was found and called. False if not found or not called.
    1193  */
    1194 function dynamic_sidebar($index = 1) {
    1195         global $wp_registered_sidebars, $wp_registered_widgets;
    1196 
    1197         if ( is_int($index) ) {
    1198                 $index = "sidebar-$index";
    1199         } else {
    1200                 $index = sanitize_title($index);
    1201                 foreach ( (array) $wp_registered_sidebars as $key => $value ) {
    1202                         if ( sanitize_title($value['name']) == $index ) {
    1203                                 $index = $key;
    1204                                 break;
    1205                         }
    1206                 }
    1207         }
    1208 
    1209         $sidebars_widgets = wp_get_sidebars_widgets();
    1210         if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
    1211                 /** This action is documented in wp-includes/widgets.php */
    1212                 do_action( 'dynamic_sidebar_before', $index, false );
    1213                 /** This action is documented in wp-includes/widgets.php */
    1214                 do_action( 'dynamic_sidebar_after',  $index, false );
    1215                 /** This filter is documented in wp-includes/widgets.php */
    1216                 return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
    1217         }
    1218 
    1219         /**
    1220          * Fires before widgets are rendered in a dynamic sidebar.
    1221          *
    1222          * Note: The action also fires for empty sidebars, and on both the front-end
    1223          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
    1224          *
    1225          * @since 3.9.0
    1226          *
    1227          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
    1228          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
    1229          *                                Default true.
    1230          */
    1231         do_action( 'dynamic_sidebar_before', $index, true );
    1232         $sidebar = $wp_registered_sidebars[$index];
    1233 
    1234         $did_one = false;
    1235         foreach ( (array) $sidebars_widgets[$index] as $id ) {
    1236 
    1237                 if ( !isset($wp_registered_widgets[$id]) ) continue;
    1238 
    1239                 $params = array_merge(
    1240                         array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
    1241                         (array) $wp_registered_widgets[$id]['params']
    1242                 );
    1243 
    1244                 // Substitute HTML id and class attributes into before_widget
    1245                 $classname_ = '';
    1246                 foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
    1247                         if ( is_string($cn) )
    1248                                 $classname_ .= '_' . $cn;
    1249                         elseif ( is_object($cn) )
    1250                                 $classname_ .= '_' . get_class($cn);
    1251                 }
    1252                 $classname_ = ltrim($classname_, '_');
    1253                 $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
    1254 
    1255                 /**
    1256                  * Filter the parameters passed to a widget's display callback.
    1257                  *
    1258                  * Note: The filter is evaluated on both the front-end and back-end,
    1259                  * including for the Inactive Widgets sidebar on the Widgets screen.
    1260                  *
    1261                  * @since 2.5.0
    1262                  *
    1263                  * @see register_sidebar()
    1264                  *
    1265                  * @param array $params {
    1266                  *     @type array $args  {
    1267                  *         An array of widget display arguments.
    1268                  *
    1269                  *         @type string $name          Name of the sidebar the widget is assigned to.
    1270                  *         @type string $id            ID of the sidebar the widget is assigned to.
    1271                  *         @type string $description   The sidebar description.
    1272                  *         @type string $class         CSS class applied to the sidebar container.
    1273                  *         @type string $before_widget HTML markup to prepend to each widget in the sidebar.
    1274                  *         @type string $after_widget  HTML markup to append to each widget in the sidebar.
    1275                  *         @type string $before_title  HTML markup to prepend to the widget title when displayed.
    1276                  *         @type string $after_title   HTML markup to append to the widget title when displayed.
    1277                  *         @type string $widget_id     ID of the widget.
    1278                  *         @type string $widget_name   Name of the widget.
    1279                  *     }
    1280                  *     @type array $widget_args {
    1281                  *         An array of multi-widget arguments.
    1282                  *
    1283                  *         @type int $number Number increment used for multiples of the same widget.
    1284                  *     }
    1285                  * }
    1286                  */
    1287                 $params = apply_filters( 'dynamic_sidebar_params', $params );
    1288 
    1289                 $callback = $wp_registered_widgets[$id]['callback'];
    1290 
    1291                 /**
    1292                  * Fires before a widget's display callback is called.
    1293                  *
    1294                  * Note: The action fires on both the front-end and back-end, including
    1295                  * for widgets in the Inactive Widgets sidebar on the Widgets screen.
    1296                  *
    1297                  * The action is not fired for empty sidebars.
    1298                  *
    1299                  * @since 3.0.0
    1300                  *
    1301                  * @param array $widget_id {
    1302                  *     An associative array of widget arguments.
    1303                  *
    1304                  *     @type string $name                Name of the widget.
    1305                  *     @type string $id                  Widget ID.
    1306                  *     @type array|callback $callback    When the hook is fired on the front-end, $callback is an array
    1307                  *                                       containing the widget object. Fired on the back-end, $callback
    1308                  *                                       is 'wp_widget_control', see $_callback.
    1309                  *     @type array          $params      An associative array of multi-widget arguments.
    1310                  *     @type string         $classname   CSS class applied to the widget container.
    1311                  *     @type string         $description The widget description.
    1312                  *     @type array          $_callback   When the hook is fired on the back-end, $_callback is populated
    1313                  *                                       with an array containing the widget object, see $callback.
    1314                  * }
    1315                  */
    1316                 do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
    1317 
    1318                 if ( is_callable($callback) ) {
    1319                         call_user_func_array($callback, $params);
    1320                         $did_one = true;
    1321                 }
    1322         }
    1323 
    1324         /**
    1325          * Fires after widgets are rendered in a dynamic sidebar.
    1326          *
    1327          * Note: The action also fires for empty sidebars, and on both the front-end
    1328          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
    1329          *
    1330          * @since 3.9.0
    1331          *
    1332          * @param int|string $index       Index, name, or ID of the dynamic sidebar.
    1333          * @param bool       $has_widgets Whether the sidebar is populated with widgets.
    1334          *                                Default true.
    1335          */
    1336         do_action( 'dynamic_sidebar_after', $index, true );
    1337 
    1338         /**
    1339          * Filter whether a sidebar has widgets.
    1340          *
    1341          * Note: The filter is also evaluated for empty sidebars, and on both the front-end
    1342          * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
    1343          *
    1344          * @since 3.9.0
    1345          *
    1346          * @param bool       $did_one Whether at least one widget was rendered in the sidebar.
    1347          *                            Default false.
    1348          * @param int|string $index   Index, name, or ID of the dynamic sidebar.
    1349          */
    1350         return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
    1351 }
    1352 
    1353 /**
    1354  * Whether widget is displayed on the front-end.
    1355  *
    1356  * Either $callback or $id_base can be used
    1357  * $id_base is the first argument when extending WP_Widget class
    1358  * Without the optional $widget_id parameter, returns the ID of the first sidebar
    1359  * in which the first instance of the widget with the given callback or $id_base is found.
    1360  * With the $widget_id parameter, returns the ID of the sidebar where
    1361  * the widget with that callback/$id_base AND that ID is found.
    1362  *
    1363  * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
    1364  * this function has to run after widgets have initialized, at action 'init' or later.
    1365  *
    1366  * @since 2.2.0
    1367  *
    1368  * @global array $wp_registered_widgets
    1369  *
    1370  * @param string $callback      Optional, Widget callback to check.
    1371  * @param int    $widget_id     Optional, but needed for checking. Widget ID.
    1372  * @param string $id_base       Optional, the base ID of a widget created by extending WP_Widget.
    1373  * @param bool   $skip_inactive Optional, whether to check in 'wp_inactive_widgets'.
    1374  * @return string|false False if widget is not active or id of sidebar in which the widget is active.
    1375  */
    1376 function is_active_widget($callback = false, $widget_id = false, $id_base = false, $skip_inactive = true) {
    1377         global $wp_registered_widgets;
    1378 
    1379         $sidebars_widgets = wp_get_sidebars_widgets();
    1380 
    1381         if ( is_array($sidebars_widgets) ) {
    1382                 foreach ( $sidebars_widgets as $sidebar => $widgets ) {
    1383                         if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) ) {
    1384                                 continue;
    1385                         }
    1386 
    1387                         if ( is_array($widgets) ) {
    1388                                 foreach ( $widgets as $widget ) {
    1389                                         if ( ( $callback && isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback ) || ( $id_base && _get_widget_id_base($widget) == $id_base ) ) {
    1390                                                 if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
    1391                                                         return $sidebar;
    1392                                         }
    1393                                 }
    1394                         }
    1395                 }
    1396         }
    1397         return false;
    1398 }
    1399 
    1400 /**
    1401  * Whether the dynamic sidebar is enabled and used by theme.
    1402  *
    1403  * @since 2.2.0
    1404  *
    1405  * @global array $wp_registered_widgets
    1406  * @global array $wp_registered_sidebars
    1407  *
    1408  * @return bool True, if using widgets. False, if not using widgets.
    1409  */
    1410 function is_dynamic_sidebar() {
    1411         global $wp_registered_widgets, $wp_registered_sidebars;
    1412         $sidebars_widgets = get_option('sidebars_widgets');
    1413         foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
    1414                 if ( count($sidebars_widgets[$index]) ) {
    1415                         foreach ( (array) $sidebars_widgets[$index] as $widget )
    1416                                 if ( array_key_exists($widget, $wp_registered_widgets) )
    1417                                         return true;
    1418                 }
    1419         }
    1420         return false;
    1421 }
    1422 
    1423 /**
    1424  * Whether a sidebar is in use.
    1425  *
    1426  * @since 2.8.0
    1427  *
    1428  * @param string|int $index Sidebar name, id or number to check.
    1429  * @return bool true if the sidebar is in use, false otherwise.
    1430  */
    1431 function is_active_sidebar( $index ) {
    1432         $index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
    1433         $sidebars_widgets = wp_get_sidebars_widgets();
    1434         $is_active_sidebar = ! empty( $sidebars_widgets[$index] );
    1435 
    1436         /**
    1437          * Filter whether a dynamic sidebar is considered "active".
    1438          *
    1439          * @since 3.9.0
    1440          *
    1441          * @param bool       $is_active_sidebar Whether or not the sidebar should be considered "active".
    1442          *                                      In other words, whether the sidebar contains any widgets.
    1443          * @param int|string $index             Index, name, or ID of the dynamic sidebar.
    1444          */
    1445         return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
    1446 }
    1447 
    1448 /* Internal Functions */
    1449 
    1450 /**
    1451  * Retrieve full list of sidebars and their widget instance IDs.
    1452  *
    1453  * Will upgrade sidebar widget list, if needed. Will also save updated list, if
    1454  * needed.
    1455  *
    1456  * @since 2.2.0
    1457  * @access private
    1458  *
    1459  * @global array $_wp_sidebars_widgets
    1460  * @global array $sidebars_widgets
    1461  *
    1462  * @param bool $deprecated Not used (argument deprecated).
    1463  * @return array Upgraded list of widgets to version 3 array format when called from the admin.
    1464  */
    1465 function wp_get_sidebars_widgets( $deprecated = true ) {
    1466         if ( $deprecated !== true )
    1467                 _deprecated_argument( __FUNCTION__, '2.8.1' );
    1468 
    1469         global $_wp_sidebars_widgets, $sidebars_widgets;
    1470 
    1471         // If loading from front page, consult $_wp_sidebars_widgets rather than options
    1472         // to see if wp_convert_widget_settings() has made manipulations in memory.
    1473         if ( !is_admin() ) {
    1474                 if ( empty($_wp_sidebars_widgets) )
    1475                         $_wp_sidebars_widgets = get_option('sidebars_widgets', array());
    1476 
    1477                 $sidebars_widgets = $_wp_sidebars_widgets;
    1478         } else {
    1479                 $sidebars_widgets = get_option('sidebars_widgets', array());
    1480         }
    1481 
    1482         if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
    1483                 unset($sidebars_widgets['array_version']);
    1484 
    1485         /**
    1486          * Filter the list of sidebars and their widgets.
    1487          *
    1488          * @since 2.7.0
    1489          *
    1490          * @param array $sidebars_widgets An associative array of sidebars and their widgets.
    1491          */
    1492         return apply_filters( 'sidebars_widgets', $sidebars_widgets );
    1493 }
    1494 
    1495 /**
    1496  * Set the sidebar widget option to update sidebars.
    1497  *
    1498  * @since 2.2.0
    1499  * @access private
    1500  *
    1501  * @param array $sidebars_widgets Sidebar widgets and their settings.
    1502  */
    1503 function wp_set_sidebars_widgets( $sidebars_widgets ) {
    1504         if ( !isset( $sidebars_widgets['array_version'] ) )
    1505                 $sidebars_widgets['array_version'] = 3;
    1506         update_option( 'sidebars_widgets', $sidebars_widgets );
    1507 }
    1508 
    1509 /**
    1510  * Retrieve default registered sidebars list.
    1511  *
    1512  * @since 2.2.0
    1513  * @access private
    1514  *
    1515  * @global array $wp_registered_sidebars
    1516  *
    1517  * @return array
    1518  */
    1519 function wp_get_widget_defaults() {
    1520         global $wp_registered_sidebars;
    1521 
    1522         $defaults = array();
    1523 
    1524         foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
    1525                 $defaults[$index] = array();
    1526 
    1527         return $defaults;
    1528 }
    1529 
    1530 /**
    1531  * Convert the widget settings from single to multi-widget format.
    1532  *
    1533  * @since 2.8.0
    1534  *
    1535  * @global array $_wp_sidebars_widgets
    1536  *
    1537  * @param string $base_name
    1538  * @param string $option_name
    1539  * @param array  $settings
    1540  * @return array
    1541  */
    1542 function wp_convert_widget_settings($base_name, $option_name, $settings) {
    1543         // This test may need expanding.
    1544         $single = $changed = false;
    1545         if ( empty($settings) ) {
    1546                 $single = true;
    1547         } else {
    1548                 foreach ( array_keys($settings) as $number ) {
    1549                         if ( 'number' == $number )
    1550                                 continue;
    1551                         if ( !is_numeric($number) ) {
    1552                                 $single = true;
    1553                                 break;
    1554                         }
    1555                 }
    1556         }
    1557 
    1558         if ( $single ) {
    1559                 $settings = array( 2 => $settings );
    1560 
    1561                 // If loading from the front page, update sidebar in memory but don't save to options
    1562                 if ( is_admin() ) {
    1563                         $sidebars_widgets = get_option('sidebars_widgets');
    1564                 } else {
    1565                         if ( empty($GLOBALS['_wp_sidebars_widgets']) )
    1566                                 $GLOBALS['_wp_sidebars_widgets'] = get_option('sidebars_widgets', array());
    1567                         $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
    1568                 }
    1569 
    1570                 foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
    1571                         if ( is_array($sidebar) ) {
    1572                                 foreach ( $sidebar as $i => $name ) {
    1573                                         if ( $base_name == $name ) {
    1574                                                 $sidebars_widgets[$index][$i] = "$name-2";
    1575                                                 $changed = true;
    1576                                                 break 2;
    1577                                         }
    1578                                 }
    1579                         }
    1580                 }
    1581 
    1582                 if ( is_admin() && $changed )
    1583                         update_option('sidebars_widgets', $sidebars_widgets);
    1584         }
    1585 
    1586         $settings['_multiwidget'] = 1;
    1587         if ( is_admin() )
    1588                 update_option( $option_name, $settings );
    1589 
    1590         return $settings;
    1591 }
    1592 
    1593 /**
    1594  * Output an arbitrary widget as a template tag.
    1595  *
    1596  * @since 2.8.0
    1597  *
    1598  * @global WP_Widget_Factory $wp_widget_factory
    1599  *
    1600  * @param string $widget   The widget's PHP class name (see default-widgets.php).
    1601  * @param array  $instance Optional. The widget's instance settings. Default empty array.
    1602  * @param array  $args {
    1603  *     Optional. Array of arguments to configure the display of the widget.
    1604  *
    1605  *     @type string $before_widget HTML content that will be prepended to the widget's HTML output.
    1606  *                                 Default `<div class="widget %s">`, where `%s` is the widget's class name.
    1607  *     @type string $after_widget  HTML content that will be appended to the widget's HTML output.
    1608  *                                 Default `</div>`.
    1609  *     @type string $before_title  HTML content that will be prepended to the widget's title when displayed.
    1610  *                                 Default `<h2 class="widgettitle">`.
    1611  *     @type string $after_title   HTML content that will be appended to the widget's title when displayed.
    1612  *                                 Default `</h2>`.
    1613  * }
    1614  */
    1615 function the_widget( $widget, $instance = array(), $args = array() ) {
    1616         global $wp_widget_factory;
    1617 
    1618         $widget_obj = $wp_widget_factory->widgets[$widget];
    1619         if ( ! ( $widget_obj instanceof WP_Widget ) ) {
    1620                 return;
    1621         }
    1622 
    1623         $before_widget = sprintf('<div class="widget %s">', $widget_obj->widget_options['classname'] );
    1624         $default_args = array( 'before_widget' => $before_widget, 'after_widget' => "</div>", 'before_title' => '<h2 class="widgettitle">', 'after_title' => '</h2>' );
    1625 
    1626         $args = wp_parse_args($args, $default_args);
    1627         $instance = wp_parse_args($instance);
    1628 
    1629         /**
    1630          * Fires before rendering the requested widget.
    1631          *
    1632          * @since 3.0.0
    1633          *
    1634          * @param string $widget   The widget's class name.
    1635          * @param array  $instance The current widget instance's settings.
    1636          * @param array  $args     An array of the widget's sidebar arguments.
    1637          */
    1638         do_action( 'the_widget', $widget, $instance, $args );
    1639 
    1640         $widget_obj->_set(-1);
    1641         $widget_obj->widget($args, $instance);
    1642 }
    1643 
    1644 /**
    1645  * Private
    1646  *
    1647  * @return string
    1648  */
    1649 function _get_widget_id_base($id) {
    1650         return preg_replace( '/-[0-9]+$/', '', $id );
    1651 }
    1652 
    1653 /**
    1654  * Handle sidebars config after theme change
    1655  *
    1656  * @access private
    1657  * @since 3.3.0
    1658  *
    1659  * @global array $sidebars_widgets
    1660  */
    1661 function _wp_sidebars_changed() {
    1662         global $sidebars_widgets;
    1663 
    1664         if ( ! is_array( $sidebars_widgets ) )
    1665                 $sidebars_widgets = wp_get_sidebars_widgets();
    1666 
    1667         retrieve_widgets(true);
    1668 }
    1669 
    1670 /**
    1671  * Look for "lost" widgets, this has to run at least on each theme change.
    1672  *
    1673  * @since 2.8.0
    1674  *
    1675  * @global array $wp_registered_sidebars
    1676  * @global array $sidebars_widgets
    1677  * @global array $wp_registered_widgets
    1678  *
    1679  * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
    1680  *                                   of 'customize' defers updates for the Customizer.
    1681  * @return array|void
    1682  */
    1683 function retrieve_widgets( $theme_changed = false ) {
    1684         global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
    1685 
    1686         $registered_sidebar_keys = array_keys( $wp_registered_sidebars );
    1687         $orphaned = 0;
    1688 
    1689         $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
    1690         if ( is_array( $old_sidebars_widgets ) ) {
    1691                 // time() that sidebars were stored is in $old_sidebars_widgets['time']
    1692                 $_sidebars_widgets = $old_sidebars_widgets['data'];
    1693 
    1694                 if ( 'customize' !== $theme_changed ) {
    1695                         remove_theme_mod( 'sidebars_widgets' );
    1696                 }
    1697 
    1698                 foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
    1699                         if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
    1700                                 continue;
    1701                         }
    1702 
    1703                         if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {
    1704                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;
    1705                                 unset( $_sidebars_widgets[$sidebar] );
    1706                         }
    1707                 }
    1708         } else {
    1709                 if ( empty( $sidebars_widgets ) )
    1710                         return;
    1711 
    1712                 unset( $sidebars_widgets['array_version'] );
    1713 
    1714                 $old = array_keys($sidebars_widgets);
    1715                 sort($old);
    1716                 sort($registered_sidebar_keys);
    1717 
    1718                 if ( $old == $registered_sidebar_keys )
    1719                         return;
    1720 
    1721                 $_sidebars_widgets = array(
    1722                         'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()
    1723                 );
    1724 
    1725                 unset( $sidebars_widgets['wp_inactive_widgets'] );
    1726 
    1727                 foreach ( $wp_registered_sidebars as $id => $settings ) {
    1728                         if ( $theme_changed ) {
    1729                                 $_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
    1730                         } else {
    1731                                 // no theme change, grab only sidebars that are currently registered
    1732                                 if ( isset( $sidebars_widgets[$id] ) ) {
    1733                                         $_sidebars_widgets[$id] = $sidebars_widgets[$id];
    1734                                         unset( $sidebars_widgets[$id] );
    1735                                 }
    1736                         }
    1737                 }
    1738 
    1739                 foreach ( $sidebars_widgets as $val ) {
    1740                         if ( is_array($val) && ! empty( $val ) )
    1741                                 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
    1742                 }
    1743         }
    1744 
    1745         // discard invalid, theme-specific widgets from sidebars
    1746         $shown_widgets = array();
    1747 
    1748         foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
    1749                 if ( !is_array($widgets) )
    1750                         continue;
    1751 
    1752                 $_widgets = array();
    1753                 foreach ( $widgets as $widget ) {
    1754                         if ( isset($wp_registered_widgets[$widget]) )
    1755                                 $_widgets[] = $widget;
    1756                 }
    1757 
    1758                 $_sidebars_widgets[$sidebar] = $_widgets;
    1759                 $shown_widgets = array_merge($shown_widgets, $_widgets);
    1760         }
    1761 
    1762         $sidebars_widgets = $_sidebars_widgets;
    1763         unset($_sidebars_widgets, $_widgets);
    1764 
    1765         // find hidden/lost multi-widget instances
    1766         $lost_widgets = array();
    1767         foreach ( $wp_registered_widgets as $key => $val ) {
    1768                 if ( in_array($key, $shown_widgets, true) )
    1769                         continue;
    1770 
    1771                 $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
    1772 
    1773                 if ( 2 > (int) $number )
    1774                         continue;
    1775 
    1776                 $lost_widgets[] = $key;
    1777         }
    1778 
    1779         $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
    1780         if ( 'customize' !== $theme_changed ) {
    1781                 wp_set_sidebars_widgets( $sidebars_widgets );
    1782         }
    1783 
    1784         return $sidebars_widgets;
    1785 }
     86require_once( ABSPATH . WPINC . '/class-wp-widget.php' );
     87require_once( ABSPATH . WPINC . '/class-wp-widget-factory.php' );
     88require_once( ABSPATH . WPINC . '/widget-functions.php' );
Note: See TracChangeset for help on using the changeset viewer.