Ticket #27504: 27504.diff
| File 27504.diff, 8.5 KB (added by , 12 years ago) |
|---|
-
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 4a00078..d420476 100644
class WP_Customize_Widgets { 906 906 static function call_widget_update( $widget_id ) { 907 907 global $wp_registered_widget_updates, $wp_registered_widget_controls; 908 908 909 $option s_transaction = new Options_Transaction();909 $option_capture = new Option_Update_Capture(); 910 910 911 $option s_transaction->start();911 $option_capture->start(); 912 912 $parsed_id = self::parse_widget_id( $widget_id ); 913 913 $option_name = 'widget_' . $parsed_id['id_base']; 914 914 … … class WP_Customize_Widgets { 920 920 if ( ! empty( $_POST['sanitized_widget_setting'] ) ) { 921 921 $sanitized_widget_setting = json_decode( self::get_post_value( 'sanitized_widget_setting' ), true ); 922 922 if ( empty( $sanitized_widget_setting ) ) { 923 $option s_transaction->rollback();923 $option_capture->rollback(); 924 924 return new WP_Error( 'malformed_data', 'Malformed sanitized_widget_setting' ); 925 925 } 926 926 927 927 $instance = self::sanitize_widget_instance( $sanitized_widget_setting ); 928 928 if ( is_null( $instance ) ) { 929 $option s_transaction->rollback();929 $option_capture->rollback(); 930 930 return new WP_Error( 'unsanitary_data', 'Unsanitary sanitized_widget_setting' ); 931 931 } 932 932 … … class WP_Customize_Widgets { 965 965 /** 966 966 * Make sure the expected option was updated 967 967 */ 968 if ( 0 !== $option s_transaction->count() ) {969 if ( count( $option s_transaction->options ) > 1 ) {970 $option s_transaction->rollback();968 if ( 0 !== $option_capture->count() ) { 969 if ( count( $option_capture->options ) > 1 ) { 970 $option_capture->rollback(); 971 971 return new WP_Error( 'unexpected_update', 'Widget unexpectedly updated more than one option.' ); 972 972 } 973 973 974 $updated_option_name = key( $option s_transaction->options );974 $updated_option_name = key( $option_capture->options ); 975 975 if ( $updated_option_name !== $option_name ) { 976 $option s_transaction->rollback();976 $option_capture->rollback(); 977 977 return new WP_Error( 'wrong_option', sprintf( 'Widget updated option "%1$s", but expected "%2$s".', $updated_option_name, $option_name ) ); 978 978 } 979 979 } … … class WP_Customize_Widgets { 998 998 $instance = $option; 999 999 } 1000 1000 1001 $option s_transaction->rollback();1001 $option_capture->stop(); 1002 1002 return compact( 'instance', 'form' ); 1003 1003 } 1004 1004 … … class WP_Customize_Widgets { 1053 1053 } 1054 1054 } 1055 1055 1056 class Option s_Transaction{1056 class Option_Update_Capture { 1057 1057 1058 1058 /** 1059 * @var array $options values updated while transaction is open1059 * @var array $options values updated while capturing is happening 1060 1060 */ 1061 1061 public $options = array(); 1062 1062 1063 1063 protected $_ignore_transients = true; 1064 1064 protected $_is_current = false; 1065 protected $_operations = array();1066 1065 1067 1066 function __construct( $ignore_transients = true ) { 1068 1067 $this->_ignore_transients = $ignore_transients; 1069 1068 } 1070 1069 1071 1070 /** 1072 * Determine whether or not the transaction is open1071 * Determine whether or not capturing is active 1073 1072 * @return bool 1074 1073 */ 1075 1074 function is_current() { … … class Options_Transaction { 1085 1084 } 1086 1085 1087 1086 /** 1088 * Get the number of op erations performed in the transaction1087 * Get the number of options updated 1089 1088 * @return bool 1090 1089 */ 1091 1090 function count() { 1092 return count( $this-> _operations );1091 return count( $this->options ); 1093 1092 } 1094 1093 1095 1094 /** 1096 1095 * Start keeping track of changes to options, and cache their new values 1097 1096 */ 1098 1097 function start() { 1099 $this->_is_current = true; 1100 add_action( 'added_option', array( $this, '_capture_added_option' ), 10, 2 ); 1101 add_action( 'updated_option', array( $this, '_capture_updated_option' ), 10, 3 ); 1102 add_action( 'delete_option', array( $this, '_capture_pre_deleted_option' ), 10, 1 ); 1103 add_action( 'deleted_option', array( $this, '_capture_deleted_option' ), 10, 1 ); 1104 } 1105 1106 /** 1107 * @action added_option 1108 * @param $option_name 1109 * @param $new_value 1110 */ 1111 function _capture_added_option( $option_name, $new_value ) { 1112 if ( $this->is_option_ignored( $option_name ) ) { 1098 if ( $this->_is_current ) { 1113 1099 return; 1114 1100 } 1115 $this->options[$option_name] = $new_value; 1116 $operation = 'add'; 1117 $this->_operations[] = compact( 'operation', 'option_name', 'new_value' ); 1101 $this->_is_current = true; 1102 add_filter( 'pre_update_option', array( $this, 'pre_update_option' ), 10, 3 ); 1118 1103 } 1119 1104 1120 1105 /** 1121 * @ action updated_option1106 * @param mixed $new_value 1122 1107 * @param string $option_name 1123 1108 * @param mixed $old_value 1124 * @param mixed $new_value 1109 * @return mixed 1110 * @filter pre_update_option 1125 1111 */ 1126 function _capture_updated_option( $option_name, $old_value, $new_value ) {1112 function pre_update_option( $new_value, $option_name, $old_value ) { 1127 1113 if ( $this->is_option_ignored( $option_name ) ) { 1128 1114 return; 1129 1115 } 1116 if ( ! isset( $this->options[$option_name] ) ) { 1117 add_filter( "pre_option_{$option_name}", array( $this, 'pre_get_option' ) ); 1118 } 1130 1119 $this->options[$option_name] = $new_value; 1131 $operation = 'update'; 1132 $this->_operations[] = compact( 'operation', 'option_name', 'old_value', 'new_value' ); 1120 return $old_value; 1133 1121 } 1134 1122 1135 protected $_pending_delete_option_autoload;1136 protected $_pending_delete_option_value;1137 1138 1123 /** 1139 * It's too bad the old_value and autoload aren't passed into the deleted_option action 1140 * @action delete_option 1141 * @param string $option_name 1124 * @param $value 1125 * @return mixed 1142 1126 */ 1143 function _capture_pre_deleted_option( $option_name ) { 1144 if ( $this->is_option_ignored( $option_name ) ) { 1145 return; 1127 function pre_get_option( $value ) { 1128 $option_name = preg_replace( '/^pre_option_/', '', current_filter() ); 1129 if ( isset( $this->options[$option_name] ) ) { 1130 $value = $this->options[$option_name]; 1131 $value = apply_filters( 'option_' . $option_name, $value ); 1146 1132 } 1147 global $wpdb; 1148 $autoload = $wpdb->get_var( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option_name ) ); // db call ok; no-cache ok 1149 $this->_pending_delete_option_autoload = $autoload; 1150 $this->_pending_delete_option_value = get_option( $option_name ); 1133 return $value; 1151 1134 } 1152 1135 1153 1136 /** 1154 * @action deleted_option 1155 * @param string $option_name 1137 * Undo any changes to the options since start() was called 1156 1138 */ 1157 function _capture_deleted_option( $option_name) {1158 if ( $this->is_option_ignored( $option_name )) {1139 function stop() { 1140 if ( ! $this->_is_current ) { 1159 1141 return; 1160 1142 } 1161 unset( $this->options[$option_name] ); 1162 $operation = 'delete'; 1163 $old_value = $this->_pending_delete_option_value; 1164 $autoload = $this->_pending_delete_option_autoload; 1165 $this->_operations[] = compact( 'operation', 'option_name', 'old_value', 'autoload' ); 1166 } 1167 1168 /** 1169 * Undo any changes to the options since start() was called 1170 */ 1171 function rollback() { 1172 remove_action( 'updated_option', array( $this, '_capture_updated_option' ), 10, 3 ); 1173 remove_action( 'added_option', array( $this, '_capture_added_option' ), 10, 2 ); 1174 remove_action( 'delete_option', array( $this, '_capture_pre_deleted_option' ), 10, 1 ); 1175 remove_action( 'deleted_option', array( $this, '_capture_deleted_option' ), 10, 1 ); 1176 while ( 0 !== count( $this->_operations ) ) { 1177 $option_operation = array_pop( $this->_operations ); 1178 if ( 'add' === $option_operation['operation'] ) { 1179 delete_option( $option_operation['option_name'] ); 1180 } 1181 else if ( 'delete' === $option_operation['operation'] ) { 1182 add_option( $option_operation['option_name'], $option_operation['old_value'], null, $option_operation['autoload'] ); 1183 } 1184 else if ( 'update' === $option_operation['operation'] ) { 1185 update_option( $option_operation['option_name'], $option_operation['old_value'] ); 1186 } 1143 remove_filter( 'pre_update_option', array( $this, 'pre_update_option' ), 10, 3 ); 1144 foreach ( array_keys( $this->options ) as $option_name ) { 1145 remove_filter( "pre_option_{$option_name}", array( $this, 'pre_get_option' ) ); 1187 1146 } 1147 $this->options = array(); 1188 1148 $this->_is_current = false; 1189 1149 } 1150 1151 function __destruct() { 1152 $this->stop(); 1153 } 1190 1154 } -
src/wp-includes/option.php
diff --git src/wp-includes/option.php src/wp-includes/option.php index e1ad731..8f5405a 100644
function update_option( $option, $value ) { 254 254 * @param mixed $old_value The old option value. 255 255 */ 256 256 $value = apply_filters( 'pre_update_option_' . $option, $value, $old_value ); 257 $value = apply_filters( 'pre_update_option', $value, $option, $old_value ); 257 258 258 259 // If the new and old values are the same, no need to update. 259 260 if ( $value === $old_value )