From 10e6dd47aded77bff54d2738d3e6ff5736388410 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Fri, 28 Mar 2014 21:46:20 -0700
Subject: [PATCH 01/40] Serialize non-scalar values when inserting meta

---
 includes/db-actions.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/includes/db-actions.php b/includes/db-actions.php
index 5bd5ace78..35cc44b18 100644
--- a/includes/db-actions.php
+++ b/includes/db-actions.php
@@ -104,6 +104,7 @@ public function insert( $recordarr ) {
 
 		foreach ( $recordarr['meta'] as $key => $vals ) {
 			foreach ( (array) $vals as $val ) {
+				$val = maybe_serialize( $val );
 				$this->insert_meta( $record_id, $key, $val );
 			}
 		}

From cc03d23a7e9de60302fba364739c000db5ba20eb Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Fri, 28 Mar 2014 21:48:05 -0700
Subject: [PATCH 02/40] Eliminate reference to undefined variable

Argument was passed to wp_stream_post_insert_error action
---
 includes/db-actions.php | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/includes/db-actions.php b/includes/db-actions.php
index 35cc44b18..07174ba07 100644
--- a/includes/db-actions.php
+++ b/includes/db-actions.php
@@ -88,10 +88,10 @@ public function insert( $recordarr ) {
 			/**
 			 * Action Hook that fires on an error during post insertion
 			 *
-			 * @param  int  $record_id  Record being inserted
+			 * @param  array  $recordarr  Record being inserted
 			 */
-			do_action( 'wp_stream_post_insert_error', $record_id );
-			return $record_id;
+			do_action( 'wp_stream_post_insert_error', $recordarr );
+			return;
 		}
 
 		self::$instance->prev_record = $record_id;

From 025e38d4800a160970ba325510098d7f80424924 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Thu, 3 Apr 2014 13:42:36 -0700
Subject: [PATCH 03/40] Refactor widgets connector to track bulk changes and to
 add support for the customizer

---
 connectors/widgets.php | 583 +++++++++++++++++++++++++++--------------
 1 file changed, 388 insertions(+), 195 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 3fd075004..2b66a6a66 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -16,9 +16,7 @@ class WP_Stream_Connector_Widgets extends WP_Stream_Connector {
 	 */
 	public static $actions = array(
 		'update_option_sidebars_widgets',
-		'sidebar_admin_setup',
-		'wp_ajax_widgets-order',
-		'widget_update_callback',
+		'updated_option',
 	);
 
 	/**
@@ -40,6 +38,7 @@ public static function get_action_labels() {
 			'added'       => __( 'Added', 'stream' ),
 			'deleted'     => __( 'Deleted', 'stream' ),
 			'deactivated' => __( 'Deactivated', 'stream' ),
+			'reactivated' => __( 'Reactivated', 'stream' ),
 			'updated'     => __( 'Updated', 'stream' ),
 			'sorted'      => __( 'Sorted', 'stream' ),
 		);
@@ -60,6 +59,8 @@ public static function get_context_labels() {
 		}
 
 		$labels['wp_inactive_widgets'] = esc_html__( 'Inactive Widgets' );
+		$labels['orphaned_widgets'] = esc_html__( 'Orphaned Widgets' );
+		$labels[''] = esc_html__( 'Unknown', 'stream' );
 
 		return $labels;
 	}
@@ -77,7 +78,7 @@ public static function action_links( $links, $record ) {
 			global $wp_registered_sidebars;
 
 			if ( array_key_exists( $sidebar, $wp_registered_sidebars ) ) {
-				$links[ __( 'Edit Widget Area', 'stream' ) ] = admin_url( 'widgets.php#' . $sidebar );
+				$links[ __( 'Edit Widget Area', 'stream' ) ] = admin_url( "widgets.php#$sidebar" );
 			}
 		}
 
@@ -85,262 +86,455 @@ public static function action_links( $links, $record ) {
 	}
 
 	/**
-	 * Tracks addition/deletion/deactivation of widgets from sidebars
+	 * @return bool
+	 */
+	public static function is_customizer_preview() {
+		global $wp_customize;
+		return ! empty( $wp_customize ) && $wp_customize->is_preview();
+	}
+
+	/**
+	 * Tracks addition/deletion/reordering/deactivation of widgets from sidebars
 	 *
 	 * @action update_option_sidebars_widgets
-	 * @param  array $old  Old sidebars
-	 * @param  array $new  New sidebars
+	 * @param  array $old  Old sidebars widgets
+	 * @param  array $new  New sidebars widgets
 	 * @return void
 	 */
 	public static function callback_update_option_sidebars_widgets( $old, $new ) {
 
-		// Disable listener if we're switching themes
+		// Disable listener if we're switching themes or if we're in the customizer
 		if ( did_action( 'after_switch_theme' ) ) {
 			return;
 		}
 
-		global $wp_stream_widget_order_operation;
+		unset( $old['array_version'] );
+		unset( $new['array_version'] );
+
+		self::handle_deactivated_widgets( $old, $new );
+		self::handle_reactivated_widgets( $old, $new );
+		self::handle_widget_deletion( $old, $new );
+		self::handle_widget_addition( $old, $new );
+		self::handle_widget_reordering( $old, $new );
+		// @todo Handle updating
+	}
 
-		$widget_id = null;
-		$sidebar   = null;
 
-		if ( $deactivated = array_diff( $new['wp_inactive_widgets'], $old['wp_inactive_widgets'] ) ) {
+	/**
+	 * Track deactivation of widgets from sidebars
+	 *
+	 * @param  array $old  Old sidebars widgets
+	 * @param  array $new  New sidebars widgets
+	 * @return void
+	 */
+	static protected function handle_deactivated_widgets( $old, $new ) {
+		$new_deactivated_widget_ids = array_diff( $new['wp_inactive_widgets'], $old['wp_inactive_widgets'] );
+		foreach ( $new_deactivated_widget_ids as $widget_id ) {
+			$sidebar_id = '';
+			foreach ( $old as $old_sidebar_id => $old_widget_ids ) {
+				if ( in_array( $widget_id, $old_widget_ids ) ) {
+					$sidebar_id = $old_sidebar_id;
+					break;
+				}
+			}
 			$action  = 'deactivated';
-			$message = _x(
-				'"%1$s" has been deactivated',
-				'1: Widget title',
-				'stream'
-			);
-
-			// It is not always the 0th key value. If a widget is dropped after any other widget in the Inactive area;
-			// then the difference would be on a non-zero key.
-			$diff_ids  = array_values( $deactivated );
-			$widget_id = $diff_ids[0];
-			$sidebar   = $old;
-
-			list( $id_base, $name, $title, $sidebar, $sidebar_name ) = array_values( self::get_widget_info( $widget_id, $sidebar ) );
+			$title = self::get_widget_title( $widget_id );
+			$name = self::get_widget_name( $widget_id );
+			if ( $name && $title ) {
+				$message = _x(
+					'"%1$s" (%2$s) widget deactivated',
+					'1: Widget title, 2: Widget name',
+					'stream'
+				);
+			} else if ( $name ) {
+				// Empty title, but we have the name
+				$message = _x(
+					'%2$s widget deactivated',
+					'2: Widget name',
+					'stream'
+				);
+			} else if ( $title ) {
+				// Likely a single widget since no name is available
+				$message = _x(
+					'"%1$s" widget deactivated',
+					'1: Widget title',
+					'stream'
+				);
+			} else {
+				// Neither a name nor a title are available, so use the sidebar ID
+				$message = _x(
+					'%3$s widget deactivated',
+					'3: Widget ID',
+					'stream'
+				);
+			}
 
 			self::log(
 				$message,
-				compact( 'title', 'sidebar_name', 'id_base', 'widget_id', 'sidebar' ),
+				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
 				null,
 				array( 'wp_inactive_widgets' => $action )
 			);
-
-			$wp_stream_widget_order_operation = null;
-
-			return;
 		}
+	}
 
-		if ( ! $widget_id ) {
-			foreach ( $new as $sidebar_id => $new_widgets ){
-				if (
-					( ! isset( $old[ $sidebar_id ] ) )
-					||
-					( ! isset( $new[ $sidebar_id ] ) )
-					||
-					( ! is_array( $old[ $sidebar_id ] ) )
-					||
-					( ! is_array( $new_widgets ) )
-					) {
-					break; // Switching themes ?, do not return so order operation is logged
-				}
-				$old_widgets = $old[ $sidebar_id ];
-
-				// Added ?
-				if ( $changed = array_diff( $new_widgets, $old_widgets ) ) {
-					$action    = 'added';
-					$message   = _x(
-						'"%1$s" has been added to "%2$s"',
-						'1: Widget title, 2: Sidebar name',
-						'stream'
-					);
-					$widget_id = reset( $changed );
-					$sidebar   = $new;
-				}
-				// Removed
-				elseif ( $changed = array_diff( $old_widgets, $new_widgets ) ) {
-					$action    = 'deleted';
-					$message   = _x(
-						'"%1$s" has been deleted from "%2$s"',
-						'1: Widget title, 2: Sidebar name',
-						'stream'
-					);
-					$widget_id = reset( $changed );
-					$sidebar   = $old;
-				}
 
-				if ( ! $widget_id ) {
-					continue;
+	/**
+	 * Track reactivation of widgets from sidebars
+	 *
+	 * @param  array $old  Old sidebars widgets
+	 * @param  array $new  New sidebars widgets
+	 * @return void
+	 */
+	static protected function handle_reactivated_widgets( $old, $new ) {
+		$new_reactivated_widget_ids = array_diff( $old['wp_inactive_widgets'], $new['wp_inactive_widgets'] );
+		foreach ( $new_reactivated_widget_ids as $widget_id ) {
+			$sidebar_id = '';
+			foreach ( $new as $new_sidebar_id => $new_widget_ids ) {
+				if ( in_array( $widget_id, $new_widget_ids ) ) {
+					$sidebar_id = $new_sidebar_id;
+					break;
 				}
+			}
 
-				$wp_stream_widget_order_operation = null;
-
-				list( $id_base, $name, $title, $sidebar, $sidebar_name ) = array_values( self::get_widget_info( $widget_id, $sidebar ) );
-
-				self::log(
-					$message,
-					compact( 'title', 'sidebar_name', 'id_base', 'widget_id', 'sidebar' ),
-					null,
-					array( $sidebar => $action )
+			$action  = 'reactivated';
+			$title = self::get_widget_title( $widget_id );
+			$name = self::get_widget_name( $widget_id );
+			if ( $name && $title ) {
+				$message = _x(
+					'"%1$s" (%2$s) widget reactivated',
+					'1: Widget title, 2: Widget name',
+					'stream'
+				);
+			} else if ( $name ) {
+				// Empty title, but we have the name
+				$message = _x(
+					'%2$s widget reactivated',
+					'2: Widget name',
+					'stream'
+				);
+			} else if ( $title ) {
+				// Likely a single widget since no name is available
+				$message = _x(
+					'"%1$s" widget reactivated',
+					'1: Widget title',
+					'stream'
+				);
+			} else {
+				// Neither a name nor a title are available, so use the sidebar ID
+				$message = _x(
+					'%3$s widget reactivated',
+					'3: Widget ID',
+					'stream'
 				);
-
-				$widget_id = null;
 			}
+			self::log(
+				$message,
+				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
+				null,
+				array( $sidebar_id => $action )
+			);
 		}
+	}
 
-		// Did anything happen ? if not, just record the reorder log entry
-		if ( $wp_stream_widget_order_operation ) {
-			call_user_func_array( array( __CLASS__, 'log' ), $wp_stream_widget_order_operation );
+	/**
+	 * Track reactivation of widgets from sidebars
+	 *
+	 * @param  array $old  Old sidebars widgets
+	 * @param  array $new  New sidebars widgets
+	 * @return void
+	 */
+	static protected function handle_widget_deletion( $old, $new ) {
+		$all_old_widget_ids = array_unique( call_user_func_array( 'array_merge', $old ) );
+		$all_new_widget_ids = array_unique( call_user_func_array( 'array_merge', $new ) );
+		$deleted_widget_ids = array_diff( $all_old_widget_ids, $all_new_widget_ids );
+		foreach ( $deleted_widget_ids as $widget_id ) {
+			$sidebar_id = '';
+			foreach ( $old as $old_sidebar_id => $old_widget_ids ) {
+				if ( in_array( $widget_id, $old_widget_ids ) ) {
+					$sidebar_id = $old_sidebar_id;
+					break;
+				}
+			}
+			$action  = 'deleted';
+			$title = self::get_widget_title( $widget_id );
+			$name = self::get_widget_name( $widget_id );
+			if ( $name && $title ) {
+				$message = _x(
+					'"%1$s" (%2$s) widget deleted',
+					'1: Widget title, 2: Widget name',
+					'stream'
+				);
+			} else if ( $name ) {
+				// Empty title, but we have the name
+				$message = _x(
+					'%2$s widget deleted',
+					'2: Widget name',
+					'stream'
+				);
+			} else if ( $title ) {
+				// Likely a single widget since no name is available
+				$message = _x(
+					'"%1$s" widget deleted',
+					'1: Widget title',
+					'stream'
+				);
+			} else {
+				// Neither a name nor a title are available, so use the sidebar ID
+				$message = _x(
+					'%3$s widget deleted',
+					'3: Widget ID',
+					'stream'
+				);
+			}
+			self::log(
+				$message,
+				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
+				null,
+				array( $sidebar_id => $action )
+			);
 		}
-
 	}
 
 	/**
-	 * Tracks widget instance updates
+	 * Track reactivation of widgets from sidebars
 	 *
-	 * @filter widget_update_callback
-	 * @param $instance
-	 * @param $new_instance
-	 * @param $old_instance
-	 * @param $widget
-	 * @return array
+	 * @param  array $old  Old sidebars widgets
+	 * @param  array $new  New sidebars widgets
+	 * @return void
 	 */
-	public static function callback_widget_update_callback( $instance, $new_instance, $old_instance, $widget ) {
-		global $wp_registered_sidebars;
-
-		$id_base   = $widget->id_base;
-		$widget_id = $widget->id;
-
-		list( $id_base, $name, $title, $sidebar, $sidebar_name ) = array_values( self::get_widget_info( $widget_id, false ) );
-		$title = isset( $new_instance['title'] ) ? $new_instance['title'] : null;
+	static protected function handle_widget_addition( $old, $new ) {
+		$all_old_widget_ids = array_unique( call_user_func_array( 'array_merge', $old ) );
+		$all_new_widget_ids = array_unique( call_user_func_array( 'array_merge', $new ) );
+		$added_widget_ids = array_diff( $all_new_widget_ids, $all_old_widget_ids );
+		foreach ( $added_widget_ids as $widget_id ) {
+			$sidebar_id = '';
+			foreach ( $new as $new_sidebar_id => $new_widget_ids ) {
+				if ( in_array( $widget_id, $new_widget_ids ) ) {
+					$sidebar_id = $new_sidebar_id;
+					break;
+				}
+			}
 
-		// If it wasn't assigned to a sidebar, then its a new thing, skip it
-		if ( $sidebar_name ) {
-			self::log(
-				_x(
-					'Updated "%1$s" in "%2$s"',
-					'1: Widget title, 2: Sidebar name',
+			$action  = 'added';
+			$title = self::get_widget_title( $widget_id );
+			$name = self::get_widget_name( $widget_id );
+			if ( $name && $title ) {
+				$message = _x(
+					'"%1$s" (%2$s) widget added',
+					'1: Widget title, 2: Widget name',
+					'stream'
+				);
+			} else if ( $name ) {
+				// Empty title, but we have the name
+				$message = _x(
+					'%2$s widget added',
+					'2: Widget name',
+					'stream'
+				);
+			} else if ( $title ) {
+				// Likely a single widget since no name is available
+				$message = _x(
+					'"%1$s" widget added',
+					'1: Widget title',
 					'stream'
-				),
-				compact( 'name', 'sidebar_name', 'title', 'id_base', 'sidebar', 'widget_id', 'new_instance', 'old_instance' ),
+				);
+			} else {
+				// Neither a name nor a title are available, so use the sidebar ID
+				$message = _x(
+					'%3$s widget added',
+					'3: Widget ID',
+					'stream'
+				);
+			}
+			self::log(
+				$message,
+				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
 				null,
-				array( $sidebar => 'updated' )
+				array( $sidebar_id => $action )
 			);
 		}
-
-		return $instance;
 	}
 
 	/**
-	 * Tracks reordering of widgets
+	 * Track reordering of widgets
 	 *
-	 * @action wp_ajax_widgets_order
+	 * @param  array $old  Old sidebars widgets
+	 * @param  array $new  New sidebars widgets
 	 * @return void
 	 */
-	public static function callback_wp_ajax_widgets_order() {
-		global $wp_stream_widget_order_operation;
+	static protected function handle_widget_reordering( $old, $new ) {
 
-		// If this was a widget update, skip adding a new record
-		if ( did_action( 'widget_update_callback' ) ) {
-			return;
-		}
-
-		$labels = self::get_context_labels();
-		$old    = self::get_sidebar_widgets();
+		$all_sidebar_ids = array_intersect( array_keys( $old ), array_keys( $new ) );
+		foreach ( $all_sidebar_ids as $sidebar_id ) {
 
-		unset( $old['array_version'] );
+			// Use intersect to ignore widget additions and removals
+			$common_widget_ids = array_intersect( $old[ $sidebar_id ], $new[ $sidebar_id ] );
+			$widget_order_changed = ( $common_widget_ids !== array_intersect( $new[ $sidebar_id ], $common_widget_ids ) );
+			if ( $widget_order_changed ) {
+				$labels = self::get_context_labels();
+				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
-		$new = $_POST['sidebars'];
+				self::log(
+					_x( 'Widgets in "%s" were reordered', 'Sidebar name', 'stream' ),
+					compact( 'sidebar_name', 'sidebar' ), // @todo We don't want to store sidebar_name in stream meta
+					null,
+					array( $sidebar_id => 'sorted' )
+				);
+			}
+		}
 
-		foreach ( $new as $sidebar_id => $widget_ids ) {
+	}
 
-			$widget_ids         = preg_replace( '#(widget-\d+_)#', '', $widget_ids );
-			$new[ $sidebar_id ] = array_filter( explode( ',', $widget_ids ) );
+	/**
+	 * Track changes to widgets
+	 *
+	 * @faction updated_option
+	 * @param string $option_name
+	 * @param array $old_value
+	 * @param array $new_value
+	 */
+	public static function callback_updated_option( $option_name, $old_value, $new_value ) {
+		// @todo What about adding widget for first time?
+		// @todo What about deleting a widget?
 
-			if ( $new[ $sidebar_id ] !== $old[ $sidebar_id ] ) {
-				$changed = $sidebar_id;
-				break;
+		if ( ! preg_match( '/^widget_(.+)$/', $option_name, $matches ) || ! is_array( $new_value ) ) {
+			return;
+		}
+		$is_multi = ! empty( $new_value['_multiwidget'] );
+		$widget_id_base = $matches[1];
+		$updates = array();
+
+		if ( $is_multi ) {
+			$widget_id_format = "$widget_id_base-%d";
+
+			unset( $new_value['_multiwidget'] );
+			unset( $old_value['_multiwidget'] );
+			$widget_numbers = array_intersect( array_keys( $old_value ), array_keys( $new_value ) ); // ignore widgets added/removed
+			foreach ( $widget_numbers as $widget_number ) {
+				$new_instance = $new_value[ $widget_number ];
+				$old_instance = $old_value[ $widget_number ];
+				if ( $old_instance !== $new_instance ) {
+					$widget_id = sprintf( $widget_id_format, $widget_number );
+					$title = ! empty( $new_instance['title'] ) ? $new_instance['title'] : null;
+					$name = self::get_widget_name( $widget_id );
+					$sidebar_id = self::get_widget_sidebar_id( $widget_id );
+					$updates[] = compact( 'widget_id', 'title', 'name', 'sidebar_id', 'old_instance' );
+				}
 			}
+		} else {
+			$widget_id = $widget_id_base;
+			$name = $widget_id; // There aren't names available for single widgets
+			$title = ! empty( $new_value['title'] ) ? $new_value['title'] : null;
+			$sidebar_id = self::get_widget_sidebar_id( $widget_id );
+			$old_instance = $old_value;
+			$updates[] = compact( 'widget_id', 'title', 'name', 'sidebar_id', 'old_instance' );
 		}
 
-		if ( isset( $changed ) ) {
-			$sidebar      = $changed;
-			$sidebar_name = isset( $labels[ $sidebar ] ) ? $labels[ $sidebar ] : esc_html__( 'Widgets', 'stream' );
+		foreach ( $updates as $update ) {
 
-			// Saving this in a global var, so it can be accessed and
-			// executed by self::callback_update_option_sidebars_widgets
-			// in case this is ONLY a reorder process
-			$wp_stream_widget_order_operation = array(
-				_x( 'Widgets in "%s" were reordered', 'Sidebar name', 'stream' ),
-				compact( 'sidebar_name', 'sidebar' ),
+			if ( $update['name'] && $update['title'] ) {
+				$message = _x(
+					'"%1$s" (%2$s) widget updated',
+					'1: Widget title, 2: Widget name',
+					'stream'
+				);
+			} else if ( $update['name'] ) {
+				// Empty title, but we have the name
+				$message = _x(
+					'%2$s widget updated',
+					'2: Widget name',
+					'stream'
+				);
+			} else if ( $update['title'] ) {
+				// Likely a single widget since no name is available
+				$message = _x(
+					'"%1$s" widget updated',
+					'1: Widget title',
+					'stream'
+				);
+			} else {
+				// Neither a name nor a title are available, so use the widget ID
+				$message = _x(
+					'%3$s widget updated',
+					'3: Widget ID',
+					'stream'
+				);
+			}
+			self::log(
+				$message,
+				compact( 'title', 'name', 'widget_id', 'sidebar_id', 'old_instance' ),
 				null,
-				array( $sidebar => 'sorted' ),
+				array( $update['sidebar_id'] => 'updated' )
 			);
 		}
 	}
 
 	/**
-	 * Returns widget info based on widget id
-	 *
-	 * @param  integer $id       Widget ID, ex: pages-1
-	 * @param  array   $sidebars Existing sidebars to search in
-	 * @return array             array( $id_base, $name, $title, $sidebar, $sidebar_name, $widget_class )
+	 * @param string $widget_id
+	 * @return string
 	 */
-	public static function get_widget_info( $id, $sidebars = array() ) {
-		global $wp_registered_widgets, $wp_widget_factory;
+	public static function get_widget_title( $widget_id ) {
+		$instance = self::get_widget_instance( $widget_id );
+		return ! empty( $instance['title'] ) ? $instance['title'] : null;
+	}
 
-		$ids = array_combine(
+	/**
+	 * @param string $widget_id
+	 * @return string|null
+	 */
+	public static function get_widget_name( $widget_id ) {
+		$widget_obj = self::get_widget_object( $widget_id );
+		return $widget_obj ? $widget_obj->name : null;
+	}
+
+	/**
+	 * @param string $widget_id
+	 * @return WP_Widget|null
+	 */
+	public static function get_widget_object( $widget_id ) {
+		global $wp_registered_widget_controls, $wp_widget_factory;
+		if ( ! isset( $wp_registered_widget_controls[ $widget_id ] ) || empty( $wp_registered_widget_controls[ $widget_id ]['id_base'] ) ) {
+			return null;
+		}
+
+		$id_base = $wp_registered_widget_controls[ $widget_id ]['id_base'];
+		$id_base_to_widget_class_map = array_combine(
 			wp_list_pluck( $wp_widget_factory->widgets, 'id_base' ),
 			array_keys( $wp_widget_factory->widgets )
 		);
 
-		$labels  = self::get_context_labels();
-		$id_base = preg_match( '#(.*)-(\d+)$#', $id, $matches ) ? $matches[1] : null;
-		$number  = $matches[2];
-		$name    = $wp_widget_factory->widgets[ $ids[ $id_base ] ]->name;
-
-		$settings = self::get_widget_settings( $id );
-		$title    = ! empty( $settings['title'] ) ? $settings['title'] : $name;
-
-		$sidebar      = null;
-		$sidebar_name = null;
-
-		if ( false === $sidebars ) {
-			$sidebars = self::get_sidebar_widgets();
-		}
-
-		foreach ( $sidebars as $_sidebar_id => $_sidebar ) {
-			if ( is_array( $_sidebar ) && in_array( $id, $_sidebar ) ) {
-				$sidebar      = $_sidebar_id;
-				$sidebar_name = isset( $labels[ $sidebar ] ) ? $labels[ $sidebar ] : esc_html__( 'Widgets', 'stream' );
-				break;
-			}
+		if ( ! isset( $id_base_to_widget_class_map[ $id_base ] ) ) {
+			return null;
 		}
 
-		return array( $id_base, $name, $title, $sidebar, $sidebar_name, $ids[ $id_base ] );
+		return $wp_widget_factory->widgets[ $id_base_to_widget_class_map[ $id_base ] ];
 	}
 
 	/**
 	 * Returns widget instance settings
 	 *
-	 * @param  string $id  Widget ID, ex: pages-1
-	 * @return array       Widget instance
+	 * @param  string $widget_id  Widget ID, ex: pages-1
+	 * @return array|null         Widget instance
 	 */
-	public static function get_widget_settings( $id ) {
-		global $wp_widget_factory, $wp_registered_widgets, $wp_widget_factory, $wp_registered_sidebars;
-
-		$id_base = preg_match( '#(.*)-(\d+)#', $id, $matches ) ? $matches[1] : null;
-		$number  = $matches[2];
-
-		$ids = array_combine(
-			wp_list_pluck( $wp_widget_factory->widgets, 'id_base' ),
-			array_keys( $wp_widget_factory->widgets )
-		);
-
-		$instance = $wp_widget_factory->widgets[ $ids[ $id_base ] ]->get_settings();
-
-		return isset( $instance[ $number ] ) ? $instance[ $number ] : array();
+	public static function get_widget_instance( $widget_id ) {
+		$instance = null;
+
+		$widget_obj = self::get_widget_object( $widget_id );
+		if ( $widget_obj && ! empty( $widget_obj->params[0]['number'] ) ) {
+			$settings = $widget_obj->get_settings();
+			$multi_number = $widget_obj->params[0]['number'];
+			if ( isset( $settings[ $multi_number ] ) && ! empty( $settings[ $multi_number ]['title'] ) ) {
+				$instance = $settings[ $multi_number ];
+			}
+		} else {
+			// Single widgets, try our best guess at the option used
+			$potential_instance = get_option( "widget_{$widget_id}" );
+			if ( ! empty( $potential_instance ) && ! empty( $potential_instance['title'] ) ) {
+				$instance = $potential_instance;
+			}
+		}
+		return $instance;
 	}
 
 	/**
@@ -348,9 +542,10 @@ public static function get_widget_settings( $id ) {
 	 *
 	 * @return array
 	 */
-	public static function get_sidebar_widgets() {
+	public static function get_sidebars_widgets() {
 		/**
 		 * Filter allows for insertion of sidebar widgets
+		 * @todo Do we need this filter?
 		 *
 		 * @param  array  Sidebar Widgets in Options table
 		 * @param  array  Inserted Sidebar Widgets
@@ -362,19 +557,17 @@ public static function get_sidebar_widgets() {
 	/**
 	 * Return the sidebar of a certain widget, based on widget_id
 	 *
-	 * @param  string $id Widget id, ex: pages-1
-	 * @return string     Sidebar id
+	 * @param  string $widget_id  Widget id, ex: pages-1
+	 * @return string             Sidebar id
 	 */
-	public static function get_widget_sidebar( $id ) {
-		$sidebars = self::get_sidebar_widgets();
-
-		foreach ( $sidebars as $sidebar_id => $bar ) {
-			if ( in_array( $id, $bar ) ) {
+	public static function get_widget_sidebar_id( $widget_id ) {
+		$sidebars_widgets = self::get_sidebars_widgets();
+		foreach ( $sidebars_widgets as $sidebar_id => $widget_ids ) {
+			if ( in_array( $widget_id, $widget_ids ) ) {
 				return $sidebar_id;
 			}
 		}
-
-		return null;
+		return 'orphaned_widgets';
 	}
 
 }

From 8ecc1070fcf48a5b333d5d9235c870f7221c1977 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 13:19:58 -0700
Subject: [PATCH 04/40] Fix detection for sorted action

---
 connectors/widgets.php | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 2b66a6a66..2799cddf7 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -367,10 +367,17 @@ static protected function handle_widget_reordering( $old, $new ) {
 
 		$all_sidebar_ids = array_intersect( array_keys( $old ), array_keys( $new ) );
 		foreach ( $all_sidebar_ids as $sidebar_id ) {
+			if ( $old[ $sidebar_id ] === $new[ $sidebar_id ] ) {
+				continue;
+			}
 
 			// Use intersect to ignore widget additions and removals
+			$all_widget_ids = array_unique( array_merge( $old[ $sidebar_id ], $new[ $sidebar_id ] ) );
 			$common_widget_ids = array_intersect( $old[ $sidebar_id ], $new[ $sidebar_id ] );
-			$widget_order_changed = ( $common_widget_ids !== array_intersect( $new[ $sidebar_id ], $common_widget_ids ) );
+			$uncommon_widget_ids = array_diff( $all_widget_ids, $common_widget_ids );
+			$new_widget_ids = array_values( array_diff( $new[ $sidebar_id ], $uncommon_widget_ids ) );
+			$old_widget_ids = array_values( array_diff( $old[ $sidebar_id ], $uncommon_widget_ids ) );
+			$widget_order_changed = ( $new_widget_ids !== $old_widget_ids );
 			if ( $widget_order_changed ) {
 				$labels = self::get_context_labels();
 				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;

From 7d1c452d80252c50ae191729bb68cb429c8529aa Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 14:54:47 -0700
Subject: [PATCH 05/40] Track widget movement to other sidebars

Still have work to do to make this work properly in Customizer
Use a different string template mechanism which prevents args from being needlessly added to Stream meta
---
 connectors/widgets.php | 79 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 76 insertions(+), 3 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 2799cddf7..4c2ac1260 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -39,6 +39,7 @@ public static function get_action_labels() {
 			'deleted'     => __( 'Deleted', 'stream' ),
 			'deactivated' => __( 'Deactivated', 'stream' ),
 			'reactivated' => __( 'Reactivated', 'stream' ),
+			'moved'       => __( 'Moved', 'stream' ),
 			'updated'     => __( 'Updated', 'stream' ),
 			'sorted'      => __( 'Sorted', 'stream' ),
 		);
@@ -103,7 +104,7 @@ public static function is_customizer_preview() {
 	 */
 	public static function callback_update_option_sidebars_widgets( $old, $new ) {
 
-		// Disable listener if we're switching themes or if we're in the customizer
+		// Disable listener if we're switching themes
 		if ( did_action( 'after_switch_theme' ) ) {
 			return;
 		}
@@ -116,7 +117,7 @@ public static function callback_update_option_sidebars_widgets( $old, $new ) {
 		self::handle_widget_deletion( $old, $new );
 		self::handle_widget_addition( $old, $new );
 		self::handle_widget_reordering( $old, $new );
-		// @todo Handle updating
+		self::handle_widget_moved( $old, $new );
 	}
 
 
@@ -238,7 +239,7 @@ static protected function handle_reactivated_widgets( $old, $new ) {
 	}
 
 	/**
-	 * Track reactivation of widgets from sidebars
+	 * Track deletion of widgets from sidebars
 	 *
 	 * @param  array $old  Old sidebars widgets
 	 * @param  array $new  New sidebars widgets
@@ -393,6 +394,78 @@ static protected function handle_widget_reordering( $old, $new ) {
 
 	}
 
+	/**
+	 * Track movement of widgets to other sidebars
+	 *
+	 * @param  array $old  Old sidebars widgets
+	 * @param  array $new  New sidebars widgets
+	 * @return void
+	 */
+	static protected function handle_widget_moved( $old, $new ) {
+
+		$all_sidebar_ids = array_intersect( array_keys( $old ), array_keys( $new ) );
+		foreach ( $all_sidebar_ids as $new_sidebar_id ) {
+			if ( $old[ $new_sidebar_id ] === $new[ $new_sidebar_id ] ) {
+				continue;
+			}
+
+			$new_widget_ids = array_diff( $new[ $new_sidebar_id ], $old[ $new_sidebar_id ] );
+
+			foreach ( $new_widget_ids as $widget_id ) {
+				// Now find the sidebar that the widget was originally located in, as long it is not wp_inactive_widgets
+				$old_sidebar_id = null;
+				foreach ( $old as $sidebar_id => $old_widget_ids ) {
+					if ( in_array( $widget_id, $old_widget_ids ) ) {
+						$old_sidebar_id = $sidebar_id;
+						break;
+					}
+				}
+				if ( ! $old_sidebar_id ) {
+					continue;
+				}
+				assert( $old_sidebar_id !== $new_sidebar_id );
+
+				$labels = self::get_context_labels();
+				$old_sidebar_name = isset( $labels[ $new_sidebar_id ] ) ? $labels[ $new_sidebar_id ] : $new_sidebar_id;
+				$new_sidebar_name = isset( $labels[ $old_sidebar_id ] ) ? $labels[ $old_sidebar_id ] : $old_sidebar_id;
+				$title = self::get_widget_title( $widget_id );
+				$name = self::get_widget_name( $widget_id );
+				if ( $name && $title ) {
+					$message = __( '"{title}" ({name}) widget moved from {old_sidebar_name} to {new_sidebar_name}', 'stream' );
+				} else if ( $name ) {
+					// Empty title, but we have the name
+					$message = __( '{name} widget moved from {old_sidebar_name} to {new_sidebar_name}', 'stream' );
+				} else if ( $title ) {
+					// Likely a single widget since no name is available
+					$message = __( '"{title}" widget moved from {old_sidebar_name} to {new_sidebar_name}', 'stream' );
+				} else {
+					// Neither a name nor a title are available, so use the sidebar ID
+					$message = __( '{widget_id} widget moved from {old_sidebar_name} to {new_sidebar_name}', 'stream' );
+				}
+
+				$tpl_vars = compact( 'title', 'name', 'old_sidebar_name', 'new_sidebar_name' );
+				$message = str_replace(
+					array_map( function ( $m ) { return '{' . $m . '}';  }, array_keys( $tpl_vars ) ),
+					array_values( $tpl_vars ),
+					$message
+				);
+
+				self::log(
+					$message,
+					compact( 'widget_id' ), // , 'new_sidebar_id', 'old_sidebar_id'
+					null,
+					array(
+						$new_sidebar_id => 'moved', // added
+						$old_sidebar_id => 'moved', // subtracted
+						// @todo add widget_id as a context?
+					)
+				);
+
+			}
+		}
+
+	}
+
 	/**
 	 * Track changes to widgets
 	 *

From fecc29f02b11eb01b5bb2142ad847640a2728628 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 15:04:23 -0700
Subject: [PATCH 06/40] Use alternate summary template for
 handle_widget_reordering

---
 connectors/widgets.php | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 4c2ac1260..29e0f8501 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -383,9 +383,11 @@ static protected function handle_widget_reordering( $old, $new ) {
 				$labels = self::get_context_labels();
 				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
+				$message = __( 'Widgets in "{sidebar_name}" were reordered', 'stream' );
+				$message = self::apply_tpl_vars( $message, compact( 'sidebar_name' ) );
 				self::log(
-					_x( 'Widgets in "%s" were reordered', 'Sidebar name', 'stream' ),
-					compact( 'sidebar_name', 'sidebar' ), // @todo We don't want to store sidebar_name in stream meta
+					$message,
+					compact( 'sidebar_id' ), // @todo Do we need to store the sidebar_id in Stream meta if if is already in the context?
 					null,
 					array( $sidebar_id => 'sorted' )
 				);
@@ -444,15 +446,10 @@ static protected function handle_widget_moved( $old, $new ) {
 				}
 
 				$tpl_vars = compact( 'title', 'name', 'old_sidebar_name', 'new_sidebar_name' );
-				$message = str_replace(
-					array_map( function ( $m ) { return '{' . $m . '}';  }, array_keys( $tpl_vars ) ),
-					array_values( $tpl_vars ),
-					$message
-				);
-
+				$message = self::apply_tpl_vars( $message, $tpl_vars );
 				self::log(
 					$message,
-					compact( 'widget_id' ), // , 'new_sidebar_id', 'old_sidebar_id'
+					compact( 'widget_id' ),
 					null,
 					array(
 						$new_sidebar_id => 'moved', // added
@@ -550,6 +547,24 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 		}
 	}
 
+	/**
+	 * Replace in $message any $tpl_vars array keys bounded by curly-braces,
+	 * supplying the $tpl_vars array values in their place. A saner approach
+	 * than using vsprintf.
+	 *
+	 * @param string $message
+	 * @param array $tpl_vars
+	 * @return string
+	 */
+	public static function apply_tpl_vars( $message, array $tpl_vars ) {
+		$message = str_replace(
+			array_map( function ( $m ) { return '{' . $m . '}'; }, array_keys( $tpl_vars ) ),
+			array_values( $tpl_vars ),
+			$message
+		);
+		return $message;
+	}
+
 	/**
 	 * @param string $widget_id
 	 * @return string

From 0aa257fc34aaf2a4fba3d12cf5d59dd94fa04753 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 15:47:51 -0700
Subject: [PATCH 07/40] Filter-out non-scalars from being applied to summary
 tpl

---
 connectors/widgets.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 29e0f8501..690d29b8f 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -557,6 +557,7 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 	 * @return string
 	 */
 	public static function apply_tpl_vars( $message, array $tpl_vars ) {
+		$tpl_vars = array_filter( $tpl_vars, function ( $v ) { return is_string( $v ) || is_numeric( $v ); } );
 		$message = str_replace(
 			array_map( function ( $m ) { return '{' . $m . '}'; }, array_keys( $tpl_vars ) ),
 			array_values( $tpl_vars ),

From e52ea0fb16ea65eb83f3e561bebdb27ebfaf6ae3 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 15:50:04 -0700
Subject: [PATCH 08/40] Update addition and deletion handlers to use new
 summary tpl

---
 connectors/widgets.php | 67 +++++++++++++++---------------------------
 1 file changed, 23 insertions(+), 44 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 690d29b8f..cc2002b67 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -248,6 +248,9 @@ static protected function handle_reactivated_widgets( $old, $new ) {
 	static protected function handle_widget_deletion( $old, $new ) {
 		$all_old_widget_ids = array_unique( call_user_func_array( 'array_merge', $old ) );
 		$all_new_widget_ids = array_unique( call_user_func_array( 'array_merge', $new ) );
+		// @todo In the customizer, moving widgets to other sidebars is problematic because each sidebar is registered as a separate setting; so we need to make sure that all $_POST['customized'] are applied?
+		// @todo The widget option is getting updated before the sidebars_widgets are updated, so we need to hook into the option update to try to cache any deletions for future lookup
+
 		$deleted_widget_ids = array_diff( $all_old_widget_ids, $all_new_widget_ids );
 		foreach ( $deleted_widget_ids as $widget_id ) {
 			$sidebar_id = '';
@@ -261,36 +264,23 @@ static protected function handle_widget_deletion( $old, $new ) {
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
 			if ( $name && $title ) {
-				$message = _x(
-					'"%1$s" (%2$s) widget deleted',
-					'1: Widget title, 2: Widget name',
-					'stream'
-				);
+				$message = __( '"{title}" ({name}) widget deleted', 'stream' );
 			} else if ( $name ) {
 				// Empty title, but we have the name
-				$message = _x(
-					'%2$s widget deleted',
-					'2: Widget name',
-					'stream'
-				);
+				$message = __( '{name} widget deleted', 'stream' );
 			} else if ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x(
-					'"%1$s" widget deleted',
-					'1: Widget title',
-					'stream'
-				);
+				$message = __( '"{title}" widget deleted', 'stream' );
 			} else {
-				// Neither a name nor a title are available, so use the sidebar ID
-				$message = _x(
-					'%3$s widget deleted',
-					'3: Widget ID',
-					'stream'
-				);
+				// Neither a name nor a title are available, so use the widget ID
+				$message = __( '{widget_id} widget deleted', 'stream' );
 			}
+
+			$tpl_vars = compact( 'name', 'title', 'widget_id' );
+			$message = self::apply_tpl_vars( $message, $tpl_vars );
 			self::log(
 				$message,
-				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
+				compact( 'widget_id', 'sidebar_id' ),
 				null,
 				array( $sidebar_id => $action )
 			);
@@ -317,40 +307,29 @@ static protected function handle_widget_addition( $old, $new ) {
 				}
 			}
 
+			// @todo should this actually be created instead of added?
+
 			$action  = 'added';
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
 			if ( $name && $title ) {
-				$message = _x(
-					'"%1$s" (%2$s) widget added',
-					'1: Widget title, 2: Widget name',
-					'stream'
-				);
+				$message = __( '"{title}" ({name}) widget added', 'stream' );
 			} else if ( $name ) {
 				// Empty title, but we have the name
-				$message = _x(
-					'%2$s widget added',
-					'2: Widget name',
-					'stream'
-				);
+				$message = __( '{name} widget added', 'stream' );
 			} else if ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x(
-					'"%1$s" widget added',
-					'1: Widget title',
-					'stream'
-				);
+				$message = __( '"{title}" widget added', 'stream' );
 			} else {
-				// Neither a name nor a title are available, so use the sidebar ID
-				$message = _x(
-					'%3$s widget added',
-					'3: Widget ID',
-					'stream'
-				);
+				// Neither a name nor a title are available, so use the widget ID
+				$message = __( '{widget_id} widget added', 'stream' );
 			}
+
+			$tpl_vars = compact( 'name', 'title', 'widget_id' );
+			$message = self::apply_tpl_vars( $message, $tpl_vars );
 			self::log(
 				$message,
-				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
+				compact( 'widget_id', 'sidebar_id' ), // @todo Do we care about sidebar_id in meta if it is already context? But there is no 'context' for what the context signifies
 				null,
 				array( $sidebar_id => $action )
 			);

From 339aaf2811c3ba078ebad2050ced9416440e7f4f Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 15:50:42 -0700
Subject: [PATCH 09/40] Re-work widget update callback to also track creates
 and deletes

---
 connectors/widgets.php | 134 +++++++++++++++++++++++++++++++----------
 1 file changed, 101 insertions(+), 33 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index cc2002b67..b6b72278d 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -36,6 +36,7 @@ public static function get_label() {
 	public static function get_action_labels() {
 		return array(
 			'added'       => __( 'Added', 'stream' ),
+			'created'     => __( 'Created', 'stream' ),
 			'deleted'     => __( 'Deleted', 'stream' ),
 			'deactivated' => __( 'Deactivated', 'stream' ),
 			'reactivated' => __( 'Reactivated', 'stream' ),
@@ -451,23 +452,42 @@ static protected function handle_widget_moved( $old, $new ) {
 	 * @param array $new_value
 	 */
 	public static function callback_updated_option( $option_name, $old_value, $new_value ) {
-		// @todo What about adding widget for first time?
-		// @todo What about deleting a widget?
+		// @todo Actions possible here are: created, updated, deleted; actions possible for sidebar contexts are added and remvoed
 
 		if ( ! preg_match( '/^widget_(.+)$/', $option_name, $matches ) || ! is_array( $new_value ) ) {
 			return;
 		}
 		$is_multi = ! empty( $new_value['_multiwidget'] );
 		$widget_id_base = $matches[1];
+
+		$creates = array();
 		$updates = array();
+		$deletes = array();
 
 		if ( $is_multi ) {
 			$widget_id_format = "$widget_id_base-%d";
 
 			unset( $new_value['_multiwidget'] );
 			unset( $old_value['_multiwidget'] );
-			$widget_numbers = array_intersect( array_keys( $old_value ), array_keys( $new_value ) ); // ignore widgets added/removed
-			foreach ( $widget_numbers as $widget_number ) {
+
+			/**
+			 * Created widgets
+			 */
+			$created_widget_numbers = array_diff( array_keys( $new_value ), array_keys( $old_value ) );
+			foreach ( $created_widget_numbers as $widget_number ) {
+				$instance = $new_value[ $widget_number ];
+				$widget_id = sprintf( $widget_id_format, $widget_number );
+				$title = ! empty( $instance['title'] ) ? $instance['title'] : null;
+				$name = self::get_widget_name( $widget_id );
+				$sidebar_id = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned yet
+				$creates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
+			}
+
+			/**
+			 * Updated widgets
+			 */
+			$updated_widget_numbers = array_intersect( array_keys( $old_value ), array_keys( $new_value ) );
+			foreach ( $updated_widget_numbers as $widget_number ) {
 				$new_instance = $new_value[ $widget_number ];
 				$old_instance = $old_value[ $widget_number ];
 				if ( $old_instance !== $new_instance ) {
@@ -475,10 +495,25 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 					$title = ! empty( $new_instance['title'] ) ? $new_instance['title'] : null;
 					$name = self::get_widget_name( $widget_id );
 					$sidebar_id = self::get_widget_sidebar_id( $widget_id );
-					$updates[] = compact( 'widget_id', 'title', 'name', 'sidebar_id', 'old_instance' );
+					$updates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'old_instance' );
 				}
 			}
+
+			/**
+			 * Deleted widgets
+			 */
+			$deleted_widget_numbers = array_diff( array_keys( $old_value ), array_keys( $new_value ) );
+			foreach ( $deleted_widget_numbers as $widget_number ) {
+				$instance = $old_value[ $widget_number ];
+				$widget_id = sprintf( $widget_id_format, $widget_number );
+				$title = ! empty( $instance['title'] ) ? $instance['title'] : null;
+				$name = self::get_widget_name( $widget_id );
+				$sidebar_id = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned anymore
+				$creates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
+			}
 		} else {
+			// Doing our best guess for tracking changes to old single widgets, assuming their options start with 'widget_'
+
 			$widget_id = $widget_id_base;
 			$name = $widget_id; // There aren't names available for single widgets
 			$title = ! empty( $new_value['title'] ) ? $new_value['title'] : null;
@@ -487,42 +522,75 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			$updates[] = compact( 'widget_id', 'title', 'name', 'sidebar_id', 'old_instance' );
 		}
 
+		/**
+		 * Log updated actions
+		 */
 		foreach ( $updates as $update ) {
-
 			if ( $update['name'] && $update['title'] ) {
-				$message = _x(
-					'"%1$s" (%2$s) widget updated',
-					'1: Widget title, 2: Widget name',
-					'stream'
-				);
+				$message = __( '"{title}" ({name}) updated', 'stream' );
 			} else if ( $update['name'] ) {
 				// Empty title, but we have the name
-				$message = _x(
-					'%2$s widget updated',
-					'2: Widget name',
-					'stream'
-				);
+				$message = __( '{name} widget updated', 'stream' );
 			} else if ( $update['title'] ) {
 				// Likely a single widget since no name is available
-				$message = _x(
-					'"%1$s" widget updated',
-					'1: Widget title',
-					'stream'
-				);
+				$message = __( '"{title}" widget updated', 'stream' );
 			} else {
-				// Neither a name nor a title are available, so use the widget ID
-				$message = _x(
-					'%3$s widget updated',
-					'3: Widget ID',
-					'stream'
-				);
+				// Neither a name nor a title are available, so use the sidebar ID
+				$message = __( '{widget_id} widget updated', 'stream' );
 			}
-			self::log(
-				$message,
-				compact( 'title', 'name', 'widget_id', 'sidebar_id', 'old_instance' ),
-				null,
-				array( $update['sidebar_id'] => 'updated' )
-			);
+
+			$tpl_vars = $update;
+			$message = self::apply_tpl_vars( $message, $tpl_vars );
+			$contexts = array( $update['sidebar_id'] => 'updated' );
+			self::log( $message, $update, null, $contexts );
+		}
+
+		/**
+		 * Log created actions
+		 * @todo We should only do these if not captured by an update to the sidebars_widgets option
+		 */
+		foreach ( $creates as $create ) {
+			if ( $create['name'] && $create['title'] ) {
+				$message = __( '"{title}" ({name}) created', 'stream' );
+			} else if ( $create['name'] ) {
+				// Empty title, but we have the name
+				$message = __( '{name} widget created', 'stream' );
+			} else if ( $create['title'] ) {
+				// Likely a single widget since no name is available
+				$message = __( '"{title}" widget created', 'stream' );
+			} else {
+				// Neither a name nor a title are available, so use the sidebar ID
+				$message = __( '{widget_id} widget created', 'stream' );
+			}
+
+			$tpl_vars = $create;
+			$message = self::apply_tpl_vars( $message, $tpl_vars );
+			$contexts = array( $create['sidebar_id'] => 'created' );
+			self::log( $message, $create, null, $contexts );
+		}
+
+		/**
+		 * Log deleted actions
+		 * @todo We should only do these if not captured by an update to the sidebars_widgets option
+		 */
+		foreach ( $deletes as $delete ) {
+			if ( $create['name'] && $delete['title'] ) {
+				$message = __( '"{title}" ({name}) deleted', 'stream' );
+			} else if ( $delete['name'] ) {
+				// Empty title, but we have the name
+				$message = __( '{name} widget deleted', 'stream' );
+			} else if ( $delete['title'] ) {
+				// Likely a single widget since no name is available
+				$message = __( '"{title}" widget deleted', 'stream' );
+			} else {
+				// Neither a name nor a title are available, so use the sidebar ID
+				$message = __( '{widget_id} widget deleted', 'stream' );
+			}
+
+			$tpl_vars = $delete;
+			$message = self::apply_tpl_vars( $message, $tpl_vars );
+			$contexts = array( $create['sidebar_id'] => 'deleted' );
+			self::log( $message, $create, null, $contexts );
 		}
 	}
 

From c010105187791a3b3293faaf50ed063a10d7223a Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 16:13:45 -0700
Subject: [PATCH 10/40] Fix logic for looking up a multi widget instance

---
 connectors/widgets.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index b6b72278d..538e5fc6c 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -664,9 +664,9 @@ public static function get_widget_instance( $widget_id ) {
 		$instance = null;
 
 		$widget_obj = self::get_widget_object( $widget_id );
-		if ( $widget_obj && ! empty( $widget_obj->params[0]['number'] ) ) {
+		if ( $widget_obj ) {
 			$settings = $widget_obj->get_settings();
-			$multi_number = $widget_obj->params[0]['number'];
+			$multi_number = intval( preg_replace( '/.+?-(?=\d+$)/', '', $widget_id ) );
 			if ( isset( $settings[ $multi_number ] ) && ! empty( $settings[ $multi_number ]['title'] ) ) {
 				$instance = $settings[ $multi_number ];
 			}

From dccd40020d0005083fb0c9923b499dfb1e5bb65d Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 16:18:04 -0700
Subject: [PATCH 11/40] Prevent widget movement record if dealing with
 active/inactive widgets

Fix label for movement to reverse from/to sidebars
Use new tpl vars for summaries
---
 connectors/widgets.php | 63 ++++++++++++------------------------------
 1 file changed, 18 insertions(+), 45 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 538e5fc6c..45564a083 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -143,33 +143,19 @@ static protected function handle_deactivated_widgets( $old, $new ) {
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
 			if ( $name && $title ) {
-				$message = _x(
-					'"%1$s" (%2$s) widget deactivated',
-					'1: Widget title, 2: Widget name',
-					'stream'
-				);
+				$message = __( '"{title}" ({name}) widget deactivated', 'stream' );
 			} else if ( $name ) {
 				// Empty title, but we have the name
-				$message = _x(
-					'%2$s widget deactivated',
-					'2: Widget name',
-					'stream'
-				);
+				$message = __( '{name} widget deactivated', 'stream' );
 			} else if ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x(
-					'"%1$s" widget deactivated',
-					'1: Widget title',
-					'stream'
-				);
+				$message = __( '"{title}" widget deactivated', 'stream' );
 			} else {
-				// Neither a name nor a title are available, so use the sidebar ID
-				$message = _x(
-					'%3$s widget deactivated',
-					'3: Widget ID',
-					'stream'
-				);
+				// Neither a name nor a title are available, so use the widget ID
+				$message = __( '{widget_id} widget deactivated', 'stream' );
 			}
+			$tpl_vars = compact( 'name', 'title', 'widget_id' );
+			$message = self::apply_tpl_vars( $message, $tpl_vars );
 
 			self::log(
 				$message,
@@ -203,33 +189,20 @@ static protected function handle_reactivated_widgets( $old, $new ) {
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
 			if ( $name && $title ) {
-				$message = _x(
-					'"%1$s" (%2$s) widget reactivated',
-					'1: Widget title, 2: Widget name',
-					'stream'
-				);
+				$message = __( '"{title}" ({name}) widget reactivated', 'stream' );
 			} else if ( $name ) {
 				// Empty title, but we have the name
-				$message = _x(
-					'%2$s widget reactivated',
-					'2: Widget name',
-					'stream'
-				);
+				$message = __( '{name} widget reactivated', 'stream' );
 			} else if ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x(
-					'"%1$s" widget reactivated',
-					'1: Widget title',
-					'stream'
-				);
+				$message = __( '"{title}" widget reactivated', 'stream' );
 			} else {
-				// Neither a name nor a title are available, so use the sidebar ID
-				$message = _x(
-					'%3$s widget reactivated',
-					'3: Widget ID',
-					'stream'
-				);
+				// Neither a name nor a title are available, so use the widget ID
+				$message = __( '{widget_id} widget reactivated', 'stream' );
 			}
+
+			$tpl_vars = compact( 'name', 'title', 'widget_id' );
+			$message = self::apply_tpl_vars( $message, $tpl_vars );
 			self::log(
 				$message,
 				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
@@ -402,14 +375,14 @@ static protected function handle_widget_moved( $old, $new ) {
 						break;
 					}
 				}
-				if ( ! $old_sidebar_id ) {
+				if ( ! $old_sidebar_id || $old_sidebar_id === 'wp_inactive_widgets' || $new_sidebar_id === 'wp_inactive_widgets' ) {
 					continue;
 				}
 				assert( $old_sidebar_id !== $new_sidebar_id );
 
 				$labels = self::get_context_labels();
-				$old_sidebar_name = isset( $labels[ $new_sidebar_id ] ) ? $labels[ $new_sidebar_id ] : $new_sidebar_id;
-				$new_sidebar_name = isset( $labels[ $old_sidebar_id ] ) ? $labels[ $old_sidebar_id ] : $old_sidebar_id;
+				$new_sidebar_name = isset( $labels[ $new_sidebar_id ] ) ? $labels[ $new_sidebar_id ] : $new_sidebar_id;
+				$old_sidebar_name = isset( $labels[ $old_sidebar_id ] ) ? $labels[ $old_sidebar_id ] : $old_sidebar_id;
 				$title = self::get_widget_title( $widget_id );
 				$name = self::get_widget_name( $widget_id );
 				if ( $name && $title ) {

From 7ba6ba74ccc55d621b363da4b050c3e361d6ff62 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 16:52:20 -0700
Subject: [PATCH 12/40] Fix widget object lookup for newly-created widgets

Eliminate warning related
---
 connectors/widgets.php | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 45564a083..fdf64dd45 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -604,17 +604,34 @@ public static function get_widget_name( $widget_id ) {
 		return $widget_obj ? $widget_obj->name : null;
 	}
 
+	/**
+	 * @param $widget_id
+	 * @return array|null
+	 */
+	public static function parse_widget_id( $widget_id ) {
+		if ( preg_match( '/^(.+)-(\d+)$/', $widget_id, $matches ) ) {
+			return array(
+				'id_base' => $matches[1],
+				'widget_number' => intval( $matches[2] ),
+			);
+		} else {
+			return null;
+		}
+	}
+
 	/**
 	 * @param string $widget_id
 	 * @return WP_Widget|null
 	 */
 	public static function get_widget_object( $widget_id ) {
-		global $wp_registered_widget_controls, $wp_widget_factory;
-		if ( ! isset( $wp_registered_widget_controls[ $widget_id ] ) || empty( $wp_registered_widget_controls[ $widget_id ]['id_base'] ) ) {
+		global $wp_widget_factory;
+
+		$parsed_widget_id = self::parse_widget_id( $widget_id );
+		if ( ! $parsed_widget_id ) {
 			return null;
 		}
 
-		$id_base = $wp_registered_widget_controls[ $widget_id ]['id_base'];
+		$id_base = $parsed_widget_id['id_base'];
 		$id_base_to_widget_class_map = array_combine(
 			wp_list_pluck( $wp_widget_factory->widgets, 'id_base' ),
 			array_keys( $wp_widget_factory->widgets )
@@ -636,10 +653,11 @@ public static function get_widget_object( $widget_id ) {
 	public static function get_widget_instance( $widget_id ) {
 		$instance = null;
 
+		$parsed_widget_id = self::parse_widget_id( $widget_id );
 		$widget_obj = self::get_widget_object( $widget_id );
-		if ( $widget_obj ) {
+		if ( $widget_obj && $parsed_widget_id ) {
 			$settings = $widget_obj->get_settings();
-			$multi_number = intval( preg_replace( '/.+?-(?=\d+$)/', '', $widget_id ) );
+			$multi_number = $parsed_widget_id['widget_number'];
 			if ( isset( $settings[ $multi_number ] ) && ! empty( $settings[ $multi_number ]['title'] ) ) {
 				$instance = $settings[ $multi_number ];
 			}
@@ -678,6 +696,7 @@ public static function get_sidebars_widgets() {
 	 */
 	public static function get_widget_sidebar_id( $widget_id ) {
 		$sidebars_widgets = self::get_sidebars_widgets();
+		unset( $sidebars_widgets['array_version'] );
 		foreach ( $sidebars_widgets as $sidebar_id => $widget_ids ) {
 			if ( in_array( $widget_id, $widget_ids ) ) {
 				return $sidebar_id;

From 01d4c4a28aa31ddb56d3478a9b89a1f578362736 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 17:04:57 -0700
Subject: [PATCH 13/40] Turn deleted action into removed action for removing
 widget from sidebar

Fix typo in logging deletions
---
 connectors/widgets.php | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index fdf64dd45..96e1dacad 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -36,6 +36,7 @@ public static function get_label() {
 	public static function get_action_labels() {
 		return array(
 			'added'       => __( 'Added', 'stream' ),
+			'removed'     => __( 'Removed', 'stream' ),
 			'created'     => __( 'Created', 'stream' ),
 			'deleted'     => __( 'Deleted', 'stream' ),
 			'deactivated' => __( 'Deactivated', 'stream' ),
@@ -115,7 +116,7 @@ public static function callback_update_option_sidebars_widgets( $old, $new ) {
 
 		self::handle_deactivated_widgets( $old, $new );
 		self::handle_reactivated_widgets( $old, $new );
-		self::handle_widget_deletion( $old, $new );
+		self::handle_widget_removal( $old, $new );
 		self::handle_widget_addition( $old, $new );
 		self::handle_widget_reordering( $old, $new );
 		self::handle_widget_moved( $old, $new );
@@ -219,7 +220,7 @@ static protected function handle_reactivated_widgets( $old, $new ) {
 	 * @param  array $new  New sidebars widgets
 	 * @return void
 	 */
-	static protected function handle_widget_deletion( $old, $new ) {
+	static protected function handle_widget_removal( $old, $new ) {
 		$all_old_widget_ids = array_unique( call_user_func_array( 'array_merge', $old ) );
 		$all_new_widget_ids = array_unique( call_user_func_array( 'array_merge', $new ) );
 		// @todo In the customizer, moving widgets to other sidebars is problematic because each sidebar is registered as a separate setting; so we need to make sure that all $_POST['customized'] are applied?
@@ -234,20 +235,20 @@ static protected function handle_widget_deletion( $old, $new ) {
 					break;
 				}
 			}
-			$action  = 'deleted';
+			$action  = 'removed';
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
 			if ( $name && $title ) {
-				$message = __( '"{title}" ({name}) widget deleted', 'stream' );
+				$message = __( '"{title}" ({name}) widget removed', 'stream' );
 			} else if ( $name ) {
 				// Empty title, but we have the name
-				$message = __( '{name} widget deleted', 'stream' );
+				$message = __( '{name} widget removed', 'stream' );
 			} else if ( $title ) {
 				// Likely a single widget since no name is available
-				$message = __( '"{title}" widget deleted', 'stream' );
+				$message = __( '"{title}" widget removed', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = __( '{widget_id} widget deleted', 'stream' );
+				$message = __( '{widget_id} widget removed', 'stream' );
 			}
 
 			$tpl_vars = compact( 'name', 'title', 'widget_id' );
@@ -482,7 +483,7 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 				$title = ! empty( $instance['title'] ) ? $instance['title'] : null;
 				$name = self::get_widget_name( $widget_id );
 				$sidebar_id = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned anymore
-				$creates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
+				$deletes[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
 			}
 		} else {
 			// Doing our best guess for tracking changes to old single widgets, assuming their options start with 'widget_'
@@ -547,7 +548,7 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 		 * @todo We should only do these if not captured by an update to the sidebars_widgets option
 		 */
 		foreach ( $deletes as $delete ) {
-			if ( $create['name'] && $delete['title'] ) {
+			if ( $delete['name'] && $delete['title'] ) {
 				$message = __( '"{title}" ({name}) deleted', 'stream' );
 			} else if ( $delete['name'] ) {
 				// Empty title, but we have the name
@@ -562,8 +563,8 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 
 			$tpl_vars = $delete;
 			$message = self::apply_tpl_vars( $message, $tpl_vars );
-			$contexts = array( $create['sidebar_id'] => 'deleted' );
-			self::log( $message, $create, null, $contexts );
+			$contexts = array( $delete['sidebar_id'] => 'deleted' );
+			self::log( $message, $delete, null, $contexts );
 		}
 	}
 

From d4983c857e3bc7e08bdd2d839c43dda2890879e4 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 22:23:59 -0700
Subject: [PATCH 14/40] Remove moved action

---
 connectors/widgets.php | 32 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 96e1dacad..e0439acbb 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -41,7 +41,6 @@ public static function get_action_labels() {
 			'deleted'     => __( 'Deleted', 'stream' ),
 			'deactivated' => __( 'Deactivated', 'stream' ),
 			'reactivated' => __( 'Reactivated', 'stream' ),
-			'moved'       => __( 'Moved', 'stream' ),
 			'updated'     => __( 'Updated', 'stream' ),
 			'sorted'      => __( 'Sorted', 'stream' ),
 		);
@@ -61,7 +60,7 @@ public static function get_context_labels() {
 			$labels[ $sidebar['id'] ] = $sidebar['name'];
 		}
 
-		$labels['wp_inactive_widgets'] = esc_html__( 'Inactive Widgets' );
+		$labels['wp_inactive_widgets'] = esc_html__( 'Inactive Widgets' ); // @todo Why esc_html??
 		$labels['orphaned_widgets'] = esc_html__( 'Orphaned Widgets' );
 		$labels[''] = esc_html__( 'Unknown', 'stream' );
 
@@ -77,25 +76,19 @@ public static function get_context_labels() {
 	 * @return array             Action links
 	 */
 	public static function action_links( $links, $record ) {
-		if ( $sidebar = get_stream_meta( $record->ID, 'sidebar', true ) ) {
+		if ( $sidebar = get_stream_meta( $record->ID, 'sidebar_id', true ) ) { // @todo Requires database upgrade 'sidebar' => 'sidebar_id'
 			global $wp_registered_sidebars;
 
 			if ( array_key_exists( $sidebar, $wp_registered_sidebars ) ) {
 				$links[ __( 'Edit Widget Area', 'stream' ) ] = admin_url( "widgets.php#$sidebar" );
 			}
+			// @todo Also old_sidebar_id and new_sidebar_id
+			// @todo Add Edit Widget link
 		}
 
 		return $links;
 	}
 
-	/**
-	 * @return bool
-	 */
-	public static function is_customizer_preview() {
-		global $wp_customize;
-		return ! empty( $wp_customize ) && $wp_customize->is_preview();
-	}
-
 	/**
 	 * Tracks addition/deletion/reordering/deactivation of widgets from sidebars
 	 *
@@ -282,8 +275,6 @@ static protected function handle_widget_addition( $old, $new ) {
 				}
 			}
 
-			// @todo should this actually be created instead of added?
-
 			$action  = 'added';
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
@@ -337,11 +328,12 @@ static protected function handle_widget_reordering( $old, $new ) {
 				$labels = self::get_context_labels();
 				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
+				$old_widget_ids = $old[ $sidebar_id ];
 				$message = __( 'Widgets in "{sidebar_name}" were reordered', 'stream' );
 				$message = self::apply_tpl_vars( $message, compact( 'sidebar_name' ) );
 				self::log(
 					$message,
-					compact( 'sidebar_id' ), // @todo Do we need to store the sidebar_id in Stream meta if if is already in the context?
+					compact( 'sidebar_id', 'old_widget_ids' ),
 					null,
 					array( $sidebar_id => 'sorted' )
 				);
@@ -401,13 +393,14 @@ static protected function handle_widget_moved( $old, $new ) {
 
 				$tpl_vars = compact( 'title', 'name', 'old_sidebar_name', 'new_sidebar_name' );
 				$message = self::apply_tpl_vars( $message, $tpl_vars );
+				// @todo instead of one record with two contexts, should we two records with one context each?
 				self::log(
 					$message,
-					compact( 'widget_id' ),
+					compact( 'widget_id', 'new_sidebar_id', 'old_sidebar_id' ),
 					null,
 					array(
-						$new_sidebar_id => 'moved', // added
-						$old_sidebar_id => 'moved', // subtracted
+						$new_sidebar_id => 'added',
+						$old_sidebar_id => 'removed',
 						// @todo add widget_id as a context?
 					)
 				);
@@ -426,8 +419,6 @@ static protected function handle_widget_moved( $old, $new ) {
 	 * @param array $new_value
 	 */
 	public static function callback_updated_option( $option_name, $old_value, $new_value ) {
-		// @todo Actions possible here are: created, updated, deleted; actions possible for sidebar contexts are added and remvoed
-
 		if ( ! preg_match( '/^widget_(.+)$/', $option_name, $matches ) || ! is_array( $new_value ) ) {
 			return;
 		}
@@ -516,6 +507,7 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			$tpl_vars = $update;
 			$message = self::apply_tpl_vars( $message, $tpl_vars );
 			$contexts = array( $update['sidebar_id'] => 'updated' );
+			unset( $update['title'], $update['name'] );
 			self::log( $message, $update, null, $contexts );
 		}
 
@@ -540,6 +532,7 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			$tpl_vars = $create;
 			$message = self::apply_tpl_vars( $message, $tpl_vars );
 			$contexts = array( $create['sidebar_id'] => 'created' );
+			unset( $create['title'], $create['name'] );
 			self::log( $message, $create, null, $contexts );
 		}
 
@@ -564,6 +557,7 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			$tpl_vars = $delete;
 			$message = self::apply_tpl_vars( $message, $tpl_vars );
 			$contexts = array( $delete['sidebar_id'] => 'deleted' );
+			unset( $delete['title'], $delete['name'] );
 			self::log( $message, $delete, null, $contexts );
 		}
 	}

From 2337ca795f1606b4b891b9cd6dcfc4da34cfe729 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 22:46:50 -0700
Subject: [PATCH 15/40] Skip logging created and deleted actions by default

---
 connectors/widgets.php | 103 ++++++++++++++++++++++++-----------------
 1 file changed, 61 insertions(+), 42 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index e0439acbb..71b0d943e 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -2,6 +2,15 @@
 
 class WP_Stream_Connector_Widgets extends WP_Stream_Connector {
 
+	/**
+	 * Whether or not 'created' and 'deleted' actions should be logged. Normally
+	 * the sidebar 'added' and 'removed' actions will correspond with these.
+	 * See note below with usage.
+	 *
+	 * @var bool
+	 */
+	public static $verbose_widget_created_deleted_actions = false;
+
 	/**
 	 * Context name
 	 *
@@ -512,53 +521,63 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 		}
 
 		/**
-		 * Log created actions
-		 * @todo We should only do these if not captured by an update to the sidebars_widgets option
+		 * In the normal case, widgets are never created or deleted in a vacuum.
+		 * Created widgets are immediately assigned to a sidebar, and deleted
+		 * widgets are immediately removed from their assigned sidebar. If,
+		 * however, widget instances get manipulated programmatically, it is
+		 * possible that they could be orphaned, in which case the following
+		 * actions would be useful to log.
 		 */
-		foreach ( $creates as $create ) {
-			if ( $create['name'] && $create['title'] ) {
-				$message = __( '"{title}" ({name}) created', 'stream' );
-			} else if ( $create['name'] ) {
-				// Empty title, but we have the name
-				$message = __( '{name} widget created', 'stream' );
-			} else if ( $create['title'] ) {
-				// Likely a single widget since no name is available
-				$message = __( '"{title}" widget created', 'stream' );
-			} else {
-				// Neither a name nor a title are available, so use the sidebar ID
-				$message = __( '{widget_id} widget created', 'stream' );
-			}
+		if ( self::$verbose_widget_created_deleted_actions ) {
 
-			$tpl_vars = $create;
-			$message = self::apply_tpl_vars( $message, $tpl_vars );
-			$contexts = array( $create['sidebar_id'] => 'created' );
-			unset( $create['title'], $create['name'] );
-			self::log( $message, $create, null, $contexts );
-		}
+			// We should only do these if not captured by an update to the sidebars_widgets option
+			/**
+			 * Log created actions
+			 */
+			foreach ( $creates as $create ) {
+				if ( $create['name'] && $create['title'] ) {
+					$message = __( '"{title}" ({name}) created', 'stream' );
+				} else if ( $create['name'] ) {
+					// Empty title, but we have the name
+					$message = __( '{name} widget created', 'stream' );
+				} else if ( $create['title'] ) {
+					// Likely a single widget since no name is available
+					$message = __( '"{title}" widget created', 'stream' );
+				} else {
+					// Neither a name nor a title are available, so use the sidebar ID
+					$message = __( '{widget_id} widget created', 'stream' );
+				}
 
-		/**
-		 * Log deleted actions
-		 * @todo We should only do these if not captured by an update to the sidebars_widgets option
-		 */
-		foreach ( $deletes as $delete ) {
-			if ( $delete['name'] && $delete['title'] ) {
-				$message = __( '"{title}" ({name}) deleted', 'stream' );
-			} else if ( $delete['name'] ) {
-				// Empty title, but we have the name
-				$message = __( '{name} widget deleted', 'stream' );
-			} else if ( $delete['title'] ) {
-				// Likely a single widget since no name is available
-				$message = __( '"{title}" widget deleted', 'stream' );
-			} else {
-				// Neither a name nor a title are available, so use the sidebar ID
-				$message = __( '{widget_id} widget deleted', 'stream' );
+				$tpl_vars = $create;
+				$message = self::apply_tpl_vars( $message, $tpl_vars );
+				$contexts = array( $create['sidebar_id'] => 'created' );
+				unset( $create['title'], $create['name'] );
+				self::log( $message, $create, null, $contexts );
 			}
 
-			$tpl_vars = $delete;
-			$message = self::apply_tpl_vars( $message, $tpl_vars );
-			$contexts = array( $delete['sidebar_id'] => 'deleted' );
-			unset( $delete['title'], $delete['name'] );
-			self::log( $message, $delete, null, $contexts );
+			/**
+			 * Log deleted actions
+			 */
+			foreach ( $deletes as $delete ) {
+				if ( $delete['name'] && $delete['title'] ) {
+					$message = __( '"{title}" ({name}) deleted', 'stream' );
+				} else if ( $delete['name'] ) {
+					// Empty title, but we have the name
+					$message = __( '{name} widget deleted', 'stream' );
+				} else if ( $delete['title'] ) {
+					// Likely a single widget since no name is available
+					$message = __( '"{title}" widget deleted', 'stream' );
+				} else {
+					// Neither a name nor a title are available, so use the sidebar ID
+					$message = __( '{widget_id} widget deleted', 'stream' );
+				}
+
+				$tpl_vars = $delete;
+				$message = self::apply_tpl_vars( $message, $tpl_vars );
+				$contexts = array( $delete['sidebar_id'] => 'deleted' );
+				unset( $delete['title'], $delete['name'] );
+				self::log( $message, $delete, null, $contexts );
+			}
 		}
 	}
 

From d9dd001a8ae7cd0500b2a59284ca6ee4212a80b0 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 5 Apr 2014 22:47:19 -0700
Subject: [PATCH 16/40] Break up moved record into one removed and one added
 record

---
 connectors/widgets.php | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 71b0d943e..0c155e8b5 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -402,18 +402,22 @@ static protected function handle_widget_moved( $old, $new ) {
 
 				$tpl_vars = compact( 'title', 'name', 'old_sidebar_name', 'new_sidebar_name' );
 				$message = self::apply_tpl_vars( $message, $tpl_vars );
-				// @todo instead of one record with two contexts, should we two records with one context each?
+
+				$sidebar_id = $old_sidebar_id;
 				self::log(
 					$message,
-					compact( 'widget_id', 'new_sidebar_id', 'old_sidebar_id' ),
+					compact( 'widget_id', 'sidebar_id' ),
 					null,
-					array(
-						$new_sidebar_id => 'added',
-						$old_sidebar_id => 'removed',
-						// @todo add widget_id as a context?
-					)
+					array( $sidebar_id => 'removed', )
 				);
 
+				$sidebar_id = $new_sidebar_id;
+				self::log(
+					$message,
+					compact( 'widget_id', 'sidebar_id' ),
+					null,
+					array( $sidebar_id => 'added', )
+				);
 			}
 		}
 

From a48e4922ff41b750b18bf1948468739a04ef8d07 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sun, 6 Apr 2014 01:08:13 -0700
Subject: [PATCH 17/40] Use experimental phpcs rule subset

---
 bin/.travis.yml   | 4 +++-
 phpcs.ruleset.xml | 3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/bin/.travis.yml b/bin/.travis.yml
index f1797e3de..7e546a393 100644
--- a/bin/.travis.yml
+++ b/bin/.travis.yml
@@ -19,10 +19,12 @@ before_script:
     - export WP_TESTS_DIR=/tmp/wordpress-tests/
     - export PLUGIN_DIR=$(pwd)
     - export PLUGIN_SLUG=$(basename $(pwd) | sed 's/^wp-//')
+    - export PHPCS_BRANCH=rule-subsets
     - if [ -e phpunit.xml ] || [ -e phpunit.xml.dist ]; then bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION; cd /tmp/wordpress/wp-content/plugins; ln -s $PLUGIN_DIR $PLUGIN_SLUG; cd $PLUGIN_DIR; fi
     - pear config-set auto_discover 1
     - pear install PHP_CodeSniffer
-    - git clone git://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git $(pear config-get php_dir)/PHP/CodeSniffer/Standards/WordPress
+    - curl -L https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/archive/$PHPCS_BRANCH.tar.gz | tar -zx --strip 1 -C $(pear config-get php_dir)/PHP/CodeSniffer/Standards/WordPress
+    - $(pear config-get php_dir)/PHP/CodeSniffer/Standards/WordPress/bin/install-subsets
     - phpenv rehash
     - npm install -g jshint
 
diff --git a/phpcs.ruleset.xml b/phpcs.ruleset.xml
index be48f0a3c..f8daca3b5 100644
--- a/phpcs.ruleset.xml
+++ b/phpcs.ruleset.xml
@@ -2,9 +2,10 @@
 <ruleset name="WordPress Coding Standards for Plugins">
 	<description>Generally-applicable sniffs for WordPress plugins</description>
 
-	<rule ref="WordPress" />
+	<rule ref="WordPress-Core-Extra" />
 
 	<exclude-pattern>*/vendor/*</exclude-pattern>
+	<exclude-pattern>*/bin/*</exclude-pattern>
 
 	<rule ref="WordPress.NamingConventions.ValidFunctionName">
 		<exclude-pattern>/tests/*</exclude-pattern><!-- because of PHPUnit method names -->

From 67e213961ee34c8efa88f3687a2435c7a12d09f4 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sun, 6 Apr 2014 01:11:38 -0700
Subject: [PATCH 18/40] Make the PHPCS WordPress ruleset directory

---
 bin/.travis.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/bin/.travis.yml b/bin/.travis.yml
index 7e546a393..e57423ed3 100644
--- a/bin/.travis.yml
+++ b/bin/.travis.yml
@@ -23,6 +23,7 @@ before_script:
     - if [ -e phpunit.xml ] || [ -e phpunit.xml.dist ]; then bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION; cd /tmp/wordpress/wp-content/plugins; ln -s $PLUGIN_DIR $PLUGIN_SLUG; cd $PLUGIN_DIR; fi
     - pear config-set auto_discover 1
     - pear install PHP_CodeSniffer
+    - mkdir -p $(pear config-get php_dir)/PHP/CodeSniffer/Standards/WordPress
     - curl -L https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/archive/$PHPCS_BRANCH.tar.gz | tar -zx --strip 1 -C $(pear config-get php_dir)/PHP/CodeSniffer/Standards/WordPress
     - $(pear config-get php_dir)/PHP/CodeSniffer/Standards/WordPress/bin/install-subsets
     - phpenv rehash

From 870fd532e8e763bb6a6f51bd40eb72c09a049b94 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sun, 6 Apr 2014 01:14:05 -0700
Subject: [PATCH 19/40] Apply PHPCS fixes and some phpDoc improvements

---
 connectors/installer.php |  6 +++--
 connectors/menus.php     |  7 ++++--
 connectors/widgets.php   |  2 +-
 includes/admin.php       |  3 +--
 includes/feeds.php       | 15 +++++++-----
 includes/filters.php     |  2 ++
 includes/list-table.php  |  9 ++++---
 includes/query.php       | 52 ++++++++++++++++++++--------------------
 includes/settings.php    |  4 ++--
 9 files changed, 54 insertions(+), 46 deletions(-)

diff --git a/connectors/installer.php b/connectors/installer.php
index fcc2f6db1..b08c031d1 100644
--- a/connectors/installer.php
+++ b/connectors/installer.php
@@ -117,7 +117,7 @@ public static function callback_upgrader_process_complete( $upgrader, $extra ) {
 			if ( 'upload' === $from ) {
 				if ( 'plugin' === $type ) {
 					$cached_plugins = wp_cache_get( 'plugins', 'plugins' );
-					$plugin_data    = $cached_plugins['/'.$upgrader->result['destination_name']];
+					$plugin_data    = $cached_plugins[ '/' . $upgrader->result['destination_name'] ];
 					if ( $plugin_data ) {
 						$plugin_data = reset( $plugin_data );
 					} else { // Probably a failed installation
@@ -195,7 +195,9 @@ public static function callback_upgrader_process_complete( $upgrader, $extra ) {
 		$context = $type . 's';
 
 		// If not doing bulk, simulate one to trigger a log operation
-		if ( ! $logs ) $logs[] = array();
+		if ( ! $logs ) {
+			$logs[] = array();
+		}
 
 		foreach ( $logs as $log ) {
 			extract( $log );
diff --git a/connectors/menus.php b/connectors/menus.php
index 8ba7b3150..077b3cf73 100644
--- a/connectors/menus.php
+++ b/connectors/menus.php
@@ -81,7 +81,8 @@ public static function action_links( $links, $record ) {
 			$menu_ids = wp_list_pluck( $menus, 'term_id' );
 
 			if ( in_array( $record->object_id, $menu_ids ) ) {
-				$links[ __( 'Edit Menu', 'stream' ) ] = admin_url( 'nav-menus.php?action=edit&menu=' . $record->object_id );
+				$path = 'nav-menus.php?action=edit&menu=' . $record->object_id;
+				$links[ __( 'Edit Menu', 'stream' ) ] = admin_url( $path );
 			}
 		}
 
@@ -148,7 +149,9 @@ public static function callback_delete_nav_menu( $term, $tt_id, $deleted_term )
 	 */
 	public static function callback_update_option_theme_mods( $old, $new ) {
 		// Disable if we're switching themes
-		if ( did_action( 'after_switch_theme' ) ) return;
+		if ( did_action( 'after_switch_theme' ) ) {
+			return;
+		}
 
 		$key = 'nav_menu_locations';
 
diff --git a/connectors/widgets.php b/connectors/widgets.php
index 83e63e787..34e0f10ee 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -77,7 +77,7 @@ public static function action_links( $links, $record ) {
 			global $wp_registered_sidebars;
 
 			if ( array_key_exists( $sidebar, $wp_registered_sidebars ) ) {
-				$links[ __( 'Edit Widget Area', 'stream' ) ] = admin_url( 'widgets.php#' . $sidebar );
+				$links[ __( 'Edit Widget Area', 'stream' ) ] = admin_url( "widgets.php#$sidebar" );
 			}
 		}
 
diff --git a/includes/admin.php b/includes/admin.php
index b2fb2d54b..ada4dd0f6 100644
--- a/includes/admin.php
+++ b/includes/admin.php
@@ -574,7 +574,6 @@ public static function dashboard_stream_activity_contents( $paged = 1 ) {
 			echo self::dashboard_widget_row( $record, $i ); //xss okay
 		}
 
-
 		echo '</ul>';
 
 		$total_items = self::dashboard_get_total_found_rows();
@@ -669,7 +668,7 @@ public static function dashboard_pagination( $args = array() ) {
 				<div class="clear"></div>
 			</div>';
 
-		echo '<div>' . $html_view_all . $html_pagination_links . '</div>';
+		echo '<div>' . $html_view_all . $html_pagination_links . '</div>'; // xss ok
 	}
 
 	/**
diff --git a/includes/feeds.php b/includes/feeds.php
index 109a87a9c..5ac1e8cfd 100644
--- a/includes/feeds.php
+++ b/includes/feeds.php
@@ -30,10 +30,11 @@ public static function load() {
 	 *
 	 * @action show_user_profile
 	 * @action edit_user_profile
+	 * @param WP_User $user
 	 * @return void
 	 */
 	public static function save_user_feed_key( $user ) {
-		if ( get_user_meta( $user->ID, self::USER_FEED_KEY, true ) && ! isset( $_GET[self::GENERATE_KEY_QUERY_VAR] ) ) {
+		if ( get_user_meta( $user->ID, self::USER_FEED_KEY, true ) && ! isset( $_GET[ self::GENERATE_KEY_QUERY_VAR ] ) ) {
 			return;
 		}
 
@@ -49,6 +50,7 @@ public static function save_user_feed_key( $user ) {
 	 *
 	 * @action show_user_profile
 	 * @action edit_user_profile
+	 * @param WP_User $user
 	 * @return string
 	 */
 	public static function user_feed_key( $user ) {
@@ -83,6 +85,7 @@ public static function user_feed_key( $user ) {
 		}
 
 		$nonce = wp_create_nonce( 'wp_stream_generate_key' );
+		$generate_feed_url = add_query_arg( array( self::GENERATE_KEY_QUERY_VAR => true, 'wp_stream_nonce' => $nonce ) ) . sprintf( '#wp-stream-highlight:%s', self::USER_FEED_KEY );
 		?>
 		<table class="form-table">
 			<tr>
@@ -90,11 +93,11 @@ public static function user_feed_key( $user ) {
 				<td>
 					<p>
 						<input type="text" name="<?php echo esc_attr( self::USER_FEED_KEY ) ?>" id="<?php echo esc_attr( self::USER_FEED_KEY ) ?>" class="regular-text code" value="<?php echo esc_attr( $key ) ?>" readonly>
-						<small><a href="<?php echo esc_url( add_query_arg( array( self::GENERATE_KEY_QUERY_VAR => true, 'wp_stream_nonce' => $nonce ) ) . sprintf( '#wp-stream-highlight:%s', self::USER_FEED_KEY ) ) ?>"><?php esc_html_e( 'Generate new key', 'stream' ) ?></a></small>
+						<small><a href="<?php echo esc_url( $generate_feed_url ); ?>"><?php esc_html_e( 'Generate new key', 'stream' ) ?></a></small>
 					</p>
 					<p class="description"><?php esc_html_e( 'This is your private key used for accessing feeds of Stream Records securely. You can change your key at any time by generating a new one using the link above.', 'stream' ) ?></p>
 					<p>
-						<a href="<?php echo esc_url( $link ) ?>" target="_blank"><?php echo esc_html_e( 'RSS Feed' ) ?></a>
+						<a href="<?php echo esc_url( $link ) ?>" target="_blank"><?php esc_html_e( 'RSS Feed' ) ?></a>
 						|
 						<a href="<?php echo esc_url( add_query_arg( array( 'type' => 'json' ), $link ) ) ?>" target="_blank"><?php echo esc_html_e( 'JSON Feed' ) ?></a>
 					</p>
@@ -113,13 +116,13 @@ public static function feed_template() {
 		$die_title   = esc_html__( 'Access Denied', 'stream' );
 		$die_message = '<h1>' . $die_title .'</h1><p>' . esc_html__( 'You don\'t have permission to view this feed, please contact your site Administrator.', 'stream' ) . '</p>';
 
-		if ( ! isset( $_GET[self::FEED_KEY_QUERY_VAR] ) || empty( $_GET[self::FEED_KEY_QUERY_VAR] ) ) {
+		if ( ! isset( $_GET[ self::FEED_KEY_QUERY_VAR ] ) || empty( $_GET[ self::FEED_KEY_QUERY_VAR ] ) ) {
 			wp_die( $die_message, $die_title );
 		}
 
 		$args = array(
 			'meta_key'   => self::USER_FEED_KEY,
-			'meta_value' => $_GET[self::FEED_KEY_QUERY_VAR],
+			'meta_value' => $_GET[ self::FEED_KEY_QUERY_VAR ],
 			'number'     => 1,
 		);
 		$user = get_users( $args );
@@ -166,7 +169,7 @@ public static function feed_template() {
 
 			header( 'Content-Type: ' . feed_content_type( 'rss-http' ) . '; charset=' . get_option( 'blog_charset' ), true );
 
-			echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?>';
+			echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?>'; // xss ok
 			?>
 
 			<rss version="2.0"
diff --git a/includes/filters.php b/includes/filters.php
index 774b0a890..32b66248e 100644
--- a/includes/filters.php
+++ b/includes/filters.php
@@ -94,7 +94,9 @@ public static function filter( $var, $filter = null, $options = array() ) {
 	}
 
 	public static function is_regex( $var ) {
+		// @codingStandardsIgnoreStart
 		$test = @preg_match( $var, '' );
+		// @codingStandardsIgnoreEnd
 
 		return $test !== false;
 	}
diff --git a/includes/list-table.php b/includes/list-table.php
index 6c6547750..dda107491 100644
--- a/includes/list-table.php
+++ b/includes/list-table.php
@@ -383,8 +383,8 @@ function column_link( $display, $key, $value = null, $title = null ) {
 	}
 
 	public function get_term_title( $term, $type ) {
-		if ( isset( WP_Stream_Connectors::$term_labels["stream_$type"][ $term ] ) ) {
-			return WP_Stream_Connectors::$term_labels["stream_$type"][ $term ];
+		if ( isset( WP_Stream_Connectors::$term_labels[ "stream_$type" ][ $term ] ) ) {
+			return WP_Stream_Connectors::$term_labels[ "stream_$type" ][ $term ];
 		}
 		else {
 			return $term;
@@ -415,7 +415,7 @@ function assemble_records( $column, $table = '' ) {
 		 *
 		 * @param bool $hidden Visibility status, default is Hide Previous Record value set in Exclude setting.
 		 */
-		$hide_disabled_column_filter = apply_filters( 'wp_stream_list_table_hide_disabled_ ' . $setting_key, ( WP_Stream_Settings::$options[ 'exclude_hide_previous_records' ] === 0 ) ? false : true );
+		$hide_disabled_column_filter = apply_filters( 'wp_stream_list_table_hide_disabled_ ' . $setting_key, ( WP_Stream_Settings::$options['exclude_hide_previous_records'] === 0 ) ? false : true );
 
 		if ( 'author' === $column ) {
 			$all_records = array();
@@ -548,7 +548,6 @@ function filters_form() {
 
 	function filter_select( $name, $title, $items, $ajax, $enabled = true ) {
 
-
 		if ( $ajax ) {
 			$out = sprintf(
 				'<select name="%s" class="chosen-select" data-placeholder="%s">%s</select>',
@@ -657,7 +656,7 @@ class="date-picker field-to"
 	}
 
 	function display() {
-		echo '<form method="get" action="' . admin_url( WP_Stream_Admin::ADMIN_PARENT_PAGE ) . '">';
+		echo '<form method="get" action="' . admin_url( WP_Stream_Admin::ADMIN_PARENT_PAGE ) . '">'; // xss ok
 		echo $this->filter_search(); // xss ok
 		parent::display();
 		echo '</form>';
diff --git a/includes/query.php b/includes/query.php
index cf6ac0017..51c5ab73a 100644
--- a/includes/query.php
+++ b/includes/query.php
@@ -60,7 +60,7 @@ public function query( $args ) {
 			'fields'                => '',
 			'ignore_context'        => null,
 			// Hide records that match the exclude rules
-			'hide_excluded'         => ! empty( WP_Stream_Settings::$options[ 'exclude_hide_previous_records' ] ),
+			'hide_excluded'         => ! empty( WP_Stream_Settings::$options['exclude_hide_previous_records'] ),
 		);
 
 		$args = wp_parse_args( $args, $defaults );
@@ -72,7 +72,7 @@ public function query( $args ) {
 		 */
 		$args = apply_filters( 'stream_query_args', $args );
 
-		if ( true === $args[ 'hide_excluded' ] ) {
+		if ( true === $args['hide_excluded'] ) {
 			$args = self::add_excluded_record_args( $args );
 		}
 
@@ -133,72 +133,72 @@ public function query( $args ) {
 		/**
 		 * PARSE __IN PARAM FAMILY
 		 */
-		if ( $args[ 'record_greater_than' ] ) {
-			$where .= $wpdb->prepare( " AND $wpdb->stream.ID > %d", (int) $args[ 'record_greater_than' ] );
+		if ( $args['record_greater_than'] ) {
+			$where .= $wpdb->prepare( " AND $wpdb->stream.ID > %d", (int) $args['record_greater_than'] );
 		}
 
-		if ( $args[ 'record__in' ] ) {
-			$record__in = array_filter( (array) $args[ 'record__in' ], 'is_numeric' );
+		if ( $args['record__in'] ) {
+			$record__in = array_filter( (array) $args['record__in'], 'is_numeric' );
 			if ( ! empty( $record__in ) ) {
 				$record__in_format = '(' . join( ',', array_fill( 0, count( $record__in ), '%d' ) ) . ')';
 				$where .= $wpdb->prepare( " AND $wpdb->stream.ID IN {$record__in_format}", $record__in );
 			}
 		}
 
-		if ( $args[ 'record__not_in' ] ) {
-			$record__not_in = array_filter( (array) $args[ 'record__not_in' ], 'is_numeric' );
+		if ( $args['record__not_in'] ) {
+			$record__not_in = array_filter( (array) $args['record__not_in'], 'is_numeric' );
 			if ( ! empty( $record__not_in ) ) {
 				$record__not_in_format = '(' . join( ',', array_fill( 0, count( $record__not_in ), '%d' ) ) . ')';
 				$where .= $wpdb->prepare( " AND $wpdb->stream.ID NOT IN {$record__not_in_format}", $record__not_in );
 			}
 		}
 
-		if ( $args[ 'record_parent' ] ) {
-			$where .= $wpdb->prepare( " AND $wpdb->stream.parent = %d", (int) $args[ 'record_parent' ] );
+		if ( $args['record_parent'] ) {
+			$where .= $wpdb->prepare( " AND $wpdb->stream.parent = %d", (int) $args['record_parent'] );
 		}
 
-		if ( $args[ 'record_parent__in' ] ) {
-			$record_parent__in = array_filter( (array) $args[ 'record_parent__in' ], 'is_numeric' );
+		if ( $args['record_parent__in'] ) {
+			$record_parent__in = array_filter( (array) $args['record_parent__in'], 'is_numeric' );
 			if ( ! empty( $record_parent__in ) ) {
 				$record_parent__in_format = '(' . join( ',', array_fill( 0, count( $record_parent__in ), '%d' ) ) . ')';
 				$where .= $wpdb->prepare( " AND $wpdb->stream.parent IN {$record_parent__in_format}", $record_parent__in );
 			}
 		}
 
-		if ( $args[ 'record_parent__not_in' ] ) {
-			$record_parent__not_in = array_filter( (array) $args[ 'record_parent__not_in' ], 'is_numeric' );
+		if ( $args['record_parent__not_in'] ) {
+			$record_parent__not_in = array_filter( (array) $args['record_parent__not_in'], 'is_numeric' );
 			if ( ! empty( $record_parent__not_in ) ) {
 				$record_parent__not_in_format = '(' . join( ',', array_fill( 0, count( $record_parent__not_in ), '%d' ) ) . ')';
 				$where .= $wpdb->prepare( " AND $wpdb->stream.parent NOT IN {$record_parent__not_in_format}", $record_parent__not_in );
 			}
 		}
 
-		if ( $args[ 'author__in' ] ) {
-			$author__in = array_filter( (array) $args[ 'author__in' ], 'is_numeric' );
+		if ( $args['author__in'] ) {
+			$author__in = array_filter( (array) $args['author__in'], 'is_numeric' );
 			if ( ! empty( $author__in ) ) {
 				$author__in_format = '(' . join( ',', array_fill( 0, count( $author__in ), '%d' ) ) . ')';
 				$where .= $wpdb->prepare( " AND $wpdb->stream.author IN {$author__in_format}", $author__in );
 			}
 		}
 
-		if ( $args[ 'author__not_in' ] ) {
-			$author__not_in = array_filter( (array) $args[ 'author__not_in' ], 'is_numeric' );
+		if ( $args['author__not_in'] ) {
+			$author__not_in = array_filter( (array) $args['author__not_in'], 'is_numeric' );
 			if ( ! empty( $author__not_in ) ) {
 				$author__not_in_format = '(' . join( ',', array_fill( 0, count( $author__not_in ), '%d' ) ) . ')';
 				$where .= $wpdb->prepare( " AND $wpdb->stream.author NOT IN {$author__not_in_format}", $author__not_in );
 			}
 		}
-		if ( $args[ 'ip__in' ] ) {
-			if ( ! empty( $args[ 'ip__in' ] ) ) {
-				$ip__in = '(' . join( ',', array_fill( 0, count( $args[ 'ip__in' ] ), '%s' ) ) . ')';
-				$where .= $wpdb->prepare( " AND $wpdb->stream.ip IN {$ip__in}", $args[ 'ip__in' ] );
+		if ( $args['ip__in'] ) {
+			if ( ! empty( $args['ip__in'] ) ) {
+				$ip__in = '(' . join( ',', array_fill( 0, count( $args['ip__in'] ), '%s' ) ) . ')';
+				$where .= $wpdb->prepare( " AND $wpdb->stream.ip IN {$ip__in}", $args['ip__in'] );
 			}
 		}
 
-		if ( $args[ 'ip__not_in' ] ) {
-			if ( ! empty( $args[ 'ip__not_in' ] ) ) {
-				$ip__not_in = '(' . join( ',', array_fill( 0, count( $args[ 'ip__not_in' ] ), '%s' ) ) . ')';
-				$where     .= $wpdb->prepare( " AND $wpdb->stream.ip NOT IN {$ip__not_in}", $args[ 'ip__not_in' ] );
+		if ( $args['ip__not_in'] ) {
+			if ( ! empty( $args['ip__not_in'] ) ) {
+				$ip__not_in = '(' . join( ',', array_fill( 0, count( $args['ip__not_in'] ), '%s' ) ) . ')';
+				$where     .= $wpdb->prepare( " AND $wpdb->stream.ip NOT IN {$ip__not_in}", $args['ip__not_in'] );
 			}
 		}
 
diff --git a/includes/settings.php b/includes/settings.php
index c4b76383b..f9249b42a 100644
--- a/includes/settings.php
+++ b/includes/settings.php
@@ -716,8 +716,8 @@ public static function get_default_connectors() {
 	 */
 	public static function get_terms_labels( $column ) {
 		$return_labels = array();
-		if ( isset ( WP_Stream_Connectors::$term_labels['stream_' . $column ] ) ) {
-			$return_labels = WP_Stream_Connectors::$term_labels['stream_' . $column ];
+		if ( isset ( WP_Stream_Connectors::$term_labels[ 'stream_' . $column ] ) ) {
+			$return_labels = WP_Stream_Connectors::$term_labels[ 'stream_' . $column ];
 			ksort( $return_labels );
 		}
 

From 6ba38885f97e674074f48c9209594b159876d1e5 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Wed, 16 Apr 2014 22:25:05 -0700
Subject: [PATCH 20/40] Allow PHPCS and WPCS to pull from different locations

 * Point to expirimental PHPCS and WPCS for rulset subsets
 * Introduce config file for managing Travis before_script environment
 * Remove phpcs.ruleset.xml since we're referencing a core ruleset

See x-team/wp-plugin-dev-lib#30
---
 .travis.before_script.sh |  5 +++++
 bin/.travis.yml          | 15 ++++++++++-----
 phpcs.ruleset.xml        | 17 -----------------
 3 files changed, 15 insertions(+), 22 deletions(-)
 create mode 100644 .travis.before_script.sh
 delete mode 100644 phpcs.ruleset.xml

diff --git a/.travis.before_script.sh b/.travis.before_script.sh
new file mode 100644
index 000000000..973cfc15d
--- /dev/null
+++ b/.travis.before_script.sh
@@ -0,0 +1,5 @@
+export PHPCS_GITHUB_SRC=x-team/PHP_CodeSniffer
+export PHPCS_GIT_TREE=subset-selection
+export WPCS_GIT_TREE=rule-subset-with-phpcs-pr
+export WPCS_STANDARD=WordPress:core-extra
+export PHPCS_INGORE='tests/*,includes/vendor/*'
diff --git a/bin/.travis.yml b/bin/.travis.yml
index f1797e3de..3c82eb26c 100644
--- a/bin/.travis.yml
+++ b/bin/.travis.yml
@@ -19,15 +19,20 @@ before_script:
     - export WP_TESTS_DIR=/tmp/wordpress-tests/
     - export PLUGIN_DIR=$(pwd)
     - export PLUGIN_SLUG=$(basename $(pwd) | sed 's/^wp-//')
+    - export PHPCS_DIR=/tmp/phpcs
+    - export PHPCS_GITHUB_SRC=squizlabs/PHP_CodeSniffer
+    - export PHPCS_GIT_TREE=master
+    - export WPCS_GITHUB_SRC=WordPress-Coding-Standards/WordPress-Coding-Standards
+    - export WPCS_GIT_TREE=master
+    - export WPCS_STANDARD=$(if [ -e phpcs.ruleset.xml ]; then echo phpcs.ruleset.xml; else echo WordPress; fi)
+    - if [ -e .travis.before_script.sh ] source .travis.before_script.sh; fi
     - if [ -e phpunit.xml ] || [ -e phpunit.xml.dist ]; then bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION; cd /tmp/wordpress/wp-content/plugins; ln -s $PLUGIN_DIR $PLUGIN_SLUG; cd $PLUGIN_DIR; fi
-    - pear config-set auto_discover 1
-    - pear install PHP_CodeSniffer
-    - git clone git://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git $(pear config-get php_dir)/PHP/CodeSniffer/Standards/WordPress
-    - phpenv rehash
+    - mkdir -p $PHPCS_DIR && curl -L https://github.com/$PHPCS_GITHUB_SRC/archive/$PHPCS_GIT_TREE.tar.gz | tar xvz --strip-components=1 -C $PHPCS_DIR
+    - mkdir -p $PHPCS_DIR/CodeSniffer/Standards/WordPress && curl -L https://github.com/$WPCS_GITHUB_SRC/archive/$WPCS_GIT_TREE.tar.gz | tar xvz --strip-components=1 -C $PHPCS_DIR/CodeSniffer/Standards/WordPress
     - npm install -g jshint
 
 script:
     - find . -path ./bin -prune -o \( -name '*.php' -o -name '*.inc' \) -exec php -lf {} \;
     - if [ -e phpunit.xml ] || [ -e phpunit.xml.dist ]; then phpunit; fi
-    - phpcs --standard=$(if [ -e phpcs.ruleset.xml ]; then echo phpcs.ruleset.xml; else echo WordPress; fi) $(find . -name '*.php')
+    - $PHPCS_DIR/scripts/phpcs --standard=$WPCS_STANDARD $(if [ -n "$PHPCS_IGNORE" ]; then echo --ignore=$PHPCS_IGNORE; fi) $(find . -name '*.php')
     - jshint .
diff --git a/phpcs.ruleset.xml b/phpcs.ruleset.xml
deleted file mode 100644
index be48f0a3c..000000000
--- a/phpcs.ruleset.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0"?>
-<ruleset name="WordPress Coding Standards for Plugins">
-	<description>Generally-applicable sniffs for WordPress plugins</description>
-
-	<rule ref="WordPress" />
-
-	<exclude-pattern>*/vendor/*</exclude-pattern>
-
-	<rule ref="WordPress.NamingConventions.ValidFunctionName">
-		<exclude-pattern>/tests/*</exclude-pattern><!-- because of PHPUnit method names -->
-	</rule>
-
-	<rule ref="WordPress.Arrays.ArrayDeclaration">
-		<exclude-pattern>/includes/settings.php</exclude-pattern>
-	</rule>
-
-</ruleset>

From 948280ed73289e021fbb904a11a343455a777352 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Wed, 16 Apr 2014 22:46:48 -0700
Subject: [PATCH 21/40] Fix .travis.yml syntax error

---
 bin/.travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bin/.travis.yml b/bin/.travis.yml
index 3c82eb26c..5cc0bf6ed 100644
--- a/bin/.travis.yml
+++ b/bin/.travis.yml
@@ -25,7 +25,7 @@ before_script:
     - export WPCS_GITHUB_SRC=WordPress-Coding-Standards/WordPress-Coding-Standards
     - export WPCS_GIT_TREE=master
     - export WPCS_STANDARD=$(if [ -e phpcs.ruleset.xml ]; then echo phpcs.ruleset.xml; else echo WordPress; fi)
-    - if [ -e .travis.before_script.sh ] source .travis.before_script.sh; fi
+    - if [ -e .travis.before_script.sh ]; then source .travis.before_script.sh; fi
     - if [ -e phpunit.xml ] || [ -e phpunit.xml.dist ]; then bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION; cd /tmp/wordpress/wp-content/plugins; ln -s $PLUGIN_DIR $PLUGIN_SLUG; cd $PLUGIN_DIR; fi
     - mkdir -p $PHPCS_DIR && curl -L https://github.com/$PHPCS_GITHUB_SRC/archive/$PHPCS_GIT_TREE.tar.gz | tar xvz --strip-components=1 -C $PHPCS_DIR
     - mkdir -p $PHPCS_DIR/CodeSniffer/Standards/WordPress && curl -L https://github.com/$WPCS_GITHUB_SRC/archive/$WPCS_GIT_TREE.tar.gz | tar xvz --strip-components=1 -C $PHPCS_DIR/CodeSniffer/Standards/WordPress

From d1a5186141acedfd09fae0ca729a08b5e0ff31eb Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Wed, 16 Apr 2014 22:49:16 -0700
Subject: [PATCH 22/40] Add xss ok for phpcs

---
 includes/dashboard.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/includes/dashboard.php b/includes/dashboard.php
index c6ced8575..ee5e8e0c1 100644
--- a/includes/dashboard.php
+++ b/includes/dashboard.php
@@ -164,7 +164,7 @@ public static function pagination( $args = array() ) {
 				<div class="clear"></div>
 			</div>';
 
-		echo '<div>' . $html_view_all . $html_pagination_links . '</div>';
+		echo '<div>' . $html_view_all . $html_pagination_links . '</div>'; // xss ok
 	}
 
 	/**

From aa8106923480d97a0dd4e52df75cf16ee0ad6ce0 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Wed, 16 Apr 2014 22:54:29 -0700
Subject: [PATCH 23/40] Use .ci-env.sh (nee .travis.before_script.sh) in
 pre-commit hook

---
 .travis.before_script.sh => .ci-env.sh | 0
 bin/.travis.yml                        | 2 +-
 bin/pre-commit                         | 6 ++++--
 3 files changed, 5 insertions(+), 3 deletions(-)
 rename .travis.before_script.sh => .ci-env.sh (100%)

diff --git a/.travis.before_script.sh b/.ci-env.sh
similarity index 100%
rename from .travis.before_script.sh
rename to .ci-env.sh
diff --git a/bin/.travis.yml b/bin/.travis.yml
index 5cc0bf6ed..89d3f4083 100644
--- a/bin/.travis.yml
+++ b/bin/.travis.yml
@@ -25,7 +25,7 @@ before_script:
     - export WPCS_GITHUB_SRC=WordPress-Coding-Standards/WordPress-Coding-Standards
     - export WPCS_GIT_TREE=master
     - export WPCS_STANDARD=$(if [ -e phpcs.ruleset.xml ]; then echo phpcs.ruleset.xml; else echo WordPress; fi)
-    - if [ -e .travis.before_script.sh ]; then source .travis.before_script.sh; fi
+    - if [ -e .ci-env.sh ]; then source .ci-env.sh; fi
     - if [ -e phpunit.xml ] || [ -e phpunit.xml.dist ]; then bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION; cd /tmp/wordpress/wp-content/plugins; ln -s $PLUGIN_DIR $PLUGIN_SLUG; cd $PLUGIN_DIR; fi
     - mkdir -p $PHPCS_DIR && curl -L https://github.com/$PHPCS_GITHUB_SRC/archive/$PHPCS_GIT_TREE.tar.gz | tar xvz --strip-components=1 -C $PHPCS_DIR
     - mkdir -p $PHPCS_DIR/CodeSniffer/Standards/WordPress && curl -L https://github.com/$WPCS_GITHUB_SRC/archive/$WPCS_GIT_TREE.tar.gz | tar xvz --strip-components=1 -C $PHPCS_DIR/CodeSniffer/Standards/WordPress
diff --git a/bin/pre-commit b/bin/pre-commit
index 8f50f0da5..088c17558 100755
--- a/bin/pre-commit
+++ b/bin/pre-commit
@@ -3,6 +3,9 @@
 
 set -e
 
+WPCS_STANDARD=$(if [ -e phpcs.ruleset.xml ]; then echo phpcs.ruleset.xml; else echo WordPress; fi)
+if [ -e .ci-env.sh ]; then source .ci-env.sh; fi
+
 message="Checking staged changes..."
 git_status_egrep='^[MARC].+'
 
@@ -59,8 +62,7 @@ if [ ${#staged_php_files[@]} != 0 ]; then
 	# PHP_CodeSniffer WordPress Coding Standards
 	echo "## phpcs"
 	if command -v phpcs >/dev/null 2>&1; then
-		phpcs_standard=$(if [ -e phpcs.ruleset.xml ]; then echo phpcs.ruleset.xml; else echo WordPress; fi)
-		phpcs -p -s -v --standard=$phpcs_standard "${staged_php_files[@]}"
+		phpcs -p -s -v --standard=$WPCS_STANDARD $(if [ -n "$PHPCS_IGNORE" ]; then echo --ignore=$PHPCS_IGNORE; fi) "${staged_php_files[@]}"
 	else
 		echo "Skipping phpcs since not installed"
 	fi

From 297ccf00b478dea05ceb8dfb1c9658f5fbe83a72 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 26 Apr 2014 00:07:56 -0700
Subject: [PATCH 24/40] Collapse changes to sidebars_widgets in customizer

Prevent widget from being incorrectly indicated as being deactivated and then reactivated in another sidebar during a move
---
 connectors/widgets.php | 41 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 39 insertions(+), 2 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 483a451e6..28ad321e0 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -28,6 +28,14 @@ class WP_Stream_Connector_Widgets extends WP_Stream_Connector {
 		'updated_option',
 	);
 
+	/**
+	 * Store the initial sidebars_widgets option when the customizer does its
+	 * multiple rounds of saving to the sidebars_widgets option.
+	 *
+	 * @var array
+	 */
+	protected static $customizer_initial_sidebars_widgets = null;
+
 	/**
 	 * Return translated context label
 	 *
@@ -107,14 +115,44 @@ public static function action_links( $links, $record ) {
 	 * @return void
 	 */
 	public static function callback_update_option_sidebars_widgets( $old, $new ) {
-
 		// Disable listener if we're switching themes
 		if ( did_action( 'after_switch_theme' ) ) {
 			return;
 		}
 
+		if ( did_action( 'customize_save' ) ) {
+			if ( is_null( self::$customizer_initial_sidebars_widgets ) ) {
+				self::$customizer_initial_sidebars_widgets = $old;
+				add_action( 'customize_save_after', array( __CLASS__, '_callback_customize_save_after' ) );
+			}
+		} else {
+			self::handle_sidebars_widgets_changes( $old, $new );
+		}
+	}
+
+	/**
+	 * Since the sidebars_widgets may get updated multiple times when saving
+	 * changes to Widgets in the Customizer, defer handling the changes until
+	 * customize_save_after.
+	 *
+	 * @see self::callback_update_option_sidebars_widgets()
+	 */
+	public static function _callback_customize_save_after() {
+		$old_sidebars_widgets = self::$customizer_initial_sidebars_widgets;
+		$new_sidebars_widgets = get_option( 'sidebars_widgets' );
+		self::handle_sidebars_widgets_changes( $old_sidebars_widgets, $new_sidebars_widgets );
+	}
+
+	/**
+	 * @param array $old
+	 * @param array $new
+	 */
+	protected static function handle_sidebars_widgets_changes( $old, $new ) {
 		unset( $old['array_version'] );
 		unset( $new['array_version'] );
+		if ( $old === $new ) {
+			return;
+		}
 
 		self::handle_deactivated_widgets( $old, $new );
 		self::handle_reactivated_widgets( $old, $new );
@@ -124,7 +162,6 @@ public static function callback_update_option_sidebars_widgets( $old, $new ) {
 		self::handle_widget_moved( $old, $new );
 	}
 
-
 	/**
 	 * Track deactivation of widgets from sidebars
 	 *

From 8f3f0882975ef5bf4d610c6f1fa556344ac43f47 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sat, 26 Apr 2014 00:13:46 -0700
Subject: [PATCH 25/40] Fix PHPCS issues

---
 includes/feeds.php      | 2 +-
 includes/list-table.php | 1 -
 includes/settings.php   | 2 +-
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/includes/feeds.php b/includes/feeds.php
index bc7979e55..3ae41b77a 100644
--- a/includes/feeds.php
+++ b/includes/feeds.php
@@ -187,7 +187,7 @@ public static function feed_template() {
 		$die_title   = esc_html__( 'Access Denied', 'stream' );
 		$die_message = '<h1>' . $die_title .'</h1><p>' . esc_html__( 'You don\'t have permission to view this feed, please contact your site Administrator.', 'stream' ) . '</p>';
 
-		if ( ! isset( $_GET[self::FEED_QUERY_VAR] ) || empty( $_GET[self::FEED_QUERY_VAR] ) ) {
+		if ( ! isset( $_GET[ self::FEED_QUERY_VAR ] ) || empty( $_GET[ self::FEED_QUERY_VAR ] ) ) {
 			wp_die( $die_message, $die_title );
 		}
 
diff --git a/includes/list-table.php b/includes/list-table.php
index 63f9e2d86..9059a250d 100644
--- a/includes/list-table.php
+++ b/includes/list-table.php
@@ -557,7 +557,6 @@ public function get_filters() {
 			'items' => $this->assemble_records( 'action' ),
 		);
 
-
 		/**
 		 * Filter allows additional filters in the list table dropdowns
 		 * Note the format of the filters above, with they key and array
diff --git a/includes/settings.php b/includes/settings.php
index 1abdeb721..2f4ea123e 100644
--- a/includes/settings.php
+++ b/includes/settings.php
@@ -591,7 +591,7 @@ public static function render_field( $field ) {
 				$output .= '</fieldset></div>';
 				break;
 			case 'select':
-				$current_value = (array) self::$options[$section . '_' . $name];
+				$current_value = (array) self::$options[ $section . '_' . $name ];
 				$default_value = isset( $default['value'] ) ? $default['value'] : '-1';
 				$default_name  = isset( $default['name'] ) ? $default['name'] : 'Choose Setting';
 

From 2d172cbb0dd2bee17e8f1ea67ad7d090b29536cf Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Thu, 1 May 2014 15:35:07 -0700
Subject: [PATCH 26/40] Eliminate apply_tpl_vars(), and restore use of _x()

---
 connectors/widgets.php | 112 ++++++++++++++++-------------------------
 1 file changed, 42 insertions(+), 70 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 602891efe..919de7a03 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -183,20 +183,19 @@ static protected function handle_deactivated_widgets( $old, $new ) {
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
 			if ( $name && $title ) {
-				$message = __( '"{title}" ({name}) widget deactivated', 'stream' );
+				$message = _x( '"%1$s" (%2$s) deactivated', '1: Title, 2: Name', 'stream' );
 			} else if ( $name ) {
 				// Empty title, but we have the name
-				$message = __( '{name} widget deactivated', 'stream' );
+				$message = _x( '%2$s deactivated', '2: Name', 'stream' );
 			} else if ( $title ) {
 				// Likely a single widget since no name is available
-				$message = __( '"{title}" widget deactivated', 'stream' );
+				$message = _x( '"%1$s" widget deactivated', '1: Title', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = __( '{widget_id} widget deactivated', 'stream' );
+				$message = _x( '%3$s widget deactivated', '3: Widget ID', 'stream' );
 			}
-			$tpl_vars = compact( 'name', 'title', 'widget_id' );
-			$message = self::apply_tpl_vars( $message, $tpl_vars );
 
+			$message = sprintf( $message, $title, $name, $widget_id );
 			self::log(
 				$message,
 				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
@@ -229,20 +228,19 @@ static protected function handle_reactivated_widgets( $old, $new ) {
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
 			if ( $name && $title ) {
-				$message = __( '"{title}" ({name}) widget reactivated', 'stream' );
+				$message = _x( '"%1$s" (%2$s) reactivated', '1: Title, 2: Name', 'stream' );
 			} else if ( $name ) {
 				// Empty title, but we have the name
-				$message = __( '{name} widget reactivated', 'stream' );
+				$message = _x( '%2$s reactivated', '2: Name', 'stream' );
 			} else if ( $title ) {
 				// Likely a single widget since no name is available
-				$message = __( '"{title}" widget reactivated', 'stream' );
+				$message = _x( '"%1$s" widget reactivated', '1: Title', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = __( '{widget_id} widget reactivated', 'stream' );
+				$message = _x( '%3$s widget reactivated', '3: Widget ID', 'stream' );
 			}
 
-			$tpl_vars = compact( 'name', 'title', 'widget_id' );
-			$message = self::apply_tpl_vars( $message, $tpl_vars );
+			$message = sprintf( $message, $title, $name, $widget_id );
 			self::log(
 				$message,
 				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
@@ -278,20 +276,19 @@ static protected function handle_widget_removal( $old, $new ) {
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
 			if ( $name && $title ) {
-				$message = __( '"{title}" ({name}) widget removed', 'stream' );
+				$message = _x( '"%1$s" (%2$s) removed', '1: Title, 2: Name', 'stream' );
 			} else if ( $name ) {
 				// Empty title, but we have the name
-				$message = __( '{name} widget removed', 'stream' );
+				$message = _x( '%2$s removed', '2: Name', 'stream' );
 			} else if ( $title ) {
 				// Likely a single widget since no name is available
-				$message = __( '"{title}" widget removed', 'stream' );
+				$message = _x( '"%1$s" widget removed', '1: Title', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = __( '{widget_id} widget removed', 'stream' );
+				$message = _x( '%3$s widget removed', '3: Widget ID', 'stream' );
 			}
 
-			$tpl_vars = compact( 'name', 'title', 'widget_id' );
-			$message = self::apply_tpl_vars( $message, $tpl_vars );
+			$message = sprintf( $message, $title, $name, $widget_id );
 			self::log(
 				$message,
 				compact( 'widget_id', 'sidebar_id' ),
@@ -325,20 +322,19 @@ static protected function handle_widget_addition( $old, $new ) {
 			$title = self::get_widget_title( $widget_id );
 			$name = self::get_widget_name( $widget_id );
 			if ( $name && $title ) {
-				$message = __( '"{title}" ({name}) widget added', 'stream' );
+				$message = _x( '"%1$s" (%2$s) added', '1: Title, 2: Name', 'stream' );
 			} else if ( $name ) {
 				// Empty title, but we have the name
-				$message = __( '{name} widget added', 'stream' );
+				$message = _x( '%2$s added', '2: Name', 'stream' );
 			} else if ( $title ) {
 				// Likely a single widget since no name is available
-				$message = __( '"{title}" widget added', 'stream' );
+				$message = _x( '"%1$s" widget added', '1: Title', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = __( '{widget_id} widget added', 'stream' );
+				$message = _x( '%3$s widget added', '3: Widget ID', 'stream' );
 			}
 
-			$tpl_vars = compact( 'name', 'title', 'widget_id' );
-			$message = self::apply_tpl_vars( $message, $tpl_vars );
+			$message = sprintf( $message, $title, $name, $widget_id );
 			self::log(
 				$message,
 				compact( 'widget_id', 'sidebar_id' ), // @todo Do we care about sidebar_id in meta if it is already context? But there is no 'context' for what the context signifies
@@ -375,8 +371,8 @@ static protected function handle_widget_reordering( $old, $new ) {
 				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
 				$old_widget_ids = $old[ $sidebar_id ];
-				$message = __( 'Widgets in "{sidebar_name}" were reordered', 'stream' );
-				$message = self::apply_tpl_vars( $message, compact( 'sidebar_name' ) );
+				$message = _x( 'Widgets in "%s" were reordered', 'Sidebar name', 'stream' );
+				$message = sprintf( $message, $sidebar_name );
 				self::log(
 					$message,
 					compact( 'sidebar_id', 'old_widget_ids' ),
@@ -425,21 +421,19 @@ static protected function handle_widget_moved( $old, $new ) {
 				$title = self::get_widget_title( $widget_id );
 				$name = self::get_widget_name( $widget_id );
 				if ( $name && $title ) {
-					$message = __( '"{title}" ({name}) widget moved from {old_sidebar_name} to {new_sidebar_name}', 'stream' );
+					$message = _x( '"%1$s" (%2$s) widget moved from %4$s to %5$s', '1: Title, 2: Name, 4: Old Sidebar, 5: New Sidebar', 'stream' );
 				} else if ( $name ) {
 					// Empty title, but we have the name
-					$message = __( '{name} widget moved from {old_sidebar_name} to {new_sidebar_name}', 'stream' );
+					$message = _x( '%2$s widget moved from %4$s to %5$s', '2: Name, 4: Old Sidebar, 5: New Sidebar', 'stream' );
 				} else if ( $title ) {
 					// Likely a single widget since no name is available
-					$message = __( '"{title}" widget moved from {old_sidebar_name} to {new_sidebar_name}', 'stream' );
+					$message = _x( '"%1$s" widget moved from %4$s to %5$s', '1: Title, 4: Old Sidebar, 5: New Sidebar', 'stream' );
 				} else {
 					// Neither a name nor a title are available, so use the sidebar ID
-					$message = __( '{widget_id} widget moved from {old_sidebar_name} to {new_sidebar_name}', 'stream' );
+					$message = _x( '%3$s widget moved from %4$s to %5$s', '3: Widget ID, 4: Old Sidebar, 5: New Sidebar', 'stream' );
 				}
 
-				$tpl_vars = compact( 'title', 'name', 'old_sidebar_name', 'new_sidebar_name' );
-				$message = self::apply_tpl_vars( $message, $tpl_vars );
-
+				$message = sprintf( $message, $title, $name, $widget_id, $old_sidebar_name, $new_sidebar_name );
 				$sidebar_id = $old_sidebar_id;
 				self::log(
 					$message,
@@ -542,20 +536,19 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 		 */
 		foreach ( $updates as $update ) {
 			if ( $update['name'] && $update['title'] ) {
-				$message = __( '"{title}" ({name}) updated', 'stream' );
+				$message = _x( '"%1$s" (%2$s) updated', '1: Title, 2: Name', 'stream' );
 			} else if ( $update['name'] ) {
 				// Empty title, but we have the name
-				$message = __( '{name} widget updated', 'stream' );
+				$message = _x( '%2$s widget updated', '2: Name', 'stream' );
 			} else if ( $update['title'] ) {
 				// Likely a single widget since no name is available
-				$message = __( '"{title}" widget updated', 'stream' );
+				$message = _x( '"%1$s" widget updated', '1: Title', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the sidebar ID
-				$message = __( '{widget_id} widget updated', 'stream' );
+				$message = _x( '%3$s widget updated', '3: Widget ID', 'stream' );
 			}
 
-			$tpl_vars = $update;
-			$message = self::apply_tpl_vars( $message, $tpl_vars );
+			$message = sprintf( $message, $update['title'], $update['name'], $update['widget_id'] );
 			$contexts = array( $update['sidebar_id'] => 'updated' );
 			unset( $update['title'], $update['name'] );
 			self::log( $message, $update, null, $contexts );
@@ -577,20 +570,19 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			 */
 			foreach ( $creates as $create ) {
 				if ( $create['name'] && $create['title'] ) {
-					$message = __( '"{title}" ({name}) created', 'stream' );
+					$message = _x( '"%1$s" (%2$s) created', '1: Title, 2: Name', 'stream' );
 				} else if ( $create['name'] ) {
 					// Empty title, but we have the name
-					$message = __( '{name} widget created', 'stream' );
+					$message = _x( '%2$s widget created', '2: Name', 'stream' );
 				} else if ( $create['title'] ) {
 					// Likely a single widget since no name is available
-					$message = __( '"{title}" widget created', 'stream' );
+					$message = _x( '"%1$s" widget created', '1: Title', 'stream' );
 				} else {
 					// Neither a name nor a title are available, so use the sidebar ID
-					$message = __( '{widget_id} widget created', 'stream' );
+					$message = _x( '%3$s widget created', '3: Widget ID', 'stream' );
 				}
 
-				$tpl_vars = $create;
-				$message = self::apply_tpl_vars( $message, $tpl_vars );
+				$message = sprintf( $message, $create['title'], $create['name'], $create['widget_id'] );
 				$contexts = array( $create['sidebar_id'] => 'created' );
 				unset( $create['title'], $create['name'] );
 				self::log( $message, $create, null, $contexts );
@@ -601,20 +593,19 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			 */
 			foreach ( $deletes as $delete ) {
 				if ( $delete['name'] && $delete['title'] ) {
-					$message = __( '"{title}" ({name}) deleted', 'stream' );
+					$message = _x( '"%1$s" (%2$s) deleted', '1: Title, 2: Name', 'stream' );
 				} else if ( $delete['name'] ) {
 					// Empty title, but we have the name
-					$message = __( '{name} widget deleted', 'stream' );
+					$message = _x( '%2$s widget deleted', '1: Name', 'stream' );
 				} else if ( $delete['title'] ) {
 					// Likely a single widget since no name is available
-					$message = __( '"{title}" widget deleted', 'stream' );
+					$message = _x( '"%1$s" widget deleted', '1: Title', 'stream' );
 				} else {
 					// Neither a name nor a title are available, so use the sidebar ID
-					$message = __( '{widget_id} widget deleted', 'stream' );
+					$message = _x( '%3$s widget deleted', '3: Widget ID', 'stream' );
 				}
 
-				$tpl_vars = $delete;
-				$message = self::apply_tpl_vars( $message, $tpl_vars );
+				$message = sprintf( $message, $delete['title'], $delete['name'], $delete['widget_id'] );
 				$contexts = array( $delete['sidebar_id'] => 'deleted' );
 				unset( $delete['title'], $delete['name'] );
 				self::log( $message, $delete, null, $contexts );
@@ -622,25 +613,6 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 		}
 	}
 
-	/**
-	 * Replace in $message any $tpl_vars array keys bounded by curly-braces,
-	 * supplying the $tpl_vars array values in their place. A saner approach
-	 * than using vsprintf.
-	 *
-	 * @param string $message
-	 * @param array $tpl_vars
-	 * @return string
-	 */
-	public static function apply_tpl_vars( $message, array $tpl_vars ) {
-		$tpl_vars = array_filter( $tpl_vars, function ( $v ) { return is_string( $v ) || is_numeric( $v ); } );
-		$message = str_replace(
-			array_map( function ( $m ) { return '{' . $m . '}'; }, array_keys( $tpl_vars ) ),
-			array_values( $tpl_vars ),
-			$message
-		);
-		return $message;
-	}
-
 	/**
 	 * @param string $widget_id
 	 * @return string

From 02309a2eb4d6c2590219a8087502ada98664e8ba Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Thu, 1 May 2014 15:38:40 -0700
Subject: [PATCH 27/40] Combined removed/added actions into one moved action

See #484
---
 connectors/widgets.php | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 919de7a03..d5f6151e5 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -54,6 +54,7 @@ public static function get_action_labels() {
 		return array(
 			'added'       => __( 'Added', 'stream' ),
 			'removed'     => __( 'Removed', 'stream' ),
+			'moved'       => __( 'Moved', 'stream' ),
 			'created'     => __( 'Created', 'stream' ),
 			'deleted'     => __( 'Deleted', 'stream' ),
 			'deactivated' => __( 'Deactivated', 'stream' ),
@@ -434,20 +435,12 @@ static protected function handle_widget_moved( $old, $new ) {
 				}
 
 				$message = sprintf( $message, $title, $name, $widget_id, $old_sidebar_name, $new_sidebar_name );
-				$sidebar_id = $old_sidebar_id;
-				self::log(
-					$message,
-					compact( 'widget_id', 'sidebar_id' ),
-					null,
-					array( $sidebar_id => 'removed', )
-				);
-
 				$sidebar_id = $new_sidebar_id;
 				self::log(
 					$message,
-					compact( 'widget_id', 'sidebar_id' ),
+					compact( 'widget_id', 'sidebar_id', 'old_sidebar_id' ),
 					null,
-					array( $sidebar_id => 'added', )
+					array( $sidebar_id => 'moved', )
 				);
 			}
 		}

From 6f3c39fb2eb6656706480b040a62f84a5004e6a8 Mon Sep 17 00:00:00 2001
From: Weston Ruter <weston@x-team.com>
Date: Sun, 11 May 2014 14:49:57 -0400
Subject: [PATCH 28/40] Reference sidebar_id instead of sidebar streammeta

---
 connectors/widgets.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index d5f6151e5..c85baf476 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -94,7 +94,7 @@ public static function get_context_labels() {
 	 * @return array             Action links
 	 */
 	public static function action_links( $links, $record ) {
-		if ( $sidebar = wp_stream_get_meta( $record->ID, 'sidebar', true ) ) { // @todo Requires database upgrade 'sidebar' => 'sidebar_id'
+		if ( $sidebar = wp_stream_get_meta( $record->ID, 'sidebar_id', true ) ) {
 			global $wp_registered_sidebars;
 
 			if ( array_key_exists( $sidebar, $wp_registered_sidebars ) ) {

From 42ca9e1461db3d20daad906f0ba54e69dcb27517 Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Wed, 11 Jun 2014 18:42:59 -0500
Subject: [PATCH 29/40] Code formatting

---
 connectors/widgets.php | 190 +++++++++++++++++++++++++----------------
 1 file changed, 118 insertions(+), 72 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 835b25e80..338e1e928 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -141,6 +141,7 @@ public static function callback_update_option_sidebars_widgets( $old, $new ) {
 	public static function _callback_customize_save_after() {
 		$old_sidebars_widgets = self::$customizer_initial_sidebars_widgets;
 		$new_sidebars_widgets = get_option( 'sidebars_widgets' );
+
 		self::handle_sidebars_widgets_changes( $old_sidebars_widgets, $new_sidebars_widgets );
 	}
 
@@ -151,6 +152,7 @@ public static function _callback_customize_save_after() {
 	protected static function handle_sidebars_widgets_changes( $old, $new ) {
 		unset( $old['array_version'] );
 		unset( $new['array_version'] );
+
 		if ( $old === $new ) {
 			return;
 		}
@@ -172,23 +174,27 @@ protected static function handle_sidebars_widgets_changes( $old, $new ) {
 	 */
 	static protected function handle_deactivated_widgets( $old, $new ) {
 		$new_deactivated_widget_ids = array_diff( $new['wp_inactive_widgets'], $old['wp_inactive_widgets'] );
+
 		foreach ( $new_deactivated_widget_ids as $widget_id ) {
 			$sidebar_id = '';
+
 			foreach ( $old as $old_sidebar_id => $old_widget_ids ) {
 				if ( in_array( $widget_id, $old_widget_ids ) ) {
 					$sidebar_id = $old_sidebar_id;
 					break;
 				}
 			}
-			$action  = 'deactivated';
-			$title = self::get_widget_title( $widget_id );
-			$name = self::get_widget_name( $widget_id );
+
+			$action = 'deactivated';
+			$title  = self::get_widget_title( $widget_id );
+			$name   = self::get_widget_name( $widget_id );
+
 			if ( $name && $title ) {
 				$message = _x( '"%1$s" (%2$s) deactivated', '1: Title, 2: Name', 'stream' );
-			} else if ( $name ) {
+			} elseif ( $name ) {
 				// Empty title, but we have the name
 				$message = _x( '%2$s deactivated', '2: Name', 'stream' );
-			} else if ( $title ) {
+			} elseif ( $title ) {
 				// Likely a single widget since no name is available
 				$message = _x( '"%1$s" widget deactivated', '1: Title', 'stream' );
 			} else {
@@ -197,6 +203,7 @@ static protected function handle_deactivated_widgets( $old, $new ) {
 			}
 
 			$message = sprintf( $message, $title, $name, $widget_id );
+
 			self::log(
 				$message,
 				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
@@ -216,8 +223,10 @@ static protected function handle_deactivated_widgets( $old, $new ) {
 	 */
 	static protected function handle_reactivated_widgets( $old, $new ) {
 		$new_reactivated_widget_ids = array_diff( $old['wp_inactive_widgets'], $new['wp_inactive_widgets'] );
+
 		foreach ( $new_reactivated_widget_ids as $widget_id ) {
 			$sidebar_id = '';
+
 			foreach ( $new as $new_sidebar_id => $new_widget_ids ) {
 				if ( in_array( $widget_id, $new_widget_ids ) ) {
 					$sidebar_id = $new_sidebar_id;
@@ -225,15 +234,16 @@ static protected function handle_reactivated_widgets( $old, $new ) {
 				}
 			}
 
-			$action  = 'reactivated';
-			$title = self::get_widget_title( $widget_id );
-			$name = self::get_widget_name( $widget_id );
+			$action = 'reactivated';
+			$title  = self::get_widget_title( $widget_id );
+			$name   = self::get_widget_name( $widget_id );
+
 			if ( $name && $title ) {
 				$message = _x( '"%1$s" (%2$s) reactivated', '1: Title, 2: Name', 'stream' );
-			} else if ( $name ) {
+			} elseif ( $name ) {
 				// Empty title, but we have the name
 				$message = _x( '%2$s reactivated', '2: Name', 'stream' );
-			} else if ( $title ) {
+			} elseif ( $title ) {
 				// Likely a single widget since no name is available
 				$message = _x( '"%1$s" widget reactivated', '1: Title', 'stream' );
 			} else {
@@ -242,6 +252,7 @@ static protected function handle_reactivated_widgets( $old, $new ) {
 			}
 
 			$message = sprintf( $message, $title, $name, $widget_id );
+
 			self::log(
 				$message,
 				compact( 'title', 'name', 'widget_id', 'sidebar_id' ),
@@ -265,23 +276,27 @@ static protected function handle_widget_removal( $old, $new ) {
 		// @todo The widget option is getting updated before the sidebars_widgets are updated, so we need to hook into the option update to try to cache any deletions for future lookup
 
 		$deleted_widget_ids = array_diff( $all_old_widget_ids, $all_new_widget_ids );
+
 		foreach ( $deleted_widget_ids as $widget_id ) {
 			$sidebar_id = '';
+
 			foreach ( $old as $old_sidebar_id => $old_widget_ids ) {
 				if ( in_array( $widget_id, $old_widget_ids ) ) {
 					$sidebar_id = $old_sidebar_id;
 					break;
 				}
 			}
-			$action  = 'removed';
-			$title = self::get_widget_title( $widget_id );
-			$name = self::get_widget_name( $widget_id );
+
+			$action = 'removed';
+			$title  = self::get_widget_title( $widget_id );
+			$name   = self::get_widget_name( $widget_id );
+
 			if ( $name && $title ) {
 				$message = _x( '"%1$s" (%2$s) removed', '1: Title, 2: Name', 'stream' );
-			} else if ( $name ) {
+			} elseif ( $name ) {
 				// Empty title, but we have the name
 				$message = _x( '%2$s removed', '2: Name', 'stream' );
-			} else if ( $title ) {
+			} elseif ( $title ) {
 				// Likely a single widget since no name is available
 				$message = _x( '"%1$s" widget removed', '1: Title', 'stream' );
 			} else {
@@ -290,6 +305,7 @@ static protected function handle_widget_removal( $old, $new ) {
 			}
 
 			$message = sprintf( $message, $title, $name, $widget_id );
+
 			self::log(
 				$message,
 				compact( 'widget_id', 'sidebar_id' ),
@@ -309,9 +325,11 @@ static protected function handle_widget_removal( $old, $new ) {
 	static protected function handle_widget_addition( $old, $new ) {
 		$all_old_widget_ids = array_unique( call_user_func_array( 'array_merge', $old ) );
 		$all_new_widget_ids = array_unique( call_user_func_array( 'array_merge', $new ) );
-		$added_widget_ids = array_diff( $all_new_widget_ids, $all_old_widget_ids );
+		$added_widget_ids   = array_diff( $all_new_widget_ids, $all_old_widget_ids );
+
 		foreach ( $added_widget_ids as $widget_id ) {
 			$sidebar_id = '';
+
 			foreach ( $new as $new_sidebar_id => $new_widget_ids ) {
 				if ( in_array( $widget_id, $new_widget_ids ) ) {
 					$sidebar_id = $new_sidebar_id;
@@ -319,15 +337,16 @@ static protected function handle_widget_addition( $old, $new ) {
 				}
 			}
 
-			$action  = 'added';
-			$title = self::get_widget_title( $widget_id );
-			$name = self::get_widget_name( $widget_id );
+			$action = 'added';
+			$title  = self::get_widget_title( $widget_id );
+			$name   = self::get_widget_name( $widget_id );
+
 			if ( $name && $title ) {
 				$message = _x( '"%1$s" (%2$s) added', '1: Title, 2: Name', 'stream' );
-			} else if ( $name ) {
+			} elseif ( $name ) {
 				// Empty title, but we have the name
 				$message = _x( '%2$s added', '2: Name', 'stream' );
-			} else if ( $title ) {
+			} elseif ( $title ) {
 				// Likely a single widget since no name is available
 				$message = _x( '"%1$s" widget added', '1: Title', 'stream' );
 			} else {
@@ -336,6 +355,7 @@ static protected function handle_widget_addition( $old, $new ) {
 			}
 
 			$message = sprintf( $message, $title, $name, $widget_id );
+
 			self::log(
 				$message,
 				compact( 'widget_id', 'sidebar_id' ), // @todo Do we care about sidebar_id in meta if it is already context? But there is no 'context' for what the context signifies
@@ -353,27 +373,28 @@ static protected function handle_widget_addition( $old, $new ) {
 	 * @return void
 	 */
 	static protected function handle_widget_reordering( $old, $new ) {
-
 		$all_sidebar_ids = array_intersect( array_keys( $old ), array_keys( $new ) );
+
 		foreach ( $all_sidebar_ids as $sidebar_id ) {
 			if ( $old[ $sidebar_id ] === $new[ $sidebar_id ] ) {
 				continue;
 			}
 
 			// Use intersect to ignore widget additions and removals
-			$all_widget_ids = array_unique( array_merge( $old[ $sidebar_id ], $new[ $sidebar_id ] ) );
-			$common_widget_ids = array_intersect( $old[ $sidebar_id ], $new[ $sidebar_id ] );
-			$uncommon_widget_ids = array_diff( $all_widget_ids, $common_widget_ids );
-			$new_widget_ids = array_values( array_diff( $new[ $sidebar_id ], $uncommon_widget_ids ) );
-			$old_widget_ids = array_values( array_diff( $old[ $sidebar_id ], $uncommon_widget_ids ) );
+			$all_widget_ids       = array_unique( array_merge( $old[ $sidebar_id ], $new[ $sidebar_id ] ) );
+			$common_widget_ids    = array_intersect( $old[ $sidebar_id ], $new[ $sidebar_id ] );
+			$uncommon_widget_ids  = array_diff( $all_widget_ids, $common_widget_ids );
+			$new_widget_ids       = array_values( array_diff( $new[ $sidebar_id ], $uncommon_widget_ids ) );
+			$old_widget_ids       = array_values( array_diff( $old[ $sidebar_id ], $uncommon_widget_ids ) );
 			$widget_order_changed = ( $new_widget_ids !== $old_widget_ids );
-			if ( $widget_order_changed ) {
-				$labels = self::get_context_labels();
-				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
+			if ( $widget_order_changed ) {
+				$labels         = self::get_context_labels();
+				$sidebar_name   = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 				$old_widget_ids = $old[ $sidebar_id ];
-				$message = _x( 'Widgets in "%s" were reordered', 'Sidebar name', 'stream' );
-				$message = sprintf( $message, $sidebar_name );
+				$message        = _x( 'Widgets in "%s" were reordered', 'Sidebar name', 'stream' );
+				$message        = sprintf( $message, $sidebar_name );
+
 				self::log(
 					$message,
 					compact( 'sidebar_id', 'old_widget_ids' ),
@@ -393,8 +414,8 @@ static protected function handle_widget_reordering( $old, $new ) {
 	 * @return void
 	 */
 	static protected function handle_widget_moved( $old, $new ) {
-
 		$all_sidebar_ids = array_intersect( array_keys( $old ), array_keys( $new ) );
+
 		foreach ( $all_sidebar_ids as $new_sidebar_id ) {
 			if ( $old[ $new_sidebar_id ] === $new[ $new_sidebar_id ] ) {
 				continue;
@@ -411,22 +432,25 @@ static protected function handle_widget_moved( $old, $new ) {
 						break;
 					}
 				}
-				if ( ! $old_sidebar_id || $old_sidebar_id === 'wp_inactive_widgets' || $new_sidebar_id === 'wp_inactive_widgets' ) {
+
+				if ( ! $old_sidebar_id || 'wp_inactive_widgets' === $old_sidebar_id || 'wp_inactive_widgets' === $new_sidebar_id ) {
 					continue;
 				}
+
 				assert( $old_sidebar_id !== $new_sidebar_id );
 
-				$labels = self::get_context_labels();
+				$labels           = self::get_context_labels();
 				$new_sidebar_name = isset( $labels[ $new_sidebar_id ] ) ? $labels[ $new_sidebar_id ] : $new_sidebar_id;
 				$old_sidebar_name = isset( $labels[ $old_sidebar_id ] ) ? $labels[ $old_sidebar_id ] : $old_sidebar_id;
-				$title = self::get_widget_title( $widget_id );
-				$name = self::get_widget_name( $widget_id );
+				$title            = self::get_widget_title( $widget_id );
+				$name             = self::get_widget_name( $widget_id );
+
 				if ( $name && $title ) {
 					$message = _x( '"%1$s" (%2$s) widget moved from %4$s to %5$s', '1: Title, 2: Name, 4: Old Sidebar, 5: New Sidebar', 'stream' );
-				} else if ( $name ) {
+				} elseif ( $name ) {
 					// Empty title, but we have the name
 					$message = _x( '%2$s widget moved from %4$s to %5$s', '2: Name, 4: Old Sidebar, 5: New Sidebar', 'stream' );
-				} else if ( $title ) {
+				} elseif ( $title ) {
 					// Likely a single widget since no name is available
 					$message = _x( '"%1$s" widget moved from %4$s to %5$s', '1: Title, 4: Old Sidebar, 5: New Sidebar', 'stream' );
 				} else {
@@ -434,8 +458,9 @@ static protected function handle_widget_moved( $old, $new ) {
 					$message = _x( '%3$s widget moved from %4$s to %5$s', '3: Widget ID, 4: Old Sidebar, 5: New Sidebar', 'stream' );
 				}
 
-				$message = sprintf( $message, $title, $name, $widget_id, $old_sidebar_name, $new_sidebar_name );
+				$message    = sprintf( $message, $title, $name, $widget_id, $old_sidebar_name, $new_sidebar_name );
 				$sidebar_id = $new_sidebar_id;
+
 				self::log(
 					$message,
 					compact( 'widget_id', 'sidebar_id', 'old_sidebar_id' ),
@@ -459,7 +484,8 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 		if ( ! preg_match( '/^widget_(.+)$/', $option_name, $matches ) || ! is_array( $new_value ) ) {
 			return;
 		}
-		$is_multi = ! empty( $new_value['_multiwidget'] );
+
+		$is_multi       = ! empty( $new_value['_multiwidget'] );
 		$widget_id_base = $matches[1];
 
 		$creates = array();
@@ -476,12 +502,14 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			 * Created widgets
 			 */
 			$created_widget_numbers = array_diff( array_keys( $new_value ), array_keys( $old_value ) );
+
 			foreach ( $created_widget_numbers as $widget_number ) {
-				$instance = $new_value[ $widget_number ];
-				$widget_id = sprintf( $widget_id_format, $widget_number );
-				$title = ! empty( $instance['title'] ) ? $instance['title'] : null;
-				$name = self::get_widget_name( $widget_id );
+				$instance   = $new_value[ $widget_number ];
+				$widget_id  = sprintf( $widget_id_format, $widget_number );
+				$title      = ! empty( $instance['title'] ) ? $instance['title'] : null;
+				$name       = self::get_widget_name( $widget_id );
 				$sidebar_id = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned yet
+
 				$creates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
 			}
 
@@ -489,14 +517,17 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			 * Updated widgets
 			 */
 			$updated_widget_numbers = array_intersect( array_keys( $old_value ), array_keys( $new_value ) );
+
 			foreach ( $updated_widget_numbers as $widget_number ) {
 				$new_instance = $new_value[ $widget_number ];
 				$old_instance = $old_value[ $widget_number ];
+
 				if ( $old_instance !== $new_instance ) {
-					$widget_id = sprintf( $widget_id_format, $widget_number );
-					$title = ! empty( $new_instance['title'] ) ? $new_instance['title'] : null;
-					$name = self::get_widget_name( $widget_id );
+					$widget_id  = sprintf( $widget_id_format, $widget_number );
+					$title      = ! empty( $new_instance['title'] ) ? $new_instance['title'] : null;
+					$name       = self::get_widget_name( $widget_id );
 					$sidebar_id = self::get_widget_sidebar_id( $widget_id );
+
 					$updates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'old_instance' );
 				}
 			}
@@ -505,22 +536,24 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			 * Deleted widgets
 			 */
 			$deleted_widget_numbers = array_diff( array_keys( $old_value ), array_keys( $new_value ) );
+
 			foreach ( $deleted_widget_numbers as $widget_number ) {
-				$instance = $old_value[ $widget_number ];
-				$widget_id = sprintf( $widget_id_format, $widget_number );
-				$title = ! empty( $instance['title'] ) ? $instance['title'] : null;
-				$name = self::get_widget_name( $widget_id );
+				$instance   = $old_value[ $widget_number ];
+				$widget_id  = sprintf( $widget_id_format, $widget_number );
+				$title      = ! empty( $instance['title'] ) ? $instance['title'] : null;
+				$name       = self::get_widget_name( $widget_id );
 				$sidebar_id = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned anymore
+
 				$deletes[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
 			}
 		} else {
 			// Doing our best guess for tracking changes to old single widgets, assuming their options start with 'widget_'
-
-			$widget_id = $widget_id_base;
-			$name = $widget_id; // There aren't names available for single widgets
-			$title = ! empty( $new_value['title'] ) ? $new_value['title'] : null;
-			$sidebar_id = self::get_widget_sidebar_id( $widget_id );
+			$widget_id    = $widget_id_base;
+			$name         = $widget_id; // There aren't names available for single widgets
+			$title        = ! empty( $new_value['title'] ) ? $new_value['title'] : null;
+			$sidebar_id   = self::get_widget_sidebar_id( $widget_id );
 			$old_instance = $old_value;
+
 			$updates[] = compact( 'widget_id', 'title', 'name', 'sidebar_id', 'old_instance' );
 		}
 
@@ -530,10 +563,10 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 		foreach ( $updates as $update ) {
 			if ( $update['name'] && $update['title'] ) {
 				$message = _x( '"%1$s" (%2$s) updated', '1: Title, 2: Name', 'stream' );
-			} else if ( $update['name'] ) {
+			} elseif ( $update['name'] ) {
 				// Empty title, but we have the name
 				$message = _x( '%2$s widget updated', '2: Name', 'stream' );
-			} else if ( $update['title'] ) {
+			} elseif ( $update['title'] ) {
 				// Likely a single widget since no name is available
 				$message = _x( '"%1$s" widget updated', '1: Title', 'stream' );
 			} else {
@@ -541,9 +574,11 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 				$message = _x( '%3$s widget updated', '3: Widget ID', 'stream' );
 			}
 
-			$message = sprintf( $message, $update['title'], $update['name'], $update['widget_id'] );
+			$message  = sprintf( $message, $update['title'], $update['name'], $update['widget_id'] );
 			$contexts = array( $update['sidebar_id'] => 'updated' );
+
 			unset( $update['title'], $update['name'] );
+
 			self::log( $message, $update, null, $contexts );
 		}
 
@@ -556,7 +591,6 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 		 * actions would be useful to log.
 		 */
 		if ( self::$verbose_widget_created_deleted_actions ) {
-
 			// We should only do these if not captured by an update to the sidebars_widgets option
 			/**
 			 * Log created actions
@@ -564,10 +598,10 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			foreach ( $creates as $create ) {
 				if ( $create['name'] && $create['title'] ) {
 					$message = _x( '"%1$s" (%2$s) created', '1: Title, 2: Name', 'stream' );
-				} else if ( $create['name'] ) {
+				} elseif ( $create['name'] ) {
 					// Empty title, but we have the name
 					$message = _x( '%2$s widget created', '2: Name', 'stream' );
-				} else if ( $create['title'] ) {
+				} elseif ( $create['title'] ) {
 					// Likely a single widget since no name is available
 					$message = _x( '"%1$s" widget created', '1: Title', 'stream' );
 				} else {
@@ -575,9 +609,11 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 					$message = _x( '%3$s widget created', '3: Widget ID', 'stream' );
 				}
 
-				$message = sprintf( $message, $create['title'], $create['name'], $create['widget_id'] );
+				$message  = sprintf( $message, $create['title'], $create['name'], $create['widget_id'] );
 				$contexts = array( $create['sidebar_id'] => 'created' );
+
 				unset( $create['title'], $create['name'] );
+
 				self::log( $message, $create, null, $contexts );
 			}
 
@@ -587,10 +623,10 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			foreach ( $deletes as $delete ) {
 				if ( $delete['name'] && $delete['title'] ) {
 					$message = _x( '"%1$s" (%2$s) deleted', '1: Title, 2: Name', 'stream' );
-				} else if ( $delete['name'] ) {
+				} elseif ( $delete['name'] ) {
 					// Empty title, but we have the name
 					$message = _x( '%2$s widget deleted', '1: Name', 'stream' );
-				} else if ( $delete['title'] ) {
+				} elseif ( $delete['title'] ) {
 					// Likely a single widget since no name is available
 					$message = _x( '"%1$s" widget deleted', '1: Title', 'stream' );
 				} else {
@@ -598,9 +634,11 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 					$message = _x( '%3$s widget deleted', '3: Widget ID', 'stream' );
 				}
 
-				$message = sprintf( $message, $delete['title'], $delete['name'], $delete['widget_id'] );
+				$message  = sprintf( $message, $delete['title'], $delete['name'], $delete['widget_id'] );
 				$contexts = array( $delete['sidebar_id'] => 'deleted' );
+
 				unset( $delete['title'], $delete['name'] );
+
 				self::log( $message, $delete, null, $contexts );
 			}
 		}
@@ -631,7 +669,7 @@ public static function get_widget_name( $widget_id ) {
 	public static function parse_widget_id( $widget_id ) {
 		if ( preg_match( '/^(.+)-(\d+)$/', $widget_id, $matches ) ) {
 			return array(
-				'id_base' => $matches[1],
+				'id_base'       => $matches[1],
 				'widget_number' => intval( $matches[2] ),
 			);
 		} else {
@@ -647,11 +685,13 @@ public static function get_widget_object( $widget_id ) {
 		global $wp_widget_factory;
 
 		$parsed_widget_id = self::parse_widget_id( $widget_id );
+
 		if ( ! $parsed_widget_id ) {
 			return null;
 		}
 
 		$id_base = $parsed_widget_id['id_base'];
+
 		$id_base_to_widget_class_map = array_combine(
 			wp_list_pluck( $wp_widget_factory->widgets, 'id_base' ),
 			array_keys( $wp_widget_factory->widgets )
@@ -671,23 +711,26 @@ public static function get_widget_object( $widget_id ) {
 	 * @return array|null         Widget instance
 	 */
 	public static function get_widget_instance( $widget_id ) {
-		$instance = null;
-
+		$instance         = null;
 		$parsed_widget_id = self::parse_widget_id( $widget_id );
-		$widget_obj = self::get_widget_object( $widget_id );
+		$widget_obj       = self::get_widget_object( $widget_id );
+
 		if ( $widget_obj && $parsed_widget_id ) {
-			$settings = $widget_obj->get_settings();
+			$settings     = $widget_obj->get_settings();
 			$multi_number = $parsed_widget_id['widget_number'];
+
 			if ( isset( $settings[ $multi_number ] ) && ! empty( $settings[ $multi_number ]['title'] ) ) {
 				$instance = $settings[ $multi_number ];
 			}
 		} else {
 			// Single widgets, try our best guess at the option used
 			$potential_instance = get_option( "widget_{$widget_id}" );
+
 			if ( ! empty( $potential_instance ) && ! empty( $potential_instance['title'] ) ) {
 				$instance = $potential_instance;
 			}
 		}
+
 		return $instance;
 	}
 
@@ -716,12 +759,15 @@ public static function get_sidebars_widgets() {
 	 */
 	public static function get_widget_sidebar_id( $widget_id ) {
 		$sidebars_widgets = self::get_sidebars_widgets();
+
 		unset( $sidebars_widgets['array_version'] );
+
 		foreach ( $sidebars_widgets as $sidebar_id => $widget_ids ) {
 			if ( in_array( $widget_id, $widget_ids ) ) {
 				return $sidebar_id;
 			}
 		}
+
 		return 'orphaned_widgets';
 	}
 

From 80e5c313a06475b4766ca264ecc2fd03ec67ef7e Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 09:55:29 -0500
Subject: [PATCH 30/40] Summary improvements to widgets added

---
 connectors/widgets.php | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 338e1e928..3b6b3860e 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -337,24 +337,26 @@ static protected function handle_widget_addition( $old, $new ) {
 				}
 			}
 
-			$action = 'added';
-			$title  = self::get_widget_title( $widget_id );
-			$name   = self::get_widget_name( $widget_id );
+			$action       = 'added';
+			$title        = self::get_widget_title( $widget_id );
+			$name         = self::get_widget_name( $widget_id );
+			$labels       = self::get_context_labels();
+			$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
 			if ( $name && $title ) {
-				$message = _x( '"%1$s" (%2$s) added', '1: Title, 2: Name', 'stream' );
+				$message = _x( '%1$s widget named "%2$s" added to "%3$s"', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
 			} elseif ( $name ) {
 				// Empty title, but we have the name
-				$message = _x( '%2$s added', '2: Name', 'stream' );
+				$message = _x( '%1$s widget added to "%3$s"', '1: Name, 3: Sidebar Name', 'stream' );
 			} elseif ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x( '"%1$s" widget added', '1: Title', 'stream' );
+				$message = _x( 'Unknown widget type named "%2$s" added to "%3$s"', '2: Title, 3: Sidebar Name', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = _x( '%3$s widget added', '3: Widget ID', 'stream' );
+				$message = _x( '%4$s widget added to "%3$s"', '4: Widget ID, 3: Sidebar Name', 'stream' );
 			}
 
-			$message = sprintf( $message, $title, $name, $widget_id );
+			$message = sprintf( $message, $name, $title, $sidebar_name, $widget_id );
 
 			self::log(
 				$message,

From 8f15fe516affe361ad0193c554502b66628d5874 Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 09:56:24 -0500
Subject: [PATCH 31/40] Summary tweak for widgets reordered

---
 connectors/widgets.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 3b6b3860e..8249ff3bf 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -394,7 +394,7 @@ static protected function handle_widget_reordering( $old, $new ) {
 				$labels         = self::get_context_labels();
 				$sidebar_name   = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 				$old_widget_ids = $old[ $sidebar_id ];
-				$message        = _x( 'Widgets in "%s" were reordered', 'Sidebar name', 'stream' );
+				$message        = _x( 'Widgets reordered in "%s"', 'Sidebar name', 'stream' );
 				$message        = sprintf( $message, $sidebar_name );
 
 				self::log(

From 64c6bb4bb769d21c26e20c297a81e090ef66ac6b Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 10:07:11 -0500
Subject: [PATCH 32/40] Summary improvements for widgets moved

---
 connectors/widgets.php | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 8249ff3bf..d25fdc980 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -441,26 +441,26 @@ static protected function handle_widget_moved( $old, $new ) {
 
 				assert( $old_sidebar_id !== $new_sidebar_id );
 
+				$name             = self::get_widget_name( $widget_id );
+				$title            = self::get_widget_title( $widget_id );
 				$labels           = self::get_context_labels();
-				$new_sidebar_name = isset( $labels[ $new_sidebar_id ] ) ? $labels[ $new_sidebar_id ] : $new_sidebar_id;
 				$old_sidebar_name = isset( $labels[ $old_sidebar_id ] ) ? $labels[ $old_sidebar_id ] : $old_sidebar_id;
-				$title            = self::get_widget_title( $widget_id );
-				$name             = self::get_widget_name( $widget_id );
+				$new_sidebar_name = isset( $labels[ $new_sidebar_id ] ) ? $labels[ $new_sidebar_id ] : $new_sidebar_id;
 
 				if ( $name && $title ) {
-					$message = _x( '"%1$s" (%2$s) widget moved from %4$s to %5$s', '1: Title, 2: Name, 4: Old Sidebar, 5: New Sidebar', 'stream' );
+					$message = _x( '%1$s widget named "%2$s" moved from "%4$s" to "%5$s"', '1: Name, 2: Title, 4: Old Sidebar Name, 5: New Sidebar Name', 'stream' );
 				} elseif ( $name ) {
 					// Empty title, but we have the name
-					$message = _x( '%2$s widget moved from %4$s to %5$s', '2: Name, 4: Old Sidebar, 5: New Sidebar', 'stream' );
+					$message = _x( '%1$s widget moved from "%4$s" to "%5$s"', '1: Name, 4: Old Sidebar Name, 5: New Sidebar Name', 'stream' );
 				} elseif ( $title ) {
 					// Likely a single widget since no name is available
-					$message = _x( '"%1$s" widget moved from %4$s to %5$s', '1: Title, 4: Old Sidebar, 5: New Sidebar', 'stream' );
+					$message = _x( 'Unknown widget type named "%2$s" moved from "%4$s" to "%5$s"', '2: Title, 4: Old Sidebar Name, 5: New Sidebar Name', 'stream' );
 				} else {
-					// Neither a name nor a title are available, so use the sidebar ID
-					$message = _x( '%3$s widget moved from %4$s to %5$s', '3: Widget ID, 4: Old Sidebar, 5: New Sidebar', 'stream' );
+					// Neither a name nor a title are available, so use the widget ID
+					$message = _x( '%3$s widget moved from "%4$s" to "%5$s"', '3: Widget ID, 4: Old Sidebar Name, 5: New Sidebar Name', 'stream' );
 				}
 
-				$message    = sprintf( $message, $title, $name, $widget_id, $old_sidebar_name, $new_sidebar_name );
+				$message    = sprintf( $message, $name, $title, $widget_id, $old_sidebar_name, $new_sidebar_name );
 				$sidebar_id = $new_sidebar_id;
 
 				self::log(

From 849d2c67f6d1e3c9ecaddd823edc136b57640df9 Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 10:18:33 -0500
Subject: [PATCH 33/40] Summary improvements for widgets updated

---
 connectors/widgets.php | 62 ++++++++++++++++++++++++------------------
 1 file changed, 35 insertions(+), 27 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index d25fdc980..4078617d4 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -506,13 +506,15 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			$created_widget_numbers = array_diff( array_keys( $new_value ), array_keys( $old_value ) );
 
 			foreach ( $created_widget_numbers as $widget_number ) {
-				$instance   = $new_value[ $widget_number ];
-				$widget_id  = sprintf( $widget_id_format, $widget_number );
-				$title      = ! empty( $instance['title'] ) ? $instance['title'] : null;
-				$name       = self::get_widget_name( $widget_id );
-				$sidebar_id = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned yet
-
-				$creates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
+				$instance     = $new_value[ $widget_number ];
+				$widget_id    = sprintf( $widget_id_format, $widget_number );
+				$title        = ! empty( $instance['title'] ) ? $instance['title'] : null;
+				$name         = self::get_widget_name( $widget_id );
+				$sidebar_id   = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned yet
+				$labels       = self::get_context_labels();
+				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
+
+				$creates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance', 'sidebar_name' );
 			}
 
 			/**
@@ -525,12 +527,14 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 				$old_instance = $old_value[ $widget_number ];
 
 				if ( $old_instance !== $new_instance ) {
-					$widget_id  = sprintf( $widget_id_format, $widget_number );
-					$title      = ! empty( $new_instance['title'] ) ? $new_instance['title'] : null;
-					$name       = self::get_widget_name( $widget_id );
-					$sidebar_id = self::get_widget_sidebar_id( $widget_id );
-
-					$updates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'old_instance' );
+					$widget_id    = sprintf( $widget_id_format, $widget_number );
+					$title        = ! empty( $new_instance['title'] ) ? $new_instance['title'] : null;
+					$name         = self::get_widget_name( $widget_id );
+					$sidebar_id   = self::get_widget_sidebar_id( $widget_id );
+					$labels       = self::get_context_labels();
+					$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
+
+					$updates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'old_instance', 'sidebar_name' );
 				}
 			}
 
@@ -540,13 +544,15 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			$deleted_widget_numbers = array_diff( array_keys( $old_value ), array_keys( $new_value ) );
 
 			foreach ( $deleted_widget_numbers as $widget_number ) {
-				$instance   = $old_value[ $widget_number ];
-				$widget_id  = sprintf( $widget_id_format, $widget_number );
-				$title      = ! empty( $instance['title'] ) ? $instance['title'] : null;
-				$name       = self::get_widget_name( $widget_id );
-				$sidebar_id = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned anymore
-
-				$deletes[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
+				$instance     = $old_value[ $widget_number ];
+				$widget_id    = sprintf( $widget_id_format, $widget_number );
+				$title        = ! empty( $instance['title'] ) ? $instance['title'] : null;
+				$name         = self::get_widget_name( $widget_id );
+				$sidebar_id   = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned anymore
+				$labels       = self::get_context_labels();
+				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
+
+				$deletes[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance', 'sidebar_name' );
 			}
 		} else {
 			// Doing our best guess for tracking changes to old single widgets, assuming their options start with 'widget_'
@@ -555,8 +561,10 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			$title        = ! empty( $new_value['title'] ) ? $new_value['title'] : null;
 			$sidebar_id   = self::get_widget_sidebar_id( $widget_id );
 			$old_instance = $old_value;
+			$labels       = self::get_context_labels();
+			$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
-			$updates[] = compact( 'widget_id', 'title', 'name', 'sidebar_id', 'old_instance' );
+			$updates[] = compact( 'widget_id', 'title', 'name', 'sidebar_id', 'old_instance', 'sidebar_name' );
 		}
 
 		/**
@@ -564,19 +572,19 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 		 */
 		foreach ( $updates as $update ) {
 			if ( $update['name'] && $update['title'] ) {
-				$message = _x( '"%1$s" (%2$s) updated', '1: Title, 2: Name', 'stream' );
+				$message = _x( '%1$s widget named "%2$s" in "%3$s" updated', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
 			} elseif ( $update['name'] ) {
 				// Empty title, but we have the name
-				$message = _x( '%2$s widget updated', '2: Name', 'stream' );
+				$message = _x( '%1$s widget in "%3$s" updated', '1: Name, 3: Sidebar Name', 'stream' );
 			} elseif ( $update['title'] ) {
 				// Likely a single widget since no name is available
-				$message = _x( '"%1$s" widget updated', '1: Title', 'stream' );
+				$message = _x( 'Unknown widget type named "%2$s" in "%3$s" updated', '2: Title, 3: Sidebar Name', 'stream' );
 			} else {
-				// Neither a name nor a title are available, so use the sidebar ID
-				$message = _x( '%3$s widget updated', '3: Widget ID', 'stream' );
+				// Neither a name nor a title are available, so use the widget ID
+				$message = _x( '%4$s widget in "%3$s" updated', '4: Widget ID, 3: Sidebar Name', 'stream' );
 			}
 
-			$message  = sprintf( $message, $update['title'], $update['name'], $update['widget_id'] );
+			$message  = sprintf( $message, $update['name'], $update['title'], $update['sidebar_name'], $update['widget_id'] );
 			$contexts = array( $update['sidebar_id'] => 'updated' );
 
 			unset( $update['title'], $update['name'] );

From 3b87954ab3069d3027bee433e24590080c168f07 Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 10:24:25 -0500
Subject: [PATCH 34/40] Summary improvements for widgets created

---
 connectors/widgets.php | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 4078617d4..e87adafa8 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -607,19 +607,19 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			 */
 			foreach ( $creates as $create ) {
 				if ( $create['name'] && $create['title'] ) {
-					$message = _x( '"%1$s" (%2$s) created', '1: Title, 2: Name', 'stream' );
+					$message = _x( '%1$s widget named "%2$s" created in "%3$s"', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
 				} elseif ( $create['name'] ) {
 					// Empty title, but we have the name
-					$message = _x( '%2$s widget created', '2: Name', 'stream' );
+					$message = _x( '%1$s widget created in "%3$s"', '1: Name, 3: Sidebar Name', 'stream' );
 				} elseif ( $create['title'] ) {
 					// Likely a single widget since no name is available
-					$message = _x( '"%1$s" widget created', '1: Title', 'stream' );
+					$message = _x( 'Unknown widget type named "%2$s" created in "%3$s"', '2: Title, 3: Sidebar Name', 'stream' );
 				} else {
-					// Neither a name nor a title are available, so use the sidebar ID
-					$message = _x( '%3$s widget created', '3: Widget ID', 'stream' );
+					// Neither a name nor a title are available, so use the widget ID
+					$message = _x( '%4$s widget created in "%3$s"', '4: Widget ID, 3: Sidebar Name', 'stream' );
 				}
 
-				$message  = sprintf( $message, $create['title'], $create['name'], $create['widget_id'] );
+				$message  = sprintf( $message, $create['name'], $create['title'], $create['sidebar_name'], $create['widget_id'] );
 				$contexts = array( $create['sidebar_id'] => 'created' );
 
 				unset( $create['title'], $create['name'] );

From 5e52f1742572c8fbec624251a474c0d14795e4db Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 10:30:15 -0500
Subject: [PATCH 35/40] No need for Sidebar Name in widget created/deleted
 summaries

---
 connectors/widgets.php | 28 ++++++++++++----------------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index e87adafa8..9ade4460b 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -511,10 +511,8 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 				$title        = ! empty( $instance['title'] ) ? $instance['title'] : null;
 				$name         = self::get_widget_name( $widget_id );
 				$sidebar_id   = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned yet
-				$labels       = self::get_context_labels();
-				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
-				$creates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance', 'sidebar_name' );
+				$creates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
 			}
 
 			/**
@@ -549,10 +547,8 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 				$title        = ! empty( $instance['title'] ) ? $instance['title'] : null;
 				$name         = self::get_widget_name( $widget_id );
 				$sidebar_id   = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned anymore
-				$labels       = self::get_context_labels();
-				$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
-				$deletes[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance', 'sidebar_name' );
+				$deletes[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
 			}
 		} else {
 			// Doing our best guess for tracking changes to old single widgets, assuming their options start with 'widget_'
@@ -607,19 +603,19 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			 */
 			foreach ( $creates as $create ) {
 				if ( $create['name'] && $create['title'] ) {
-					$message = _x( '%1$s widget named "%2$s" created in "%3$s"', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
+					$message = _x( '%1$s widget named "%2$s" created', '1: Name, 2: Title', 'stream' );
 				} elseif ( $create['name'] ) {
 					// Empty title, but we have the name
-					$message = _x( '%1$s widget created in "%3$s"', '1: Name, 3: Sidebar Name', 'stream' );
+					$message = _x( '%1$s widget created', '1: Name', 'stream' );
 				} elseif ( $create['title'] ) {
 					// Likely a single widget since no name is available
-					$message = _x( 'Unknown widget type named "%2$s" created in "%3$s"', '2: Title, 3: Sidebar Name', 'stream' );
+					$message = _x( 'Unknown widget type named "%2$s" created', '2: Title', 'stream' );
 				} else {
 					// Neither a name nor a title are available, so use the widget ID
-					$message = _x( '%4$s widget created in "%3$s"', '4: Widget ID, 3: Sidebar Name', 'stream' );
+					$message = _x( '%3$s widget created', '3: Widget ID', 'stream' );
 				}
 
-				$message  = sprintf( $message, $create['name'], $create['title'], $create['sidebar_name'], $create['widget_id'] );
+				$message  = sprintf( $message, $create['name'], $create['title'], $create['widget_id'] );
 				$contexts = array( $create['sidebar_id'] => 'created' );
 
 				unset( $create['title'], $create['name'] );
@@ -632,19 +628,19 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			 */
 			foreach ( $deletes as $delete ) {
 				if ( $delete['name'] && $delete['title'] ) {
-					$message = _x( '"%1$s" (%2$s) deleted', '1: Title, 2: Name', 'stream' );
+					$message = _x( '%1$s widget named "%2$s" deleted', '1: Name, 2: Title', 'stream' );
 				} elseif ( $delete['name'] ) {
 					// Empty title, but we have the name
-					$message = _x( '%2$s widget deleted', '1: Name', 'stream' );
+					$message = _x( '%1$s widget deleted', '1: Name', 'stream' );
 				} elseif ( $delete['title'] ) {
 					// Likely a single widget since no name is available
-					$message = _x( '"%1$s" widget deleted', '1: Title', 'stream' );
+					$message = _x( 'Unknown widget type named "%2$s" deleted', '2: Title', 'stream' );
 				} else {
-					// Neither a name nor a title are available, so use the sidebar ID
+					// Neither a name nor a title are available, so use the widget ID
 					$message = _x( '%3$s widget deleted', '3: Widget ID', 'stream' );
 				}
 
-				$message  = sprintf( $message, $delete['title'], $delete['name'], $delete['widget_id'] );
+				$message  = sprintf( $message, $delete['name'], $delete['title'], $delete['widget_id'] );
 				$contexts = array( $delete['sidebar_id'] => 'deleted' );
 
 				unset( $delete['title'], $delete['name'] );

From e31de41d79f3f727b96e3b61ad5ee8ae71817b75 Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 10:31:36 -0500
Subject: [PATCH 36/40] Reordering vars for consistency

---
 connectors/widgets.php | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 9ade4460b..cdb741f62 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -338,8 +338,8 @@ static protected function handle_widget_addition( $old, $new ) {
 			}
 
 			$action       = 'added';
-			$title        = self::get_widget_title( $widget_id );
 			$name         = self::get_widget_name( $widget_id );
+			$title        = self::get_widget_title( $widget_id );
 			$labels       = self::get_context_labels();
 			$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
@@ -508,8 +508,8 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			foreach ( $created_widget_numbers as $widget_number ) {
 				$instance     = $new_value[ $widget_number ];
 				$widget_id    = sprintf( $widget_id_format, $widget_number );
-				$title        = ! empty( $instance['title'] ) ? $instance['title'] : null;
 				$name         = self::get_widget_name( $widget_id );
+				$title        = ! empty( $instance['title'] ) ? $instance['title'] : null;
 				$sidebar_id   = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned yet
 
 				$creates[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );
@@ -526,8 +526,8 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 
 				if ( $old_instance !== $new_instance ) {
 					$widget_id    = sprintf( $widget_id_format, $widget_number );
-					$title        = ! empty( $new_instance['title'] ) ? $new_instance['title'] : null;
 					$name         = self::get_widget_name( $widget_id );
+					$title        = ! empty( $new_instance['title'] ) ? $new_instance['title'] : null;
 					$sidebar_id   = self::get_widget_sidebar_id( $widget_id );
 					$labels       = self::get_context_labels();
 					$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
@@ -544,8 +544,8 @@ public static function callback_updated_option( $option_name, $old_value, $new_v
 			foreach ( $deleted_widget_numbers as $widget_number ) {
 				$instance     = $old_value[ $widget_number ];
 				$widget_id    = sprintf( $widget_id_format, $widget_number );
-				$title        = ! empty( $instance['title'] ) ? $instance['title'] : null;
 				$name         = self::get_widget_name( $widget_id );
+				$title        = ! empty( $instance['title'] ) ? $instance['title'] : null;
 				$sidebar_id   = self::get_widget_sidebar_id( $widget_id ); // @todo May not be assigned anymore
 
 				$deletes[] = compact( 'name', 'title', 'widget_id', 'sidebar_id', 'instance' );

From b8624e48a8bdd776e47402ed43318e895740a64e Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 10:34:42 -0500
Subject: [PATCH 37/40] Summary improvements for widgets removed

---
 connectors/widgets.php | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index cdb741f62..41c893d6e 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -287,24 +287,26 @@ static protected function handle_widget_removal( $old, $new ) {
 				}
 			}
 
-			$action = 'removed';
-			$title  = self::get_widget_title( $widget_id );
-			$name   = self::get_widget_name( $widget_id );
+			$action       = 'removed';
+			$name         = self::get_widget_name( $widget_id );
+			$title        = self::get_widget_title( $widget_id );
+			$labels       = self::get_context_labels();
+			$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
 			if ( $name && $title ) {
-				$message = _x( '"%1$s" (%2$s) removed', '1: Title, 2: Name', 'stream' );
+				$message = _x( '%1$s widget named "%2$s" removed from "%3$s"', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
 			} elseif ( $name ) {
 				// Empty title, but we have the name
-				$message = _x( '%2$s removed', '2: Name', 'stream' );
+				$message = _x( '%1$s widget removed from "%3$s"', '1: Name, 3: Sidebar Name', 'stream' );
 			} elseif ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x( '"%1$s" widget removed', '1: Title', 'stream' );
+				$message = _x( 'Unknown widget type named "%2$s" removed from "%3$s"', '2: Title, 3: Sidebar Name', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = _x( '%3$s widget removed', '3: Widget ID', 'stream' );
+				$message = _x( '%4$s widget removed from "%3$s"', '4: Widget ID, 3: Sidebar Name', 'stream' );
 			}
 
-			$message = sprintf( $message, $title, $name, $widget_id );
+			$message = sprintf( $message, $name, $title, $sidebar_name, $widget_id );
 
 			self::log(
 				$message,

From ed8f6237a5f816a02ad838bc00a3e4cbb448c6e4 Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 10:37:07 -0500
Subject: [PATCH 38/40] Summary improvements for widgets reactivated

---
 connectors/widgets.php | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 41c893d6e..9a8f27d5b 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -234,24 +234,26 @@ static protected function handle_reactivated_widgets( $old, $new ) {
 				}
 			}
 
-			$action = 'reactivated';
-			$title  = self::get_widget_title( $widget_id );
-			$name   = self::get_widget_name( $widget_id );
+			$action       = 'reactivated';
+			$name         = self::get_widget_name( $widget_id );
+			$title        = self::get_widget_title( $widget_id );
+			$labels       = self::get_context_labels();
+			$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
 			if ( $name && $title ) {
-				$message = _x( '"%1$s" (%2$s) reactivated', '1: Title, 2: Name', 'stream' );
+				$message = _x( '%1$s widget named "%2$s" in "%3$s" reactivated', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
 			} elseif ( $name ) {
 				// Empty title, but we have the name
-				$message = _x( '%2$s reactivated', '2: Name', 'stream' );
+				$message = _x( '%1$s widget in "%3$s" reactivated', '1: Name, 3: Sidebar Name', 'stream' );
 			} elseif ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x( '"%1$s" widget reactivated', '1: Title', 'stream' );
+				$message = _x( 'Unknown widget type named "%2$s" in "%3$s" reactivated', '2: Title, 3: Sidebar Name', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = _x( '%3$s widget reactivated', '3: Widget ID', 'stream' );
+				$message = _x( '%4$s widget in "%3$s" reactivated', '4: Widget ID, 3: Sidebar Name', 'stream' );
 			}
 
-			$message = sprintf( $message, $title, $name, $widget_id );
+			$message = sprintf( $message, $name, $title, $sidebar_name, $widget_id );
 
 			self::log(
 				$message,

From 4527a59ce478600f9f53a95916810284902ebcbf Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 10:38:30 -0500
Subject: [PATCH 39/40] Summary improvements for widgets deactivated

---
 connectors/widgets.php | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 9a8f27d5b..563f7e66e 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -185,24 +185,26 @@ static protected function handle_deactivated_widgets( $old, $new ) {
 				}
 			}
 
-			$action = 'deactivated';
-			$title  = self::get_widget_title( $widget_id );
-			$name   = self::get_widget_name( $widget_id );
+			$action       = 'deactivated';
+			$name         = self::get_widget_name( $widget_id );
+			$title        = self::get_widget_title( $widget_id );
+			$labels       = self::get_context_labels();
+			$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
 			if ( $name && $title ) {
-				$message = _x( '"%1$s" (%2$s) deactivated', '1: Title, 2: Name', 'stream' );
+				$message = _x( '%1$s widget named "%2$s" in "%3$s" deactivated', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
 			} elseif ( $name ) {
 				// Empty title, but we have the name
-				$message = _x( '%2$s deactivated', '2: Name', 'stream' );
+				$message = _x( '%1$s widget in "%3$s" deactivated', '1: Name, 3: Sidebar Name', 'stream' );
 			} elseif ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x( '"%1$s" widget deactivated', '1: Title', 'stream' );
+				$message = _x( 'Unknown widget type named "%2$s" in "%3$s" deactivated', '2: Title, 3: Sidebar Name', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = _x( '%3$s widget deactivated', '3: Widget ID', 'stream' );
+				$message = _x( '%4$s widget in "%3$s" deactivated', '4: Widget ID, 3: Sidebar Name', 'stream' );
 			}
 
-			$message = sprintf( $message, $title, $name, $widget_id );
+			$message = sprintf( $message, $name, $title, $sidebar_name, $widget_id );
 
 			self::log(
 				$message,

From 3b134b15918fc876042438952228a3de6441adac Mon Sep 17 00:00:00 2001
From: Frankie Jarrett <frankie@x-team.com>
Date: Thu, 10 Jul 2014 10:42:14 -0500
Subject: [PATCH 40/40] Widget summary grammar tweaks

---
 connectors/widgets.php | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/connectors/widgets.php b/connectors/widgets.php
index 563f7e66e..de873fa8a 100644
--- a/connectors/widgets.php
+++ b/connectors/widgets.php
@@ -192,16 +192,16 @@ static protected function handle_deactivated_widgets( $old, $new ) {
 			$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
 
 			if ( $name && $title ) {
-				$message = _x( '%1$s widget named "%2$s" in "%3$s" deactivated', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
+				$message = _x( '%1$s widget named "%2$s" from "%3$s" deactivated', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
 			} elseif ( $name ) {
 				// Empty title, but we have the name
-				$message = _x( '%1$s widget in "%3$s" deactivated', '1: Name, 3: Sidebar Name', 'stream' );
+				$message = _x( '%1$s widget from "%3$s" deactivated', '1: Name, 3: Sidebar Name', 'stream' );
 			} elseif ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x( 'Unknown widget type named "%2$s" in "%3$s" deactivated', '2: Title, 3: Sidebar Name', 'stream' );
+				$message = _x( 'Unknown widget type named "%2$s" from "%3$s" deactivated', '2: Title, 3: Sidebar Name', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = _x( '%4$s widget in "%3$s" deactivated', '4: Widget ID, 3: Sidebar Name', 'stream' );
+				$message = _x( '%4$s widget from "%3$s" deactivated', '4: Widget ID, 3: Sidebar Name', 'stream' );
 			}
 
 			$message = sprintf( $message, $name, $title, $sidebar_name, $widget_id );
@@ -215,7 +215,6 @@ static protected function handle_deactivated_widgets( $old, $new ) {
 		}
 	}
 
-
 	/**
 	 * Track reactivation of widgets from sidebars
 	 *
@@ -236,26 +235,24 @@ static protected function handle_reactivated_widgets( $old, $new ) {
 				}
 			}
 
-			$action       = 'reactivated';
-			$name         = self::get_widget_name( $widget_id );
-			$title        = self::get_widget_title( $widget_id );
-			$labels       = self::get_context_labels();
-			$sidebar_name = isset( $labels[ $sidebar_id ] ) ? $labels[ $sidebar_id ] : $sidebar_id;
+			$action = 'reactivated';
+			$name   = self::get_widget_name( $widget_id );
+			$title  = self::get_widget_title( $widget_id );
 
 			if ( $name && $title ) {
-				$message = _x( '%1$s widget named "%2$s" in "%3$s" reactivated', '1: Name, 2: Title, 3: Sidebar Name', 'stream' );
+				$message = _x( '%1$s widget named "%2$s" reactivated', '1: Name, 2: Title', 'stream' );
 			} elseif ( $name ) {
 				// Empty title, but we have the name
-				$message = _x( '%1$s widget in "%3$s" reactivated', '1: Name, 3: Sidebar Name', 'stream' );
+				$message = _x( '%1$s widget reactivated', '1: Name', 'stream' );
 			} elseif ( $title ) {
 				// Likely a single widget since no name is available
-				$message = _x( 'Unknown widget type named "%2$s" in "%3$s" reactivated', '2: Title, 3: Sidebar Name', 'stream' );
+				$message = _x( 'Unknown widget type named "%2$s" reactivated', '2: Title', 'stream' );
 			} else {
 				// Neither a name nor a title are available, so use the widget ID
-				$message = _x( '%4$s widget in "%3$s" reactivated', '4: Widget ID, 3: Sidebar Name', 'stream' );
+				$message = _x( '%3$s widget reactivated', '3: Widget ID', 'stream' );
 			}
 
-			$message = sprintf( $message, $name, $title, $sidebar_name, $widget_id );
+			$message = sprintf( $message, $name, $title, $widget_id );
 
 			self::log(
 				$message,