Index: wp-includes/widgets.php
===================================================================
--- wp-includes/widgets.php	(revision 6555)
+++ wp-includes/widgets.php	(working copy)
@@ -2,13 +2,11 @@
 
 /* Global Variables */
 
-global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_styles, $wp_registered_widget_defaults;
+global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls;
 
 $wp_registered_sidebars = array();
 $wp_registered_widgets = array();
 $wp_registered_widget_controls = array();
-$wp_registered_widget_styles = array();
-$wp_register_widget_defaults = false;
 
 /* Template tags & API functions */
 
@@ -95,9 +93,8 @@
 }
 
 function wp_register_sidebar_widget($id, $name, $output_callback, $options = array()) {
+	global $wp_registered_widgets;
 
-	global $wp_registered_widgets, $wp_register_widget_defaults;
-
 	if ( empty($output_callback) ) {
 		unset($wp_registered_widgets[$id]);
 		return;
@@ -113,10 +110,20 @@
 	);
 	$widget = array_merge($widget, $options);
 
-	if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || !$wp_register_widget_defaults) )
+	if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) )
 		$wp_registered_widgets[$id] = $widget;
 }
 
+function wp_widget_description( $id ) {
+	if ( !is_scalar($id) )
+		return;
+
+	global $wp_registered_widgets;
+
+	if ( isset($wp_registered_widgets[$id]['description']) )
+		return wp_specialchars( $wp_registered_widgets[$id]['description'] );
+}
+
 function unregister_sidebar_widget($id) {
 	return wp_unregister_sidebar_widget($id);
 }
@@ -149,23 +156,27 @@
 	call_user_func_array('wp_register_widget_control', $args);
 }
 
+/* $options: height, width, id_base
+ *   height: never used
+ *   width:  width of fully expanded control form.  Try hard to use the default width.
+ *   id_base: for widgets which allow multiple instances (such as the text widget), an id_base must be provided.
+ *            the widget id will ennd up looking like {$id_base}-{$unique_number}
+ */
 function wp_register_widget_control($id, $name, $control_callback, $options = array()) {
-	global $wp_registered_widget_controls, $wp_register_widget_defaults;
+	global $wp_registered_widget_controls;
 
 	if ( empty($control_callback) ) {
 		unset($wp_registered_widget_controls[$id]);
 		return;
 	}
 
-	if ( isset($wp_registered_widget_controls[$id]) && $wp_register_widget_defaults )
+	if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
 		return;
 
-	$defaults = array('width' => 300, 'height' => 200);
+	$defaults = array('width' => 250, 'height' => 200 ); // height is never used
 	$options = wp_parse_args($options, $defaults);
 	$options['width'] = (int) $options['width'];
 	$options['height'] = (int) $options['height'];
-	$options['width'] = $options['width'] > 90 ? $options['width'] + 60 : 360;
-	$options['height'] = $options['height'] > 60 ? $options['height'] + 40 : 240;
 
 	$widget = array(
 		'name' => $name,
@@ -234,15 +245,17 @@
 	return $did_one;
 }
 
+/* @return mixed false if widget is not active or id of sidebar in which the widget is active
+ */
 function is_active_widget($callback) {
 	global $wp_registered_widgets;
 
 	$sidebars_widgets = wp_get_sidebars_widgets(false);
 
-	if ( is_array($sidebars_widgets) ) foreach ( $sidebars_widgets as $widgets )
+	if ( is_array($sidebars_widgets) ) foreach ( $sidebars_widgets as $sidebar => $widgets )
 		if ( is_array($widgets) ) foreach ( $widgets as $widget )
 			if ( $wp_registered_widgets[$widget]['callback'] == $callback )
-				return true;
+				return $sidebar;
 
 	return false;
 }
@@ -387,16 +400,22 @@
 	$title = attribute_escape($options['title']);
 	$exclude = attribute_escape( $options['exclude'] );
 ?>
-			<p><label for="pages-title"><?php _e('Title:'); ?> <input style="width: 250px;" id="pages-title" name="pages-title" type="text" value="<?php echo $title; ?>" /></label></p>
-			<p><label for="pages-sortby"><?php _e( 'Sort by:' ); ?>
-				<select name="pages-sortby" id="pages-sortby">
+		<p><label for="pages-title"><?php _e('Title:'); ?> <input class="widefat" id="pages-title" name="pages-title" type="text" value="<?php echo $title; ?>" /></label></p>
+		<p>
+			<label for="pages-sortby"><?php _e( 'Sort by:' ); ?>
+				<select name="pages-sortby" id="pages-sortby" class="widefat">
 					<option value="post_title"<?php selected( $options['sortby'], 'post_title' ); ?>><?php _e('Page title'); ?></option>
 					<option value="menu_order"<?php selected( $options['sortby'], 'menu_order' ); ?>><?php _e('Page order'); ?></option>
 					<option value="ID"<?php selected( $options['sortby'], 'ID' ); ?>><?php _e( 'Page ID' ); ?></option>
-				</select></label></p>
-			<p><label for="pages-exclude"><?php _e( 'Exclude:' ); ?> <input type="text" value="<?php echo $exclude; ?>" name="pages-exclude" id="pages-exclude" style="width: 180px;" /></label><br />
-			<small><?php _e( 'Page IDs, separated by commas.' ); ?></small></p>
-			<input type="hidden" id="pages-submit" name="pages-submit" value="1" />
+				</select>
+			</label>
+		</p>
+		<p>
+			<label for="pages-exclude"><?php _e( 'Exclude:' ); ?> <input type="text" value="<?php echo $exclude; ?>" name="pages-exclude" id="pages-exclude" class="widefat" /></label>
+			<br />
+			<small><?php _e( 'Page IDs, separated by commas.' ); ?></small>
+		</p>
+		<input type="hidden" id="pages-submit" name="pages-submit" value="1" />
 <?php
 }
 
@@ -463,9 +482,12 @@
 	$dropdown = $options['dropdown'] ? 'checked="checked"' : '';
 	$title = attribute_escape($options['title']);
 ?>
-			<p><label for="archives-title"><?php _e('Title:'); ?> <input style="width: 250px;" id="archives-title" name="archives-title" type="text" value="<?php echo $title; ?>" /></label></p>
-			<p style="text-align:right;margin-right:40px;"><label for="archives-count"><?php _e('Show post counts'); ?> <input class="checkbox" type="checkbox" <?php echo $count; ?> id="archives-count" name="archives-count" /></label></p>
-			<p style="text-align:right;margin-right:40px;"><label for="archives-dropdown"><?php _e('Display as a drop down'); ?> <input class="checkbox" type="checkbox" <?php echo $dropdown; ?> id="archives-dropdown" name="archives-dropdown" /></label></p>
+			<p><label for="archives-title"><?php _e('Title:'); ?> <input class="widefat" id="archives-title" name="archives-title" type="text" value="<?php echo $title; ?>" /></label></p>
+			<p>
+				<label for="archives-count"><input class="checkbox" type="checkbox" <?php echo $count; ?> id="archives-count" name="archives-count" /> <?php _e('Show post counts'); ?></label>
+				<br />
+				<label for="archives-dropdown"><input class="checkbox" type="checkbox" <?php echo $dropdown; ?> id="archives-dropdown" name="archives-dropdown" /> <?php _e('Display as a drop down'); ?></label>
+			</p>
 			<input type="hidden" id="archives-submit" name="archives-submit" value="1" />
 <?php
 }
@@ -499,7 +521,7 @@
 	}
 	$title = attribute_escape($options['title']);
 ?>
-			<p><label for="meta-title"><?php _e('Title:'); ?> <input style="width: 250px;" id="meta-title" name="meta-title" type="text" value="<?php echo $title; ?>" /></label></p>
+			<p><label for="meta-title"><?php _e('Title:'); ?> <input class="widefat" id="meta-title" name="meta-title" type="text" value="<?php echo $title; ?>" /></label></p>
 			<input type="hidden" id="meta-submit" name="meta-submit" value="1" />
 <?php
 }
@@ -527,14 +549,23 @@
 	}
 	$title = attribute_escape($options['title']);
 ?>
-			<p><label for="calendar-title"><?php _e('Title:'); ?> <input style="width: 250px;" id="calendar-title" name="calendar-title" type="text" value="<?php echo $title; ?>" /></label></p>
+			<p><label for="calendar-title"><?php _e('Title:'); ?> <input class="widefat" id="calendar-title" name="calendar-title" type="text" value="<?php echo $title; ?>" /></label></p>
 			<input type="hidden" id="calendar-submit" name="calendar-submit" value="1" />
 <?php
 }
 
