Index: wp-includes/widgets.php
===================================================================
--- wp-includes/widgets.php	(revision 32680)
+++ wp-includes/widgets.php	(working copy)
@@ -13,7 +13,192 @@
  * @subpackage Widgets
  */
 
+interface WP_Widget_AdminInterface {
+
+	/**
+	 * Update a particular instance.
+	 *
+	 * This function should check that $new_instance is set correctly. The newly-calculated
+	 * value of `$instance` should be returned. If false is returned, the instance won't be
+	 * saved/updated.
+	 *
+	 * @param array $new_instance
+	 * New settings for this instance as input by the user via {@see WP_Widget::form()}.
+	 * @param array $old_instance
+	 * Old settings for this instance.
+	 * @return array
+	 * Settings to save or bool false to cancel saving.
+	 */
+	public function update( $new_instance, $old_instance );
+
+	/**
+	 * Output the settings update form.
+	 *
+	 * @param array $instance Current settings.
+	 * @return string Default return is 'noform'.
+	 */
+	public function form( $instance );
+
+}
+
+interface WP_Widget_Display_TitleInterface {
+
+	/**
+	 * Return the title of the widget
+	 *
+	 * @param $instance
+	 *
+	 * @return mixed|void
+	 */
+	public function widget_title( $instance );
+
+}
+
+interface WP_Widget_DisplayInterface extends WP_Widget_Display_TitleInterface {
+
+	/**
+	 * Echo the widget content.
+	 *
+	 * @param array $args
+	 * Display arguments including before_title, after_title, before_widget, and after_widget.
+	 * @param array $instance
+	 * The settings for the particular instance of the widget.
+	 */
+	public function widget( $args, $instance );
+
+}
+
+interface WP_Widget_Display_EventInterface extends WP_Widget_Display_TitleInterface {
+
+	/**
+	 * Verify settings
+	 *
+	 * Used to determine whether we should render the widget or not.
+	 *
+	 * @param array $instance
+	 * @return bool
+	 */
+	public function verify_settings( $instance );
+
+	/**
+	 * Default treatment of before widget markup
+	 *
+	 * @param $args
+	 * @param $instance
+	 */
+	public function before_widget( $args, $instance );
+
+	/**
+	 * Output the custom markup content for the widget
+	 *
+	 * Subclasses will override this to create their output
+	 */
+	public function widget_markup( $args, $instance );
+
+	/**
+	 * Default treatment of after widget markup
+	 *
+	 * @param $args
+	 * @param $instance
+	 */
+	public function after_widget( $args, $instance );
+
+}
+
+interface WP_Widget_SettingInterface {
+
+	/**
+	 * @return array
+	 *     array(
+	 *         'id_base' => 'whatever',
+	 *         'name' => 'whatever-name',
+	 *         'widget_options' => array(),
+	 *         'control_options' => array(),
+	 *     )
+	 */
+	public function settings();
+
+}
+
 /**
+ * Defines the WordPress Widget type.
+ *
+ * All widgets must implement this empty interface for type hinting.
+ */
+interface WP_Widget_ControlInterface { }
+
+/**
+ * Stub of defaults for implementing interface.
+ */
+final class WP_Widget_Admin_Form_Missing implements WP_Widget_AdminInterface {
+
+	/**
+	 * @internal Inherits phpdoc from interface.
+	 */
+	public function update( $new_instance, $old_instance ) {
+		return $new_instance;
+	}
+
+	/**
+	 * @internal Inherits phpdoc from interface.
+	 */
+	public function form( $instance ) {
+		echo '<p class="no-options-widget">' . __('There are no options for this widget.') . '</p>';
+		return 'noform';
+	}
+}
+
+/**
+ * Stub of widget that displays title and before widget and after widget content.
+ */
+final class WP_Widget_Display_Nothing implements WP_Widget_Display_EventInterface {
+
+	/**
+	 * @internal Inherits phpdoc from interface.
+	 */
+	public function verify_settings( $instance ) {
+		return true;
+	}
+
+	/**
+	 * @internal Inherits phpdoc from interface.
+	 */
+	public function before_widget( $args, $instance ) {
+		$title = $this->widget_title( $instance );
+		echo $args['before_widget'];
+		if ( $title ) {
+			echo $args['before_title'] . $title . $args['after_title'];
+		}
+	}
+
+	/**
+	 * @internal Inherits phpdoc from interface.
+	 */
+	public function widget_markup( $args, $instance ) {}
+
+	/**
+	 * @internal Inherits phpdoc from interface.
+	 */
+	public function after_widget( $args, $instance ) {
+		echo $args['after_widget'];
+	}
+
+	/**
+	 * @internal Inherits phpdoc from interface.
+	 */
+	public function widget_title( $instance ) {
+		$id_base = preg_replace( '/(wp_)?widget_/', '', strtolower(get_class($this)) );
+		if (property_exists($this, 'id_base') ) {
+			$id_base = $this->id_base;
+		} else if ( $this instanceof WP_Widget_SettingInterface ) {
+			$settings = $this->settings();
+			$id_base = isset($settings['id_base']) ? $settings['id_base'] : $id_base;
+		}
+		return widget_title_filter( $instance, $id_base );
+	}
+}
+
+/**
  * This class must be extended for each widget and WP_Widget::widget(), WP_Widget::update()
  * and WP_Widget::form() need to be over-ridden.
  *
@@ -21,7 +206,7 @@
  * @subpackage Widgets
  * @since 2.8.0
  */
