diff --git a/wp-admin/includes/widgets.php b/wp-admin/includes/widgets.php
index 6c53d843ba..be12a3f7bf 100644
--- a/wp-admin/includes/widgets.php
+++ b/wp-admin/includes/widgets.php
@@ -2,7 +2,7 @@
// $_search is unsanitized
function wp_list_widgets( $show = 'all', $_search = false ) {
- global $wp_registered_widgets, $sidebars_widgets;
+ global $wp_registered_widgets, $sidebars_widgets, $wp_registered_widget_controls;
if ( $_search ) {
// sanitize
$search = preg_replace( '/[^\w\s]/', '', $_search );
@@ -52,17 +52,31 @@ function wp_list_widgets( $show = 'all', $_search = false ) {
$widget_control_template = ob_get_contents();
ob_end_clean();
+ $widget_id = $widget['id']; // save this for later in case we mess with $widget['id']
+
$is_multi = false !== strpos( $widget_control_template, '%i%' );
if ( !$sidebar || $is_multi ) {
- if ( $is_multi )
- $already_shown[] = $widget['callback']; // it's a multi-widget. We only need to show it in the list once.
- $action = 'add';
- $add_url = wp_nonce_url( add_query_arg( array(
+ $add_query = array(
'sidebar' => $sidebar,
- 'add' => $widget['id'],
'key' => false,
'edit' => false
- ) ), "add-widget_$widget[id]" );
+ );
+ if ( $is_multi ) {
+ // it's a multi-widget. We only need to show it in the list once.
+ $already_shown[] = $widget['callback'];
+ $num = array_pop( explode( '-', $widget['id'] ) );
+ $id_base = $wp_registered_widget_controls[$widget['id']]['id_base'];
+ // so that we always add a new one when clicking "add"
+ while ( isset($wp_registered_widgets["$id_base-$num"]) )
+ $num++;
+ $widget['id'] = "$id_base-$num";
+ $add_query['base'] = $id_base;
+ $add_query['key'] = $num;
+ $add_query['sidebar'] = $GLOBALS['sidebar'];
+ }
+ $add_query['add'] = $widget['id'];
+ $action = 'add';
+ $add_url = wp_nonce_url( add_query_arg( $add_query ), "add-widget_$widget[id]" );
} else {
$action = 'edit';
$edit_url = clean_url( add_query_arg( array(
@@ -110,7 +124,7 @@ function wp_list_widgets( $show = 'all', $_search = false ) {
-
+
@@ -174,7 +188,7 @@ function wp_widget_control( $sidebar_args ) {
$key = $sidebar_id ? array_search( $widget_id, $sidebars_widgets[$sidebar_id] ) : 'no-key'; // position of widget in sidebar
- $edit = $edit_widget > 0 && $key && $edit_widget == $key; // (bool) are we currently editing this widget
+ $edit = -1 < $edit_widget && is_numeric($key) && $edit_widget === $key; // (bool) are we currently editing this widget
$id_format = $widget['id'];
// We aren't showing a widget control, we're outputing a template for a mult-widget control
@@ -240,7 +254,7 @@ function wp_widget_control( $sidebar_args ) {
- ">
+ ">
diff --git a/wp-admin/widgets.php b/wp-admin/widgets.php
index 07bfe9aaa1..4a8751d159 100644
--- a/wp-admin/widgets.php
+++ b/wp-admin/widgets.php
@@ -46,10 +46,11 @@ if ( empty( $sidebars_widgets ) )
if ( empty( $sidebars_widgets[$sidebar] ) )
$sidebars_widgets[$sidebar] = array();
-$http_post = ( 'POST' == $_SERVER['REQUEST_METHOD'] );
+$http_post = 'post' == strtolower($_SERVER['REQUEST_METHOD']);
// We're updating a sidebar
if ( $http_post && isset($sidebars_widgets[$_POST['sidebar']]) ) {
+ check_admin_referer( 'edit-sidebar_' . $_POST['sidebar'] );
/* Hack #1
* The widget_control is overloaded. It updates the widget's options AND echoes out the widget's HTML form.
@@ -81,7 +82,7 @@ if ( $http_post && isset($sidebars_widgets[$_POST['sidebar']]) ) {
if ( !$val )
unset($_POST['widget-id'][$key]);
- // Reset the key numbering and stare
+ // Reset the key numbering and store
$new_sidebar = isset( $_POST['widget-id'] ) && is_array( $_POST['widget-id'] ) ? array_values( $_POST['widget-id'] ) : array();
$sidebars_widgets[$_POST['sidebar']] = $new_sidebar;
wp_set_sidebars_widgets( $sidebars_widgets );
@@ -96,14 +97,65 @@ if ( $http_post && isset($sidebars_widgets[$_POST['sidebar']]) ) {
// What widget (if any) are we editing
$edit_widget = -1;
-$query_args = array('add', 'remove', 'key', 'edit', '_wpnonce', 'message' );
+$query_args = array('add', 'remove', 'key', 'edit', '_wpnonce', 'message', 'base' );
if ( isset($_GET['add']) && $_GET['add'] ) {
// Add to the end of the sidebar
+ $control_callback;
if ( isset($wp_registered_widgets[$_GET['add']]) ) {
check_admin_referer( "add-widget_$_GET[add]" );
$sidebars_widgets[$sidebar][] = $_GET['add'];
wp_set_sidebars_widgets( $sidebars_widgets );
+ } elseif ( isset($_GET['base']) && isset($_GET['key']) ) { // It's a multi-widget
+ check_admin_referer( "add-widget_$_GET[add]" );
+ // Copy minimal info from an existing instance of this widget to a new instance
+ foreach ( $wp_registered_widget_controls as $control ) {
+ if ( $_GET['base'] === $control['id_base'] ) {
+ $control_callback = $control['callback'];
+ $num = (int) $_GET['key'];
+ $control['params'][0]['number'] = $num;
+ $control['id'] = $control['id_base'] . '-' . $num;
+ $wp_registered_widget_controls[$control['id']] = $control;
+ $sidebars_widgets[$sidebar][] = $control['id'];
+ break;
+ }
+ }
+ }
+
+ // it's a multi-widget. The only way to add multi-widgets without JS is to actually submit POST content...
+ // so here we go
+ if ( is_callable( $control_callback ) ) {
+ require_once( 'admin-header.php' );
+ ?>
+
+
+
diff --git a/wp-includes/widgets.php b/wp-includes/widgets.php
index 750b7b28f2..92c048b205 100644
--- a/wp-includes/widgets.php
+++ b/wp-includes/widgets.php
@@ -1189,7 +1189,7 @@ function wp_widget_rss_control($widget_args) {
$show_author = 0;
$show_date = 0;
} else {
- extract( $options[$number] );
+ extract( (array) $options[$number] );
}
wp_widget_rss_form( compact( 'number', 'title', 'url', 'items', 'error', 'show_summary', 'show_author', 'show_date' ) );