-function wp_widget_text($args, $number = 1) {
-	extract($args);
+// See large comment section at end of this file
+function wp_widget_text($args, $widget_args = 1) {
+	extract( $args, EXTR_SKIP );
+	if ( is_numeric($widget_args) )
+		$widget_args = array( 'number' => $widget_args );
+	$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+	extract( $widget_args, EXTR_SKIP );
+
 	$options = get_option('widget_text');
+	if ( !isset($options[$number]) )
+		return;
+
 	$title = $options[$number]['title'];
 	$text = apply_filters( 'widget_text', $options[$number]['text'] );
 ?>
@@ -545,80 +576,98 @@
 <?php
 }
 
-function wp_widget_text_control($number) {
-	$options = $newoptions = get_option('widget_text');
+function wp_widget_text_control($widget_args) {
+	global $wp_registered_widgets;
+	static $updated = false;
+
+	if ( is_numeric($widget_args) )
+		$widget_args = array( 'number' => $widget_args );
+	$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+	extract( $widget_args, EXTR_SKIP );
+
+	$options = get_option('widget_text');
 	if ( !is_array($options) )
-		$options = $newoptions = array();
-	if ( $_POST["text-submit-$number"] ) {
-		$newoptions[$number]['title'] = strip_tags(stripslashes($_POST["text-title-$number"]));
-		$newoptions[$number]['text'] = stripslashes($_POST["text-text-$number"]);
-		if ( !current_user_can('unfiltered_html') )
-			$newoptions[$number]['text'] = stripslashes(wp_filter_post_kses($newoptions[$number]['text']));
-	}
-	if ( $options != $newoptions ) {
-		$options = $newoptions;
+		$options = array();
+
+	if ( !$updated && !empty($_POST['sidebar']) ) {
+		$sidebar = (string) $_POST['sidebar'];
+
+		$sidebars_widgets = wp_get_sidebars_widgets();
+		if ( isset($sidebars_widgets[$sidebar]) )
+			$this_sidebar =& $sidebars_widgets[$sidebar];
+		else
+			$this_sidebar = array();
+
+		foreach ( $this_sidebar as $_widget_id ) {
+			if ( 'wp_widget_text' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
+				$widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
+				unset($options[$widget_number]);
+			}
+		}
+
+		foreach ( (array) $_POST['widget-text'] as $widget_number => $widget_text ) {
+			$title = strip_tags(stripslashes($widget_text['title']));
+			if ( current_user_can('unfiltered_html') )
+				$text = stripslashes( $widget_text['text'] );
+			else
+				$text = stripslashes(wp_filter_post_kses( $widget_text['text'] ));
+			$options[$widget_number] = compact( 'title', 'text' );
+		}
+
 		update_option('widget_text', $options);
+		$updated = true;
 	}
-	$title = attribute_escape($options[$number]['title']);
-	$text = format_to_edit($options[$number]['text']);
-?>
-			<input style="width: 450px;" id="text-title-<?php echo $number; ?>" name="text-title-<?php echo $number; ?>" type="text" value="<?php echo $title; ?>" />
-			<textarea style="width: 450px; height: 280px;" id="text-text-<?php echo $number; ?>" name="text-text-<?php echo $number; ?>"><?php echo $text; ?></textarea>
-			<input type="hidden" id="text-submit-<?php echo "$number"; ?>" name="text-submit-<?php echo "$number"; ?>" value="1" />
-<?php
-}
 
-function wp_widget_text_setup() {
-	$options = $newoptions = get_option('widget_text');
-	if ( isset($_POST['text-number-submit']) ) {
-		$number = (int) $_POST['text-number'];
-		if ( $number > 9 ) $number = 9;
-		if ( $number < 1 ) $number = 1;
-		$newoptions['number'] = $number;
+	if ( -1 == $number ) {
+		$title = '';
+		$text = '';
+		$number = '%i%';
+	} else {
+		$title = attribute_escape($options[$number]['title']);
+		$text = format_to_edit($options[$number]['text']);
 	}
-	if ( $options != $newoptions ) {
-		$options = $newoptions;
-		update_option('widget_text', $options);
-		wp_widget_text_register($options['number']);
-	}
-}
-
-function wp_widget_text_page() {
-	$options = get_option('widget_text');
 ?>
-	<div class="wrap">
-		<form method="POST">
-			<h2><?php _e('Text Widgets'); ?></h2>
-			<p style="line-height: 30px;"><?php _e('How many text widgets would you like?'); ?>
-			<select id="text-number" name="text-number" value="<?php echo $options['number']; ?>">
-<?php for ( $i = 1; $i < 10; ++$i ) echo "<option value='$i' ".($options['number']==$i ? "selected='selected'" : '').">$i</option>"; ?>
-			</select>
-			<span class="submit"><input type="submit" name="text-number-submit" id="text-number-submit" value="<?php echo attribute_escape(__('Save')); ?>" /></span></p>
-		</form>
-	</div>
+		<p>
+			<input class="widefat" id="text-title-<?php echo $number; ?>" name="widget-text[<?php echo $number; ?>][title]" type="text" value="<?php echo $title; ?>" />
+			<textarea class="widefat" rows="16" cols="20" id="text-text-<?php echo $number; ?>" name="widget-text[<?php echo $number; ?>][text]"><?php echo $text; ?></textarea>
+			<input type="hidden" id="text-submit-<?php echo $number; ?>" name="text-submit-<?php echo $number; ?>" value="1" />
+		</p>
 <?php
 }
 
 function wp_widget_text_register() {
 	$options = get_option('widget_text');
-	$number = $options['number'];
-	if ( $number < 1 ) $number = 1;
-	if ( $number > 9 ) $number = 9;
-	$dims = array('width' => 460, 'height' => 350);
-	$class = array('classname' => 'widget_text');
-	for ($i = 1; $i <= 9; $i++) {
-		$name = sprintf(__('Text %d'), $i);
-		$id = "text-$i"; // Never never never translate an id
-		wp_register_sidebar_widget($id, $name, $i <= $number ? 'wp_widget_text' : /* unregister */ '', $class, $i);
-		wp_register_widget_control($id, $name, $i <= $number ? 'wp_widget_text_control' : /* unregister */ '', $dims, $i);
+	$widget_ops = array('classname' => 'widget_text', 'description' => __('Arbitrary text or HTML'));
+	$control_ops = array('width' => 460, 'height' => 350, 'id_base' => 'text');
+	$name = __('Text');
+
+	// If there are none, we register the widget's existance with a generic template
+	if ( !$options ) {
+		wp_register_sidebar_widget( 'text-1', $name, 'wp_widget_text', $widget_ops, array( 'number' => -1 ) );
+		wp_register_widget_control( 'text-1', $name, 'wp_widget_text_control', $control_ops, array( 'number' => -1 ) );
 	}
-	add_action('sidebar_admin_setup', 'wp_widget_text_setup');
-	add_action('sidebar_admin_page', 'wp_widget_text_page');
+
+	foreach ( array_keys($options) as $o ) {
+		// Old widgets can have null values for some reason
+		if ( !isset($options[$o]['title']) || !isset($options[$o]['text']) )
+			continue;
+		$id = "text-$o"; // Never never never translate an id
+		wp_register_sidebar_widget($id, $name, 'wp_widget_text', $widget_ops, array( 'number' => $o ));
+		wp_register_widget_control($id, $name, 'wp_widget_text_control', $control_ops, array( 'number' => $o ));
+	}
 }
 
-function wp_widget_categories($args, $number = 1) {
-	extract($args);
+// See large comment section at end of this file
+function wp_widget_categories($args, $widget_args = 1) {
+	extract($args, EXTR_SKIP);
+	if ( is_numeric($widget_args) )
+		$widget_args = array( 'number' => $widget_args );
+	$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+	extract($widget_args, EXTR_SKIP);
+
 	$options = get_option('widget_categories');
+	if ( !isset($options[$number]) )
+		return;
 
 	$c = $options[$number]['count'] ? '1' : '0';
 	$h = $options[$number]['hierarchical'] ? '1' : '0';
@@ -635,7 +684,8 @@
 		wp_dropdown_categories($cat_args . '&show_option_none= ' . __('Select Category'));
 ?>
 
-<script type='text/javascript'><!--
+<script type='text/javascript'>
+/* <![CDATA[ */
     var dropdown = document.getElementById("cat");
     function onCatChange() {
 		if ( dropdown.options[dropdown.selectedIndex].value > 0 ) {
@@ -643,7 +693,8 @@
 		}
     }
     dropdown.onchange = onCatChange;
---></script>
+/* ]]> */
+</script>
 
 <?php
 	} else {
@@ -657,97 +708,123 @@
 	echo $after_widget;
 }
 
-function wp_widget_categories_control( $number ) {
-	$options = $newoptions = get_option('widget_categories');
+function wp_widget_categories_control( $widget_args ) {
+	global $wp_registered_widgets;
+	static $updated = false;
 
-	if ( !is_array( $options ) ) {
-		$options = $newoptions = get_option( 'widget_categories' );
-	}
+	if ( is_numeric($widget_args) )
+		$widget_args = array( 'number' => $widget_args );
+	$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+	extract($widget_args, EXTR_SKIP);
 
-	if ( $_POST['categories-submit-' . $number] ) {
-		$newoptions[$number]['count'] = isset($_POST['categories-count-' . $number]);
-		$newoptions[$number]['hierarchical'] = isset($_POST['categories-hierarchical-' . $number]);
-		$newoptions[$number]['dropdown'] = isset($_POST['categories-dropdown-' . $number]);
-		$newoptions[$number]['title'] = strip_tags(stripslashes($_POST['categories-title-' . $number]));
-	}
+	$options = get_option('widget_categories');
 
-	if ( $options != $newoptions ) {
-		$options = $newoptions;
+	if ( !is_array( $options ) )
+		$options = array();
+
+	if ( !$updated && !empty($_POST['sidebar']) ) {
+		$sidebar = (string) $_POST['sidebar'];
+		
+		$sidebars_widgets = wp_get_sidebars_widgets();
+		if ( isset($sidebars_widgets[$sidebar]) )
+			$this_sidebar =& $sidebars_widgets[$sidebar];
+		else
+			$this_sidebar = array();
+		
+		foreach ( $this_sidebar as $_widget_id ) {
+			if ( 'wp_widget_categories' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
+				$widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
+				unset($options[$widget_number]);
+			}   
+		}
+
+		foreach ( (array) $_POST['widget-categories'] as $widget_number => $widget_cat ) {
+			$title = trim(strip_tags(stripslashes($widget_cat['title'])));
+			$count = isset($widget_cat['count']);
+			$hierarchical = isset($widget_cat['hierarchical']);
+			$dropdown = isset($widget_cat['dropdown']);
+			$options[$widget_number] = compact( 'title', 'count', 'hierarchical', 'dropdown' );
+		}
+
 		update_option('widget_categories', $options);
+		$updated = true;
 	}
 
-	$title = attribute_escape( $options[$number]['title'] );
+	if ( -1 == $number ) {
+		$title = '';
+		$count = false;
+		$hierarchical = false;
+		$dropdown = false;
+		$number = '%i%';
+	} else {
+		$title = attribute_escape( $options[$number]['title'] );
+		$count = (bool) $options[$number]['count'];
+		$hierarchical = (bool) $options[$number]['hierarchical'];
+		$dropdown = (bool) $options[$number]['dropdown'];
+	}
 ?>
-			<p><label for="categories-title-<?php echo $number; ?>">
-				<?php _e( 'Title:' ); ?> <input style="width:300px" id="categories-title-<?php echo $number; ?>" name="categories-title-<?php echo $number; ?>" type="text" value="<?php echo $title; ?>" />
-			</label></p>
+			<p>
+				<label for="categories-title-<?php echo $number; ?>">
+					<?php _e( 'Title:' ); ?> 
+					<input class="widefat" id="categories-title-<?php echo $number; ?>" name="widget-categories[<?php echo $number; ?>][title]" type="text" value="<?php echo $title; ?>" />
+				</label>
+			</p>
 
-			<p><label for="categories-dropdown-<?php echo $number; ?>">
-				<input type="checkbox" class="checkbox" id="categories-dropdown-<?php echo $number; ?>" name="categories-dropdown-<?php echo $number; ?>"<?php echo $options[$number]['dropdown'] ? ' checked="checked"' : ''; ?> /> <?php _e( 'Show as dropdown' ); ?>
-			</label></p>
+			<p>
+				<label for="categories-dropdown-<?php echo $number; ?>">
+					<input type="checkbox" class="checkbox" id="categories-dropdown-<?php echo $number; ?>" name="widget-categories[<?php echo $number; ?>][dropdown]"<?php checked( $dropdown, true ); ?> />
+					<?php _e( 'Show as dropdown' ); ?>
+				</label>
+				<br />
+				<label for="categories-count-<?php echo $number; ?>">
+					<input type="checkbox" class="checkbox" id="categories-count-<?php echo $number; ?>" name="widget-categories[<?php echo $number; ?>][count]"<?php checked( $count, true ); ?> />
+					<?php _e( 'Show post counts' ); ?>
+				</label>
+				<br />
+				<label for="categories-hierarchical-<?php echo $number; ?>">
+					<input type="checkbox" class="checkbox" id="categories-hierarchical-<?php echo $number; ?>" name="widget-categories[<?php echo $number; ?>][hierarchical]"<?php checked( $hierarchical, true ); ?> />
+					<?php _e( 'Show hierarchy' ); ?>
+				</label>
+			</p>
 
-			<p><label for="categories-count-<?php echo $number; ?>">
-				<input type="checkbox" class="checkbox" id="categories-count-<?php echo $number; ?>" name="categories-count-<?php echo $number; ?>"<?php echo $options[$number]['count'] ? ' checked="checked"' : ''; ?> /> <?php _e( 'Show post counts' ); ?>
-			</label></p>
-
-			<p><label for="categories-hierarchical-<?php echo $number; ?>">
-				<input type="checkbox" class="checkbox" id="categories-hierarchical-<?php echo $number; ?>" name="categories-hierarchical-<?php echo $number; ?>"<?php echo $options[$number]['hierarchical'] ? ' checked="checked"' : ''; ?> /> <?php _e( 'Show hierarchy' ); ?>
-			</label></p>
-
 			<input type="hidden" id="categories-submit-<?php echo $number; ?>" name="categories-submit-<?php echo $number; ?>" value="1" />
 <?php
 }
 
-function wp_widget_categories_setup() {
-	$options = $newoptions = get_option( 'widget_categories' );
+function wp_widget_categories_register() {
+	$options = get_option( 'widget_categories' );
+	if ( isset($options['title']) )
+		$options = wp_widget_categories_upgrade();
 
-	if ( isset( $_POST['categories-number-submit'] ) ) {
-		$number = (int) $_POST['categories-number'];
+	$widget_ops = array( 'classname' => 'widget_categories', 'description' => __( "A list or dropdown of categories" ) );
 
-		if ( $number > 9 ) {
-			$number = 9;
-		} elseif ( $number < 1 ) {
-			$number = 1;
-		}
+	$name = __( 'Categories' );
 
-		$newoptions['number'] = $number;
+	// If there are none, we register the widget's existance with a generic template
+	if ( !$options ) {
+		wp_register_sidebar_widget( 'categories-1', $name, 'wp_widget_categories', $widget_ops, array( 'number' => -1 ) );
+		wp_register_widget_control( 'categories-1', $name, 'wp_widget_categories_control', array( 'id_base' => 'categories' ), array( 'number' => -1 ) );
 	}
 
-	if ( $newoptions != $options ) {
-		$options = $newoptions;
-		update_option( 'widget_categories', $options );
-		wp_widget_categories_register( $options['number'] );
+	foreach ( array_keys($options) as $o ) {
+		// Old widgets can have null values for some reason
+		if ( !isset($options[$o]['title']) )
+			continue;
+		$id = "categories-$o";
+		wp_register_sidebar_widget( $id, $name, 'wp_widget_categories', $widget_ops, array( 'number' => $o ) );
+		wp_register_widget_control( $id, $name, 'wp_widget_categories_control', array( 'id_base' => 'categories' ), array( 'number' => $o ) );
 	}
-}
 
-function wp_widget_categories_page() {
-	$options = get_option( 'widget_categories' );
-?>
-	<div class="wrap">
-		<form method="post">
-			<h2><?php _e( 'Categories Widgets' ); ?></h2>
-			<p style="line-height: 30px;"><?php _e( 'How many categories widgets would you like?' ); ?>
-				<select id="categories-number" name="categories-number" value="<?php echo attribute_escape( $options['number'] ); ?>">
-					<?php
-						for ( $i = 1; $i < 10; $i++ ) {
-							echo '<option value="' . $i . '"' . ( $i == $options['number'] ? ' selected="selected"' : '' ) . '>' . $i . "</option>\n";
-						}
-					?>
-				</select>
-				<span class="submit">
-					<input type="submit" value="<?php echo attribute_escape( __( 'Save' ) ); ?>" id="categories-number-submit" name="categories-number-submit" />
-				</span>
-			</p>
-		</form>
-	</div>
-<?php
 }
 
 function wp_widget_categories_upgrade() {
 	$options = get_option( 'widget_categories' );
 
-	$newoptions = array( 'number' => 1, 1 => $options );
+	if ( !isset( $options['title'] ) )
+		return $options;
 
+	$newoptions = array( 1 => $options );
+
 	update_option( 'widget_categories', $newoptions );
 
 	$sidebars_widgets = get_option( 'sidebars_widgets' );
@@ -764,50 +841,9 @@
 			update_option( 'sidebars_widgets', $new_widgets );
 	}
 
-	if ( isset( $_POST['categories-submit'] ) ) {
-		$_POST['categories-submit-1'] = $_POST['categories-submit'];
-		$_POST['categories-count-1'] = $_POST['categories-count'];
-		$_POST['categories-hierarchical-1'] = $_POST['categories-hierarchical'];
-		$_POST['categories-dropdown-1'] = $_POST['categories-dropdown'];
-		$_POST['categories-title-1'] = $_POST['categories-title'];
-		foreach ( $_POST as $k => $v )
-			if ( substr($k, -5) == 'order' )
-				$_POST[$k] = str_replace('categories', 'categories-1', $v);
-	}
-
 	return $newoptions;
 }
 
-function wp_widget_categories_register() {
-	$options = get_option( 'widget_categories' );
-	if ( !isset($options['number']) )
-		$options = wp_widget_categories_upgrade();
-	$number = (int) $options['number'];
-
-	if ( $number > 9 ) {
-		$number = 9;
-	} elseif ( $number < 1 ) {
-		$number = 1;
-	}
-
-	$dims = array( 'width' => 350, 'height' => 170 );
-	$class = array( 'classname' => 'widget_categories' );
-
-	for ( $i = 1; $i <= 9; $i++ ) {
-		$name = sprintf( __( 'Categories %d' ), $i );
-		$id = 'categories-' . $i;
-
-		$widget_callback = ( $i <= $number ) ? 'wp_widget_categories' : '';
-		$control_callback = ( $i <= $number ) ? 'wp_widget_categories_control' : '';
-
-		wp_register_sidebar_widget( $id, $name, $widget_callback, $class, $i );
-		wp_register_widget_control( $id, $name, $control_callback, $dims, $i );
-	}
-
-	add_action( 'sidebar_admin_setup', 'wp_widget_categories_setup' );
-	add_action( 'sidebar_admin_page', 'wp_widget_categories_page' );
-}
-
 function wp_widget_recent_entries($args) {
 	if ( $output = wp_cache_get('widget_recent_entries') )
 		return print($output);
@@ -861,8 +897,13 @@
 	if ( !$number = (int) $options['number'] )
 		$number = 5;
 ?>
-			<p><label for="recent-entries-title"><?php _e('Title:'); ?> <input style="width: 250px;" id="recent-entries-title" name="recent-entries-title" type="text" value="<?php echo $title; ?>" /></label></p>
-			<p><label for="recent-entries-number"><?php _e('Number of posts to show:'); ?> <input style="width: 25px; text-align: center;" id="recent-entries-number" name="recent-entries-number" type="text" value="<?php echo $number; ?>" /></label> <?php _e('(at most 15)'); ?></p>
+
+			<p><label for="recent-entries-title"><?php _e('Title:'); ?> <input class="widefat" id="recent-entries-title" name="recent-entries-title" type="text" value="<?php echo $title; ?>" /></label></p>
+			<p>
+				<label for="recent-entries-number"><?php _e('Number of posts to show:'); ?> <input style="width: 25px; text-align: center;" id="recent-entries-number" name="recent-entries-number" type="text" value="<?php echo $number; ?>" /></label>
+				<br />
+				<small><?php _e('(at most 15)'); ?></small>
+			</p>
 			<input type="hidden" id="recent-entries-submit" name="recent-entries-submit" value="1" />
 <?php
 }
@@ -916,8 +957,12 @@
 	if ( !$number = (int) $options['number'] )
 		$number = 5;
 ?>
-			<p><label for="recent-comments-title"><?php _e('Title:'); ?> <input style="width: 250px;" id="recent-comments-title" name="recent-comments-title" type="text" value="<?php echo $title; ?>" /></label></p>
-			<p><label for="recent-comments-number"><?php _e('Number of comments to show:'); ?> <input style="width: 25px; text-align: center;" id="recent-comments-number" name="recent-comments-number" type="text" value="<?php echo $number; ?>" /></label> <?php _e('(at most 15)'); ?></p>
+			<p><label for="recent-comments-title"><?php _e('Title:'); ?> <input class="widefat" id="recent-comments-title" name="recent-comments-title" type="text" value="<?php echo $title; ?>" /></label></p>
+			<p>
+				<label for="recent-comments-number"><?php _e('Number of comments to show:'); ?> <input style="width: 25px; text-align: center;" id="recent-comments-number" name="recent-comments-number" type="text" value="<?php echo $number; ?>" /></label>
+				<br />
+				<small><?php _e('(at most 15)'); ?></small>
+			</p>
 			<input type="hidden" id="recent-comments-submit" name="recent-comments-submit" value="1" />
 <?php
 }
@@ -929,21 +974,30 @@
 }
 
 function wp_widget_recent_comments_register() {
-	$dims = array('width' => 320, 'height' => 90);
-	$class = array('classname' => 'widget_recent_comments');
-	wp_register_sidebar_widget('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments', $class);
-	wp_register_widget_control('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments_control', $dims);
+	$widget_ops = array('classname' => 'widget_recent_comments', 'description' => __( 'The most recent comments' ) );
+	wp_register_sidebar_widget('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments', $widget_ops);
+	wp_register_widget_control('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments_control');
 
 	if ( is_active_widget('wp_widget_recent_comments') )
 		add_action('wp_head', 'wp_widget_recent_comments_style');
 }
 
-function wp_widget_rss($args, $number = 1) {
-	require_once(ABSPATH . WPINC . '/rss.php');
-	extract($args);
+// See large comment section at end of this file
+function wp_widget_rss($args, $widget_args = 1) {
+	extract($args, EXTR_SKIP);
+	if ( is_numeric($widget_args) )
+		$widget_args = array( 'number' => $widegt_args );
+	$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+	extract($widget_args, EXTR_SKIP);
+
 	$options = get_option('widget_rss');
-	if ( isset($options['error']) && $options['error'] )
+
+	if ( !isset($options[$number]) )
 		return;
+
+	if ( isset($options[$number]['error']) && $options[$number]['error'] )
+		return;
+
 	$num_items = (int) $options[$number]['items'];
 	$show_summary = $options[$number]['show_summary'];
 	if ( empty($num_items) || $num_items < 1 || $num_items > 10 ) $num_items = 10;
@@ -952,6 +1006,9 @@
 		$url = substr($url, 1);
 	if ( empty($url) )
 		return;
+
+	require_once(ABSPATH . WPINC . '/rss.php');
+
 	$rss = fetch_rss($url);
 	$link = clean_url(strip_tags($rss->channel['link']));
 	while ( strstr($link, 'http') != $link )
@@ -1002,88 +1059,123 @@
 	echo $after_widget;
 }
 
-function wp_widget_rss_control($number) {
-	$options = $newoptions = get_option('widget_rss');
-	if ( $_POST["rss-submit-$number"] ) {
-		$newoptions[$number]['items'] = (int) $_POST["rss-items-$number"];
-		$url = sanitize_url(strip_tags(stripslashes($_POST["rss-url-$number"])));
-		$newoptions[$number]['title'] = trim(strip_tags(stripslashes($_POST["rss-title-$number"])));
-		if ( $url !== $options[$number]['url'] ) {
-			require_once(ABSPATH . WPINC . '/rss.php');
-			$rss = fetch_rss($url);
-			if ( is_object($rss) ) {
-				$newoptions[$number]['url'] = $url;
-				$newoptions[$number]['error'] = false;
-			} else {
-				$newoptions[$number]['error'] = true;
-				$newoptions[$number]['url'] = wp_specialchars(__('Error: could not find an RSS or ATOM feed at that URL.'), 1);
+function wp_widget_rss_control($widget_args) {
+	global $wp_registered_widgets;
+	static $updated = false;
+
+	if ( is_numeric($widget_args) )
+		$widget_args = array( 'number' => $widget_args );
+	$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+	extract($widget_args, EXTR_SKIP);
+
+	$options = get_option('widget_rss');
+	if ( !is_array($options) )
+		$options = array();
+
+	$urls = array();
+	foreach ( $options as $option )
+		if ( isset($option['url']) )
+			$urls[$option['url']] = true;
+
+	if ( !$updated && !empty($_POST['sidebar']) ) {
+		$sidebar = (string) $_POST['sidebar'];
+
+		$sidebars_widgets = wp_get_sidebars_widgets();
+		if ( isset($sidebars_widgets[$sidebar]) )
+			$this_sidebar =& $sidebars_widgets[$sidebar];
+		else
+			$this_sidebar = array();
+	
+		foreach ( $this_sidebar as $_widget_id ) {
+			if ( 'wp_widget_rss' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
+				$widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
+				unset($options[$widget_number]);
 			}
 		}
-	}
-	if ( $options != $newoptions ) {
-		$options = $newoptions;
+
+		foreach( (array) $_POST['widget-rss'] as $widget_number => $widget_rss ) {
+			$items = (int) $widget_rss['items'];
+			if ( $items < 1 )
+				$items = 10;
+			$url = sanitize_url(strip_tags(stripslashes($widget_rss['url'])));
+			$title = trim(strip_tags(stripslashes($widget_rss['title'])));
+
+			if ( !isset($urls[$url]) ) {
+				require_once(ABSPATH . WPINC . '/rss.php');
+				$rss = fetch_rss($url);
+				$error = false;
+				if ( !is_object($rss) ) {
+					$url = wp_specialchars(__('Error: could not find an RSS or ATOM feed at that URL.'), 1);
+					$error = sprintf(__('Error in RSS %1$d'), $widget_number );
+				}
+			}
+			$options[$widget_number] = compact( 'title', 'url', 'items', 'error' );
+		}
+
 		update_option('widget_rss', $options);
+		$updated = true;
 	}
-	$url = attribute_escape($options[$number]['url']);
-	$items = (int) $options[$number]['items'];
-	$title = attribute_escape($options[$number]['title']);
-	if ( empty($items) || $items < 1 ) $items = 10;
-?>
-			<p style="text-align:center;"><?php _e('Enter the RSS feed URL here:'); ?></p>
-			<input style="width: 400px;" id="rss-url-<?php echo "$number"; ?>" name="rss-url-<?php echo "$number"; ?>" type="text" value="<?php echo $url; ?>" />
-			<p style="text-align:center;"><?php _e('Give the feed a title (optional):'); ?></p>
-			<input style="width: 400px;" id="rss-title-<?php echo "$number"; ?>" name="rss-title-<?php echo "$number"; ?>" type="text" value="<?php echo $title; ?>" />
-			<p style="text-align:center; line-height: 30px;"><?php _e('How many items would you like to display?'); ?> <select id="rss-items-<?php echo $number; ?>" name="rss-items-<?php echo $number; ?>"><?php for ( $i = 1; $i <= 10; ++$i ) echo "<option value='$i' ".($items==$i ? "selected='selected'" : '').">$i</option>"; ?></select></p>
-			<input type="hidden" id="rss-submit-<?php echo "$number"; ?>" name="rss-submit-<?php echo $number; ?>" value="1" />
-<?php
-}
 
-function wp_widget_rss_setup() {
-	$options = $newoptions = get_option('widget_rss');
-	if ( isset($_POST['rss-number-submit']) ) {
-		$number = (int) $_POST['rss-number'];
-		if ( $number > 9 ) $number = 9;
-		if ( $number < 1 ) $number = 1;
-		$newoptions['number'] = $number;
+	if ( -1 == $number ) {
+		$title = '';
+		$url = '';
+		$items = 10;
+		$error = false;
+		$number = '%i%';
+	} else {
+		$title = attribute_escape($options[$number]['title']);
+		$url = attribute_escape($options[$number]['url']);
+		$items = (int) $options[$number]['items'];
+		if ( $items < 1 )
+			$items = 10;
+		$error = $options[$number]['error'];
 	}
-	if ( $options != $newoptions ) {
-		$options = $newoptions;
-		update_option('widget_rss', $options);
-		wp_widget_rss_register($options['number']);
-	}
-}
 
-function wp_widget_rss_page() {
-	$options = get_option('widget_rss');
 ?>
-	<div class="wrap">
-		<form method="POST">
-			<h2><?php _e('RSS Feed Widgets'); ?></h2>
-			<p style="line-height: 30px;"><?php _e('How many RSS widgets would you like?'); ?>
-			<select id="rss-number" name="rss-number" value="<?php echo $options['number']; ?>">
-<?php for ( $i = 1; $i < 10; ++$i ) echo "<option value='$i' ".($options['number']==$i ? "selected='selected'" : '').">$i</option>"; ?>
-			</select>
-			<span class="submit"><input type="submit" name="rss-number-submit" id="rss-number-submit" value="<?php echo attribute_escape(__('Save')); ?>" /></span></p>
-		</form>
-	</div>
+			<p>
+				<label for="rss-url-<?php echo $number; ?>"><?php _e('Enter the RSS feed URL here:'); ?>
+					<input class="widefat" id="rss-url-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][url]" type="text" value="<?php echo $url; ?>" />
+				</label>
+			</p>
+			<p>
+				<label for="rss-title-<?php echo $number; ?>"><?php _e('Give the feed a title (optional):'); ?>
+					<input class="widefat" id="rss-title-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][title]" type="text" value="<?php echo $title; ?>" />
+				</label>
+			</p>
+			<p>
+				<label for="rss-items-<?php echo $number; ?>"><?php _e('How many items would you like to display?'); ?>
+					<select id="rss-items-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][items]">
+						<?php
+							for ( $i = 1; $i <= 10; ++$i )
+								echo "<option value='$i' " . ( $items == $i ? "selected='selected'" : '' ) . ">$i</option>";
+						?>
+					</select>
+				</label>
+			</p>
+			<input type="hidden" id="rss-submit-<?php echo $number; ?>" name="rss-submit-<?php echo $number; ?>" value="1" />
 <?php
 }
 
 function wp_widget_rss_register() {
 	$options = get_option('widget_rss');
-	$number = $options['number'];
-	if ( $number < 1 ) $number = 1;
-	if ( $number > 9 ) $number = 9;
-	$dims = array('width' => 410, 'height' => 200);
-	$class = array('classname' => 'widget_rss');
-	for ($i = 1; $i <= 9; $i++) {
-		$name = sprintf(__('RSS %d'), $i);
-		$id = "rss-$i"; // Never never never translate an id
-		wp_register_sidebar_widget($id, $name, $i <= $number ? 'wp_widget_rss' : /* unregister */ '', $class, $i);
-		wp_register_widget_control($id, $name, $i <= $number ? 'wp_widget_rss_control' : /* unregister */ '', $dims, $i);
+	$widget_ops = array('classname' => 'widget_rss', 'description' => __( 'Entries from any RSS or Atom feed' ));
+	$control_ops = array('width' => 410, 'height' => 200, 'id_base' => 'rss');
+	$name = __('RSS');
+
+	// If there are none, we register the widget's existance with a generic template
+	if ( !$options ) {
+		wp_register_sidebar_widget( 'rss-1', $name, 'wp_widget_rss', $widget_ops, array( 'number' => -1 ) );
+		wp_register_widget_control( 'rss-1', $name, 'wp_widget_rss_control', $control_ops, array( 'number' => -1 ) );
 	}
-	add_action('sidebar_admin_setup', 'wp_widget_rss_setup');
-	add_action('sidebar_admin_page', 'wp_widget_rss_page');
+
+	foreach ( array_keys($options) as $o ) {
+		// Old widgets can have null values for some reason
+		if ( !isset($options[$o]['url']) || !isset($options[$o]['title']) || !isset($options[$o]['items']) )
+			contine;
+		$id = "rss-$o"; // Never never never translate an id
+		wp_register_sidebar_widget($id, $name, 'wp_widget_rss', $widget_ops, array( 'number' => $o ));
+		wp_register_widget_control($id, $name, 'wp_widget_rss_control', $control_ops, array( 'number' => $o ));
+	}
 }
 
 function wp_widget_tag_cloud($args) {
@@ -1112,7 +1204,7 @@
 	$title = attribute_escape( $options['title'] );
 ?>
 	<p><label for="tag-cloud-title">
-	<?php _e('Title:') ?> <input type="text" style="width:300px" id="tag-cloud-title" name="tag-cloud-title" value="<?php echo $title ?>" /></label>
+	<?php _e('Title:') ?> <input type="text" class="widefat" id="tag-cloud-title" name="tag-cloud-title" value="<?php echo $title ?>" /></label>
 	</p>
 	<input type="hidden" name="tag-cloud-submit" id="tag-cloud-submit" value="1" />
 <?php
@@ -1122,52 +1214,165 @@
 	if ( !is_blog_installed() )
 		return;
 
-	$GLOBALS['wp_register_widget_defaults'] = true;
+	$widget_ops = array('classname' => 'widget_pages', 'description' => __( "Your blog's WordPress Pages") );
+	wp_register_sidebar_widget('pages', __('Pages'), 'wp_widget_pages', $widget_ops);
+	wp_register_widget_control('pages', __('Pages'), 'wp_widget_pages_control' );
 
-	$dims90 = array( 'height' => 90, 'width' => 300 );
-	$dims100 = array( 'height' => 100, 'width' => 300 );
-	$dims150 = array( 'height' => 150, 'width' => 300 );
+	$widget_ops = array('classname' => 'widget_calendar', 'description' => __( "A calendar of your blog's posts") );
+	wp_register_sidebar_widget('calendar', __('Calendar'), 'wp_widget_calendar', $widget_ops);
+	wp_register_widget_control('calendar', __('Calendar'), 'wp_widget_calendar_control' );
 
-	$class = array('classname' => 'widget_pages');
-	wp_register_sidebar_widget('pages', __('Pages'), 'wp_widget_pages', $class);
-	wp_register_widget_control('pages', __('Pages'), 'wp_widget_pages_control', $dims150);
+	$widget_ops = array('classname' => 'widget_archive', 'description' => __( "A monthly archive of your blog's posts") );
+	wp_register_sidebar_widget('archives', __('Archives'), 'wp_widget_archives', $widget_ops);
+	wp_register_widget_control('archives', __('Archives'), 'wp_widget_archives_control' );
 
-	$class['classname'] = 'widget_calendar';
-	wp_register_sidebar_widget('calendar', __('Calendar'), 'wp_widget_calendar', $class);
-	wp_register_widget_control('calendar', __('Calendar'), 'wp_widget_calendar_control', $dims90);
+	$widget_ops = array('classname' => 'widget_links', 'description' => __( "Your blogroll") );
+	wp_register_sidebar_widget('links', __('Links'), 'wp_widget_links', $widget_ops);
 
-	$class['classname'] = 'widget_archives';
-	wp_register_sidebar_widget('archives', __('Archives'), 'wp_widget_archives', $class);
-	wp_register_widget_control('archives', __('Archives'), 'wp_widget_archives_control', $dims100);
+	$widget_ops = array('classname' => 'widget_meta', 'description' => __( "Log in/out, admin, feed and WordPress links") );
+	wp_register_sidebar_widget('meta', __('Meta'), 'wp_widget_meta', $widget_ops);
+	wp_register_widget_control('meta', __('Meta'), 'wp_widget_meta_control' );
 
-	$class['classname'] = 'widget_links';
-	wp_register_sidebar_widget('links', __('Links'), 'wp_widget_links', $class);
+	$widget_ops = array('classname' => 'widget_search', 'description' => __( "A search form for your blog") );
+	wp_register_sidebar_widget('search', __('Search'), 'wp_widget_search', $widget_ops);
 
-	$class['classname'] = 'widget_meta';
-	wp_register_sidebar_widget('meta', __('Meta'), 'wp_widget_meta', $class);
-	wp_register_widget_control('meta', __('Meta'), 'wp_widget_meta_control', $dims90);
+	$widget_ops = array('classname' => 'widget_recent_entries', 'description' => __( "The most recent posts on your blog") );
+	wp_register_sidebar_widget('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries', $widget_ops);
+	wp_register_widget_control('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries_control' );
 
-	$class['classname'] = 'widget_search';
-	wp_register_sidebar_widget('search', __('Search'), 'wp_widget_search', $class);
+	$widget_ops = array('classname' => 'widget_tag_cloud', 'description' => __( "Your most used tags in cloud format") );
+	wp_register_sidebar_widget('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud', $widget_ops);
+	wp_register_widget_control('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud_control' );
 
-	$class['classname'] = 'widget_recent_entries';
-	wp_register_sidebar_widget('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries', $class);
-	wp_register_widget_control('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries_control', $dims90);
-
-	$class['classname'] = 'widget_tag_cloud';
-	wp_register_sidebar_widget('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud', $class);
-	wp_register_widget_control('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud_control', 'width=300&height=160');
-
 	wp_widget_categories_register();
 	wp_widget_text_register();
 	wp_widget_rss_register();
 	wp_widget_recent_comments_register();
 
-	$GLOBALS['wp_register_widget_defaults'] = false;
-
 	do_action('widgets_init');
 }
 
 add_action('init', 'wp_widgets_init', 1);
 
+/* Pattern for widget which allows multiple instances (such as the text widget)
+
+// Displays widget on blag
+// $widget_args: number
+//    number: which of the several widgets of this type do we mean
+function widget_many( $args, $widget_args = 1 ) {
+	extract( $args, EXTR_SKIP );
+	if ( is_numeric($widget_args) )
+		$widget_args = array( 'number' => $widget_args );
+	$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+	extract( $widget_args, EXTR_SKIP );
+	
+	// Data should be stored as array:  array( number => data for that instance of the widget, ... )
+	$options = get_option('widget_many');
+	if ( !isset($options[$number]) )
+		return;
+
+	echo $before_widget;
+
+	// Do stuff for this widget, drawing data from $options[$number]
+
+	echo $after_widget;
+}
+
+// Displays form for a particular instance of the widget.  Also updates the data after a POST submit
+// $widget_args: number
+//    number: which of the several widgets of this type do we mean
+function widget_many_control( $widget_args = 1 ) {
+	global $wp_registered_widgets;
+	static $updated = false; // Whether or not we have already updated the data after a POST submit
+
+	if ( is_numeric($widget_args) )
+		$widget_args = array( 'number' => $widget_args );
+	$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+	extract( $widget_args, EXTR_SKIP );
+
+	// Data should be stored as array:  array( number => data for that instance of the widget, ... )
+	$options = get_option('widget_many');
+	if ( !is_array($options) )
+		$options = array();
+
+	// We need to update the data
+	if ( !$updated && !empty($_POST['sidebar']) ) {
+		// Tells us what sidebar to put the data in
+		$sidebar = (string) $_POST['sidebar'];
+
+		$sidebars_widgets = wp_get_sidebars_widgets();
+		if ( isset($sidebars_widgets[$sidebar]) )
+			$this_sidebar =& $sidebars_widgets[$sidebar];
+		else
+			$this_sidebar = array();
+
+		foreach ( $this_sidebar as $_widget_id ) {
+			// Remove all widgets of this type from the sidebar.  We'll add the new data in a second.  This makes sure we don't get any duplicate data
+			// since widget ids aren't necessarily persistent across multiple updates
+			if ( 'widget_many' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
+				$widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
+				unset($options[$widget_number]);
+			}
+		}
+
+		foreach ( (array) $_POST['widget-many'] as $widget_number => $widget_many_instance ) {
+			// compile data from $widget_many_instance
+			$something = wp_specialchars( $widget_many_instance['something'] );
+			$options[$widget_number] = array( 'something' => $something );  // Even simple widgets should store stuff in array, rather than in scalar
+		}
+
+		update_option('widget_text', $options);
+
+		$updated = true; // So that we don't go through this more than once
+	}
+
+
+	// Here we echo out the form
+	if ( -1 == $number ) { // We echo out a template for a form which can be converted to a specific form later via JS
+		$something = '';
+		$number = '%i%';
+	} else {
+		$something = attribute_escape($options[$number]['something']);
+	}
+
+	// The form has inputs with names like widget-many[$number][something] so that all data for that instance of
+	// the widget are stored in one $_POST variable: $_POST['widget-many'][$number]
 ?>
+		<p>
+			<input class="widefat" id="widget-many-something-<?php echo $number; ?>" name="widget-many[<?php echo $number; ?>][something]" type="text" value="<?php echo $data; ?>" />
+			<input type="hidden" id="widget-many-submit-<?php echo $number; ?>" name="widget-many-<?php echo $number; ?>" value="1" />
+		</p>
+<?php
+}
+
+// Registers each instance of our widget on startup
+function widget_many_register() {
+	$options = get_option('widget_many');
+	$widget_ops = array('classname' => 'widget_many', 'description' => __('Widget which allows multiple instances'));
+	$control_ops = array('width' => 400, 'height' => 350, 'id_base' => 'many');
+	$name = __('Many');
+
+	// If there are none, we register the widget's existance with a generic template
+	if ( !$options ) {
+		wp_register_sidebar_widget( 'many-1', $name, 'widget_many', $widget_ops, array( 'number' => -1 ) );
+		wp_register_widget_control( 'many-1', $name, 'widget_many_control', $control_ops, array( 'number' => -1 ) );
+	}
+
+	foreach ( array_keys($options) as $o ) {
+		// Old widgets can have null values for some reason
+		if ( !isset($options[$o]['something']) ) // we used 'something' above in our exampple.  Replace with with whatever your real data are.
+			continue;
+
+		// $id should look like {$id_base}-{$o}
+		$id = "many-$o"; // Never never never translate an id
+		wp_register_sidebar_widget( $id, $name, 'wp_widget_text', $widget_ops, array( 'number' => $o ) );
+		wp_register_widget_control( $id, $name, 'wp_widget_text_control', $control_ops, array( 'number' => $o ) );
+	}
+}
+
+// This is important
+add_action( 'widgets_init', 'widget_many_register' )
+
+*/
+
+?>
Index: wp-includes/script-loader.php
===================================================================
--- wp-includes/script-loader.php	(revision 6555)
+++ wp-includes/script-loader.php	(working copy)
@@ -79,7 +79,7 @@
 
 		$this->add( 'jquery', '/wp-includes/js/jquery/jquery.js', false, '1.1.4');
 		$this->add( 'jquery-form', '/wp-includes/js/jquery/jquery.form.js', array('jquery'), '1.0.3');
-		$this->add( 'interface', '/wp-includes/js/jquery/interface.js', array('jquery'), '1.2');
+		$this->add( 'interface', '/wp-includes/js/jquery/interface.js', array('jquery'), '1.2' );
 		$this->add( 'dimensions', '/wp-includes/js/jquery/jquery.dimensions.min.js', array('jquery'), '1.1.2');
 		$this->add( 'suggest', '/wp-includes/js/jquery/suggest.js', array('dimensions'), '1.1');
 		$this->add( 'schedule', '/wp-includes/js/jquery/jquery.schedule.js', array('jquery'), '20');
@@ -143,6 +143,7 @@
 				'saveText' => attribute_escape(__('Save &raquo;')),
 				'confirmText' => __("Are you sure you want to delete the file '%title%'?\nClick ok to delete or cancel to go back.")
 			) );
+			$this->add( 'admin-widgets', '/wp-admin/js/widgets.js', array( 'interface' ), mt_rand() );
 		}
 	}
 
Index: wp-admin/admin-ajax.php
===================================================================
--- wp-admin/admin-ajax.php	(revision 6555)
+++ wp-admin/admin-ajax.php	(working copy)
@@ -1,9 +1,9 @@
 <?php
+define('DOING_AJAX', true);
+
 require_once('../wp-config.php');
 require_once('includes/admin.php');
 
-define('DOING_AJAX', true);
-
 if ( !is_user_logged_in() )
 	die('-1');
 
Index: wp-admin/includes/widgets.php
===================================================================
--- wp-admin/includes/widgets.php	(revision 0)
+++ wp-admin/includes/widgets.php	(revision 0)
@@ -0,0 +1,368 @@
+<?php
+
+// $_search is unsanitized
+function wp_list_widgets( $show = 'all', $_search = false ) {
+	global $wp_registered_widgets, $sidebars_widgets;
+	if ( $_search ) {
+		// sanitize
+		$search = preg_replace( '/[^\w\s]/', '', $_search );
+		// array of terms
+		$search_terms = preg_split( '/[\s]/', $search, -1, PREG_SPLIT_NO_EMPTY );
+	} else {
+		$search_terms = array();
+	}
+
+	if ( !in_array( $show, array( 'all', 'unused', 'used' ) ) )
+		$show = 'all';
+?>
+
+	<ul id='widget-list'>
+		<?php
+		$no_widgets_shown = true;
+		$already_shown = array();
+		foreach ( $wp_registered_widgets as $name => $widget ) :
+			if ( in_array( $widget['callback'], $already_shown ) )
+				continue;
+			$already_shown[] = $widget['callback'];
+
+			if ( $search_terms ) {
+				$hit = false;
+				// Simple case-insensitive search.  Boolean OR.
+				$search_text = preg_replace( '/[^\w]/', '', $widget['name'] );
+				if ( isset($widget['description']) )
+					$search_text .= preg_replace( '/[^\w]/', '', $widget['description'] );
+
+				foreach ( $search_terms as $search_term ) {
+					if ( stristr( $search_text, $search_term ) ) {
+						$hit = true;
+						break;
+					}
+				}
+				if ( !$hit )
+					continue;
+			}
+
+			$sidebar = is_active_widget( $widget['callback'] );
+			if ( ( 'unused' == $show && $sidebar ) || ( 'used' == $show && !$sidebar ) )
+				continue;
+
+			ob_start();
+				wp_widget_control( 'no-key', $widget['id'], 'template' );
+			$widget_control_template = ob_get_contents();
+			ob_end_clean();
+
+			if ( !$sidebar || false !== strpos( $widget_control_template, '%i%' ) ) {
+				$action = 'add'; 
+				$add_url = wp_nonce_url( add_query_arg( array(
+					'sidebar' => $sidebar,
+					'add' => $widget['id'],
+					'key' => false,
+					'edit' => false
+				) ), "add-widget_$widget[id]" );
+			} else {
+				$action = 'edit';
+				$edit_url = add_query_arg( array(
+					'sidebar' => $sidebar,
+					'edit' => $widget['id'],
+					'key' => array_search( $widget['id'], $sidebars_widgets[$sidebar] ),
+				) );
+				$widget_control_template = "<textarea>$widget_control_template</textarea>";
+			}
+
+			$no_widgets_shown = false;
+
+		?>
+
+		<li id="widget-list-item-<?php echo attribute_escape( $widget['id'] ); ?>" class="widget-list-item">
+			<h4 class="widget-title widget-draggable">
+
+				<?php echo wp_specialchars( $widget['name'] ); ?>
+
+				<?php if ( 'add' == $action ) : ?>
+
+				<a class="widget-action widget-control-add" href="<?php echo $add_url; ?>"><?php _e( 'Add' ); ?></a>
+
+				<?php elseif ( 'edit' == $action ) :
+					// We echo a hidden edit link for the sake of the JS.  Edit links are shown (needlessly?) after a widget is added.
+				?>
+
+				<a class="widget-action widget-control-edit" href="<?php echo $edit_url; ?>" style="display: none;"><?php _e( 'Edit' ); ?></a>
+
+				<?php endif; ?>
+
+			</h4>
+
+
+			<ul id="widget-control-info-<?php echo $widget['id']; ?>" class="widget-control-info">
+
+				<?php echo $widget_control_template; ?>
+
+			</ul>
+
+			<?php if ( 'add' == $action ) : ?>
+			<?php endif; ?>
+
+			<div class="widget-description">
+				<?php echo wp_widget_description( $widget['id'] ); ?>
+			</div>
+
+			<br class="clear" />
+
+		</li>
+
+		<?php endforeach; if ( $no_widgets_shown ) : ?>
+		
+		<li><?php _e( 'No matching widgets' ); ?></li>
+
+		<?php endif; ?>
+
+	</ul>
+<?php
+}
+
+function wp_list_widget_controls( $widgets, $edit_widget = -1 ) {
+?>
+
+		<ul class="widget-control-list">
+
+<?php
+	foreach ( $widgets as $key => $widget )
+		wp_widget_control( $key, $widget, $key == $edit_widget ? 'edit' : 'display' );
+?>
+
+		</ul>
+
+<?php
+}
+
+
+/*
+ * Displays the control form for widget of type $widget at position $key.
+ * $display
+ *  == 'display': Normal, "closed" form.
+ *  == 'edit': "open" form
+ *  == 'template': generates a form template to be used by JS
+ */
+function wp_widget_control( $key, $widget, $display = 'display' ) {
+	static $i = 0;
+	global $wp_registered_widgets, $wp_registered_widget_controls;
+	$control = $wp_registered_widget_controls[$widget];
+	$widget  = $wp_registered_widgets[$widget];
+
+	$id_format = $widget['id'];
+	if ( 'template' == $display && isset($control['params'][0]['number']) ) {
+		// number == -1 implies a template where id numbers are replaced by a generic '%i%'
+		$control['params'][0]['number'] = -1;
+		// if given, id_base means widget id's should be constructed like {$id_base}-{$id_number}
+		if ( isset($control['id_base']) )
+			$id_format = $control['id_base'] . '-%i%';
+	}
+?>
+
+		<li id="widget-list-control-item-<?php echo ++$i; ?>-<?php echo $widget['id']; ?>" class="widget-list-control-item widget-sortable">
+			<h4 class="widget-title">
+
+				<?php echo $widget['name']; // TODO: Up/Down links for noJS reordering? ?>
+
+				<?php if ( 'edit' == $display ) : ?>
+
+				<a class="widget-action widget-control-edit" href="<?php echo remove_query_arg( array( 'edit', 'key' ) ); ?>"><?php _e('Cancel'); ?></a>
+
+				<?php else : ?>
+
+				<a class="widget-action widget-control-edit" href="<?php echo add_query_arg( array( 'edit' => $id_format, 'key' => $key ) ); ?>"><?php _e('Edit'); ?></a>
+
+				<?php endif; ?>
+
+			</h4>
+
+			<div class="widget-control"<?php if ( 'edit' == $display ) echo ' style="display: block;"'; ?>>
+
+				<?php
+				if ( $control )
+					call_user_func_array( $control['callback'], $control['params'] );
+				else
+					echo '<p>' . __('There are no options for this widget.') . '</p>';
+				?>
+
+				<input type="hidden" name="widget-id[]" value="<?php echo $id_format; ?>" />
+				<input type="hidden" class="widget-width" value="<?php echo $control['width']; ?>" />
+
+				<div class="widget-control-actions">
+
+					<?php if ( $control && 'edit' != $display ) : ?>
+
+					<a class="widget-action widget-control-save edit alignleft" href="#save:<?php echo $id_format; ?>"><?php _e('Save'); ?></a>
+
+					<?php endif; ?>
+
+					<a class="widget-action widget-control-remove delete alignright" href="<?php echo add_query_arg( array( 'remove' => $id_format, 'key' => $key ), wp_nonce_url( null, "remove-widget_$widget[id]" ) ); ?>"><?php _e('Remove'); ?></a>
+					<br class="clear" />
+				</div>
+			</div>
+		</li>
+
+<?php
+}
+
+function temp_widget_css() {
+?>
+
+<style type="text/css">
+/* 2 column liquid layout */
+div.widget-liquid-left-holder {
+	float: left;
+	clear: left;
+	width: 100%;
+	margin-right: -310px;
+}
+
+div.widget-liquid-left {
+	margin-right: 310px;
+}
+
+div.widget-liquid-right {
+	float: right;
+	clear: right;
+	width: 300px;
+}
+
+p.submit {
+	clear: both;
+}
+
+/* pasitioning etc. */
+form#widgets-filter {
+	position: relative;
+}
+
+p#widget-search {
+	position: absolute;
+	right: 0;
+	top: 0;
+	margin: 0;
+}
+
+ul#widget-list {
+	list-style: none;
+	margin: 0;
+	padding: 0;
+}
+
+ul#widget-list li.widget-list-item {
+	padding: .7em 1em;
+	margin: 0;
+	border-top:    1px solid #ccc;
+	border-bottom: 1px solid #ccc;
+	background-color: transparent;
+	line-height: 1;
+}
+
+ul#widget-list li.widget-list-item h4.widget-title {
+	position: relative;
+	margin: 0;
+	padding: .5em 1em;
+	width: 200px;
+	float: left;
+	background-color: #ccc;
+	color: #000;
+}
+
+#dragHelper h4.widget-title {
+	color: #fff;
+	background-color: #2683ae;
+	padding: .5em 1em;
+	margin: 0;
+}
+
+ul#widget-list li.widget-list-item div.widget-description {
+	display: block;
+	margin: 0 0 0 200px;
+	padding: 0 0 0 4em;
+}
+
+
+ul#widget-list li.widget-list-item ul.widget-control-info {
+	display: none;
+}
+
+div#sidebar-info {
+	padding: 0 1em;
+	margin-bottom: 1em;
+}
+
+ul.widget-control-list {
+	list-style: none;
+	margin: 0;
+	padding: 0 1em;
+}
+
+li.widget-list-control-item {
+	background-color: #eaf3fa;
+	margin: 0 0 1em;
+}
+
+li.widget-list-control-item h4, #dragHelper li.widget-list-control-item h4 {
+	position: relative;
+	margin: 0;
+	background-color: #2683ae;
+	padding: .5em 1em;
+	color: #fff;
+}
+
+div.widget-control a.widget-action, div.widget-control a.widget-action:hover {
+	padding: .5em 1em;
+}
+
+h4.widget-title a {
+	position: absolute;
+	right: 1em;
+	text-decoration: underline;
+	border-bottom: none;
+}
+
+li.widget-list-control-item h4.widget-title a, li.widget-list-control-item h4.widget-title a:visited {
+	color: #fff;
+}
+
+li.widget-list-control-item h4.widget-title a:hover {
+	color: #fff;
+	text-decoration: none;
+	border-bottom: none;
+}
+
+li.widget-list-control-item div.widget-control {
+	display: none;
+	margin: 1em;
+	padding: 0 10px 0 0; /* Correction for padding, margin, border of inputs */
+}
+
+li.widget-list-control-item div.widget-control p {
+	margin: 0 0 1em;
+	padding: 0;
+}
+
+ul.widget-control-list div.widget-control-actions {
+	margin-right: -10px; /* Correction for padding, margin, border of inputs */
+	padding: 0 0 1em;
+}
+
+ul.widget-control-list .sorthelper {
+	background-color: #ccf3fa;
+
+}
+
+#current-widgets .drop-widget-here {
+	background-color: #ffc
+}
+
+ul.widget-control-list select option {
+}
+</style>
+
+<?php
+}
+
+add_action( 'admin_head', 'temp_widget_css' );
+
+?>
Index: wp-admin/includes/admin.php
===================================================================
--- wp-admin/includes/admin.php	(revision 6555)
+++ wp-admin/includes/admin.php	(working copy)
@@ -13,6 +13,7 @@
 require_once(ABSPATH . 'wp-admin/includes/theme.php');
 require_once(ABSPATH . 'wp-admin/includes/user.php');
 require_once(ABSPATH . 'wp-admin/includes/update.php');
