Programmatically‎ Creating a WordPress Widget Instance

Occasionally in WordPress development one finds the need to create an instance of a widget programmatically‎. I found a need for this when writing some unit tests for my WordPoints plugin. The code that you can use to do this is below. It shouldn’t be hard to understand its use.

/**
 * Programmatically save a new widget instance.
 *
 * Based on wp_ajax_save_widget().
 *
 * @param string $id_base    The base ID for instances of this widget.
 * @param array  $settings   The settings for this widget instance. Optional.
 * @param string $sidebar_id The ID of the sidebar to add the widget to. Optional.
 *
 * @return bool Whether the widget was saved successfully.
 */
function my_add_widget( $id_base, array $settings = array(), $sidebar_id = null ) {

	global $wp_registered_widget_updates;
	static $multi_number = 0;
	$multi_number++;

	$sidebars = wp_get_sidebars_widgets();

	if ( isset( $sidebar_id ) ) {

		$sidebar = ( isset( $sidebars[ $sidebar_id ] ) ) ? $sidebars[ $sidebar_id ] : array();

	} else {

		$sidebar_id = key( $sidebars );
		$sidebar = array_shift( $sidebars );
	}

	$sidebar[] = $id_base . '-' . $multi_number;

	$_POST['sidebar'] = $sidebar_id;
	$_POST[ "widget-{$id_base}" ] = array( $multi_number => $settings );
	$_POST['widget-id'] = $sidebar;

	if (
		! isset( $wp_registered_widget_updates[ $id_base ] )
		|| ! is_callable( $wp_registered_widget_updates[ $id_base ]['callback'] )
	) {

		return false;
	}

	$control = $wp_registered_widget_updates[ $id_base ];

	return call_user_func_array( $control['callback'], $control['params'] );
}

Example usage:

my_add_widget( 
	'rss'
	,array( 
		'title' => 'Test Widget', 
		'items' => 5, 
		'url'   => 'https://codesymphony.co/feed/' 
	)
	,'sidebar-1'
);

Enjoy!

10 thoughts on “Programmatically‎ Creating a WordPress Widget Instance

    1. J.D. Grimes

      You need to make sure that you have the correct sidebar ID. The 'sidebar-1' is just an example, you need to get the correct ID for the sidebar that you want to add the widget to.

      Reply
    1. J.D. Grimes

      Try changing this part of the function:

          if (
              ! isset( $wp_registered_widget_updates[ $id_base ] )
              || ! is_callable( $wp_registered_widget_updates[ $id_base ]['callback'] )
          ) {
               error_log( 'Failed here' ); // Added line
              return false;
          }
      

      This will tell you if the false return value is coming from there, if the error is logged. If the error is not logged, then the false is coming from the final line in the function, that calls the callback:

          return call_user_func_array( $control['callback'], $control['params'] );
      
      Reply
  1. Сергей

    Array ( [callback] => Array ( [0] => WP_Widget_Pages Object ( [id_base] => pages [name] => Страницы [option_name] => widget_pages [alt_option_name] => [widget_options] => Array ( [classname] => widget_pages [customize_selective_refresh] => 1 [description] => Список страниц вашего сайта. ) [control_options] => Array ( [id_base] => pages ) [number] => 1 [id] => pages-1 [updated] => ) [1] => update_callback ) [params] => Array ( [0] => Array ( [number] => -1 ) ) [id_base] => pages )

    Array ( [callback] => Array ( [0] => WP_Widget_Tag_Cloud Object ( [id_base] => tag_cloud [name] => Облако меток [option_name] => widget_tag_cloud [alt_option_name] => [widget_options] => Array ( [classname] => widget_tag_cloud [customize_selective_refresh] => 1 [description] => Облако часто используемых меток. ) [control_options] => Array ( [id_base] => tag_cloud ) [number] => 2 [id] => tag_cloud-2 [updated] => ) [1] => update_callback ) [params] => Array ( [0] => Array ( [number] => -1 ) ) [id_base] => tag_cloud )

    Array ( [callback] => Array ( [0] => WP_Widget_Calendar Object ( [id_base] => calendar [name] => Календарь [option_name] => widget_calendar [alt_option_name] => [widget_options] => Array ( [classname] => widget_calendar [customize_selective_refresh] => 1 [description] => Календарь записей вашего сайта. ) [control_options] => Array ( [id_base] => calendar ) [number] => 3 [id] => calendar-3 [updated] => ) [1] => update_callback ) [params] => Array ( [0] => Array ( [number] => -1 ) ) [id_base] => calendar )

    This is example for three wigets, one blog:

    $control = $wp_registered_widget_updates[ $id_base ];
    print_r($control);

    Reply
    1. J.D. Grimes

      Hmm… It seems like it should be working then. I guess that update_callback() does not actually return true on success, just null. Can you double-check that the widget is actually not being added?

      Reply
      1. Сергей

        Yes, I’m checking, but there’s really no widget ..
        http://df.ag007.ru/

        I’m test it:
        $good_need_wig = array();
        foreach($w_base_name_list as $wig){
        if(!$res = is_active_widget( 0, 0, $wig)){
        $good_need_wig[] = $wig;
        }
        }

        Such a list should be
        $w_base_name_list = array(‘search’, ‘recent-posts’, ‘pages’, ‘recent-comments’, ‘archives’, ‘categories’, ‘meta’, ‘tag_cloud’, ‘calendar’);

        Everything seems to work. BUT! Maybe I just can not apply it correctly for some reason …

        Reply

Leave a Reply

Your email address will not be published. Required fields are marked *