home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / widgets.php < prev    next >
Encoding:
PHP Script  |  2017-12-06  |  54.1 KB  |  1,650 lines

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