Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I would like to programmatically add widgets to my two sidebars that I've got. I couldn't find any official way of doing it?

I started looking in the database. I've found that it's the 'sidebars_widgets' option which puts widgets on sidebars. When looking at the options the widget names has a number added to the end like: widget_name-6. Where does that number come from?

Any idea on how to fix this?

share|improve this question
6  
You should add your answer down there to answer your own question :) –  helenhousandi Aug 22 '11 at 15:28
    
For a great rundown on sidebar widgets, check out this article: justintadlock.com/archives/2010/11/08/sidebars-in-wordpress. –  Joshua Aug 22 '11 at 15:58
    
Monitor the action parameter of ajax call that is made when a widget is added, and then find the code related to that action ajax hook and see how its done in core. Simple! ;) –  Ashfame Apr 9 '12 at 21:50
5  
Please re-post your solution as an answer and accept it as "the" answer to your problem. –  EAMann Apr 11 '12 at 21:52
add comment

2 Answers

When I started this answer it should be just a small note. Well, I failed. Sorry! Stay with me, there is a goody hidden deep down …

How WordPress widgets are stored

The list of widget is stored in an option named 'sidebars_widgets'. A var_export() may give something like the following:

array (
  'wp_inactive_widgets' => 
  array (
  ),
  'top-widget' => 
  array (
  ),
  'bottom-widget' => 
  array (
  ),
  'array_version' => 3,
)

Ignore 'wp_inactive_widgets' and 'array_version'. We don't have to care about those.
The other keys are identifier for registered sidebars. In this case the sidebars may have been registered with this code:

// Register two sidebars.
$sidebars = array ( 'a' => 'top-widget', 'b' => 'bottom-widget' );
foreach ( $sidebars as $sidebar )
{
    register_sidebar(
        array (
            'name'          => $sidebar,
            'id'            => $sidebar,
            'before_widget' => '',
            'after_widget'  => ''
        )
    );
}

By default the sidebars are empty after registration. Of course.

For each registered widget class a separate option is created, containing all necessary options. The option is prefixed by the string widget_. To get the options for all active RSS widgets we have to look into …

get_option( 'widget_rss' );

Possible output:

array (
  2 => 
  array (
    'title' => 'WordPress Stack Exchange',
    'url' => 'http://wordpress.stackexchange.com/feeds',
    'link' => 'http://wordpress.stackexchange.com/questions',
    'items' => 5,
    'show_summary' => 1,
    'show_author' => 0,
    'show_date' => 0,
  ),
)

Note the number 2. The arguments for multiple instances are all stored in this one option sorted by numbers.

To see which widget classes are already known to WordPress go to wp-admin/options.php and scroll down until you see something like this:

screen shot of serialized widget options

Yes, serialized data. No, you can't read those here. Don't worry, you don't have to.

A demo widget

To illustrate the inner workings better I have written a very simple demo widget:

/**
 * Super simple widget.
 */
class T5_Demo_Widget extends WP_Widget
{
    public function __construct()
    {                      // id_base        ,  visible name
        parent::__construct( 't5_demo_widget', 'T5 Demo Widget' );
    }

    public function widget( $args, $instance )
    {
        echo $args['before_widget'], wpautop( $instance['text'] ), $args['after_widget'];
    }

    public function form( $instance )
    {
        $text = isset ( $instance['text'] )
            ? esc_textarea( $instance['text'] ) : '';
        printf(
            '<textarea class="widefat" rows="7" cols="20" id="%1$s" name="%2$s">%3$s</textarea>',
            $this->get_field_id( 'text' ),
            $this->get_field_name( 'text' ),
            $text
        );
    }
}

Note the constructor: 't5_demo_widget' is the $id_base, the identifier for this widget. As you can see in the screen shot its arguments are stored in the option widget_t5_demo_widget. All your custom widgets will be treated like this. You don't have to guess the name. And since you have written your widgets (probably) you know all the arguments from your class' $instance parameters.

Theme basics