-class WP_Widget {
+class WP_Widget implements WP_Widget_ControlInterface, WP_Widget_DisplayInterface, WP_Widget_AdminInterface {
 
 	/**
 	 * Root ID for all widgets of this type.
@@ -89,6 +274,12 @@
 	 */
 	public $updated = false;
 
+	/**
+	 *
+	 * @var type
+	 */
+	public $admin_instance = null;
+
 	// Member functions that you must over-ride.
 
 	/**
@@ -104,10 +295,32 @@
 	 * @param array $instance The settings for the particular instance of the widget.
 	 */
 	public function widget( $args, $instance ) {
-		die('function WP_Widget::widget() must be over-ridden in a sub-class.');
+		if ($this instanceof WP_Widget_Display_EventInterface) {
+			//verify that we should be showing the widget
+			if ( ! $this->verify_settings( $instance ) ) {
+				return;
+			}
+
+			$this->before_widget( $args, $instance );
+			$this->widget_markup( $args, $instance );
+			$this->after_widget( $args, $instance );
+		} else {
+			die('function WP_Widget::widget() must be over-ridden in a sub-class.');
+		}
 	}
 
 	/**
+	 * Return the title of the widget
+	 *
+	 * @param $instance
+	 *
+	 * @return mixed|void
+	 */
+	public function widget_title( $instance ) {
+		return widget_title_filter( $instance, $this->id_base );
+	}
+
+	/**
 	 * Update a particular instance.
 	 *
 	 * This function should check that $new_instance is set correctly. The newly-calculated
@@ -123,7 +336,11 @@
 	 * @return array Settings to save or bool false to cancel saving.
 	 */
 	public function update( $new_instance, $old_instance ) {
-		return $new_instance;
+		$obj = $this->admin_instance;
+		if ( ! ( $obj instanceof WP_Widget_AdminInterface ) ) {
+			$obj = new WP_Widget_Admin_Form_Missing;
+		}
+		return $obj->update( $new_instance, $old_instance );
 	}
 
 	/**
@@ -136,8 +353,11 @@
 	 * @return string Default return is 'noform'.
 	 */
 	public function form($instance) {
-		echo '<p class="no-options-widget">' . __('There are no options for this widget.') . '</p>';
-		return 'noform';
+		$obj = $this->admin_instance;
+		if ( ! ( $obj instanceof WP_Widget_AdminInterface ) ) {
+			$obj = new WP_Widget_Admin_Form_Missing;
+		}
+		return $obj->form( $instance );
 	}
 
 	// Functions you'll need to call.
@@ -689,6 +909,10 @@
 
 /* Template tags & API functions */
 
+function widget_title_filter($instance, $id_base) {
+	return apply_filters( 'widget_title', ! isset($instance['title']  ) || empty( $instance['title'] ) ? '' : $instance['title'], $instance, $id_base );
+}
+
 /**
  * Register a widget
  *