+require_once(ABSPATH . 'wp-admin/includes/widgets.php');
 
 require_once(ABSPATH . WPINC . '/registration.php');
 
Index: wp-admin/js/widgets.js
===================================================================
--- wp-admin/js/widgets.js	(revision 0)
+++ wp-admin/js/widgets.js	(revision 0)
@@ -0,0 +1,112 @@
+jQuery(function($) {
+	$('.noscript-action').remove();
+
+	// TODO: i18n
+	var addText  = 'Add';
+	var editText = 'Edit';
+	var cancText = 'Cancel';
+	var increment = 1;
+
+	// Open or close widget control form
+	var toggleWidget = function( li ) {
+		var width = li.find('input.widget-width').val();
+		return li.children('div.widget-control').each( function() {
+			var t = $(this);
+			if ( t.is(':visible') ) {
+				t.animate( { height: 'hide' } );
+				if ( width > 250 )
+					li.animate( { marginLeft: 0 } );
+				t.siblings('h4').children('a').text( editText );
+			} else {
+				t.animate( { height: 'show' } );
+				if ( width > 250 )
+					li.animate( { marginLeft: ( width - 250 ) * -1 } );
+				t.siblings('h4').children('a').text( cancText );
+			}
+		} ).end();
+	};
+
+	// onclick for edit links
+	var editClick = function() {
+		var q = wpAjax.unserialize( this.href );
+		// if link is in available widgets list, make sure it points to the current sidebar
+		if ( ( q.sidebar && q.sidebar == $('#sidebar').val() ) || q.add ) {
+			var w = q.edit || q.add;
+			toggleWidget( $('#current-sidebar .widget-control-list input[@name^="widget-id"][@value=' + w + ']').parents('li:first') ).blur();
+			return false;
+		} else if ( q.sidebar ) { // otherwise, redirect to correct page
+			return true;
+		}
+
+		// If link is in current widgets list, just open the form
+		toggleWidget( $(this).parents('li:first') ).blur();
+		return false;
+	};
+
+	// onclick for add links
+	var addClick = function() {
+		var oldLi = $(this).parents('li:first').find('ul.widget-control-info li');
+		var newLi = oldLi.clone();
+
+		if ( newLi.html().match( /%i%/ ) ) {
+			// supplid form is a template, replace %i% by unique id
+			var i = $('#generated-time').val() + increment.toString();
+			increment++;
+			newLi.html( newLi.html().replace( /%i%/g, i ) );
+		} else {
+			$(this).text( editText ).unbind().click( editClick );
+			// save form content in textarea so we don't have any conflicting HTML ids
+			oldLi.html( '<textarea>' + oldLi.html() + '</textarea>' );
+		}
+
+		// add event handlers
+		addWidgetControls( newLi );
+
+		// add widget to sidebar sortable
+		widgetSortable.append( newLi ).SortableAddItem( newLi[0] );
+
+		// increment widget counter
+		var n = parseInt( $('#widget-count').text(), 10 ) + 1;
+		$('#widget-count').text( n.toString() )
+
+		return false;
+	};
+
+	// add event handlers to all links found in context
+	var addWidgetControls = function( context ) {
+		if ( !context )
+			context = document;
+		
+		$('a.widget-control-edit', context).click( editClick );
+
+		// onclick for save links
+		$('a.widget-control-save', context).click( function() {
+			toggleWidget( $(this).parents('li:first') ).blur()
+			return false;
+		} );
+
+		// onclick for remove links
+		$('a.widget-control-remove', context).click( function() {
+			var w = $(this).parents('li:first').find('input[@name^="widget-id"]').val();
+			$(this).parents('li:first').remove();
+			var t = $('#widget-list ul#widget-control-info-' + w + ' textarea');
+			t.parent().html( t.text() ).parents('li.widget-list-item:first').children( 'h4' ).children('a.widget-action')
+				.show().text( addText ).unbind().click( addClick );
+			var n = parseInt( $('#widget-count').text(), 10 ) - 1;
+			$('#widget-count').text( n.toString() )
+			return false;
+		} );
+	}
+
+	addWidgetControls();
+
+	$('a.widget-control-add').click( addClick );
+
+	// initialize sortable
+	var widgetSortable = $('#current-sidebar .widget-control-list').Sortable( {
+		accept: 'widget-sortable',
+		helperclass: 'sorthelper',
+		handle: 'h4.widget-title'
+	} );
+
+});
Index: wp-admin/widgets.php
===================================================================
--- wp-admin/widgets.php	(revision 6555)
+++ wp-admin/widgets.php	(working copy)
@@ -1,360 +1,272 @@
 <?php
 
