Make WordPress Core

Ticket #27419: 27419.patch

File 27419.patch, 9.8 KB (added by ocean90, 11 years ago)
  • src/wp-includes/class-wp-customize-widgets.php

     
    932932         * Find and invoke the widget update and control callbacks. Requires that
    933933         * $_POST be populated with the instance data.
    934934         *
    935          * @throws Widget_Customizer_Exception
    936          * @throws Exception
    937935         *
    938          * @param string $widget_id
    939          * @return array
     936         * @param string      $widget_id
     937         * @return array|bool False on failure, array on success.
    940938         */
    941939        static function call_widget_update( $widget_id ) {
    942940                global $wp_registered_widget_updates, $wp_registered_widget_controls;
    943941
    944942                $options_transaction = new Options_Transaction();
    945943
    946                 try {
    947                         $options_transaction->start();
    948                         $parsed_id   = self::parse_widget_id( $widget_id );
    949                         $option_name = 'widget_' . $parsed_id['id_base'];
     944                $options_transaction->start();
     945                $parsed_id   = self::parse_widget_id( $widget_id );
     946                $option_name = 'widget_' . $parsed_id['id_base'];
    950947
    951                         /**
    952                          * If a previously-sanitized instance is provided, populate the input vars
    953                          * with its values so that the widget update callback will read this instance
    954                          */
    955                         $added_input_vars = array();
    956                         if ( ! empty( $_POST['sanitized_widget_setting'] ) ) {
    957                                 $sanitized_widget_setting = json_decode( self::get_post_value( 'sanitized_widget_setting' ), true );
    958                                 if ( empty( $sanitized_widget_setting ) ) {
    959                                         throw new Widget_Customizer_Exception( 'Malformed sanitized_widget_setting' );
    960                                 }
    961                                 $instance = self::sanitize_widget_instance( $sanitized_widget_setting );
    962                                 if ( is_null( $instance ) ) {
    963                                         throw new Widget_Customizer_Exception( 'Unsanitary sanitized_widget_setting' );
    964                                 }
    965                                 if ( ! is_null( $parsed_id['number'] ) ) {
    966                                         $value = array();
    967                                         $value[$parsed_id['number']] = $instance;
    968                                         $key = 'widget-' . $parsed_id['id_base'];
     948                /**
     949                 * If a previously-sanitized instance is provided, populate the input vars
     950                 * with its values so that the widget update callback will read this instance
     951                 */
     952                $added_input_vars = array();
     953                if ( ! empty( $_POST['sanitized_widget_setting'] ) ) {
     954                        $sanitized_widget_setting = json_decode( self::get_post_value( 'sanitized_widget_setting' ), true );
     955                        if ( empty( $sanitized_widget_setting ) ) {
     956                                $options_transaction->rollback();
     957                                return false;
     958                        }
     959
     960                        $instance = self::sanitize_widget_instance( $sanitized_widget_setting );
     961                        if ( is_null( $instance ) ) {
     962                                $options_transaction->rollback();
     963                                return false;
     964                        }
     965
     966                        if ( ! is_null( $parsed_id['number'] ) ) {
     967                                $value = array();
     968                                $value[$parsed_id['number']] = $instance;
     969                                $key = 'widget-' . $parsed_id['id_base'];
     970                                $_REQUEST[$key] = $_POST[$key] = wp_slash( $value );
     971                                $added_input_vars[] = $key;
     972                        } else {
     973                                foreach ( $instance as $key => $value ) {
    969974                                        $_REQUEST[$key] = $_POST[$key] = wp_slash( $value );
    970975                                        $added_input_vars[] = $key;
    971                                 } else {
    972                                         foreach ( $instance as $key => $value ) {
    973                                                 $_REQUEST[$key] = $_POST[$key] = wp_slash( $value );
    974                                                 $added_input_vars[] = $key;
    975                                         }
    976976                                }
    977977                        }
     978                }
    978979
    979                         /**
    980                          * Invoke the widget update callback
    981                          */
    982                         foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
    983                                 if ( $name === $parsed_id['id_base'] && is_callable( $control['callback'] ) ) {
    984                                         ob_start();
    985                                         call_user_func_array( $control['callback'], $control['params'] );
    986                                         ob_end_clean();
    987                                         break;
    988                                 }
     980                /**
     981                 * Invoke the widget update callback
     982                 */
     983                foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
     984                        if ( $name === $parsed_id['id_base'] && is_callable( $control['callback'] ) ) {
     985                                ob_start();
     986                                call_user_func_array( $control['callback'], $control['params'] );
     987                                ob_end_clean();
     988                                break;
    989989                        }
     990                }
    990991
    991                         // Clean up any input vars that were manually added
    992                         foreach ( $added_input_vars as $key ) {
    993                                 unset( $_POST[$key] );
    994                                 unset( $_REQUEST[$key] );
    995                         }
     992                // Clean up any input vars that were manually added
     993                foreach ( $added_input_vars as $key ) {
     994                        unset( $_POST[$key] );
     995                        unset( $_REQUEST[$key] );
     996                }
    996997
    997                         /**
    998                          * Make sure the expected option was updated
    999                          */
    1000                         if ( 0 !== $options_transaction->count() ) {
    1001                                 if ( count( $options_transaction->options ) > 1 ) {
    1002                                         throw new Widget_Customizer_Exception( sprintf( 'Widget %1$s unexpectedly updated more than one option.', $widget_id ) );
    1003                                 }
    1004                                 $updated_option_name = key( $options_transaction->options );
    1005                                 if ( $updated_option_name !== $option_name ) {
    1006                                         throw new Widget_Customizer_Exception( sprintf( 'Widget %1$s updated option "%2$s", but expected "%3$s".', $widget_id, $updated_option_name, $option_name ) );
    1007                                 }
     998                /**
     999                 * Make sure the expected option was updated
     1000                 */
     1001                if ( 0 !== $options_transaction->count() ) {
     1002                        if ( count( $options_transaction->options ) > 1 ) {
     1003                                $options_transaction->rollback();
     1004                                return false;
    10081005                        }
    10091006
    1010                         /**
    1011                          * Obtain the widget control with the updated instance in place
    1012                          */
    1013                         ob_start();
    1014                         $form = $wp_registered_widget_controls[$widget_id];
    1015                         if ( $form ) {
    1016                                 call_user_func_array( $form['callback'], $form['params'] );
     1007                        $updated_option_name = key( $options_transaction->options );
     1008                        if ( $updated_option_name !== $option_name ) {
     1009                                $options_transaction->rollback();
     1010                                return false;
    10171011                        }
    1018                         $form = ob_get_clean();
     1012                }
    10191013
    1020                         /**
    1021                          * Obtain the widget instance
    1022                         */
    1023                         $option = get_option( $option_name );
    1024                         if ( null !== $parsed_id['number'] ) {
    1025                                 $instance = $option[$parsed_id['number']];
    1026                         } else {
    1027                                 $instance = $option;
    1028                         }
     1014                /**
     1015                 * Obtain the widget control with the updated instance in place
     1016                */
     1017                ob_start();
     1018                $form = $wp_registered_widget_controls[$widget_id];
     1019                if ( $form ) {
     1020                        call_user_func_array( $form['callback'], $form['params'] );
     1021                }
     1022                $form = ob_get_clean();
    10291023
    1030                         $options_transaction->rollback();
    1031                         return compact( 'instance', 'form' );
     1024                /**
     1025                 * Obtain the widget instance
     1026                 */
     1027                $option = get_option( $option_name );
     1028                if ( null !== $parsed_id['number'] ) {
     1029                        $instance = $option[$parsed_id['number']];
     1030                } else {
     1031                        $instance = $option;
    10321032                }
    1033                 catch ( Exception $e ) {
    1034                         $options_transaction->rollback();
    1035                         throw $e;
    1036                 }
     1033
     1034                $options_transaction->rollback();
     1035                return compact( 'instance', 'form' );
    10371036        }
    10381037
    10391038        /**
     
    10431042         *
    10441043         * @see wp_ajax_save_widget
    10451044         * @todo Reuse wp_ajax_save_widget now that we have option transactions?
    1046          * @action wp_ajax_update_widget
    10471045         */
    10481046        static function wp_ajax_update_widget() {
    1049                 $generic_error = __( 'An error has occurred. Please reload the page and try again.' );
     1047                if ( ! check_ajax_referer( self::UPDATE_WIDGET_AJAX_ACTION, self::UPDATE_WIDGET_NONCE_POST_KEY, false ) ) {
     1048                        wp_send_json_error();
     1049                }
    10501050
    1051                 try {
    1052                         if ( ! check_ajax_referer( self::UPDATE_WIDGET_AJAX_ACTION, self::UPDATE_WIDGET_NONCE_POST_KEY, false ) ) {
    1053                                 throw new Widget_Customizer_Exception( __( 'Nonce check failed. Reload and try again?' ) );
    1054                         }
    1055                         if ( ! current_user_can( 'edit_theme_options' ) ) {
    1056                                 throw new Widget_Customizer_Exception( __( 'Current user cannot!' ) );
    1057                         }
    1058                         if ( ! isset( $_POST['widget-id'] ) ) {
    1059                                 throw new Widget_Customizer_Exception( __( 'Incomplete request' ) );
    1060                         }
     1051                if ( ! current_user_can( 'edit_theme_options' ) ) {
     1052                        wp_send_json_error();
     1053                }
    10611054
    1062                         unset( $_POST[self::UPDATE_WIDGET_NONCE_POST_KEY], $_POST['action'] );
     1055                if ( ! isset( $_POST['widget-id'] ) ) {
     1056                        wp_send_json_error();
     1057                }
    10631058
    1064                         do_action( 'load-widgets.php' );
    1065                         do_action( 'widgets.php' );
    1066                         do_action( 'sidebar_admin_setup' );
     1059                unset( $_POST[self::UPDATE_WIDGET_NONCE_POST_KEY], $_POST['action'] );
    10671060
    1068                         $widget_id = self::get_post_value( 'widget-id' );
    1069                         $parsed_id = self::parse_widget_id( $widget_id );
    1070                         $id_base   = $parsed_id['id_base'];
     1061                do_action( 'load-widgets.php' );
     1062                do_action( 'widgets.php' );
     1063                do_action( 'sidebar_admin_setup' );
    10711064
    1072                         if ( isset( $_POST['widget-' . $id_base] ) && is_array( $_POST['widget-' . $id_base] ) && preg_match( '/__i__|%i%/', key( $_POST['widget-' . $id_base] ) ) ) {
    1073                                 throw new Widget_Customizer_Exception( 'Cannot pass widget templates to create new instances; apply template vars in JS' );
    1074                         }
     1065                $widget_id = self::get_post_value( 'widget-id' );
     1066                $parsed_id = self::parse_widget_id( $widget_id );
     1067                $id_base   = $parsed_id['id_base'];
    10751068
    1076                         $updated_widget = self::call_widget_update( $widget_id ); // => {instance,form}
    1077                         $form = $updated_widget['form'];
    1078                         $instance = self::sanitize_widget_js_instance( $updated_widget['instance'] );
     1069                if ( isset( $_POST['widget-' . $id_base] ) && is_array( $_POST['widget-' . $id_base] ) && preg_match( '/__i__|%i%/', key( $_POST['widget-' . $id_base] ) ) ) {
     1070                        wp_send_json_error();
     1071                }
    10791072
    1080                         wp_send_json_success( compact( 'form', 'instance' ) );
    1081                 }
    1082                 catch( Exception $e ) {
    1083                         if ( $e instanceof Widget_Customizer_Exception ) {
    1084                                 $message = $e->getMessage();
    1085                         } else {
    1086                                 error_log( sprintf( '%s in %s: %s', get_class( $e ), __FUNCTION__, $e->getMessage() ) );
    1087                                 $message = $generic_error;
    1088                         }
    1089                         wp_send_json_error( compact( 'message' ) );
    1090                 }
     1073                $updated_widget = self::call_widget_update( $widget_id ); // => {instance,form}
     1074                $form = $updated_widget['form'];
     1075                $instance = self::sanitize_widget_js_instance( $updated_widget['instance'] );
     1076
     1077                wp_send_json_success( compact( 'form', 'instance' ) );
    10911078        }
    10921079}
    10931080
    1094 class Widget_Customizer_Exception extends Exception {}
    1095 
    10961081class Options_Transaction {
    10971082
    10981083        /**
     
    12241209                        else if ( 'update' === $option_operation['operation'] ) {
    12251210                                update_option( $option_operation['option_name'], $option_operation['old_value'] );
    12261211                        }
    1227                         else {
    1228                                 throw new Exception( 'Unexpected operation' );
    1229                         }
    12301212                }
    12311213                $this->_is_current = false;
    12321214        }