Ticket #27112: 27112.no-options-transaction.diff
File 27112.no-options-transaction.diff, 7.8 KB (added by , 11 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 94d5974..b1436e8 100644
class WP_Customize_Widgets { 941 941 static function call_widget_update( $widget_id ) { 942 942 global $wp_registered_widget_updates, $wp_registered_widget_controls; 943 943 944 $option s_transaction = new Options_Transaction();944 $option_capture = new Option_Update_Capture(); 945 945 946 946 try { 947 $option s_transaction->start();947 $option_capture->start(); 948 948 $parsed_id = self::parse_widget_id( $widget_id ); 949 949 $option_name = 'widget_' . $parsed_id['id_base']; 950 950 … … class WP_Customize_Widgets { 997 997 /** 998 998 * Make sure the expected option was updated 999 999 */ 1000 if ( 0 !== $option s_transaction->count() ) {1001 if ( count( $option s_transaction->options ) > 1 ) {1000 if ( 0 !== $option_capture->count() ) { 1001 if ( count( $option_capture->options ) > 1 ) { 1002 1002 throw new Widget_Customizer_Exception( sprintf( 'Widget %1$s unexpectedly updated more than one option.', $widget_id ) ); 1003 1003 } 1004 $updated_option_name = key( $option s_transaction->options );1004 $updated_option_name = key( $option_capture->options ); 1005 1005 if ( $updated_option_name !== $option_name ) { 1006 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 1007 } … … class WP_Customize_Widgets { 1027 1027 $instance = $option; 1028 1028 } 1029 1029 1030 $option s_transaction->rollback();1030 $option_capture->stop(); 1031 1031 return compact( 'instance', 'form' ); 1032 1032 } 1033 1033 catch ( Exception $e ) { 1034 $option s_transaction->rollback();1034 $option_capture->stop(); 1035 1035 throw $e; 1036 1036 } 1037 1037 } … … class WP_Customize_Widgets { 1093 1093 1094 1094 class Widget_Customizer_Exception extends Exception {} 1095 1095 1096 class Option s_Transaction{1096 class Option_Update_Capture { 1097 1097 1098 1098 /** 1099 * @var array $options values updated while transaction is open1099 * @var array $options values updated while capturing is happening 1100 1100 */ 1101 1101 public $options = array(); 1102 1102 1103 1103 protected $_ignore_transients = true; 1104 1104 protected $_is_current = false; 1105 protected $_operations = array();1106 1105 1107 1106 function __construct( $ignore_transients = true ) { 1108 1107 $this->_ignore_transients = $ignore_transients; … … class Options_Transaction { 1125 1124 } 1126 1125 1127 1126 /** 1128 * Get the number of op erations performed in the transaction1127 * Get the number of options updated 1129 1128 * @return bool 1130 1129 */ 1131 1130 function count() { 1132 return count( $this-> _operations );1131 return count( $this->options ); 1133 1132 } 1134 1133 1135 1134 /** 1136 1135 * Start keeping track of changes to options, and cache their new values 1137 1136 */ 1138 1137 function start() { 1139 $this->_is_current = true; 1140 add_action( 'added_option', array( $this, '_capture_added_option' ), 10, 2 ); 1141 add_action( 'updated_option', array( $this, '_capture_updated_option' ), 10, 3 ); 1142 add_action( 'delete_option', array( $this, '_capture_pre_deleted_option' ), 10, 1 ); 1143 add_action( 'deleted_option', array( $this, '_capture_deleted_option' ), 10, 1 ); 1144 } 1145 1146 /** 1147 * @action added_option 1148 * @param $option_name 1149 * @param $new_value 1150 */ 1151 function _capture_added_option( $option_name, $new_value ) { 1152 if ( $this->is_option_ignored( $option_name ) ) { 1138 if ( $this->_is_current ) { 1153 1139 return; 1154 1140 } 1155 $this->options[$option_name] = $new_value; 1156 $operation = 'add'; 1157 $this->_operations[] = compact( 'operation', 'option_name', 'new_value' ); 1141 $this->_is_current = true; 1142 add_filter( 'pre_update_option', array( $this, 'pre_update_option' ), 10, 3 ); 1158 1143 } 1159 1144 1160 1145 /** 1161 * @ action updated_option1146 * @param mixed $new_value 1162 1147 * @param string $option_name 1163 1148 * @param mixed $old_value 1164 * @param mixed $new_value 1149 * @return mixed 1150 * @filter pre_update_option 1165 1151 */ 1166 function _capture_updated_option( $option_name, $old_value, $new_value ) {1152 function pre_update_option( $new_value, $option_name, $old_value ) { 1167 1153 if ( $this->is_option_ignored( $option_name ) ) { 1168 1154 return; 1169 1155 } 1156 if ( ! isset( $this->options[$option_name] ) ) { 1157 add_filter( "pre_option_{$option_name}", array( $this, 'pre_get_option' ) ); 1158 } 1170 1159 $this->options[$option_name] = $new_value; 1171 $operation = 'update'; 1172 $this->_operations[] = compact( 'operation', 'option_name', 'old_value', 'new_value' ); 1160 return $old_value; 1173 1161 } 1174 1162 1175 protected $_pending_delete_option_autoload;1176 protected $_pending_delete_option_value;1177 1178 1163 /** 1179 * It's too bad the old_value and autoload aren't passed into the deleted_option action 1180 * @action delete_option 1181 * @param string $option_name 1164 * @param $value 1165 * @return mixed 1182 1166 */ 1183 function _capture_pre_deleted_option( $option_name ) { 1184 if ( $this->is_option_ignored( $option_name ) ) { 1185 return; 1167 function pre_get_option( $value ) { 1168 $option_name = preg_replace( '/^pre_option_/', '', current_filter() ); 1169 if ( isset( $this->options[$option_name] ) ) { 1170 $value = $this->options[$option_name]; 1171 $value = apply_filters( 'option_' . $option_name, $value ); 1186 1172 } 1187 global $wpdb; 1188 $autoload = $wpdb->get_var( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option_name ) ); // db call ok; no-cache ok 1189 $this->_pending_delete_option_autoload = $autoload; 1190 $this->_pending_delete_option_value = get_option( $option_name ); 1173 return $value; 1191 1174 } 1192 1175 1193 1176 /** 1194 * @action deleted_option 1195 * @param string $option_name 1177 * Undo any changes to the options since start() was called 1196 1178 */ 1197 function _capture_deleted_option( $option_name) {1198 if ( $this->is_option_ignored( $option_name )) {1179 function stop() { 1180 if ( ! $this->_is_current ) { 1199 1181 return; 1200 1182 } 1201 unset( $this->options[$option_name] ); 1202 $operation = 'delete'; 1203 $old_value = $this->_pending_delete_option_value; 1204 $autoload = $this->_pending_delete_option_autoload; 1205 $this->_operations[] = compact( 'operation', 'option_name', 'old_value', 'autoload' ); 1206 } 1207 1208 /** 1209 * Undo any changes to the options since start() was called 1210 */ 1211 function rollback() { 1212 remove_action( 'updated_option', array( $this, '_capture_updated_option' ), 10, 3 ); 1213 remove_action( 'added_option', array( $this, '_capture_added_option' ), 10, 2 ); 1214 remove_action( 'delete_option', array( $this, '_capture_pre_deleted_option' ), 10, 1 ); 1215 remove_action( 'deleted_option', array( $this, '_capture_deleted_option' ), 10, 1 ); 1216 while ( 0 !== count( $this->_operations ) ) { 1217 $option_operation = array_pop( $this->_operations ); 1218 if ( 'add' === $option_operation['operation'] ) { 1219 delete_option( $option_operation['option_name'] ); 1220 } 1221 else if ( 'delete' === $option_operation['operation'] ) { 1222 add_option( $option_operation['option_name'], $option_operation['old_value'], null, $option_operation['autoload'] ); 1223 } 1224 else if ( 'update' === $option_operation['operation'] ) { 1225 update_option( $option_operation['option_name'], $option_operation['old_value'] ); 1226 } 1227 else { 1228 throw new Exception( 'Unexpected operation' ); 1229 } 1183 remove_filter( 'pre_update_option', array( $this, 'pre_update_option' ), 10, 3 ); 1184 foreach ( array_keys( $this->options ) as $option_name ) { 1185 remove_filter( "pre_option_{$option_name}", array( $this, 'pre_get_option' ) ); 1230 1186 } 1187 $this->options = array(); 1231 1188 $this->_is_current = false; 1232 1189 } 1190 1191 function __destruct() { 1192 $this->stop(); 1193 } 1233 1194 } -
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 )