Indexes of widgets instances starts with ‘2’ in ‘wp_options’ table

The why part can be found in ticket #24889.

Let me quote @azaozz:

When support for multi-use widgets was introduced, a lot of widgets
got converted from “single” to “multi” at the same time. To keep
backward compatibility and not break the existing widgets, there was
some conversion code that would set the “single” widgets instances to
*-1 (not sure why not *-0, it was a long time ago). In order to not overwrite the converted data, the new multi-widgets instances had to
start form 2. As @tyxla mentions, this doesn’t break anything and if
changed to -0 or -1, in theory can still overwrite someone’s single
widgets.

The available Text widget is listed in the global $wp_registered_widgets as:

[text-1] => Array
    (
        [name] => Text
        [id] => text-1
        [callback] => Array
            (
                [0] => WP_Widget_Text Object
                    (
                        [id_base] => text
                        [name] => Text
                        [option_name] => widget_text
                        [alt_option_name] => 
                        [widget_options] => Array
                            (
                                [classname] => widget_text
                                [customize_selective_refresh] => 1
                                Indexes of widgets instances starts with '2' in 'wp_options' table => Arbitrary text or HTML.
                            )

                        [control_options] => Array
                            (
                                [id_base] => text
                                [width] => 400
                                [height] => 350
                            )

                        [number] => 1
                        [id] => text-1
                        [updated] => 
                    )

                [1] => display_callback
            )

        [params] => Array
            (
                [0] => Array
                    (
                        [number] => -1
                    )

            )

        [classname] => widget_text
        [customize_selective_refresh] => 1
        Indexes of widgets instances starts with '2' in 'wp_options' table => Arbitrary text or HTML.
    )

I think the 1, in the text-1 id, comes from this part of the WP_Widget::_register():

if ( $empty ) {
    // If there are none, we register the widget's existence with a generic template.
    $this->_set( 1 );
    $this->_register_one();
}

When the available multi widgets are listed with wp_list_widgets(), the next_widget_id_number() function is used to calculate the next widget id number. It’s defined as:

function next_widget_id_number( $id_base ) {
    global $wp_registered_widgets;
    $number = 1;

    foreach ( $wp_registered_widgets as $widget_id => $widget ) {
        if ( preg_match( "https://wordpress.stackexchange.com/" . $id_base . '-([0-9]+)$/', $widget_id, $matches ) )
            $number = max($number, $matches[1]);
    }
    $number++;

    return $number;
}

For the text-1 id, the next widget id number is max( 1, 1 ) + 1 = 2.

So when we drag the first multi Text widget over an available sidebar, the widget_text option is stored as (adjusted for better readability):

a:2:{
i:2;a:3:{s:5:"title";s:0:"";s:4:"text";s:0:"";s:6:"filter";b:0;}s:12:"_multiwidget";i:1;
}

where we notice the i:2 part and the sidebars_widgets option will contain the text_2 instance.

Hope it helps.

Leave a Comment