First you have to register some sidebars and the custom widget. The proper action for this is easy to remember: 'widgets_init'. Put everything into a container – a class or a function. For simplicity I'll use a function named t5_default_widget_demo().

All of the following code goes into the functions.php. The class T5_Demo_Widget should be loaded already. I just put it into the same file …

add_action( 'widgets_init', 't5_default_widget_demo' );

function t5_default_widget_demo()
{
    // Register our own widget.
    register_widget( 'T5_Demo_Widget' );

    // Register two sidebars.
    $sidebars = array ( 'a' => 'top-widget', 'b' => 'bottom-widget' );
    foreach ( $sidebars as $sidebar )
    {
        register_sidebar(
            array (
                'name'          => $sidebar,
                'id'            => $sidebar,
                'before_widget' => '',
                'after_widget'  => ''
            )
        );
    }

So far, so simple. Our theme is now widget ready, the demo widget is known. Now the fun.

$active_widgets = get_option( 'sidebars_widgets' );

if ( ! empty ( $active_widgets[ $sidebars['a'] ] )
    or ! empty ( $active_widgets[ $sidebars['b'] ] )
)
{   // Okay, no fun anymore. There is already some content.
    return;
}

You really don't want to destroy the user settings. If there is already some content in the sidebars your code should not run over it. That's why we stop in this case.

Okay, assumed the sidebars are empty … we need a counter:

$counter = 1;

Widgets are numbered. These numbers are second identifiers for WordPress.

Let's get the array to change it:

$active_widgets = get_option( 'sidebars_widgets' );

We need a counter too (more on that later):

$counter = 1;

And here is how we use the counter, the sidebar names and the the widget arguments (well, we have just one argument: text).

// Add a 'demo' widget to the top sidebar …
$active_widgets[ $sidebars['a'] ][0] = 't5_demo_widget-' . $counter;
// … and write some text into it:
$demo_widget_content[ $counter ] = array ( 'text' => "This works!\n\nAmazing!" );

$counter++;

Note how the widget identifier is created: the id_base, a minus - and the counter. The content of the widget is stored in another variable $demo_widget_content. Here is the counter the key and the widget arguments are stored in an array.

We increment the counter by one when we are done to avoid collisions.

That was easy. Now a RSS widget. More fields, more fun!

$active_widgets[ $sidebars['a'] ][] = 'rss-' . $counter;
// The latest 15 questions from WordPress Stack Exchange.
$rss_content[ $counter ] = array (
    'title'        => 'WordPress Stack Exchange',
    'url'          => 'http://wordpress.stackexchange.com/feeds',
    'link'         => 'http://wordpress.stackexchange.com/questions',
    'items'        => 15,
    'show_summary' => 0,
    'show_author'  => 1,
    'show_date'    => 1,
);
update_option( 'widget_rss', $rss_content );

$counter++;

Here is something new: update_option() this will store the RSS widget argument in a separate option. WordPress will find these automatically later.
We didn't save the demo widget arguments because we add a second instance to our second sidebar now …

// Okay, now to our second sidebar. We make it short.
$active_widgets[ $sidebars['b'] ][] = 't5_demo_widget-' . $counter;
#$demo_widget_content = get_option( 'widget_t5_demo_widget', array() );
$demo_widget_content[ $counter ] = array ( 'text' => 'The second instance of our amazing demo widget.' );
update_option( 'widget_t5_demo_widget', $demo_widget_content );

… and save all arguments for the t5_demo_widget in one rush. No need to update the same option two times.

Well, enough widgets for today, let's save the sidebars_widgets too:

update_option( 'sidebars_widgets', $active_widgets );

Now WordPress will know that there are some registered widgets and where the arguments for each widget are stored. A var_export() on the sidebar_widgets will look like this:

array (
  'wp_inactive_widgets' => 
  array (
  ),
  'top-widget' => 
  array (
    0 => 't5_demo_widget-1',
    1 => 'rss-2',
  ),
  'bottom-widget' => 
  array (
    0 => 't5_demo_widget-3',
  ),
  'array_version' => 3,
)

The complete code again:

add_action( 'widgets_init', 't5_default_widget_demo' );

function t5_default_widget_demo()
{
    // Register our own widget.
    register_widget( 'T5_Demo_Widget' );

    // Register two sidebars.
    $sidebars = array ( 'a' => 'top-widget', 'b' => 'bottom-widget' );
    foreach ( $sidebars as $sidebar )
    {
        register_sidebar(
            array (
                'name'          => $sidebar,
                'id'            => $sidebar,
                'before_widget' => '',
                'after_widget'  => ''
            )
        );
    }

    // Okay, now the funny part.

    // We don't want to undo user changes, so we look for changes first.
    $active_widgets = get_option( 'sidebars_widgets' );

    if ( ! empty ( $active_widgets[ $sidebars['a'] ] )
        or ! empty ( $active_widgets[ $sidebars['b'] ] )
    )
    {   // Okay, no fun anymore. There is already some content.
        return;
    }

    // The sidebars are empty, let's put something into them.
    // How about a RSS widget and two instances of our demo widget?

    // Note that widgets are numbered. We need a counter:
    $counter = 1;

    // Add a 'demo' widget to the top sidebar …
    $active_widgets[ $sidebars['a'] ][0] = 't5_demo_widget-' . $counter;
    // … and write some text into it:
    $demo_widget_content[ $counter ] = array ( 'text' => "This works!\n\nAmazing!" );
    #update_option( 'widget_t5_demo_widget', $demo_widget_content );

    $counter++;

    // That was easy. Now a RSS widget. More fields, more fun!
    $active_widgets[ $sidebars['a'] ][] = 'rss-' . $counter;
    // The latest 15 questions from WordPress Stack Exchange.
    $rss_content[ $counter ] = array (
        'title'        => 'WordPress Stack Exchange',
        'url'          => 'http://wordpress.stackexchange.com/feeds',
        'link'         => 'http://wordpress.stackexchange.com/questions',
        'items'        => 15,
        'show_summary' => 0,
        'show_author'  => 1,
        'show_date'    => 1,
    );
    update_option( 'widget_rss', $rss_content );

    $counter++;

    // Okay, now to our second sidebar. We make it short.
    $active_widgets[ $sidebars['b'] ][] = 't5_demo_widget-' . $counter;
    #$demo_widget_content = get_option( 'widget_t5_demo_widget', array() );
    $demo_widget_content[ $counter ] = array ( 'text' => 'The second instance of our amazing demo widget.' );
    update_option( 'widget_t5_demo_widget', $demo_widget_content );

    // Now save the $active_widgets array.
    update_option( 'sidebars_widgets', $active_widgets );
}

If you go to wp-admin/widgets.php now you will see three pre-set widgets:

screen shot of active widgets

And that's it. Use …

dynamic_sidebar( 'top-widget' );
dynamic_sidebar( 'bottom-widget' );

… to print the widgets out.

There is a small glitch: You have to load the front-end two times for the initial registration. If anyone can help out here I'll be very grateful.

share|improve this answer
    
This is really interesting .. but wouldn´t this code add a "new" widget in every page load `? also, another interesting issue is how can one control those widgets, including their content from within a plugin as opposed to theme ( loads earlier ? ) –  krembo99 Aug 3 '13 at 8:36
1  
@krembo99 The widgets are not added when the sidebars are not empty. The code works in a plugin exactly the same way. –  toscho Aug 3 '13 at 11:46
    
Top notch. Had to put my own spin on it but this helped a lot! –  Foxinni Oct 1 '13 at 11:06
add comment

This is how you do it:

    $widgets = array(
    'middle-sidebar' => array(
        'widget_name'
    ),
    'right-sidebar' => array(
        'widget2_name-1'
    )
);
update_option('sidebars_widgets', $widgets);

The -number can be used if you later want to add options to the widget with something like this:

    update_option('widget_widget_name', array(
    1 => array(
        'title' => 'The tile',
        'number' => 4
    ),
    '_multiwidget' => 1
));
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.