: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Retrieve full list of sidebars and their widget instance IDs.
* Will upgrade sidebar widget list, if needed. Will also save updated list, if
* @global array $_wp_sidebars_widgets
* @global array $sidebars_widgets
* @param bool $deprecated Not used (argument deprecated).
* @return array Upgraded list of widgets to version 3 array format when called from the admin.
function wp_get_sidebars_widgets( $deprecated = true ) {
if ( true !== $deprecated ) {
_deprecated_argument( __FUNCTION__, '2.8.1' );
global $_wp_sidebars_widgets, $sidebars_widgets;
* If loading from front page, consult $_wp_sidebars_widgets rather than options
* to see if wp_convert_widget_settings() has made manipulations in memory.
if ( empty( $_wp_sidebars_widgets ) ) {
$_wp_sidebars_widgets = get_option( 'sidebars_widgets', array() );
$sidebars_widgets = $_wp_sidebars_widgets;
$sidebars_widgets = get_option( 'sidebars_widgets', array() );
if ( is_array( $sidebars_widgets ) && isset( $sidebars_widgets['array_version'] ) ) {
unset( $sidebars_widgets['array_version'] );
* Filters the list of sidebars and their widgets.
* @param array $sidebars_widgets An associative array of sidebars and their widgets.
return apply_filters( 'sidebars_widgets', $sidebars_widgets );
* Retrieves the registered sidebar with the given ID.
* @global array $wp_registered_sidebars The registered sidebars.
* @param string $id The sidebar ID.
* @return array|null The discovered sidebar, or null if it is not registered.
function wp_get_sidebar( $id ) {
global $wp_registered_sidebars;
foreach ( (array) $wp_registered_sidebars as $sidebar ) {
if ( $sidebar['id'] === $id ) {
if ( 'wp_inactive_widgets' === $id ) {
'id' => 'wp_inactive_widgets',
'name' => __( 'Inactive widgets' ),
* Set the sidebar widget option to update sidebars.
* @global array $_wp_sidebars_widgets
* @param array $sidebars_widgets Sidebar widgets and their settings.
function wp_set_sidebars_widgets( $sidebars_widgets ) {
global $_wp_sidebars_widgets;
// Clear cached value used in wp_get_sidebars_widgets().
$_wp_sidebars_widgets = null;
if ( ! isset( $sidebars_widgets['array_version'] ) ) {
$sidebars_widgets['array_version'] = 3;
update_option( 'sidebars_widgets', $sidebars_widgets );
* Retrieve default registered sidebars list.
* @global array $wp_registered_sidebars The registered sidebars.
function wp_get_widget_defaults() {
global $wp_registered_sidebars;
foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
$defaults[ $index ] = array();
* Converts the widget settings from single to multi-widget format.
* @global array $_wp_sidebars_widgets
* @param string $base_name Root ID for all widgets of this type.
* @param string $option_name Option name for this widget type.
* @param array $settings The array of widget instance settings.
* @return array The array of widget settings converted to multi-widget format.
function wp_convert_widget_settings( $base_name, $option_name, $settings ) {
// This test may need expanding.
if ( empty( $settings ) ) {
foreach ( array_keys( $settings ) as $number ) {
if ( 'number' === $number ) {
if ( ! is_numeric( $number ) ) {
$settings = array( 2 => $settings );
// If loading from the front page, update sidebar in memory but don't save to options.
$sidebars_widgets = get_option( 'sidebars_widgets' );
if ( empty( $GLOBALS['_wp_sidebars_widgets'] ) ) {
$GLOBALS['_wp_sidebars_widgets'] = get_option( 'sidebars_widgets', array() );
$sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
if ( is_array( $sidebar ) ) {
foreach ( $sidebar as $i => $name ) {
if ( $base_name === $name ) {
$sidebars_widgets[ $index ][ $i ] = "$name-2";
if ( is_admin() && $changed ) {
update_option( 'sidebars_widgets', $sidebars_widgets );
$settings['_multiwidget'] = 1;
update_option( $option_name, $settings );
* Output an arbitrary widget as a template tag.
* @global WP_Widget_Factory $wp_widget_factory
* @param string $widget The widget's PHP class name (see class-wp-widget.php).
* @param array $instance Optional. The widget's instance settings. Default empty array.
* Optional. Array of arguments to configure the display of the widget.
* @type string $before_widget HTML content that will be prepended to the widget's HTML output.
* Default `<div class="widget %s">`, where `%s` is the widget's class name.
* @type string $after_widget HTML content that will be appended to the widget's HTML output.
* @type string $before_title HTML content that will be prepended to the widget's title when displayed.
* Default `<h2 class="widgettitle">`.
* @type string $after_title HTML content that will be appended to the widget's title when displayed.
function the_widget( $widget, $instance = array(), $args = array() ) {
global $wp_widget_factory;
if ( ! isset( $wp_widget_factory->widgets[ $widget ] ) ) {
/* translators: %s: register_widget() */
__( 'Widgets need to be registered using %s, before they can be displayed.' ),
'<code>register_widget()</code>'
$widget_obj = $wp_widget_factory->widgets[ $widget ];
if ( ! ( $widget_obj instanceof WP_Widget ) ) {
'before_widget' => '<div class="widget %s">',
'after_widget' => '</div>',
'before_title' => '<h2 class="widgettitle">',
'after_title' => '</h2>',
$args = wp_parse_args( $args, $default_args );
$args['before_widget'] = sprintf( $args['before_widget'], $widget_obj->widget_options['classname'] );
$instance = wp_parse_args( $instance );
/** This filter is documented in wp-includes/class-wp-widget.php */
$instance = apply_filters( 'widget_display_callback', $instance, $widget_obj, $args );
if ( false === $instance ) {
* Fires before rendering the requested widget.
* @param string $widget The widget's class name.
* @param array $instance The current widget instance's settings.
* @param array $args An array of the widget's sidebar arguments.
do_action( 'the_widget', $widget, $instance, $args );
$widget_obj->widget( $args, $instance );
* Retrieves the widget ID base value.
* @param string $id Widget ID.
* @return string Widget ID base.
function _get_widget_id_base( $id ) {
return preg_replace( '/-[0-9]+$/', '', $id );
* Handle sidebars config after theme change
* @global array $sidebars_widgets
function _wp_sidebars_changed() {
global $sidebars_widgets;
if ( ! is_array( $sidebars_widgets ) ) {
$sidebars_widgets = wp_get_sidebars_widgets();
retrieve_widgets( true );
* Validates and remaps any "orphaned" widgets to wp_inactive_widgets sidebar,
* and saves the widget settings. This has to run at least on each theme change.
* For example, let's say theme A has a "footer" sidebar, and theme B doesn't have one.
* After switching from theme A to theme B, all the widgets previously assigned
* to the footer would be inaccessible. This function detects this scenario, and
* moves all the widgets previously assigned to the footer under wp_inactive_widgets.
* Despite the word "retrieve" in the name, this function actually updates the database
* and the global `$sidebars_widgets`. For that reason it should not be run on front end,
* unless the `$theme_changed` value is 'customize' (to bypass the database write).
* @global array $wp_registered_sidebars The registered sidebars.
* @global array $sidebars_widgets
* @global array $wp_registered_widgets The registered widgets.
* @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
* of 'customize' defers updates for the Customizer.
* @return array Updated sidebars widgets.
function retrieve_widgets( $theme_changed = false ) {
global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
$registered_sidebars_keys = array_keys( $wp_registered_sidebars );
$registered_widgets_ids = array_keys( $wp_registered_widgets );
if ( ! is_array( get_theme_mod( 'sidebars_widgets' ) ) ) {
if ( empty( $sidebars_widgets ) ) {
unset( $sidebars_widgets['array_version'] );
$sidebars_widgets_keys = array_keys( $sidebars_widgets );
sort( $sidebars_widgets_keys );
sort( $registered_sidebars_keys );
if ( $sidebars_widgets_keys === $registered_sidebars_keys ) {
$sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids );
return $sidebars_widgets;
// Discard invalid, theme-specific widgets from sidebars.
$sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids );
$sidebars_widgets = wp_map_sidebars_widgets( $sidebars_widgets );
// Find hidden/lost multi-widget instances.
$shown_widgets = array_merge( ...array_values( $sidebars_widgets ) );
$lost_widgets = array_diff( $registered_widgets_ids, $shown_widgets );
foreach ( $lost_widgets as $key => $widget_id ) {
$number = preg_replace( '/.+?-([0-9]+)$/', '$1', $widget_id );
// Only keep active and default widgets.
if ( is_numeric( $number ) && (int) $number < 2 ) {
unset( $lost_widgets[ $key ] );
$sidebars_widgets['wp_inactive_widgets'] = array_merge( $lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets'] );
if ( 'customize' !== $theme_changed ) {
// Update the widgets settings in the database.
wp_set_sidebars_widgets( $sidebars_widgets );
return $sidebars_widgets;
* Compares a list of sidebars with their widgets against an allowed list.
* @since 4.9.2 Always tries to restore widget assignments from previous data, not just if sidebars needed mapping.
* @global array $wp_registered_sidebars The registered sidebars.
* @param array $existing_sidebars_widgets List of sidebars and their widget instance IDs.
* @return array Mapped sidebars widgets.
function wp_map_sidebars_widgets( $existing_sidebars_widgets ) {
global $wp_registered_sidebars;
$new_sidebars_widgets = array(
'wp_inactive_widgets' => array(),
// Short-circuit if there are no sidebars to map.
if ( ! is_array( $existing_sidebars_widgets ) || empty( $existing_sidebars_widgets ) ) {
return $new_sidebars_widgets;
foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) {
if ( 'wp_inactive_widgets' === $sidebar || str_starts_with( $sidebar, 'orphaned_widgets' ) ) {
$new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], (array) $widgets );
unset( $existing_sidebars_widgets[ $sidebar ] );
// If old and new theme have just one sidebar, map it and we're done.
if ( 1 === count( $existing_sidebars_widgets ) && 1 === count( $wp_registered_sidebars ) ) {
$new_sidebars_widgets[ key( $wp_registered_sidebars ) ] = array_pop( $existing_sidebars_widgets );
return $new_sidebars_widgets;
// Map locations with the same slug.
$existing_sidebars = array_keys( $existing_sidebars_widgets );
foreach ( $wp_registered_sidebars as $sidebar => $name ) {
if ( in_array( $sidebar, $existing_sidebars, true ) ) {
$new_sidebars_widgets[ $sidebar ] = $existing_sidebars_widgets[ $sidebar ];
unset( $existing_sidebars_widgets[ $sidebar ] );
} elseif ( ! array_key_exists( $sidebar, $new_sidebars_widgets ) ) {
$new_sidebars_widgets[ $sidebar ] = array();
// If there are more sidebars, try to map them.
if ( ! empty( $existing_sidebars_widgets ) ) {
* If old and new theme both have sidebars that contain phrases
* from within the same group, make an educated guess and map it.
$common_slug_groups = array(
array( 'sidebar', 'primary', 'main', 'right' ),
array( 'second', 'left' ),
array( 'sidebar-2', 'footer', 'bottom' ),
array( 'header', 'top' ),
// Go through each group...
foreach ( $common_slug_groups as $slug_group ) {
// ...and see if any of these slugs...
foreach ( $slug_group as $slug ) {
// ...and any of the new sidebars...
foreach ( $wp_registered_sidebars as $new_sidebar => $args ) {
if ( false === stripos( $new_sidebar, $slug ) && false === stripos( $slug, $new_sidebar ) ) {
// Then see if any of the existing sidebars...
foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) {
// ...and any slug in the same group...
foreach ( $slug_group as $slug ) {
// ... have a match as well.
if ( false === stripos( $sidebar, $slug ) && false === stripos( $slug, $sidebar ) ) {
// Make sure this sidebar wasn't mapped and removed previously.
if ( ! empty( $existing_sidebars_widgets[ $sidebar ] ) ) {
// We have a match that can be mapped!
$new_sidebars_widgets[ $new_sidebar ] = array_merge( $new_sidebars_widgets[ $new_sidebar ], $existing_sidebars_widgets[ $sidebar ] );
// Remove the mapped sidebar so it can't be mapped again.
unset( $existing_sidebars_widgets[ $sidebar ] );
// Go back and check the next new sidebar.
} // End foreach ( $slug_group as $slug ).
} // End foreach ( $existing_sidebars_widgets as $sidebar => $widgets ).
} // End foreach ( $wp_registered_sidebars as $new_sidebar => $args ).
} // End foreach ( $slug_group as $slug ).
} // End foreach ( $common_slug_groups as $slug_group ).
// Move any left over widgets to inactive sidebar.
foreach ( $existing_sidebars_widgets as $widgets ) {
if ( is_array( $widgets ) && ! empty( $widgets ) ) {
$new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], $widgets );
// Sidebars_widgets settings from when this theme was previously active.
$old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
$old_sidebars_widgets = isset( $old_sidebars_widgets['data'] ) ? $old_sidebars_widgets['data'] : false;
if ( is_array( $old_sidebars_widgets ) ) {
// Remove empty sidebars, no need to map those.
$old_sidebars_widgets = array_filter( $old_sidebars_widgets );
// Only check sidebars that are empty or have not been mapped to yet.
foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ) {
if ( array_key_exists( $new_sidebar, $old_sidebars_widgets ) && ! empty( $new_widgets ) ) {