Ticket #27419: 27419.patch
File 27419.patch, 9.8 KB (added by , 11 years ago) |
---|
-
src/wp-includes/class-wp-customize-widgets.php
932 932 * Find and invoke the widget update and control callbacks. Requires that 933 933 * $_POST be populated with the instance data. 934 934 * 935 * @throws Widget_Customizer_Exception936 * @throws Exception937 935 * 938 * @param string $widget_id939 * @return array 936 * @param string $widget_id 937 * @return array|bool False on failure, array on success. 940 938 */ 941 939 static function call_widget_update( $widget_id ) { 942 940 global $wp_registered_widget_updates, $wp_registered_widget_controls; 943 941 944 942 $options_transaction = new Options_Transaction(); 945 943 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']; 950 947 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 ) { 969 974 $_REQUEST[$key] = $_POST[$key] = wp_slash( $value ); 970 975 $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 }976 976 } 977 977 } 978 } 978 979 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; 989 989 } 990 } 990 991 991 992 993 994 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 } 996 997 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; 1008 1005 } 1009 1006 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; 1017 1011 } 1018 $form = ob_get_clean();1012 } 1019 1013 1020 1021 * Obtain the widget instance1022 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(); 1029 1023 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; 1032 1032 } 1033 catch ( Exception $e ) { 1034 $options_transaction->rollback(); 1035 throw $e; 1036 } 1033 1034 $options_transaction->rollback(); 1035 return compact( 'instance', 'form' ); 1037 1036 } 1038 1037 1039 1038 /** … … 1043 1042 * 1044 1043 * @see wp_ajax_save_widget 1045 1044 * @todo Reuse wp_ajax_save_widget now that we have option transactions? 1046 * @action wp_ajax_update_widget1047 1045 */ 1048 1046 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 } 1050 1050 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 } 1061 1054 1062 unset( $_POST[self::UPDATE_WIDGET_NONCE_POST_KEY], $_POST['action'] ); 1055 if ( ! isset( $_POST['widget-id'] ) ) { 1056 wp_send_json_error(); 1057 } 1063 1058 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'] ); 1067 1060 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' ); 1071 1064 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']; 1075 1068 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 } 1079 1072 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' ) ); 1091 1078 } 1092 1079 } 1093 1080 1094 class Widget_Customizer_Exception extends Exception {}1095 1096 1081 class Options_Transaction { 1097 1082 1098 1083 /** … … 1224 1209 else if ( 'update' === $option_operation['operation'] ) { 1225 1210 update_option( $option_operation['option_name'], $option_operation['old_value'] ); 1226 1211 } 1227 else {1228 throw new Exception( 'Unexpected operation' );1229 }1230 1212 } 1231 1213 $this->_is_current = false; 1232 1214 }