Ticket #17817: 17817.11.patch
File 17817.11.patch, 28.3 KB (added by , 10 years ago) |
---|
-
new file src/wp-includes/class-wp-hook.php
diff --git src/wp-includes/class-wp-hook.php src/wp-includes/class-wp-hook.php new file mode 100644 index 0000000..557d10e
- + 1 <?php 2 3 /** 4 * Class WP_Hook 5 */ 6 class WP_Hook implements IteratorAggregate, ArrayAccess { 7 public $callbacks = array(); 8 9 /** @var array The priority keys of actively running iterations of a hook */ 10 private $iterations = array(); 11 12 /** @var int How recursively has this hook been called? */ 13 private $nesting_level = 0; 14 15 /** 16 * Hook a function or method to a specific filter action. 17 * 18 * @param callback $function_to_add The callback to be run when the filter is applied. 19 * @param int $priority (optional) The order in which the functions associated with a particular action are executed. Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action. 20 * Default 10. 21 * @param int $accepted_args (optional) The number of arguments the function accepts. 22 * Default 1. 23 * @param string $tag The name of the filter to hook the $function_to_add callback to. 24 * @return void 25 */ 26 public function add_filter( $function_to_add, $priority, $accepted_args, $tag ) { 27 $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority); 28 $priority_existed = isset($this->callbacks[$priority]); 29 $this->callbacks[$priority][$idx] = array( 'function' => $function_to_add, 'accepted_args' => $accepted_args ); 30 if ( !$priority_existed && count($this->callbacks) > 1 ) { 31 ksort($this->callbacks, SORT_NUMERIC); 32 } 33 34 if ( $this->nesting_level > 0 ) { 35 $this->resort_active_iterations(); 36 } 37 } 38 39 /** 40 * When a hook's callbacks are changed mid-iteration, the priority 41 * keys need to be reset, with the array pointer at the correct 42 * location 43 * 44 * @return void 45 */ 46 private function resort_active_iterations() { 47 $new_priorities = array_keys($this->callbacks); 48 49 // if there are no remaining hooks, clear out all running iterations 50 if ( empty($new_priorities) ) { 51 foreach ( $this->iterations as $index => $iteration ) { 52 $this->iterations[$index] = $new_priorities; 53 } 54 return; 55 } 56 57 $min = min($new_priorities); 58 foreach ( $this->iterations as $index => $iteration ) { 59 $current = current($iteration); 60 $this->iterations[$index] = $new_priorities; 61 62 if ( $current < $min ) { 63 array_unshift( $this->iterations[$index], $current ); 64 continue; 65 } 66 while ( current($this->iterations[$index]) < $current ) { 67 if ( next($this->iterations[$index]) === FALSE ) { 68 break; 69 }; 70 } 71 } 72 } 73 74 /** 75 * @param string $function_key 76 * @param int $priority 77 * 78 * @return bool Whether the callback existed before it was removed 79 */ 80 public function remove_filter( $function_key, $priority ) { 81 $exists = isset($this->callbacks[$priority][$function_key]); 82 if ( $exists ) { 83 unset($this->callbacks[$priority][$function_key]); 84 if ( empty($this->callbacks[$priority]) ) { 85 unset($this->callbacks[$priority]); 86 if ( $this->nesting_level > 0 ) { 87 $this->resort_active_iterations(); 88 } 89 } 90 } 91 return $exists; 92 } 93 94 /** 95 * Check if an specific action has been registered for this hook. 96 * 97 * @param string $function_key The hashed index of the filter 98 * @return mixed The priority of that hook is returned, or false if the function is not attached. 99 */ 100 public function has_filter( $function_key ) { 101 foreach ( $this->callbacks as $priority => &$callbacks ) { 102 if ( isset($callbacks[$function_key]) ) { 103 return $priority; 104 } 105 } 106 return false; 107 } 108 109 /** 110 * Check if any callbacks have been registered for this hook 111 * 112 * @return bool 113 */ 114 public function has_filters() { 115 foreach ( $this->callbacks as &$callbacks ) { 116 if ( !empty($callbacks) ) { 117 return TRUE; 118 } 119 } 120 return FALSE; 121 } 122 123 /** 124 * Remove all of the callbacks from the filter. 125 * 126 * @param int|bool $priority The priority number to remove. 127 * @return void 128 */ 129 public function remove_all_filters( $priority = false ) { 130 if ( empty($this->callbacks) ) { 131 return; 132 } 133 if( false !== $priority && isset($this->callbacks[$priority]) ) { 134 unset($this->callbacks[$priority]); 135 } else { 136 $this->callbacks = array(); 137 } 138 if ( $this->nesting_level > 0 ) { 139 $this->resort_active_iterations(); 140 } 141 } 142 143 /** 144 * Call the functions added to a filter hook. 145 * 146 * @param mixed $value The value to filter. 147 * @param array $args Arguments to pass to callbacks 148 * 149 * @return mixed The filtered value after all hooked functions are applied to it 150 */ 151 public function apply_filters( $value, &$args ) { 152 if ( empty($this->callbacks) ) { 153 return $value; 154 } 155 $nesting_level = $this->nesting_level++; 156 $this->iterations[$nesting_level] = array_keys($this->callbacks); 157 158 do { 159 $priority = current($this->iterations[$nesting_level]); 160 foreach ( $this->callbacks[$priority] as $the_ ) { 161 $args[0] = $value; 162 $value = call_user_func_array( $the_['function'], array_slice( $args, 0, (int)$the_['accepted_args'] ) ); 163 } 164 } while ( next($this->iterations[$nesting_level]) !== FALSE ); 165 166 unset($this->iterations[$nesting_level]); 167 $this->nesting_level--; 168 return $value; 169 } 170 171 /** 172 * Execute functions hooked on a specific action hook. 173 * 174 * @param mixed $args Arguments to pass to callbacks 175 * @return void 176 */ 177 public function do_action( &$args ) { 178 if ( empty($this->callbacks) ) { 179 return; 180 } 181 $nesting_level = $this->nesting_level++; 182 $this->iterations[$nesting_level] = array_keys($this->callbacks); 183 $num_args = count($args); 184 185 do { 186 $priority = current($this->iterations[$nesting_level]); 187 foreach ( $this->callbacks[$priority] as $the_ ) { 188 $func =& $the_['function']; 189 // avoid the array_slice if possible 190 if ( $the_['accepted_args'] == 0 ) { 191 call_user_func_array( $func, array() ); 192 } elseif ( $the_['accepted_args'] >= $num_args ) { 193 call_user_func_array( $func, $args ); 194 } else { 195 call_user_func_array( $func, array_slice( $args, 0, (int) $the_['accepted_args'] ) ); 196 } 197 } 198 } while ( next($this->iterations[$nesting_level]) !== FALSE ); 199 200 unset($this->iterations[$nesting_level]); 201 $this->nesting_level--; 202 } 203 204 /** 205 * Process the functions hooked into the 'all' hook. 206 * 207 * @param array $args Arguments to pass to callbacks 208 * @return void 209 */ 210 public function do_all_hook( &$args ) { 211 $nesting_level = $this->nesting_level++; 212 $this->iterations[$nesting_level] = array_keys($this->callbacks); 213 214 do { 215 $priority = current($this->iterations[$nesting_level]); 216 foreach ( $this->callbacks[$priority] as $the_ ) { 217 call_user_func_array($the_['function'], $args ); 218 } 219 } while ( next($this->iterations[$nesting_level]) !== FALSE ); 220 221 unset($this->iterations[$nesting_level]); 222 $this->nesting_level--; 223 } 224 225 /** 226 * Retrieve an external iterator 227 * 228 * Provided for backwards compatibility with plugins that iterate over the 229 * $wp_filter global 230 * 231 * @link http://php.net/manual/en/iteratoraggregate.getiterator.php 232 * @return Traversable An instance of an object implementing Iterator or 233 * Traversable 234 */ 235 public function getIterator() { 236 return new ArrayIterator($this->callbacks); 237 } 238 239 /** 240 * Some plugins may set up filters before WordPress has initialized. 241 * Normalize them to WP_Hook objects. 242 * 243 * @param array $filters 244 * @return WP_Hook[] 245 */ 246 public static function build_preinitialized_hooks( $filters ) { 247 /** @var WP_Hook[] $normalized */ 248 $normalized = array(); 249 foreach ( $filters as $tag => $callback_groups ) { 250 if ( is_object($callback_groups) && $callback_groups instanceof WP_Hook ) { 251 $normalized[$tag] = $callback_groups; 252 continue; 253 } 254 $hook = new WP_Hook(); 255 foreach ( $callback_groups as $priority => $callbacks ) { 256 foreach ( $callbacks as $cb ) { 257 $hook->add_filter( $cb['function'], $priority, $cb['accepted_args'], $tag ); 258 } 259 } 260 $normalized[$tag] = $hook; 261 } 262 return $normalized; 263 } 264 265 /** 266 * Whether an offset exists 267 * 268 * @link http://php.net/manual/en/arrayaccess.offsetexists.php 269 * 270 * @param mixed $offset An offset to check for. 271 * 272 * @return boolean true on success or false on failure. 273 */ 274 public function offsetExists( $offset ) { 275 return isset( $this->callbacks[$offset] ); 276 } 277 278 /** 279 * Offset to retrieve 280 * 281 * @link http://php.net/manual/en/arrayaccess.offsetget.php 282 * 283 * @param mixed $offset The offset to retrieve. 284 * 285 * @return mixed 286 */ 287 public function offsetGet( $offset ) { 288 return isset( $this->callbacks[$offset] ) ? $this->callbacks[$offset] : null; 289 } 290 291 /** 292 * Offset to set 293 * 294 * @link http://php.net/manual/en/arrayaccess.offsetset.php 295 * 296 * @param mixed $offset The offset to assign the value to. 297 * @param mixed $value The value to set. 298 * 299 * @return void 300 */ 301 public function offsetSet( $offset, $value ) { 302 if ( is_null( $offset ) ) { 303 $this->callbacks[] = $value; 304 } else { 305 $this->callbacks[$offset] = $value; 306 } 307 } 308 309 /** 310 * Offset to unset 311 * 312 * @link http://php.net/manual/en/arrayaccess.offsetunset.php 313 * 314 * @param mixed $offset The offset to unset. 315 * 316 * @return void 317 */ 318 public function offsetUnset( $offset ) { 319 unset( $this->callbacks[$offset] ); 320 } 321 322 323 } 324 -
src/wp-includes/plugin.php
diff --git src/wp-includes/plugin.php src/wp-includes/plugin.php index f76eb75..eac8e17 100644
20 20 */ 21 21 22 22 // Initialize the filter globals. 23 global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter; 23 require( ABSPATH . '/wp-includes/class-wp-hook.php' ); 24 /** @var WP_Hook[] $wp_filter */ 25 global $wp_filter, $wp_actions, $wp_current_filter; 24 26 25 if ( ! isset( $wp_filter ) ) 27 if ( !empty( $wp_filter ) ) { 28 $wp_filter = WP_Hook::build_preinitialized_hooks( $wp_filter ); 29 } else { 26 30 $wp_filter = array(); 31 } 27 32 28 33 if ( ! isset( $wp_actions ) ) 29 34 $wp_actions = array(); 30 35 31 if ( ! isset( $merged_filters ) )32 $merged_filters = array();33 34 36 if ( ! isset( $wp_current_filter ) ) 35 37 $wp_current_filter = array(); 36 38 … … if ( ! isset( $wp_current_filter ) ) 66 68 * @since 0.71 67 69 * 68 70 * @global array $wp_filter A multidimensional array of all hooks and the callbacks hooked to them. 69 * @global array $merged_filters Tracks the tags that need to be merged for later. If the hook is added,70 * it doesn't need to run through that process.71 71 * 72 72 * @param string $tag The name of the filter to hook the $function_to_add callback to. 73 73 * @param callback $function_to_add The callback to be run when the filter is applied. … … if ( ! isset( $wp_current_filter ) ) 80 80 * @return boolean true 81 81 */ 82 82 function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { 83 global $wp_filter, $merged_filters; 83 global $wp_filter; 84 if ( !isset($wp_filter[$tag]) ) { 85 $wp_filter[$tag] = new WP_Hook(); 86 } 87 $wp_filter[$tag]->add_filter( $function_to_add, $priority, $accepted_args, $tag ); 84 88 85 $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);86 $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);87 unset( $merged_filters[ $tag ] );88 89 return true; 89 90 } 90 91 … … function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 105 106 * return value. 106 107 */ 107 108 function has_filter($tag, $function_to_check = false) { 108 // Don't reset the internal array pointer 109 $wp_filter = $GLOBALS['wp_filter']; 110 111 $has = ! empty( $wp_filter[ $tag ] ); 112 113 // Make sure at least one priority has a filter callback 114 if ( $has ) { 115 $exists = false; 116 foreach ( $wp_filter[ $tag ] as $callbacks ) { 117 if ( ! empty( $callbacks ) ) { 118 $exists = true; 119 break; 120 } 121 } 109 global $wp_filter; 122 110 123 if ( ! $exists ) { 124 $has = false; 125 } 126 } 111 $has = isset($wp_filter[$tag]) && $wp_filter[$tag]->has_filters(); 127 112 128 113 if ( false === $function_to_check || false == $has ) 129 114 return $has; … … function has_filter($tag, $function_to_check = false) { 131 116 if ( !$idx = _wp_filter_build_unique_id($tag, $function_to_check, false) ) 132 117 return false; 133 118 134 foreach ( (array) array_keys($wp_filter[$tag]) as $priority ) { 135 if ( isset($wp_filter[$tag][$priority][$idx]) ) 136 return $priority; 137 } 138 139 return false; 119 return $wp_filter[$tag]->has_filter($idx); 140 120 } 141 121 142 122 /** … … function has_filter($tag, $function_to_check = false) { 167 147 * @since 0.71 168 148 * 169 149 * @global array $wp_filter Stores all of the filters. 170 * @global array $merged_filters Merges the filter hooks using this function.171 150 * @global array $wp_current_filter Stores the list of current filters with the current one last. 172 151 * 173 152 * @param string $tag The name of the filter hook. … … function has_filter($tag, $function_to_check = false) { 176 155 * @return mixed The filtered value after all hooked functions are applied to it. 177 156 */ 178 157 function apply_filters( $tag, $value ) { 179 global $wp_filter, $ merged_filters, $wp_current_filter;158 global $wp_filter, $wp_current_filter; 180 159 181 160 $args = array(); 182 161 … … function apply_filters( $tag, $value ) { 185 164 $wp_current_filter[] = $tag; 186 165 $args = func_get_args(); 187 166 _wp_call_all_hook($args); 167 array_shift($args); 188 168 } 189 169 190 170 if ( !isset($wp_filter[$tag]) ) { … … function apply_filters( $tag, $value ) { 196 176 if ( !isset($wp_filter['all']) ) 197 177 $wp_current_filter[] = $tag; 198 178 199 // Sort. 200 if ( !isset( $merged_filters[ $tag ] ) ) { 201 ksort($wp_filter[$tag]); 202 $merged_filters[ $tag ] = true; 203 } 204 205 reset( $wp_filter[ $tag ] ); 206 207 if ( empty($args) ) 179 if ( empty($args) ) { 208 180 $args = func_get_args(); 181 array_shift($args); 182 } 209 183 210 do { 211 foreach( (array) current($wp_filter[$tag]) as $the_ ) 212 if ( !is_null($the_['function']) ){ 213 $args[1] = $value; 214 $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args'])); 215 } 216 217 } while ( next($wp_filter[$tag]) !== false ); 184 $value = $wp_filter[$tag]->apply_filters( $value, $args ); 218 185 219 186 array_pop( $wp_current_filter ); 220 187 … … function apply_filters( $tag, $value ) { 230 197 * @since 3.0.0 231 198 * 232 199 * @global array $wp_filter Stores all of the filters 233 * @global array $merged_filters Merges the filter hooks using this function.234 200 * @global array $wp_current_filter Stores the list of current filters with the current one last 235 201 * 236 202 * @param string $tag The name of the filter hook. … … function apply_filters( $tag, $value ) { 238 204 * @return mixed The filtered value after all hooked functions are applied to it. 239 205 */ 240 206 function apply_filters_ref_array($tag, $args) { 241 global $wp_filter, $ merged_filters, $wp_current_filter;207 global $wp_filter, $wp_current_filter; 242 208 243 209 // Do 'all' actions first 244 210 if ( isset($wp_filter['all']) ) { … … function apply_filters_ref_array($tag, $args) { 256 222 if ( !isset($wp_filter['all']) ) 257 223 $wp_current_filter[] = $tag; 258 224 259 // Sort 260 if ( !isset( $merged_filters[ $tag ] ) ) { 261 ksort($wp_filter[$tag]); 262 $merged_filters[ $tag ] = true; 263 } 264 265 reset( $wp_filter[ $tag ] ); 266 267 do { 268 foreach( (array) current($wp_filter[$tag]) as $the_ ) 269 if ( !is_null($the_['function']) ) 270 $args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); 271 272 } while ( next($wp_filter[$tag]) !== false ); 225 $value = $wp_filter[$tag]->apply_filters( $args[0], $args ); 273 226 274 227 array_pop( $wp_current_filter ); 275 228 276 return $ args[0];229 return $value; 277 230 } 278 231 279 232 /** … … function apply_filters_ref_array($tag, $args) { 295 248 * @return boolean Whether the function existed before it was removed. 296 249 */ 297 250 function remove_filter( $tag, $function_to_remove, $priority = 10 ) { 298 $function_to_remove = _wp_filter_build_unique_id( $tag, $function_to_remove, $priority ); 299 300 $r = isset( $GLOBALS['wp_filter'][ $tag ][ $priority ][ $function_to_remove ] ); 251 global $wp_filter; 301 252 302 if ( true === $r ) { 303 unset( $GLOBALS['wp_filter'][ $tag ][ $priority ][ $function_to_remove ] ); 304 if ( empty( $GLOBALS['wp_filter'][ $tag ][ $priority ] ) ) { 305 unset( $GLOBALS['wp_filter'][ $tag ][ $priority ] ); 306 } 307 if ( empty( $GLOBALS['wp_filter'][ $tag ] ) ) { 308 $GLOBALS['wp_filter'][ $tag ] = array(); 253 $r = false; 254 if ( isset($wp_filter[$tag]) ) { 255 $function_to_remove = _wp_filter_build_unique_id($tag, $function_to_remove, $priority); 256 $r = $wp_filter[$tag]->remove_filter($function_to_remove, $priority); 257 if ( empty($wp_filter[$tag]->callbacks) ) { 258 unset($wp_filter[$tag]); 309 259 } 310 unset( $GLOBALS['merged_filters'][ $tag ] );311 260 } 312 261 313 262 return $r; … … function remove_filter( $tag, $function_to_remove, $priority = 10 ) { 323 272 * @return bool True when finished. 324 273 */ 325 274 function remove_all_filters( $tag, $priority = false ) { 326 global $wp_filter, $merged_filters; 327 328 if ( isset( $wp_filter[ $tag ]) ) { 329 if ( false !== $priority && isset( $wp_filter[ $tag ][ $priority ] ) ) { 330 $wp_filter[ $tag ][ $priority ] = array(); 331 } else { 332 $wp_filter[ $tag ] = array(); 333 } 334 } 275 global $wp_filter; 335 276 336 if ( isset( $merged_filters[ $tag ] ) ) { 337 unset( $merged_filters[ $tag ] ); 277 if( isset($wp_filter[$tag]) ) { 278 $wp_filter[$tag]->remove_all_filters($priority); 279 unset($wp_filter[$tag]); 338 280 } 339 281 340 282 return true; … … function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) 454 396 * @return null Will return null if $tag does not exist in $wp_filter array. 455 397 */ 456 398 function do_action($tag, $arg = '') { 457 global $wp_filter, $wp_actions, $ merged_filters, $wp_current_filter;399 global $wp_filter, $wp_actions, $wp_current_filter; 458 400 459 401 if ( ! isset($wp_actions[$tag]) ) 460 402 $wp_actions[$tag] = 1; … … function do_action($tag, $arg = '') { 485 427 for ( $a = 2; $a < func_num_args(); $a++ ) 486 428 $args[] = func_get_arg($a); 487 429 488 // Sort 489 if ( !isset( $merged_filters[ $tag ] ) ) { 490 ksort($wp_filter[$tag]); 491 $merged_filters[ $tag ] = true; 492 } 493 494 reset( $wp_filter[ $tag ] ); 495 496 do { 497 foreach ( (array) current($wp_filter[$tag]) as $the_ ) 498 if ( !is_null($the_['function']) ) 499 call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); 500 501 } while ( next($wp_filter[$tag]) !== false ); 430 $wp_filter[$tag]->do_action( $args ); 502 431 503 432 array_pop($wp_current_filter); 504 433 } … … function did_action($tag) { 537 466 * @return null Will return null if $tag does not exist in $wp_filter array 538 467 */ 539 468 function do_action_ref_array($tag, $args) { 540 global $wp_filter, $wp_actions, $ merged_filters, $wp_current_filter;469 global $wp_filter, $wp_actions, $wp_current_filter; 541 470 542 471 if ( ! isset($wp_actions[$tag]) ) 543 472 $wp_actions[$tag] = 1; … … function do_action_ref_array($tag, $args) { 560 489 if ( !isset($wp_filter['all']) ) 561 490 $wp_current_filter[] = $tag; 562 491 563 // Sort 564 if ( !isset( $merged_filters[ $tag ] ) ) { 565 ksort($wp_filter[$tag]); 566 $merged_filters[ $tag ] = true; 567 } 568 569 reset( $wp_filter[ $tag ] ); 570 571 do { 572 foreach( (array) current($wp_filter[$tag]) as $the_ ) 573 if ( !is_null($the_['function']) ) 574 call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); 575 576 } while ( next($wp_filter[$tag]) !== false ); 492 $wp_filter[$tag]->do_action( $args ); 577 493 578 494 array_pop($wp_current_filter); 579 495 } … … function register_uninstall_hook( $file, $callback ) { 828 744 */ 829 745 function _wp_call_all_hook($args) { 830 746 global $wp_filter; 831 832 reset( $wp_filter['all'] ); 833 do { 834 foreach( (array) current($wp_filter['all']) as $the_ ) 835 if ( !is_null($the_['function']) ) 836 call_user_func_array($the_['function'], $args); 837 838 } while ( next($wp_filter['all']) !== false ); 747 $wp_filter['all']->do_all_hook($args); 839 748 } 840 749 841 750 /** -
tests/phpunit/includes/functions.php
diff --git tests/phpunit/includes/functions.php tests/phpunit/includes/functions.php index e8d30cb..64f28f7 100644
2 2 3 3 // For adding hooks before loading WP 4 4 function tests_add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { 5 global $wp_filter , $merged_filters;5 global $wp_filter; 6 6 7 7 $idx = _test_filter_build_unique_id($tag, $function_to_add, $priority); 8 8 $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); 9 unset( $merged_filters[ $tag ] );10 9 return true; 11 10 } 12 11 13 12 function _test_filter_build_unique_id($tag, $function, $priority) { 14 global $wp_filter;15 static $filter_id_count = 0;16 17 13 if ( is_string($function) ) 18 14 return $function; 19 15 -
tests/phpunit/includes/testcase.php
diff --git tests/phpunit/includes/testcase.php tests/phpunit/includes/testcase.php index 39d97d0..ff54216 100644
class WP_UnitTestCase extends PHPUnit_Framework_TestCase { 120 120 * @return void 121 121 */ 122 122 protected function _backup_hooks() { 123 $globals = array( ' merged_filters', 'wp_actions', 'wp_current_filter', 'wp_filter' );123 $globals = array( 'wp_actions', 'wp_current_filter', 'wp_filter' ); 124 124 foreach ( $globals as $key ) { 125 125 self::$hooks_saved[ $key ] = $GLOBALS[ $key ]; 126 126 } … … class WP_UnitTestCase extends PHPUnit_Framework_TestCase { 137 137 * @return void 138 138 */ 139 139 protected function _restore_hooks() { 140 $globals = array( ' merged_filters', 'wp_actions', 'wp_current_filter', 'wp_filter' );140 $globals = array( 'wp_actions', 'wp_current_filter', 'wp_filter' ); 141 141 foreach ( $globals as $key ) { 142 142 if ( isset( self::$hooks_saved[ $key ] ) ) { 143 143 $GLOBALS[ $key ] = self::$hooks_saved[ $key ]; -
tests/phpunit/tests/actions.php
diff --git tests/phpunit/tests/actions.php tests/phpunit/tests/actions.php index 583c8ce..7b13234 100644
class Tests_Actions extends WP_UnitTestCase { 114 114 $this->assertEquals( array( $val1 ), array_pop( $argsvar2 ) ); 115 115 } 116 116 117 /** 118 * Test that multiple callbacks receive the correct number of args even when the number 119 * is less than, or greater than previous hooks. 120 * 121 * @see https://core.trac.wordpress.org/ticket/17817#comment:72 122 */ 123 function test_action_args_3() { 124 $a1 = new MockAction(); 125 $a2 = new MockAction(); 126 $a3 = new MockAction(); 127 $tag = rand_str(); 128 $val1 = rand_str(); 129 $val2 = rand_str(); 130 131 // a1 accepts two arguments, a2 doesn't, a3 accepts two arguments 132 add_action($tag, array(&$a1, 'action'), 10, 2); 133 add_action($tag, array(&$a2, 'action')); 134 add_action($tag, array(&$a3, 'action'), 10, 2); 135 // call the action with two arguments 136 do_action($tag, $val1, $val2); 137 138 $call_count = $a1->get_call_count(); 139 // a1 should be called with both args 140 $this->assertEquals(1, $call_count); 141 $argsvar1 = $a1->get_args(); 142 $this->assertEquals( array( $val1, $val2 ), array_pop( $argsvar1 ) ); 143 144 // a2 should be called with one only 145 $this->assertEquals(1, $a2->get_call_count()); 146 $argsvar2 = $a2->get_args(); 147 $this->assertEquals( array( $val1 ), array_pop( $argsvar2 ) ); 148 149 // a3 should be called with both args 150 $this->assertEquals(1, $a3->get_call_count()); 151 $argsvar3 = $a3->get_args(); 152 $this->assertEquals( array( $val1, $val2 ), array_pop( $argsvar3 ) ); 153 } 154 117 155 function test_action_priority() { 118 156 $a = new MockAction(); 119 157 $tag = rand_str(); … … class Tests_Actions extends WP_UnitTestCase { 258 296 } 259 297 260 298 /** 299 * @ticket 17817 300 */ 301 function test_action_recursion() { 302 $tag = rand_str(); 303 $a = new MockAction(); 304 $b = new MockAction(); 305 306 add_action( $tag, array($a, 'action'), 11, 1 ); 307 add_action( $tag, array($b, 'action'), 13, 1 ); 308 add_action( $tag, array($this, 'action_that_causes_recursion'), 12, 1 ); 309 do_action( $tag, $tag ); 310 311 $this->assertEquals( 2, $a->get_call_count(), 'recursive actions should call all callbacks with earlier priority' ); 312 $this->assertEquals( 2, $b->get_call_count(), 'recursive actions should call callbacks with later priority' ); 313 } 314 315 function action_that_causes_recursion( $tag ) { 316 static $recursing = FALSE; 317 if ( !$recursing ) { 318 $recursing = TRUE; 319 do_action( $tag, $tag ); 320 } 321 $recursing = FALSE; 322 } 323 324 /** 325 * @ticket 9968 326 */ 327 function test_action_callback_manipulation_while_running() { 328 $tag = rand_str(); 329 $a = new MockAction(); 330 $b = new MockAction(); 331 $c = new MockAction(); 332 $d = new MockAction(); 333 $e = new MockAction(); 334 335 add_action( $tag, array($a, 'action'), 11, 2 ); 336 add_action( $tag, array($this, 'action_that_manipulates_a_running_hook'), 12, 2 ); 337 add_action( $tag, array($b, 'action'), 12, 2 ); 338 339 do_action( $tag, $tag, array($a,$b,$c,$d,$e) ); 340 do_action( $tag, $tag, array($a,$b,$c,$d,$e) ); 341 342 $this->assertEquals( 2, $a->get_call_count(), 'callbacks should run unless otherwise instructed' ); 343 $this->assertEquals( 1, $b->get_call_count(), 'callback removed by same priority callback should still get called' ); 344 $this->assertEquals( 1, $c->get_call_count(), 'callback added by same priority callback should not get called' ); 345 $this->assertEquals( 2, $d->get_call_count(), 'callback added by earlier priority callback should get called' ); 346 $this->assertEquals( 1, $e->get_call_count(), 'callback added by later priority callback should not get called' ); 347 } 348 349 function action_that_manipulates_a_running_hook( $tag, $mocks ) { 350 remove_action( $tag, array($mocks[1], 'action'), 12, 2 ); 351 add_action( $tag, array($mocks[2], 'action' ), 12, 2 ); 352 add_action( $tag, array($mocks[3], 'action' ), 13, 2 ); 353 add_action( $tag, array($mocks[4], 'action' ), 10, 2 ); 354 } 355 356 /** 357 * @ticket 17817 358 * 359 * This specificaly addresses the concern raised at 360 * https://core.trac.wordpress.org/ticket/17817#comment:52 361 */ 362 function test_remove_anonymous_callback() { 363 $tag = rand_str(); 364 $a = new MockAction(); 365 add_action( $tag, array( $a, 'action' ), 12, 1 ); 366 $this->assertTrue( has_action( $tag ) ); 367 368 $hook = $GLOBALS['wp_filter'][ $tag ]; 369 370 // From http://wordpress.stackexchange.com/a/57088/6445 371 foreach ( $hook as $priority => $filter ) { 372 foreach ( $filter as $identifier => $function ) { 373 if ( is_array( $function) 374 && is_a( $function['function'][0], 'MockAction' ) 375 && 'action' === $function['function'][1] 376 ) { 377 remove_filter( 378 $tag, 379 array ( $function['function'][0], 'action' ), 380 $priority 381 ); 382 } 383 } 384 } 385 386 $this->assertFalse( has_action( $tag ) ); 387 } 388 389 390 /** 391 * Test the ArrayAccess methods of WP_Hook 392 * 393 * @ticket 17817 394 */ 395 function test_array_access_of_wp_filter_global() { 396 global $wp_filter; 397 $tag = rand_str(); 398 399 add_action( $tag, '__return_null', 11, 1 ); 400 401 $this->assertTrue( isset($wp_filter[$tag][11]) ); 402 $this->assertArrayHasKey( '__return_null', $wp_filter[$tag][11] ); 403 404 unset( $wp_filter[$tag][11] ); 405 $this->assertFalse( has_action( $tag, '__return_null' ) ); 406 407 $wp_filter[$tag][11] = array( '__return_null' => array( 'function' => '__return_null', 'accepted_args' => 1 ) ); 408 $this->assertEquals( 11, has_action( $tag, '__return_null' ) ); 409 410 } 411 412 /** 261 413 * Make sure current_action() behaves as current_filter() 262 414 * 263 415 * @ticket 14994 -
tests/phpunit/tests/filters.php
diff --git tests/phpunit/tests/filters.php tests/phpunit/tests/filters.php index b4ee12f..34fdf56 100644
class Tests_Filters extends WP_UnitTestCase { 293 293 remove_all_filters( $tag, 12 ); 294 294 $this->assertFalse( has_filter( $tag ) ); 295 295 } 296 297 /**298 * @ticket 29070299 */300 function test_has_filter_doesnt_reset_wp_filter() {301 add_action( 'action_test_has_filter_doesnt_reset_wp_filter', '__return_null', 1 );302 add_action( 'action_test_has_filter_doesnt_reset_wp_filter', '__return_null', 2 );303 add_action( 'action_test_has_filter_doesnt_reset_wp_filter', '__return_null', 3 );304 add_action( 'action_test_has_filter_doesnt_reset_wp_filter', array( $this, '_action_test_has_filter_doesnt_reset_wp_filter' ), 4 );305 306 do_action( 'action_test_has_filter_doesnt_reset_wp_filter' );307 }308 function _action_test_has_filter_doesnt_reset_wp_filter() {309 global $wp_filter;310 311 has_action( 'action_test_has_filter_doesnt_reset_wp_filter', '_function_that_doesnt_exist' );312 313 $filters = current( $wp_filter['action_test_has_filter_doesnt_reset_wp_filter'] );314 $the_ = current( $filters );315 $this->assertEquals( $the_['function'], array( $this, '_action_test_has_filter_doesnt_reset_wp_filter' ) );316 }317 296 }