Auto-Add a Widget to a Sidebar on Plugin Activation
Let's not repeat our work adding widgets to sidebars.
We just rolled out a new post type that requires a special widget in the sidebar to have the frontend work properly. Sure I could manually go to 100 sites and add it, but we'll be rolling out the new CPT gradually, so why not just automate the widget at when we activate the plugin?
WordPress stores widget configuration in two database options:
sidebars_widgets— maps sidebar IDs to arrays of widget instance IDs (e.g.my_widget-2)widget_{base_id}— stores the settings for each instance of a widget
You can write directly to both options inside your plugin's activation hook.
Minimal Example
register_activation_hook( __FILE__, 'myplugin_activate' );
function myplugin_activate() {
$sidebar_id = 'my-custom-sidebar';
// Bail if the widget is already in the sidebar.
$sidebars_widgets = get_option( 'sidebars_widgets', [] );
if ( ! empty( $sidebars_widgets[ $sidebar_id ] ) ) {
foreach ( $sidebars_widgets[ $sidebar_id ] as $widget_id ) {
if ( strpos( $widget_id, 'my_widget-' ) === 0 ) {
return;
}
}
}
// Find the next unused instance number (WordPress starts at 2).
$instances = get_option( 'widget_my_widget', [ '_multiwidget' => 1 ] );
$num = 2;
while ( isset( $instances[ $num ] ) ) {
$num++;
}
// Store the new widget instance (add any default settings here).
$instances[ $num ] = [];
update_option( 'widget_my_widget', $instances );
// Add the widget to the sidebar.
$sidebars_widgets[ $sidebar_id ][] = 'my_widget-' . $num;
update_option( 'sidebars_widgets', $sidebars_widgets );
}
Replace my-custom-sidebar with your sidebar ID and my_widget with the base ID you passed to WP_Widget::__construct().
A Few Things Worth Knowing
Instance numbers start at 2. WordPress reserves index 1 internally and begins numbering real instances at 2. The loop above finds the next available slot so you don't overwrite an existing widget if the plugin is ever deactivated and reactivated.
The idempotency check matters. Without the early-return check, every reactivation would append another copy of the widget to the sidebar. The loop looks for any my_widget-* entry before doing any writing.
The widget class doesn't need to be loaded. The activation hook fires before widgets_init, so your widget class won't be registered yet. That's fine — you're only manipulating database options, not instantiating the widget.
The sidebar doesn't need to be registered yet either. sidebars_widgets is just an option array. WordPress will match the key to the registered sidebar at runtime, so writing to it before the sidebar is registered is safe.
This pattern works equally well for object-oriented plugins — just move the logic into a private method and call it from your activate() method.