Make WordPress Core

Ticket #27504: 27504.3.patch

File 27504.3.patch, 42.4 KB (added by westonruter, 12 years ago)

Convert static WP_Customize_Widgets class into instantiated class. Changes also pushed to GitHub: https://github.com/x-team/wordpress-develop/pull/1/files

  • src/wp-admin/includes/ajax-actions.php

    diff --git src/wp-admin/includes/ajax-actions.php src/wp-admin/includes/ajax-actions.php
    index e7f4f6b..a6b47f9 100644
    function wp_ajax_save_widget() { 
    15881588}
    15891589
    15901590function wp_ajax_update_widget() {
    1591         WP_Customize_Widgets::wp_ajax_update_widget();
     1591        global $wp_customize;
     1592        $wp_customize->widgets->wp_ajax_update_widget();
    15921593}
    15931594
    15941595function wp_ajax_upload_attachment() {
  • src/wp-includes/class-wp-customize-control.php

    diff --git src/wp-includes/class-wp-customize-control.php src/wp-includes/class-wp-customize-control.php
    index cce9195..e520b6d 100644
    class WP_Widget_Form_Customize_Control extends WP_Customize_Control { 
    10801080                );
    10811081
    10821082                $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) );
    1083                 echo WP_Customize_Widgets::get_widget_control( $args );
     1083                echo $this->manager->widgets->get_widget_control( $args );
    10841084        }
    10851085}
    10861086
  • src/wp-includes/class-wp-customize-manager.php

    diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php
    index 7f337f5..cc41801 100644
    final class WP_Customize_Manager { 
    3737         */
    3838        protected $previewing = false;
    3939
     40        /**
     41         * Methods and properties deailing with managing widgets in the customizer
     42         *
     43         * @var WP_Customize_Widgets
     44         */
     45        public $widgets;
     46
    4047        protected $settings = array();
    4148        protected $sections = array();
    4249        protected $controls = array();
    final class WP_Customize_Manager { 
    6370                require( ABSPATH . WPINC . '/class-wp-customize-control.php' );
    6471                require( ABSPATH . WPINC . '/class-wp-customize-widgets.php' );
    6572
    66                 WP_Customize_Widgets::setup(); // This should be integrated.
     73                $this->widgets = new WP_Customize_Widgets( $this );
    6774
    6875                add_filter( 'wp_die_handler', array( $this, 'wp_die_handler' ) );
    6976
  • src/wp-includes/class-wp-customize-widgets.php

    diff --git src/wp-includes/class-wp-customize-widgets.php src/wp-includes/class-wp-customize-widgets.php
    index 055afa2..a37cb98 100644
    class WP_Customize_Widgets { 
    1313        const UPDATE_WIDGET_NONCE_POST_KEY = 'update-sidebar-widgets-nonce';
    1414
    1515        /**
     16         * @access public
     17         * @var WP_Customize_Manager
     18         */
     19        public $manager;
     20
     21        /**
    1622         * All id_bases for widgets defined in core
    1723         *
    1824         * @since 3.9.0
    class WP_Customize_Widgets { 
    2026         * @access protected
    2127         * @var array
    2228         */
    23         protected static $core_widget_id_bases = array(
     29        protected $core_widget_id_bases = array(
    2430                'archives',
    2531                'calendar',
    2632                'categories',
    class WP_Customize_Widgets { 
    4248         * @access protected
    4349         * @var
    4450         */
    45         protected static $_customized;
     51        protected $_customized;
    4652
    4753        /**
    4854         * @since 3.9.0
    class WP_Customize_Widgets { 
    5056         * @access protected
    5157         * @var array
    5258         */
    53         protected static $_prepreview_added_filters = array();
     59        protected $_prepreview_added_filters = array();
    5460
    5561        /**
    5662         * @since 3.9.0
    class WP_Customize_Widgets { 
    5864         * @access protected
    5965         * @var array
    6066         */
    61         static protected $rendered_sidebars = array();
     67        protected $rendered_sidebars = array();
    6268
    6369        /**
    6470         * @since 3.9.0
    class WP_Customize_Widgets { 
    6672         * @access protected
    6773         * @var array
    6874         */
    69         static protected $rendered_widgets = array();
     75        protected $rendered_widgets = array();
    7076
    7177        /**
    7278         * Initial loader.
    class WP_Customize_Widgets { 
    7581         * @static
    7682         * @access public
    7783         */
    78         static function setup() {
    79                 add_action( 'after_setup_theme',                       array( __CLASS__, 'setup_widget_addition_previews' ) );
    80                 add_action( 'customize_controls_init',                 array( __CLASS__, 'customize_controls_init' ) );
    81                 add_action( 'customize_register',                      array( __CLASS__, 'schedule_customize_register' ), 1 );
    82                 add_action( 'customize_controls_enqueue_scripts',      array( __CLASS__, 'customize_controls_enqueue_deps' ) );
    83                 add_action( 'customize_controls_print_footer_scripts', array( __CLASS__, 'output_widget_control_templates' ) );
    84                 add_action( 'customize_preview_init',                  array( __CLASS__, 'customize_preview_init' ) );
    85 
    86                 add_action( 'dynamic_sidebar',                         array( __CLASS__, 'tally_rendered_widgets' ) );
    87                 add_filter( 'is_active_sidebar',                       array( __CLASS__, 'tally_sidebars_via_is_active_sidebar_calls' ), 10, 2 );
    88                 add_filter( 'dynamic_sidebar_has_widgets',             array( __CLASS__, 'tally_sidebars_via_dynamic_sidebar_calls' ), 10, 2 );
     84        function __construct( WP_Customize_Manager $manager ) {
     85                $this->manager = $manager;
     86
     87                add_action( 'after_setup_theme',                       array( $this, 'setup_widget_addition_previews' ) );
     88                add_action( 'customize_controls_init',                 array( $this, 'customize_controls_init' ) );
     89                add_action( 'customize_register',                      array( $this, 'schedule_customize_register' ), 1 );
     90                add_action( 'customize_controls_enqueue_scripts',      array( $this, 'customize_controls_enqueue_deps' ) );
     91                add_action( 'customize_controls_print_footer_scripts', array( $this, 'output_widget_control_templates' ) );
     92                add_action( 'customize_preview_init',                  array( $this, 'customize_preview_init' ) );
     93
     94                add_action( 'dynamic_sidebar',                         array( $this, 'tally_rendered_widgets' ) );
     95                add_filter( 'is_active_sidebar',                       array( $this, 'tally_sidebars_via_is_active_sidebar_calls' ), 10, 2 );
     96                add_filter( 'dynamic_sidebar_has_widgets',             array( $this, 'tally_sidebars_via_dynamic_sidebar_calls' ), 10, 2 );
    8997        }
    9098
    9199        /**
    class WP_Customize_Widgets { 
    100108         * @param mixed  $default Default post value.
    101109         * @return mixed Unslashed post value or default value.
    102110         */
    103         static function get_post_value( $name, $default = null ) {
     111        function get_post_value( $name, $default = null ) {
    104112                if ( ! isset( $_POST[ $name ] ) ) {
    105113                        return $default;
    106114                }
    class WP_Customize_Widgets { 
    119127         * @access public
    120128         * @global WP_Customize_Manager $wp_customize
    121129         */
    122         static function setup_widget_addition_previews() {
    123                 global $wp_customize;
     130        function setup_widget_addition_previews() {
    124131                $is_customize_preview = (
    125                         ( ! empty( $wp_customize ) )
     132                        ( ! empty( $this->manager ) )
    126133                        &&
    127134                        ( ! is_admin() )
    128135                        &&
    129                         ( 'on' === self::get_post_value( 'wp_customize' ) )
     136                        ( 'on' === $this->get_post_value( 'wp_customize' ) )
    130137                        &&
    131                         check_ajax_referer( 'preview-customize_' . $wp_customize->get_stylesheet(), 'nonce', false )
     138                        check_ajax_referer( 'preview-customize_' . $this->manager->get_stylesheet(), 'nonce', false )
    132139                );
    133140
    134141                $is_ajax_widget_update = (
    135142                        ( defined( 'DOING_AJAX' ) && DOING_AJAX )
    136143                        &&
    137                         self::get_post_value( 'action' ) === self::UPDATE_WIDGET_AJAX_ACTION
     144                        $this->get_post_value( 'action' ) === self::UPDATE_WIDGET_AJAX_ACTION
    138145                        &&
    139146                        check_ajax_referer( self::UPDATE_WIDGET_AJAX_ACTION, self::UPDATE_WIDGET_NONCE_POST_KEY, false )
    140147                );
    class WP_Customize_Widgets { 
    142149                $is_ajax_customize_save = (
    143150                        ( defined( 'DOING_AJAX' ) && DOING_AJAX )
    144151                        &&
    145                         self::get_post_value( 'action' ) === 'customize_save'
     152                        $this->get_post_value( 'action' ) === 'customize_save'
    146153                        &&
    147                         check_ajax_referer( 'save-customize_' . $wp_customize->get_stylesheet(), 'nonce' )
     154                        check_ajax_referer( 'save-customize_' . $this->manager->get_stylesheet(), 'nonce' )
    148155                );
    149156
    150157                $is_valid_request = ( $is_ajax_widget_update || $is_customize_preview || $is_ajax_customize_save );
    class WP_Customize_Widgets { 
    154161
    155162                // Input from customizer preview.
    156163                if ( isset( $_POST['customized'] ) ) {
    157                         $customized = json_decode( self::get_post_value( 'customized' ), true );
     164                        $customized = json_decode( $this->get_post_value( 'customized' ), true );
    158165                }
    159166
    160167                // Input from ajax widget update request.
    161168                else {
    162169                        $customized    = array();
    163                         $id_base       = self::get_post_value( 'id_base' );
    164                         $widget_number = (int) self::get_post_value( 'widget_number' );
     170                        $id_base       = $this->get_post_value( 'id_base' );
     171                        $widget_number = (int) $this->get_post_value( 'widget_number' );
    165172                        $option_name   = 'widget_' . $id_base;
    166173                        $customized[$option_name] = array();
    167174                        if ( false !== $widget_number ) {
    class WP_Customize_Widgets { 
    170177                        }
    171178                }
    172179
    173                 $function = array( __CLASS__, 'prepreview_added_sidebars_widgets' );
     180                $function = array( $this, 'prepreview_added_sidebars_widgets' );
    174181
    175182                $hook = 'option_sidebars_widgets';
    176183                add_filter( $hook, $function );
    177                 self::$_prepreview_added_filters[] = compact( 'hook', 'function' );
     184                $this->_prepreview_added_filters[] = compact( 'hook', 'function' );
    178185
    179186                $hook = 'default_option_sidebars_widgets';
    180187                add_filter( $hook, $function );
    181                 self::$_prepreview_added_filters[] = compact( 'hook', 'function' );
     188                $this->_prepreview_added_filters[] = compact( 'hook', 'function' );
    182189
    183190                foreach ( $customized as $setting_id => $value ) {
    184191                        if ( preg_match( '/^(widget_.+?)(\[(\d+)\])?$/', $setting_id, $matches ) ) {
    185                                 $body     = sprintf( 'return %s::prepreview_added_widget_instance( $value, %s );', __CLASS__, var_export( $setting_id, true ) );
     192                                // @todo refactor using closures when PHP 5.3 is minimum requred version for WordPress
     193                                $body     = sprintf( 'global $wp_customize; return $wp_customize->widgets->prepreview_added_widget_instance( $value, %s );', var_export( $setting_id, true ) );
    186194                                $function = create_function( '$value', $body );
     195                                // @todo replace above two lines with following once PHP 5.3 happens in WordPress
     196                                // $self = $this; // not needed in PHP 5.4
     197                                // $function = function ( $value ) use ( $self, $setting_id ) {
     198                                //      return $self->manager->widgets->prepreview_added_widget_instance( $value, $setting_id );
     199                                //};
     200
    187201                                $option   = $matches[1];
    188202
    189203                                $hook = sprintf( 'option_%s', $option );
    190204                                add_filter( $hook, $function );
    191                                 self::$_prepreview_added_filters[] = compact( 'hook', 'function' );
     205                                $this->_prepreview_added_filters[] = compact( 'hook', 'function' );
    192206
    193207                                $hook = sprintf( 'default_option_%s', $option );
    194208                                add_filter( $hook, $function );
    195                                 self::$_prepreview_added_filters[] = compact( 'hook', 'function' );
     209                                $this->_prepreview_added_filters[] = compact( 'hook', 'function' );
    196210
    197211                                /**
    198212                                 * Make sure the option is registered so that the update_option won't fail due to
    class WP_Customize_Widgets { 
    202216                        }
    203217                }
    204218
    205                 self::$_customized = $customized;
     219                $this->_customized = $customized;
    206220        }
    207221
    208222        /**
    class WP_Customize_Widgets { 
    219233         * @param array $sidebars_widgets Array of
    220234         * @return array
    221235         */
    222         static function prepreview_added_sidebars_widgets( $sidebars_widgets ) {
    223                 foreach ( self::$_customized as $setting_id => $value ) {
     236        function prepreview_added_sidebars_widgets( $sidebars_widgets ) {
     237                foreach ( $this->_customized as $setting_id => $value ) {
    224238                        if ( preg_match( '/^sidebars_widgets\[(.+?)\]$/', $setting_id, $matches ) ) {
    225239                                $sidebar_id = $matches[1];
    226240                                $sidebars_widgets[$sidebar_id] = $value;
    class WP_Customize_Widgets { 
    244258         * @param string $setting_id Widget setting ID.
    245259         * @return array Parsed widget instance.
    246260         */
    247         static function prepreview_added_widget_instance( $instance, $setting_id ) {
    248                 if ( isset( self::$_customized[$setting_id] ) ) {
    249                         $parsed_setting_id = self::parse_widget_setting_id( $setting_id );
     261        function prepreview_added_widget_instance( $instance, $setting_id ) {
     262                if ( isset( $this->_customized[$setting_id] ) ) {
     263                        $parsed_setting_id = $this->parse_widget_setting_id( $setting_id );
    250264                        $widget_number     = $parsed_setting_id['number'];
    251265
    252266                        // Single widget
    class WP_Customize_Widgets { 
    276290         * @static
    277291         * @access public
    278292         */
    279         static function remove_prepreview_filters() {
    280                 foreach ( self::$_prepreview_added_filters as $prepreview_added_filter ) {
     293        function remove_prepreview_filters() {
     294                foreach ( $this->_prepreview_added_filters as $prepreview_added_filter ) {
    281295                        remove_filter( $prepreview_added_filter['hook'], $prepreview_added_filter['function'] );
    282296                }
    283                 self::$_prepreview_added_filters = array();
     297                $this->_prepreview_added_filters = array();
    284298        }
    285299
    286300        /**
    class WP_Customize_Widgets { 
    290304         * @static
    291305         * @access public
    292306         */
    293         static function customize_controls_init() {
     307        function customize_controls_init() {
    294308                do_action( 'load-widgets.php' );
    295309                do_action( 'widgets.php' );
    296310                do_action( 'sidebar_admin_setup' );
    class WP_Customize_Widgets { 
    303317         * @since 3.9.0
    304318         * @static
    305319         * @access public
    306          *
    307          * @param WP_Customize_Manager $wp_customize Customizer instance.
    308320         */
    309         static function schedule_customize_register( $wp_customize ) {
     321        function schedule_customize_register() {
    310322                if ( is_admin() ) { // @todo for some reason, $wp_customize->is_preview() is true here?
    311                         self::customize_register( $wp_customize );
     323                        $this->customize_register();
    312324                } else {
    313                         add_action( 'wp', array( __CLASS__, 'customize_register' ) );
     325                        add_action( 'wp', array( $this, 'customize_register' ) );
    314326                }
    315327        }
    316328
    class WP_Customize_Widgets { 
    320332         * @since 3.9.0
    321333         * @static
    322334         * @access public
    323          *
    324          * @param WP_Customize_Manager $wp_customize Customizer instance.
    325335         */
    326         static function customize_register( $wp_customize = null ) {
     336        function customize_register() {
    327337                global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_sidebars;
    328                 if ( ! ( $wp_customize instanceof WP_Customize_Manager ) ) {
    329                         $wp_customize = $GLOBALS['wp_customize'];
    330                 }
    331338
    332339                $sidebars_widgets = array_merge(
    333340                        array( 'wp_inactive_widgets' => array() ),
    class WP_Customize_Widgets { 
    342349                 * since a widget may get suppressed from a sidebar via a plugin (like Widget Visibility).
    343350                 */
    344351                foreach ( array_keys( $wp_registered_widgets ) as $widget_id ) {
    345                         $setting_id   = self::get_setting_id( $widget_id );
    346                         $setting_args = self::get_setting_args( $setting_id );
    347                         $setting_args['sanitize_callback']    = array( __CLASS__, 'sanitize_widget_instance' );
    348                         $setting_args['sanitize_js_callback'] = array( __CLASS__, 'sanitize_widget_js_instance' );
    349                         $wp_customize->add_setting( $setting_id, $setting_args );
     352                        $setting_id   = $this->get_setting_id( $widget_id );
     353                        $setting_args = $this->get_setting_args( $setting_id );
     354                        $setting_args['sanitize_callback']    = array( $this, 'sanitize_widget_instance' );
     355                        $setting_args['sanitize_js_callback'] = array( $this, 'sanitize_widget_js_instance' );
     356                        $this->manager->add_setting( $setting_id, $setting_args );
    350357                        $new_setting_ids[] = $setting_id;
    351358                }
    352359
    class WP_Customize_Widgets { 
    363370                         */
    364371                        if ( $is_registered_sidebar || $is_inactive_widgets ) {
    365372                                $setting_id   = sprintf( 'sidebars_widgets[%s]', $sidebar_id );
    366                                 $setting_args = self::get_setting_args( $setting_id );
    367                                 $setting_args['sanitize_callback']    = array( __CLASS__, 'sanitize_sidebar_widgets' );
    368                                 $setting_args['sanitize_js_callback'] = array( __CLASS__, 'sanitize_sidebar_widgets_js_instance' );
    369                                 $wp_customize->add_setting( $setting_id, $setting_args );
     373                                $setting_args = $this->get_setting_args( $setting_id );
     374                                $setting_args['sanitize_callback']    = array( $this, 'sanitize_sidebar_widgets' );
     375                                $setting_args['sanitize_js_callback'] = array( $this, 'sanitize_sidebar_widgets_js_instance' );
     376                                $this->manager->add_setting( $setting_id, $setting_args );
    370377                                $new_setting_ids[] = $setting_id;
    371378
    372379                                /**
    class WP_Customize_Widgets { 
    381388                                                'priority' => 1000 + array_search( $sidebar_id, array_keys( $wp_registered_sidebars ) ),
    382389                                        );
    383390                                        $section_args = apply_filters( 'customizer_widgets_section_args', $section_args, $section_id, $sidebar_id );
    384                                         $wp_customize->add_section( $section_id, $section_args );
     391                                        $this->manager->add_section( $section_id, $section_args );
    385392
    386393                                        $control = new WP_Widget_Area_Customize_Control(
    387                                                 $wp_customize,
     394                                                $this->manager,
    388395                                                $setting_id,
    389396                                                array(
    390397                                                        'section' => $section_id,
    class WP_Customize_Widgets { 
    393400                                                )
    394401                                        );
    395402                                        $new_setting_ids[] = $setting_id;
    396                                         $wp_customize->add_control( $control );
     403                                        $this->manager->add_control( $control );
    397404                                }
    398405                        }
    399406
    class WP_Customize_Widgets { 
    405412                                        continue;
    406413                                }
    407414                                $registered_widget = $GLOBALS['wp_registered_widgets'][$widget_id];
    408                                 $setting_id = self::get_setting_id( $widget_id );
     415                                $setting_id = $this->get_setting_id( $widget_id );
    409416                                $id_base = $GLOBALS['wp_registered_widget_controls'][$widget_id]['id_base'];
    410417                                assert( false !== is_active_widget( $registered_widget['callback'], $registered_widget['id'], false, false ) );
    411418                                $control = new WP_Widget_Form_Customize_Control(
    412                                         $wp_customize,
     419                                        $this->manager,
    413420                                        $setting_id,
    414421                                        array(
    415422                                                'label' => $registered_widget['name'],
    class WP_Customize_Widgets { 
    420427                                                'priority' => $i,
    421428                                                'width' => $wp_registered_widget_controls[$widget_id]['width'],
    422429                                                'height' => $wp_registered_widget_controls[$widget_id]['height'],
    423                                                 'is_wide' => self::is_wide_widget( $widget_id ),
     430                                                'is_wide' => $this->is_wide_widget( $widget_id ),
    424431                                        )
    425432                                );
    426                                 $wp_customize->add_control( $control );
     433                                $this->manager->add_control( $control );
    427434                        }
    428435                }
    429436
    class WP_Customize_Widgets { 
    433440                 */
    434441                if ( did_action( 'customize_preview_init' ) ) {
    435442                        foreach ( $new_setting_ids as $new_setting_id ) {
    436                                 $wp_customize->get_setting( $new_setting_id )->preview();
     443                                $this->manager->get_setting( $new_setting_id )->preview();
    437444                        }
    438445                }
    439446
    440                 self::remove_prepreview_filters();
     447                $this->remove_prepreview_filters();
    441448        }
    442449
    443450        /**
    class WP_Customize_Widgets { 
    450457         * @param string $widget_id Widget ID.
    451458         * @return string Maybe-parsed widget ID.
    452459         */
    453         static function get_setting_id( $widget_id ) {
    454                 $parsed_widget_id = self::parse_widget_id( $widget_id );
     460        function get_setting_id( $widget_id ) {
     461                $parsed_widget_id = $this->parse_widget_id( $widget_id );
    455462                $setting_id = sprintf( 'widget_%s', $parsed_widget_id['id_base'] );
    456463                if ( ! is_null( $parsed_widget_id['number'] ) ) {
    457464                        $setting_id .= sprintf( '[%d]', $parsed_widget_id['number'] );
    class WP_Customize_Widgets { 
    474481         * @param string $widget_id Widget ID.
    475482         * @return bool Whether or not the widget is a "wide" widget.
    476483         */
    477         static function is_wide_widget( $widget_id ) {
     484        function is_wide_widget( $widget_id ) {
    478485                global $wp_registered_widget_controls;
    479                 $parsed_widget_id = self::parse_widget_id( $widget_id );
     486                $parsed_widget_id = $this->parse_widget_id( $widget_id );
    480487                $width = $wp_registered_widget_controls[$widget_id]['width'];
    481                 $is_core = in_array( $parsed_widget_id['id_base'], self::$core_widget_id_bases );
     488                $is_core = in_array( $parsed_widget_id['id_base'], $this->core_widget_id_bases );
    482489                $is_wide = ( $width > 250 && ! $is_core );
    483490
    484491                /**
    class WP_Customize_Widgets { 
    503510         * @param string $widget_id Widget ID.
    504511         * @return array Array containing a widget's id_base and number components.
    505512         */
    506         static function parse_widget_id( $widget_id ) {
     513        function parse_widget_id( $widget_id ) {
    507514                $parsed = array(
    508515                        'number' => null,
    509516                        'id_base' => null,
    class WP_Customize_Widgets { 
    529536         * @return WP_Error|array Array contain a widget's id_base and number components,
    530537         *                        or a WP_Error object.
    531538         */
    532         static function parse_widget_setting_id( $setting_id ) {
     539        function parse_widget_setting_id( $setting_id ) {
    533540                if ( ! preg_match( '/^(widget_(.+?))(?:\[(\d+)\])?$/', $setting_id, $matches ) ) {
    534541                        return new WP_Error( 'invalid_setting_id', 'Invalid widget setting ID' );
    535542                }
    class WP_Customize_Widgets { 
    546553         * @static
    547554         * @access public
    548555         */
    549         static function customize_controls_enqueue_deps() {
     556        function customize_controls_enqueue_deps() {
    550557                wp_enqueue_style( 'customize-widgets' );
    551558                wp_enqueue_script( 'customize-widgets' );
    552559
    553560                // Export available widgets with control_tpl removed from model
    554561                // since plugins need templates to be in the DOM
    555562                $available_widgets = array();
    556                 foreach ( self::get_available_widgets() as $available_widget ) {
     563                foreach ( $this->get_available_widgets() as $available_widget ) {
    557564                        unset( $available_widget['control_tpl'] );
    558565                        $available_widgets[] = $available_widget;
    559566                }
    class WP_Customize_Widgets { 
    601608                                'save_btn_tooltip' => ( 'Save and preview changes before publishing them.' ),
    602609                                'remove_btn_label' => __( 'Remove' ),
    603610                                'remove_btn_tooltip' => ( 'Trash widget by moving it to the inactive widgets sidebar.' ),
    604                                 'error' => __('An error has occurred. Please reload the page and try again.'),
     611                                'error' => __( 'An error has occurred. Please reload the page and try again.' ),
    605612                        ),
    606613                        'tpl' => array(
    607614                                'widget_reorder_nav' => $widget_reorder_nav_tpl,
    class WP_Customize_Widgets { 
    626633         * @static
    627634         * @access public
    628635         */
    629         static function output_widget_control_templates() {
     636        function output_widget_control_templates() {
    630637                ?>
    631638                <div id="widgets-left"><!-- compatibility with JS which looks for widget templates here -->
    632639                <div id="available-widgets">
    633640                        <div id="available-widgets-filter">
    634641                                <input type="search" placeholder="<?php esc_attr_e( 'Find widgets&hellip;' ) ?>">
    635642                        </div>
    636                         <?php foreach ( self::get_available_widgets() as $available_widget ): ?>
     643                        <?php foreach ( $this->get_available_widgets() as $available_widget ): ?>
    637644                                <div id="widget-tpl-<?php echo esc_attr( $available_widget['id'] ) ?>" data-widget-id="<?php echo esc_attr( $available_widget['id'] ) ?>" class="widget-tpl <?php echo esc_attr( $available_widget['id'] ) ?>" tabindex="0">
    638645                                        <?php echo $available_widget['control_tpl']; // xss ok ?>
    639646                                </div>
    class WP_Customize_Widgets { 
    654661         * @param array  $overrides Array of setting overrides.
    655662         * @return array Possibly modified setting arguments.
    656663         */
    657         static function get_setting_args( $id, $overrides = array() ) {
     664        function get_setting_args( $id, $overrides = array() ) {
    658665                $args = array(
    659666                        'type' => 'option',
    660667                        'capability' => 'edit_theme_options',
    class WP_Customize_Widgets { 
    677684         * @param array $widget_ids Array of widget IDs.
    678685         * @return array Array of sanitized widget IDs.
    679686         */
    680         static function sanitize_sidebar_widgets( $widget_ids ) {
     687        function sanitize_sidebar_widgets( $widget_ids ) {
    681688                global $wp_registered_widgets;
    682689                $widget_ids = array_map( 'strval', (array) $widget_ids );
    683690                $sanitized_widget_ids = array();
    class WP_Customize_Widgets { 
    699706         * @see wp_list_widgets()
    700707         * @return array
    701708         */
    702         static function get_available_widgets() {
     709        function get_available_widgets() {
    703710                static $available_widgets = array();
    704711                if ( ! empty( $available_widgets ) ) {
    705712                        return $available_widgets;
    class WP_Customize_Widgets { 
    709716                require_once ABSPATH . '/wp-admin/includes/widgets.php'; // for next_widget_id_number()
    710717
    711718                $sort = $wp_registered_widgets;
    712                 usort( $sort, array( __CLASS__, '_sort_name_callback' ) );
     719                usort( $sort, array( $this, '_sort_name_callback' ) );
    713720                $done = array();
    714721
    715722                foreach ( $sort as $widget ) {
    class WP_Customize_Widgets { 
    753760                        }
    754761
    755762                        $list_widget_controls_args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) );
    756                         $control_tpl = self::get_widget_control( $list_widget_controls_args );
     763                        $control_tpl = $this->get_widget_control( $list_widget_controls_args );
    757764
    758765                        // The properties here are mapped to the Backbone Widget model
    759766                        $available_widget = array_merge(
    class WP_Customize_Widgets { 
    768775                                        'transport' => 'refresh',
    769776                                        'width' => $wp_registered_widget_controls[$widget['id']]['width'],
    770777                                        'height' => $wp_registered_widget_controls[$widget['id']]['height'],
    771                                         'is_wide' => self::is_wide_widget( $widget['id'] ),
     778                                        'is_wide' => $this->is_wide_widget( $widget['id'] ),
    772779                                )
    773780                        );
    774781
    class WP_Customize_Widgets { 
    788795         * @param array $widget_b The second widget to compare.
    789796         * @return int Reorder position for the current widget comparison.
    790797         */
    791         static function _sort_name_callback( $widget_a, $widget_b ) {
     798        function _sort_name_callback( $widget_a, $widget_b ) {
    792799                return strnatcasecmp( $widget_a['name'], $widget_b['name'] );
    793800        }
    794801
    class WP_Customize_Widgets { 
    803810         * @param array $args Widget control arguments.
    804811         * @return string Widget control form HTML markup.
    805812         */
    806         static function get_widget_control( $args ) {
     813        function get_widget_control( $args ) {
    807814                ob_start();
    808815                call_user_func_array( 'wp_widget_control', $args );
    809816                $replacements = array(
    class WP_Customize_Widgets { 
    822829         * @static
    823830         * @access public
    824831         */
    825         static function customize_preview_init() {
    826                 add_filter( 'sidebars_widgets',   array( __CLASS__, 'preview_sidebars_widgets' ), 1 );
    827                 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'customize_preview_enqueue' ) );
    828                 add_action( 'wp_print_styles',    array( __CLASS__, 'inject_preview_css' ), 1 );
    829                 add_action( 'wp_footer',          array( __CLASS__, 'export_preview_data' ), 20 );
     832        function customize_preview_init() {
     833                add_filter( 'sidebars_widgets',   array( $this, 'preview_sidebars_widgets' ), 1 );
     834                add_action( 'wp_enqueue_scripts', array( $this, 'customize_preview_enqueue' ) );
     835                add_action( 'wp_print_styles',    array( $this, 'inject_preview_css' ), 1 );
     836                add_action( 'wp_footer',          array( $this, 'export_preview_data' ), 20 );
    830837        }
    831838
    832839        /**
    class WP_Customize_Widgets { 
    843850         *
    844851         * @param array $sidebars_widgets List of widgets for the current sidebar.
    845852         */
    846         static function preview_sidebars_widgets( $sidebars_widgets ) {
     853        function preview_sidebars_widgets( $sidebars_widgets ) {
    847854                $sidebars_widgets = get_option( 'sidebars_widgets' );
    848855                unset( $sidebars_widgets['array_version'] );
    849856                return $sidebars_widgets;
    class WP_Customize_Widgets { 
    856863         * @static
    857864         * @access public
    858865         */
    859         static function customize_preview_enqueue() {
     866        function customize_preview_enqueue() {
    860867                wp_enqueue_script( 'customize-preview-widgets' );
    861                 }
     868        }
    862869
    863870        /**
    864871         * Insert default style for highlighted widget at early point so theme
    class WP_Customize_Widgets { 
    870877         *
    871878         * @action wp_print_styles
    872879         */
    873         static function inject_preview_css() {
     880        function inject_preview_css() {
    874881                ?>
    875882                <style>
    876883                .widget-customizer-highlighted-widget {
    class WP_Customize_Widgets { 
    891898         * @static
    892899         * @access public
    893900         */
    894         static function export_preview_data() {
     901        function export_preview_data() {
    895902                // Prepare customizer settings to pass to Javascript.
    896903                $settings = array(
    897                         'renderedSidebars'   => array_fill_keys( array_unique( self::$rendered_sidebars ), true ),
    898                         'renderedWidgets'    => array_fill_keys( array_keys( self::$rendered_widgets ), true ),
     904                        'renderedSidebars'   => array_fill_keys( array_unique( $this->rendered_sidebars ), true ),
     905                        'renderedWidgets'    => array_fill_keys( array_keys( $this->rendered_widgets ), true ),
    899906                        'registeredSidebars' => array_values( $GLOBALS['wp_registered_sidebars'] ),
    900907                        'registeredWidgets'  => $GLOBALS['wp_registered_widgets'],
    901908                        'l10n'               => array(
    class WP_Customize_Widgets { 
    922929         *
    923930         * @param array $widget Rendered widget to tally.
    924931         */
    925         static function tally_rendered_widgets( $widget ) {
    926                 self::$rendered_widgets[$widget['id']] = true;
     932        function tally_rendered_widgets( $widget ) {
     933                $this->rendered_widgets[$widget['id']] = true;
    927934        }
    928935
    929936        /**
    class WP_Customize_Widgets { 
    937944         * @param bool    $is_active  Whether the sidebar is active.
    938945         * @pasram string $sidebar_id Sidebar ID.
    939946         */
    940         static function tally_sidebars_via_is_active_sidebar_calls( $is_active, $sidebar_id ) {
     947        function tally_sidebars_via_is_active_sidebar_calls( $is_active, $sidebar_id ) {
    941948                if ( isset( $GLOBALS['wp_registered_sidebars'][$sidebar_id] ) ) {
    942                         self::$rendered_sidebars[] = $sidebar_id;
     949                        $this->rendered_sidebars[] = $sidebar_id;
    943950                }
    944951                // We may need to force this to true, and also force-true the value for dynamic_sidebar_has_widgets
    945952                // if we want to ensure that there is an area to drop widgets into, if the sidebar is empty.
    class WP_Customize_Widgets { 
    957964         * @param bool   $has_widgets Whether the current sidebar has widgets.
    958965         * @param string $sidebar_id  Sidebar ID.
    959966         */
    960         static function tally_sidebars_via_dynamic_sidebar_calls( $has_widgets, $sidebar_id ) {
     967        function tally_sidebars_via_dynamic_sidebar_calls( $has_widgets, $sidebar_id ) {
    961968                if ( isset( $GLOBALS['wp_registered_sidebars'][$sidebar_id] ) ) {
    962                         self::$rendered_sidebars[] = $sidebar_id;
     969                        $this->rendered_sidebars[] = $sidebar_id;
    963970                }
    964971                /*
    965972                 * We may need to force this to true, and also force-true the value for is_active_sidebar
    class WP_Customize_Widgets { 
    983990         * @param array $instance Widget instance.
    984991         * @return string Widget instance's hash key.
    985992         */
    986         protected static function get_instance_hash_key( $instance ) {
     993        protected function get_instance_hash_key( $instance ) {
    987994                $hash = md5( AUTH_KEY . serialize( $instance ) );
    988995                return $hash;
    989996        }
    class WP_Customize_Widgets { 
    10031010         * @param array $value Widget instance to sanitize.
    10041011         * @return array Sanitized widget instance.
    10051012         */
    1006         static function sanitize_widget_instance( $value ) {
     1013        function sanitize_widget_instance( $value ) {
    10071014                if ( $value === array() ) {
    10081015                        return $value;
    10091016                }
    class WP_Customize_Widgets { 
    10251032                if ( false === $instance ) {
    10261033                        return null;
    10271034                }
    1028                 if ( self::get_instance_hash_key( $instance ) !== $value['instance_hash_key'] ) {
     1035                if ( $this->get_instance_hash_key( $instance ) !== $value['instance_hash_key'] ) {
    10291036                        return null;
    10301037                }
    10311038                return $instance;
    class WP_Customize_Widgets { 
    10431050         * @param array $value Widget instance to convert to JSON.
    10441051         * @return array JSON-converted widget instance.
    10451052         */
    1046         static function sanitize_widget_js_instance( $value ) {
     1053        function sanitize_widget_js_instance( $value ) {
    10471054                if ( empty( $value['is_widget_customizer_js_value'] ) ) {
    10481055                        $serialized = serialize( $value );
    10491056                        $value = array(
    10501057                                'encoded_serialized_instance' => base64_encode( $serialized ),
    10511058                                'title' => empty( $value['title'] ) ? '' : $value['title'],
    10521059                                'is_widget_customizer_js_value' => true,
    1053                                 'instance_hash_key' => self::get_instance_hash_key( $value ),
     1060                                'instance_hash_key' => $this->get_instance_hash_key( $value ),
    10541061                        );
    10551062                }
    10561063                return $value;
    class WP_Customize_Widgets { 
    10671074         * @param array $widget_ids List of widget IDs.
    10681075         * @return array Parsed list of widget IDs.
    10691076         */
    1070         static function sanitize_sidebar_widgets_js_instance( $widget_ids ) {
     1077        function sanitize_sidebar_widgets_js_instance( $widget_ids ) {
    10711078                global $wp_registered_widgets;
    10721079                $widget_ids = array_values( array_intersect( $widget_ids, array_keys( $wp_registered_widgets ) ) );
    10731080                return $widget_ids;
    class WP_Customize_Widgets { 
    10851092         * @param  string $widget_id Widget ID.
    10861093         * @return WP_Error|array Array containing the updated widget information. WP_Error, otherwise.
    10871094         */
    1088         static function call_widget_update( $widget_id ) {
     1095        function call_widget_update( $widget_id ) {
    10891096                global $wp_registered_widget_updates, $wp_registered_widget_controls;
    10901097
    1091                 $options_transaction = new Options_Transaction();
    1092 
    1093                 $options_transaction->start();
    1094                 $parsed_id   = self::parse_widget_id( $widget_id );
     1098                $this->start_capturing_option_updates();
     1099                $parsed_id   = $this->parse_widget_id( $widget_id );
    10951100                $option_name = 'widget_' . $parsed_id['id_base'];
    10961101
    10971102                /*
    class WP_Customize_Widgets { 
    11001105                 */
    11011106                $added_input_vars = array();
    11021107                if ( ! empty( $_POST['sanitized_widget_setting'] ) ) {
    1103                         $sanitized_widget_setting = json_decode( self::get_post_value( 'sanitized_widget_setting' ), true );
     1108                        $sanitized_widget_setting = json_decode( $this->get_post_value( 'sanitized_widget_setting' ), true );
    11041109                        if ( empty( $sanitized_widget_setting ) ) {
    1105                                 $options_transaction->rollback();
     1110                                $this->stop_capturing_option_updates();
    11061111                                return new WP_Error( 'malformed_data', 'Malformed sanitized_widget_setting' );
    11071112                        }
    11081113
    1109                         $instance = self::sanitize_widget_instance( $sanitized_widget_setting );
     1114                        $instance = $this->sanitize_widget_instance( $sanitized_widget_setting );
    11101115                        if ( is_null( $instance ) ) {
    1111                                 $options_transaction->rollback();
     1116                                $this->stop_capturing_option_updates();
    11121117                                return new WP_Error( 'unsanitary_data', 'Unsanitary sanitized_widget_setting' );
    11131118                        }
    11141119
    class WP_Customize_Widgets { 
    11431148                }
    11441149
    11451150                // Make sure the expected option was updated.
    1146                 if ( 0 !== $options_transaction->count() ) {
    1147                         if ( count( $options_transaction->options ) > 1 ) {
    1148                                 $options_transaction->rollback();
     1151                if ( 0 !== $this->count_captured_options() ) {
     1152                        if ( $this->count_captured_options() > 1 ) {
     1153                                $this->stop_capturing_option_updates();
    11491154                                return new WP_Error( 'unexpected_update', 'Widget unexpectedly updated more than one option.' );
    11501155                        }
    11511156
    1152                         $updated_option_name = key( $options_transaction->options );
     1157                        $updated_option_name = key( $this->get_captured_options() );
    11531158                        if ( $updated_option_name !== $option_name ) {
    1154                                 $options_transaction->rollback();
     1159                                $this->stop_capturing_option_updates();
    11551160                                return new WP_Error( 'wrong_option', sprintf( 'Widget updated option "%1$s", but expected "%2$s".', $updated_option_name, $option_name ) );
    11561161                        }
    11571162                }
    class WP_Customize_Widgets { 
    11721177                        $instance = $option;
    11731178                }
    11741179
    1175                 $options_transaction->rollback();
     1180                $this->stop_capturing_option_updates();
    11761181                return compact( 'instance', 'form' );
    11771182        }
    11781183
    class WP_Customize_Widgets { 
    11891194         * @todo Reuse wp_ajax_save_widget now that we have option transactions?
    11901195         * @action wp_ajax_update_widget
    11911196         */
    1192         static function wp_ajax_update_widget() {
     1197        function wp_ajax_update_widget() {
    11931198
    11941199                if ( ! is_user_logged_in() ) {
    11951200                        wp_die( 0 );
    class WP_Customize_Widgets { 
    12111216                do_action( 'widgets.php' );
    12121217                do_action( 'sidebar_admin_setup' );
    12131218
    1214                 $widget_id = self::get_post_value( 'widget-id' );
    1215                 $parsed_id = self::parse_widget_id( $widget_id );
     1219                $widget_id = $this->get_post_value( 'widget-id' );
     1220                $parsed_id = $this->parse_widget_id( $widget_id );
    12161221                $id_base   = $parsed_id['id_base'];
    12171222
    12181223                if ( isset( $_POST['widget-' . $id_base] ) && is_array( $_POST['widget-' . $id_base] ) && preg_match( '/__i__|%i%/', key( $_POST['widget-' . $id_base] ) ) ) {
    12191224                        wp_send_json_error();
    12201225                }
    12211226
    1222                 $updated_widget = self::call_widget_update( $widget_id ); // => {instance,form}
     1227                $updated_widget = $this->call_widget_update( $widget_id ); // => {instance,form}
    12231228                if ( is_wp_error( $updated_widget ) ) {
    12241229                        wp_send_json_error();
    12251230                }
    12261231
    12271232                $form = $updated_widget['form'];
    1228                 $instance = self::sanitize_widget_js_instance( $updated_widget['instance'] );
     1233                $instance = $this->sanitize_widget_js_instance( $updated_widget['instance'] );
    12291234
    12301235                wp_send_json_success( compact( 'form', 'instance' ) );
    12311236        }
    1232 }
    12331237
    1234 class Options_Transaction {
     1238        /***************************************************************************
     1239         * Option Update Capturing
     1240         ***************************************************************************/
    12351241
    12361242        /**
    1237          * @var array $options values updated while transaction is open
     1243         * @var array $_captured_options values updated while capturing is happening
    12381244         */
    1239         public $options = array();
    1240 
    1241         protected $_ignore_transients = true;
    1242         protected $_is_current = false;
    1243         protected $_operations = array();
    1244 
    1245         function __construct( $ignore_transients = true ) {
    1246                 $this->_ignore_transients = $ignore_transients;
    1247         }
     1245        protected $_captured_options = array();
    12481246
    12491247        /**
    1250          * Determine whether or not the transaction is open
    1251          * @return bool
     1248         * @var bool $_is_current whether capturing is currently happening or not
    12521249         */
    1253         function is_current() {
    1254                 return $this->_is_current;
    1255         }
     1250        protected $_is_capturing_option_updates = false;
    12561251
    12571252        /**
    12581253         * @param $option_name
    12591254         * @return boolean
    12601255         */
    1261         function is_option_ignored( $option_name ) {
    1262                 return ( $this->_ignore_transients && 0 === strpos( $option_name, '_transient_' ) );
     1256        protected function is_option_capture_ignored( $option_name ) {
     1257                return ( 0 === strpos( $option_name, '_transient_' ) );
    12631258        }
    12641259
    12651260        /**
    1266          * Get the number of operations performed in the transaction
    1267          * @return bool
     1261         * Get options updated
     1262         * @return array
    12681263         */
    1269         function count() {
    1270                 return count( $this->_operations );
     1264        protected function get_captured_options() {
     1265                return $this->_captured_options;
    12711266        }
    12721267
    12731268        /**
    1274          * Start keeping track of changes to options, and cache their new values
     1269         * Get the number of options updated
     1270         * @return bool
    12751271         */
    1276         function start() {
    1277                 $this->_is_current = true;
    1278                 add_action( 'added_option', array( $this, '_capture_added_option' ), 10, 2 );
    1279                 add_action( 'updated_option', array( $this, '_capture_updated_option' ), 10, 3 );
    1280                 add_action( 'delete_option', array( $this, '_capture_pre_deleted_option' ), 10, 1 );
    1281                 add_action( 'deleted_option', array( $this, '_capture_deleted_option' ), 10, 1 );
     1272        protected function count_captured_options() {
     1273                return count( $this->_captured_options );
    12821274        }
    12831275
    12841276        /**
    1285          * @action added_option
    1286          * @param $option_name
    1287          * @param $new_value
     1277         * Start keeping track of changes to options, and cache their new values
    12881278         */
    1289         function _capture_added_option( $option_name, $new_value ) {
    1290                 if ( $this->is_option_ignored( $option_name ) ) {
     1279        protected function start_capturing_option_updates() {
     1280                if ( $this->_is_capturing_option_updates ) {
    12911281                        return;
    12921282                }
    1293                 $this->options[$option_name] = $new_value;
    1294                 $operation = 'add';
    1295                 $this->_operations[] = compact( 'operation', 'option_name', 'new_value' );
     1283
     1284                $this->_is_capturing_option_updates = true;
     1285                add_filter( 'pre_update_option', array( $this, '_capture_filter_pre_update_option' ), 10, 3 );
    12961286        }
    12971287
    12981288        /**
    1299          * @action updated_option
     1289         * @access private
     1290         * @param mixed $new_value
    13001291         * @param string $option_name
    13011292         * @param mixed $old_value
    1302          * @param mixed $new_value
     1293         * @return mixed
    13031294         */
    1304         function _capture_updated_option( $option_name, $old_value, $new_value ) {
    1305                 if ( $this->is_option_ignored( $option_name ) ) {
     1295        function _capture_filter_pre_update_option( $new_value, $option_name, $old_value ) {
     1296                if ( $this->is_option_capture_ignored( $option_name ) ) {
    13061297                        return;
    13071298                }
    1308                 $this->options[$option_name] = $new_value;
    1309                 $operation = 'update';
    1310                 $this->_operations[] = compact( 'operation', 'option_name', 'old_value', 'new_value' );
    1311         }
    1312 
    1313         protected $_pending_delete_option_autoload;
    1314         protected $_pending_delete_option_value;
    13151299
    1316         /**
    1317          * It's too bad the old_value and autoload aren't passed into the deleted_option action
    1318          * @action delete_option
    1319          * @param string $option_name
    1320          */
    1321         function _capture_pre_deleted_option( $option_name ) {
    1322                 if ( $this->is_option_ignored( $option_name ) ) {
    1323                         return;
     1300                if ( ! isset( $this->_captured_options[$option_name] ) ) {
     1301                        add_filter( "pre_option_{$option_name}", array( $this, '_capture_filter_pre_get_option' ) );
    13241302                }
    1325                 global $wpdb;
    1326                 $autoload = $wpdb->get_var( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option_name ) ); // db call ok; no-cache ok
    1327                 $this->_pending_delete_option_autoload = $autoload;
    1328                 $this->_pending_delete_option_value    = get_option( $option_name );
     1303
     1304                $this->_captured_options[$option_name] = $new_value;
     1305
     1306                return $old_value;
    13291307        }
    13301308
    13311309        /**
    1332          * @action deleted_option
    1333          * @param string $option_name
     1310         * @access private
     1311         * @param mixed $value
     1312         * @return mixed
    13341313         */
    1335         function _capture_deleted_option( $option_name ) {
    1336                 if ( $this->is_option_ignored( $option_name ) ) {
    1337                         return;
     1314        function _capture_filter_pre_get_option( $value ) {
     1315                $option_name = preg_replace( '/^pre_option_/', '', current_filter() );
     1316                if ( isset( $this->_captured_options[$option_name] ) ) {
     1317                        $value = $this->_captured_options[$option_name];
     1318                        $value = apply_filters( 'option_' . $option_name, $value );
    13381319                }
    1339                 unset( $this->options[$option_name] );
    1340                 $operation = 'delete';
    1341                 $old_value = $this->_pending_delete_option_value;
    1342                 $autoload  = $this->_pending_delete_option_autoload;
    1343                 $this->_operations[] = compact( 'operation', 'option_name', 'old_value', 'autoload' );
     1320
     1321                return $value;
    13441322        }
    13451323
    13461324        /**
    13471325         * Undo any changes to the options since start() was called
    13481326         */
    1349         function rollback() {
    1350                 remove_action( 'updated_option', array( $this, '_capture_updated_option' ), 10, 3 );
    1351                 remove_action( 'added_option', array( $this, '_capture_added_option' ), 10, 2 );
    1352                 remove_action( 'delete_option', array( $this, '_capture_pre_deleted_option' ), 10, 1 );
    1353                 remove_action( 'deleted_option', array( $this, '_capture_deleted_option' ), 10, 1 );
    1354                 while ( 0 !== count( $this->_operations ) ) {
    1355                         $option_operation = array_pop( $this->_operations );
    1356                         if ( 'add' === $option_operation['operation'] ) {
    1357                                 delete_option( $option_operation['option_name'] );
    1358                         }
    1359                         else if ( 'delete' === $option_operation['operation'] ) {
    1360                                 add_option( $option_operation['option_name'], $option_operation['old_value'], null, $option_operation['autoload'] );
    1361                         }
    1362                         else if ( 'update' === $option_operation['operation'] ) {
    1363                                 update_option( $option_operation['option_name'], $option_operation['old_value'] );
    1364                         }
     1327        protected function stop_capturing_option_updates() {
     1328                if ( ! $this->_is_capturing_option_updates ) {
     1329                        return;
    13651330                }
    1366                 $this->_is_current = false;
     1331
     1332                remove_filter( '_capture_filter_pre_update_option', array( $this, '_capture_filter_pre_update_option' ), 10, 3 );
     1333                foreach ( array_keys( $this->_captured_options ) as $option_name ) {
     1334                        remove_filter( "pre_option_{$option_name}", array( $this, '_capture_filter_pre_get_option' ) );
     1335                }
     1336
     1337                $this->_captured_options = array();
     1338                $this->_is_capturing_option_updates = false;
    13671339        }
    13681340}
  • src/wp-includes/option.php

    diff --git src/wp-includes/option.php src/wp-includes/option.php
    index 0091c12..4cc8c28 100644
    function update_option( $option, $value ) { 
    255255         */
    256256        $value = apply_filters( 'pre_update_option_' . $option, $value, $old_value );
    257257
     258        /**
     259         * Filter an option before its value is (maybe) serialized and updated.
     260         *
     261         * @since 3.9.0
     262         *
     263         * @param mixed  $value     The new, unserialized option value.
     264         * @param string $option    Name of the option.
     265         * @param mixed  $old_value The old option value.
     266         */
     267        $value = apply_filters( 'pre_update_option', $value, $option, $old_value );
     268
    258269        // If the new and old values are the same, no need to update.
    259270        if ( $value === $old_value )
    260271                return false;