-require_once 'admin.php';
+require_once( 'admin.php' );
 
 if ( ! current_user_can('switch_themes') )
 	wp_die( __( 'Cheatin&#8217; uh?' ));
 
-wp_enqueue_script('interface');
+wp_enqueue_script( array( 'wp-lists', 'admin-widgets' ) );
 
-function wp_widgets_admin_head() {
-	global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls;
-?>
-	<?php wp_admin_css( 'css/widgets' ); ?>
-	<!--[if IE 7]>
-	<style type="text/css">
-		#palette { float: <?php echo ( get_bloginfo( 'text_direction' ) == 'rtl' ) ? 'right' : 'left'; ?>; }
-	</style>
-	<![endif]-->
-<?php
+do_action( 'sidebar_admin_setup' );
 
-	$cols = array();
-	foreach ( $wp_registered_sidebars as $index => $sidebar ) {
-		$cols[] = '\'' . $index . '\'';
-	}
-	$cols = implode( ', ', $cols );
+$title = __( 'Widgets' );
+$parent_file = 'themes.php';
 
-	$widgets = array();
-	foreach ( $wp_registered_widgets as $name => $widget ) {
-		$widgets[] = '\'' . $widget['id'] . '\'';
-	}
-	$widgets = implode( ', ', $widgets );
+// $sidebar = What sidebar are we editing?
+if ( isset($_GET['sidebar']) && isset($wp_registered_sidebars[$_GET['sidebar']]) ) {
+	$sidebar = attribute_escape( $_GET['sidebar'] );
+} elseif ( is_array($wp_registered_sidebars) && !empty($wp_registered_sidebars) ) {
+	// By default we look at the first defined sidebar
+	$sidebar = array_shift( array_keys($wp_registered_sidebars) );
+} else {
+	// If no sidebars, die.
+	require_once( 'admin-header.php' );
 ?>
-<script type="text/javascript">
-// <![CDATA[
-	var cols = [<?php echo $cols; ?>];
-	var widgets = [<?php echo $widgets; ?>];
-	var controldims = new Array;
-	<?php foreach ( $wp_registered_widget_controls as $name => $widget ) : ?>
-		controldims['#<?php echo $widget['id']; ?>control'] = new Array;
-		controldims['#<?php echo $widget['id']; ?>control']['width'] = <?php echo (int) $widget['width']; ?>;
-		controldims['#<?php echo $widget['id']; ?>control']['height'] = <?php echo (int) $widget['height']; ?>;
-	<?php endforeach; ?>
-	function initWidgets() {
-	<?php foreach ( $wp_registered_widget_controls as $name => $widget ) : ?>
-		jQuery('#<?php echo $widget['id']; ?>popper').click(function() {popControl('#<?php echo $widget['id']; ?>control');});
-		jQuery('#<?php echo $widget['id']; ?>closer').click(function() {unpopControl('#<?php echo $widget['id']; ?>control');});
-		jQuery('#<?php echo $widget['id']; ?>control').Draggable({handle: '.controlhandle', zIndex: 1000});
-		if ( true && window.opera )
-			jQuery('#<?php echo $widget['id']; ?>control').css('border','1px solid #bbb');
-	<?php endforeach; ?>
-		jQuery('#shadow').css('opacity','0');
-		jQuery(widgets).each(function(o) {o='#widgetprefix-'+o; jQuery(o).css('position','relative');} );
-	}
-	function resetDroppableHeights() {
-		var max = 6;
-		jQuery.map(cols, function(o) {
-			var c = jQuery('#' + o + ' li').length;
-			if ( c > max ) max = c;
-		});
-		var maxheight = 35 * ( max + 1);
-		jQuery.map(cols, function(o) {
-			height = 0 == jQuery('#' + o + ' li').length ? maxheight - jQuery('#' + o + 'placemat').height() : maxheight;
-			jQuery('#' + o).height(height);
-		});
-	}
-	function maxHeight(elm) {
-		htmlheight = document.body.parentNode.clientHeight;
-		bodyheight = document.body.clientHeight;
-		var height = htmlheight > bodyheight ? htmlheight : bodyheight;
-		jQuery(elm).height(height);
-	}
-	function getViewportDims() {
-		var x,y;
-		if (self.innerHeight) { // all except Explorer
-			x = self.innerWidth;
-			y = self.innerHeight;
-		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
-			x = document.documentElement.clientWidth;
-			y = document.documentElement.clientHeight;
-		} else if (document.body) { // other Explorers
-			x = document.body.clientWidth;
-			y = document.body.clientHeight;
-		}
-		return new Array(x,y);
-	}
-	function dragChange(o) {
-		var p = getViewportDims();
-		var screenWidth = p[0];
-		var screenHeight = p[1];
-		var elWidth = parseInt( jQuery(o).css('width') );
-		var elHeight = parseInt( jQuery(o).css('height') );
-		var elLeft = parseInt( jQuery(o).css('left') );
-		var elTop = parseInt( jQuery(o).css('top') );
-		if ( screenWidth < ( parseInt(elLeft) + parseInt(elWidth) ) )
-			jQuery(o).css('left', ( screenWidth - elWidth ) + 'px' );
-		if ( screenHeight < ( parseInt(elTop) + parseInt(elHeight) ) )
-			jQuery(o).css('top', ( screenHeight - elHeight ) + 'px' );
-		if ( elLeft < 1 )
-			jQuery(o).css('left', '1px');
-		if ( elTop < 1 )
-			jQuery(o).css('top', '1px');
-	}
-	function popControl(elm) {
-		var x = ( document.body.clientWidth - controldims[elm]['width'] ) / 2;
-		var y = ( document.body.parentNode.clientHeight - controldims[elm]['height'] ) / 2;
-		jQuery(elm).css({display: 'block', width: controldims[elm]['width'] + 'px', height: controldims[elm]['height'] + 'px', position: 'absolute', right: x + 'px', top: y + 'px', zIndex: '1000' });
-		jQuery(elm).attr('class','control');
-		jQuery('#shadow').click(function() {unpopControl(elm);});
-		window.onresize = function(){maxHeight('#shadow');dragChange(elm);};
-		popShadow();
-	}
-	function popShadow() {
-		maxHeight('#shadow');
-		jQuery('#shadow').css({zIndex: '999', display: 'block'});
-		jQuery('#shadow').fadeTo('fast', 0.2);
-	}
-	function unpopShadow() {
-		jQuery('#shadow').fadeOut('fast', function() {jQuery('#shadow').hide()});
-	}
-	function unpopControl(el) {
-		jQuery(el).attr('class','hidden');
-		jQuery(el).hide();
-		unpopShadow();
-	}
-	function serializeAll() {
-	<?php $i = 0; foreach ( $wp_registered_sidebars as $index => $sidebar ) : $i++; ?>
-		var serial<?php echo $i ?> = jQuery.SortSerialize('<?php echo $index ?>');
-		jQuery('#<?php echo $index ?>order').attr('value',serial<?php echo $i ?>.hash.replace(/widgetprefix-/g, ''));
-	<?php endforeach; ?>
-	}
-	function updateAll() {
-		jQuery.map(cols, function(o) {
-			if ( jQuery('#' + o + ' li').length )
-				jQuery('#'+o+'placemat span.handle').hide();
-			else
-				jQuery('#'+o+'placemat span.handle').show();
-		});
-		resetDroppableHeights();
-	}
-	jQuery(document).ready( function() {
-		updateAll();
-		initWidgets();
-	});
-// ]]>
-</script>
+
+	<div class="error">
+		<p><?php _e( 'No Sidebars Defined' ); ?></p>
+	</div>
+
+	<div class="wrap"> 
+		<p><?php _e( 'You are seeing this message because the theme you are currently using isn&#8217;t widget-aware, meaning that it has no sidebars that you are able to change. For information on making your theme widget-aware, please <a href="http://automattic.com/code/widgets/themes/">follow these instructions</a>.' ); /* TODO: article on codex */; ?></p>
+	</div>
+
 <?php
+	require_once( 'admin-footer.php' );
+	exit;
 }
-add_action( 'admin_head', 'wp_widgets_admin_head' );
-do_action( 'sidebar_admin_setup' );
 
-function wp_widget_draggable( $name ) {
-	global $wp_registered_widgets, $wp_registered_widget_controls;
+// These are the widgets grouped by sidebar
+$sidebars_widgets = wp_get_sidebars_widgets();
+if ( empty( $sidebars_widgets ) )
+	$sidebars_widgets = wp_get_widget_defaults();
 
-	if ( !isset( $wp_registered_widgets[$name] ) ) {
-		return;
-	}
+// for the sake of PHP warnings
+if ( empty( $sidebars_widgets[$sidebar] ) )
+	$sidebars_widgets[$sidebar] = array();
 
-	$sanitized_name = sanitize_title( $wp_registered_widgets[$name]['id'] );
-	$link_title = __( 'Configure' );
-	$popper = ( isset( $wp_registered_widget_controls[$name] ) )
-		? ' <div class="popper" id="' . $sanitized_name . 'popper" title="' . $link_title . '">&#8801;</div>'
-		: '';
+$http_post = ( 'POST' == $_SERVER['REQUEST_METHOD'] );
 
-	$output = '<li class="module" id="widgetprefix-%1$s"><span class="handle">%2$s</span></li>';
+// We're updating a sidebar
+if ( $http_post && isset($sidebars_widgets[$_POST['sidebar']]) ) {
 
-	printf( $output, $sanitized_name, $wp_registered_widgets[$name]['name'] . $popper );
-}
+	/* Hack #1
+	 * The widget_control is overloaded.  It updates the widget's options AND echoes out the widget's HTML form.
+	 * Since we want to update before sending out any headers, we have to catchi it with an output buffer
+	 */
+	ob_start();
+		/* There can be multiple widgets of the same type, but the widget_control for that
+		 * widget type needs only be called once.
+		 */
+		$already_done = array();
 
-$title = __( 'Widgets' );
-$parent_file = 'themes.php';
+		foreach ( $wp_registered_widget_controls as $name => $control ) {
+			if ( in_array( $control['callback'], $already_done ) )
+				continue;
 
-require_once 'admin-header.php';
+			if ( is_callable( $control['callback'] ) )
+				call_user_func_array( $control['callback'], $control['params'] );
+		}
+	ob_end_clean();
 
-if ( count( $wp_registered_sidebars ) < 1 ) {
-?>
-	<div class="wrap">
-		<h2><?php _e( 'No Sidebars Defined' ); ?></h2>
+	// Prophylactic.  Take out empty ids.
+	foreach ( (array) $_POST['widget-id'] as $key => $val )
+		if ( !$val )
+			unset($_POST['widget-id'][$key]);
 
-		<p><?php _e( 'You are seeing this message because the theme you are currently using isn&#8217;t widget-aware, meaning that it has no sidebars that you are able to change. For information on making your theme widget-aware, please <a href="http://automattic.com/code/widgets/themes/">follow these instructions</a>.' ); /* TODO: article on codex */; ?></p>
-	</div>
-<?php
+	// Reset the key numbering and stare
+	$new_sidebar = array_values( $_POST['widget-id'] );
+	$sidebars_widgets[$_POST['sidebar']] = $new_sidebar;
+	wp_set_sidebars_widgets( $sidebars_widgets );
 
-	require_once 'admin-footer.php';
+	// Re-register just in case
+	wp_widgets_init();
+
+	wp_redirect( add_query_arg( 'message', 'updated' ) );
 	exit;
 }
 
-$sidebars_widgets = wp_get_sidebars_widgets();
 
-if ( empty( $sidebars_widgets ) ) {
-	$sidebars_widgets = wp_get_widget_defaults();
+
+
+// What widget (if any) are we editing
+$edit_widget = -1;
+
+$query_args = array('add', 'remove', 'key', 'edit', '_wpnonce', 'message' );
+
+if ( isset($_GET['add']) && $_GET['add'] ) {
+	// Add to the end of the sidebar
+	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 );
+	}
+	wp_redirect( remove_query_arg( $query_args ) );
+	exit;
+} elseif ( isset($_GET['remove']) && $_GET['remove'] && isset($_GET['key']) && is_numeric($_GET['key']) ) {
+	// Remove from sidebar the widget of type $_GET['remove'] and in position $_GET['key']
+	$key = (int) $_GET['key'];
+	if ( -1 < $key && ( $keys = array_keys($sidebars_widgets[$sidebar], $_GET['remove']) ) && in_array($key, $keys) ) {
+		check_admin_referer( "remove-widget_$_GET[remove]" );
+		unset($sidebars_widgets[$sidebar][$key]);
+		$sidebars_widgets[$sidebar] = array_values($sidebars_widgets[$sidebar]);
+		wp_set_sidebars_widgets( $sidebars_widgets );
+	}
+	wp_redirect( remove_query_arg( $query_args ) );
+	exit;
+} elseif ( isset($_GET['edit']) && $_GET['edit'] && isset($_GET['key']) && is_numeric($_GET['key']) ) {
+	// Edit widget of type $_GET['edit'] and position $_GET['key']
+	$key = (int) $_GET['key'];
+	if ( -1 < $key && ( $keys = array_keys($sidebars_widgets[$sidebar], $_GET['edit']) ) && in_array($key, $keys) )
+		$edit_widget = $key;
 }
 
-if ( isset( $_POST['action'] ) ) {
-	check_admin_referer( 'widgets-save-widget-order' );
+// Total number of registered sidebars
+$sidebar_widget_count = count($sidebars_widgets[$sidebar]);
 
-	switch ( $_POST['action'] ) {
-		case 'default' :
-			$sidebars_widgets = wp_get_widget_defaults();
-			wp_set_sidebars_widgets( $sidebars_widgets );
-		break;
+// This is sort of lame since "widget" won't be converted to "widgets" in the JS
+if ( 1 < $sidebars_count = count($wp_registered_sidebars) )
+	$sidebar_info_text = __ngettext( 'You are using %1$s widget in the "%2$s" sidebar.', 'You are using %1$s widgets in the "%2$s" sidebar.', $sidebar_widget_count );
+else
+	$sidebar_info_text = __ngettext( 'You are using %1$s widget in the sidebar.', 'You are using %1$s widgets in the sidebar.', $sidebar_widget_count );
 
-		case 'save_widget_order' :
-			$sidebars_widgets = array();
 
-			foreach ( $wp_registered_sidebars as $index => $sidebar ) {
-				$postindex = $index . 'order';
+$sidebar_info_text = sprintf( wp_specialchars( $sidebar_info_text ), "<span id='widget-count'>$sidebar_widget_count</span>", $wp_registered_sidebars[$sidebar]['name'] );
 
-				parse_str( $_POST[$postindex], $order );
+$page = isset($_GET['apage']) ? abs( (int) $_GET['apage'] ) : 1;
 
-				$new_order = $order[$index];
+/* TODO: Paginate widgets list
+$page_links = paginate_links( array(
+	'base'    => add_query_arg( 'apage', '%#%' ),
+	'format'  => '',
+	'total'   => ceil(($total = 105 )/ 10),
+	'current' => $page
+));
+*/
+$page_links = false;
 
-				if ( is_array( $new_order ) ) {
-					foreach ( $new_order as $sanitized_name ) {
-						foreach ( $wp_registered_widgets as $name => $widget ) {
-							if ( $sanitized_name == $widget['id'] ) {
-								$sidebars_widgets[$index][] = $name;
-							}
-						}
-					}
-				}
-			}
+// Unsanitized!
+$widget_search = isset($_GET['s']) ? $_GET['s'] : false;
 
-			wp_set_sidebars_widgets( $sidebars_widgets );
-		break;
-	}
-}
+// Not entirely sure what all should be here
+$show_values = array(
+	''       => $widget_search ? __( 'Show any widgets' ) : __( 'Show all widgets' ),
+	'unused' => __( 'Show unused widgets' ),
+	'used'   => __( 'Show used widgets' )
+);
 
-ksort( $wp_registered_widgets );
+$show = isset($_GET['show']) && isset($show_values[$_GET['show']]) ? attribute_escape( $_GET['show'] ) : false;
 
-$inactive_widgets = array();
 
-foreach ( $wp_registered_widgets as $name => $widget ) {
-	$is_active = false;
+$messages = array(
+	'updated' => __('Changes saved.')
+);
 
-	foreach ( $wp_registered_sidebars as $index => $sidebar ) {
-		if ( is_array( $sidebars_widgets[$index] ) && in_array( $name, $sidebars_widgets[$index] ) ) {
-			$is_active = true;
-			break;
-		}
-	}
+require_once( 'admin-header.php' );
 
-	if ( !$is_active ) {
-		$inactive_widgets[] = $name;
-	}
-}
+if ( isset($_GET['message']) && isset($messages[$_GET['message']]) ) : ?>
 
-$containers = array( 'palette' );
+<div id="message" class="updated fade"><p><?php echo $messages[$_GET['message']]; ?></p></div>
 
-foreach ( $wp_registered_sidebars as $index => $sidebar ) {
-	$containers[] = $index;
-}
+<?php endif; ?>
 
-$c_string = '';
+<div class="wrap">
 
-foreach ( $containers as $container ) {
-	$c_string .= '"' . $container . '",';
-}
+	<form id="widgets-filter" action="" method="get">
 
-$c_string = substr( $c_string, 0, -1 );
+	<h2><?php _e( 'Widgets' ); ?></h2>
+	<p id="widget-search">
+		<input type="text" id="widget-search-input" name="s" value="<?php echo attribute_escape( $widget_search ); ?>" />
+		<input type="submit" value="<?php _e( 'Search Widgets' ); ?>" />
+	</p>
 
-if ( isset( $_POST['action'] ) ) {
-?>
-	<div class="fade updated" id="message">
-		<p><?php printf( __( 'Sidebar updated. <a href="%s">View site &raquo;</a>' ), get_bloginfo( 'url' ) . '/' ); ?></p>
+	<div class="widget-liquid-left-holder">
+	<div id="available-widgets-filter" class="widget-liquid-left">
+		<h3><?php printf( __('Available Widgets %s'), '<a href="#help:avaliable-widgets" class="wp-context-help">?</a>' ); ?></h3>
+		<p>
+			<select name="show">
+<?php foreach ( $show_values as $show_value => $show_text ) : $show_value = attribute_escape( $show_value ); ?>
+				<option value='<?php echo $show_value; ?>'<?php selected( $show_value, $show ); ?>><?php echo wp_specialchars( $show_text ); ?></option>
+<?php endforeach; ?>
+			</select>
+			<input type="submit" value="<?php _e('Show' ); ?>" />
+		</p>
+<?php if ( $page_links ) : ?>
+		<p class="pagenav">
+			<?php echo $page_links; ?>
+
+		</p>
+<?php endif; ?>
 	</div>
-<?php
-}
-?>
-	<div class="wrap">
-		<h2><?php _e( 'Sidebar Arrangement' ); ?></h2>
+	</div>
 
-		<p><?php _e( 'You can drag and drop widgets onto your sidebar below.' ); ?></p>
+	<div id="available-sidebars" class="widget-liquid-right">
+		<h3><?php printf( __('Current Widgets %s'), '<a href="#help:current-widgets" class="wp-context-help">?</a>' ); ?></h3>
 
-		<form id="sbadmin" method="post" onsubmit="serializeAll();">
-			<p class="submit">
-				<input type="submit" value="<?php _e( 'Save Changes &raquo;' ); ?>" />
-			</p>
-			<div id="zones">
-			<?php
-				foreach ( $wp_registered_sidebars as $index => $sidebar ) {
-			?>
-				<input type="hidden" id="<?php echo $index; ?>order" name="<?php echo $index; ?>order" value="" />
+<?php if ( 1 < $sidebars_count ) : ?>
 
-				<div class="dropzone">
-					<h3><?php echo $sidebar['name']; ?></h3>
+		<p>
+			<select id="sidebar-selector" name="sidebar">
+<?php foreach ( $wp_registered_sidebars as $sidebar_id => $registered_sidebar ) : $sidebar_id = attribute_escape( $sidebar_id ); ?>
+				<option value='<?php echo $sidebar_id; ?>'<?php selected( $sidebar_id, $sidebar ); ?>><?php echo wp_specialchars( $registered_sidebar['name'] ); ?></option>
+<?php endforeach; ?>
+			</select>
+			<input type="submit" value="<?php _e('Go' ); ?>" />
+		</p>
 
-					<div id="<?php echo $index; ?>placemat" class="placemat">
-						<span class="handle">
-							<h4><?php _e( 'Default Sidebar' ); ?></h4>
-							<?php _e( 'Your theme will display its usual sidebar when this box is empty. Dragging widgets into this box will replace the usual sidebar with your customized sidebar.' ); ?>
-						</span>
-					</div>
+<?php endif; ?>
 
-					<ul id="<?php echo $index; ?>">
-					<?php
-						if ( is_array( $sidebars_widgets[$index] ) ) {
-							foreach ( $sidebars_widgets[$index] as $name ) {
-								wp_widget_draggable( $name );
-							}
-						}
-					?>
-					</ul>
-				</div>
-			<?php
-				}
-			?>
+	</div>
 
-			</div>
+	</form>
 
-			<div id="palettediv">
-				<h3><?php _e( 'Available Widgets' ); ?></h3>
+	<div id="widget-content" class="widget-liquid-left-holder">
 
-				<ul id="palette">
-				<?php
-					foreach ( $inactive_widgets as $name ) {
-						wp_widget_draggable( $name );
-					}
-				?>
-				</ul>
-			</div>
+		<div id="available-widgets" class="widget-liquid-left">
 
-			<script type="text/javascript">
-			// <![CDATA[
-				jQuery(document).ready(function(){
-			<?php foreach ( $containers as $container ) { ?>
-					jQuery('ul#<?php echo $container; ?>').Sortable({
-						accept: 'module', activeclass: 'activeDraggable', opacity: 0.8, revert: true, onStop: updateAll
-					});
-			<?php } ?>
-				});
-			// ]]>
-			</script>
+			<?php wp_list_widgets( $show, $widget_search ); // This lists all the widgets for the query ( $show, $search ) ?>
 
-			<p class="submit">
-			<?php wp_nonce_field( 'widgets-save-widget-order' ); ?>
-				<input type="hidden" name="action" id="action" value="save_widget_order" />
-				<input type="submit" value="<?php _e( 'Save Changes &raquo;' ); ?>" />
+<?php if ( $page_links ) : ?>
+			<p class="pagenav">
+				<?php echo $page_links; ?>
+
 			</p>
+<?php endif; ?>
 
-			<div id="controls">
-			<?php foreach ( $wp_registered_widget_controls as $name => $widget ) { ?>
-				<div class="hidden" id="<?php echo $widget['id']; ?>control">
-					<span class="controlhandle"><?php echo $widget['name']; ?></span>
-					<span id="<?php echo $widget['id']; ?>closer" class="controlcloser">&#215;</span>
-					<div class="controlform">
-					<?php call_user_func_array( $widget['callback'], $widget['params'] ); ?>
-					</div>
-				</div>
-			<?php } ?>
-			</div>
-		</form>
+		</div>
+	</div>
 
-		<br class="clear" />
+	<form id="widget-controls" action="" method="post">
+
+	<div id="current-widgets-head" class="widget-liquid-right">
+
+		<div id="sidebar-info">
+			<p><?php echo $sidebar_info_text; ?></p>
+			<p><?php _e( 'Add more from the Available Widgets section.' ); ?></p>
+		</div>
+
 	</div>
 
-	<div id="shadow"> </div>
+	<div id="current-widgets" class="widget-liquid-right">
+		<input type="hidden" id='sidebar' name='sidebar' value="<?php echo $sidebar; ?>" />
 
-	<?php do_action( 'sidebar_admin_page' ); ?>
+		<div id="current-sidebar">
 
-<?php require_once 'admin-footer.php'; ?>
+			<?php wp_list_widget_controls( $sidebars_widgets[$sidebar], $edit_widget ); // Show the control forms for each of the widgets in this sidebar ?>
+
+		</div>
+	</div>
+
+	<p class="submit">
+		<input type="hidden" id="generated-time" name="generated-time" value="<?php echo time(); ?>" />
+		<input type="submit" name="save-widgets" value="<?php _e( 'Save Changes' ); ?>" />
+	</p>
+
+	</form>
+
+</div>
+
+<?php do_action( 'sidebar_admin_page' ); ?>
+
+<?php require_once( 'admin-footer.php' ); ?>
+

