Make WordPress Core

Changeset 33746


Ignore:
Timestamp:
08/26/2015 02:39:50 AM (9 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.