From 32b55e7e7ad705c5b9098d8b01babc8864b1dc94 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Tue, 9 Aug 2016 01:44:20 +0000 Subject: [PATCH] Boostrap/Load: Improve forward compatiblity of plugin global backup methods. [37588] added methods to backup the plugin globals, for ensuring that advanced cache drop-ins don't overwrite hooks that've been added earlier in the load process. The method for restoring the plugin globals wasn't compatible with the implementation of `WP_Hook` in #17817. `WP_Hook` implements `ArrayAccess`, so `_restore_plugin_globals()` was treating it as an array, and inadvertantly overwriting the `WP_Hook` object with a plain array. To avoid having to re-write this code as part of #17817, we now use `add_filter()` to restore any hooks that were added by cache drop-ins, which `WP_Hook` correctly supports. Props pento, jorbin. See #36819. git-svn-id: https://develop.svn.wordpress.org/trunk@38223 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/plugin.php | 49 +++++++++++++++++++++++++-------- src/wp-settings.php | 2 +- tests/phpunit/tests/actions.php | 30 ++++++++++++++++---- 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/wp-includes/plugin.php b/src/wp-includes/plugin.php index 479990a653..6e3a21e0a3 100644 --- a/src/wp-includes/plugin.php +++ b/src/wp-includes/plugin.php @@ -1019,19 +1019,21 @@ function _wp_filter_build_unique_id($tag, $function, $priority) { * * @return array the staticvar from the first time it is set. */ -function _backup_plugin_globals(){ +function _backup_plugin_globals( $backup = true ) { global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter; static $backup_globals = array(); - if ( empty( $backup_globals ) ) { + if ( $backup ) { $backup_globals = array( 'backup_wp_filter' => $wp_filter, 'backup_wp_actions' => $wp_actions, 'backup_merged_filters' => $merged_filters, 'backup_wp_current_filter' => $wp_current_filter, ); - }; + + $wp_filter = $wp_actions = array(); + } return $backup_globals; } @@ -1047,24 +1049,49 @@ function _backup_plugin_globals(){ * @global array $wp_current_filter Stores the list of current filters with the current one last. * @staticvar array $backup_globals Backed up globals. */ -function _restore_plugin_globals(){ +function _restore_plugin_globals() { global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter; - $backup_globals = _backup_plugin_globals(); + $backup_globals = _backup_plugin_globals( false ); - if ( $wp_filter !== $backup_globals['backup_wp_filter'] ){ - $wp_filter = array_merge_recursive( $wp_filter, $backup_globals['backup_wp_filter'] ); + if ( empty( $wp_filter ) ) { + $wp_filter = $backup_globals['backup_wp_filter']; + } else { + $added_filters = $wp_filter; + $wp_filter = $backup_globals['backup_wp_filter']; + + foreach ( $added_filters as $tag => $callback_groups ) { + // Loop through callback groups. + foreach ( $callback_groups as $priority => $callbacks ) { + + // Loop through callbacks. + foreach ( $callbacks as $cb ) { + add_filter( $tag, $cb['function'], $priority, $cb['accepted_args'] ); + } + } + } } - if ( $wp_actions !== $backup_globals['backup_wp_actions'] ){ - $wp_actions = array_merge_recursive( $wp_actions, $backup_globals['backup_wp_actions'] ); + if ( empty ( $wp_actions ) ) { + $wp_actions = $backup_globals['backup_wp_actions']; + } else { + $run_actions = $wp_actions; + $wp_actions = $backup_globals['backup_wp_actions']; + + foreach( $run_actions as $action => $count ) { + if ( ! isset( $wp_actions[ $action ] ) ) { + $wp_actions[ $action ] = 0; + } + + $wp_actions[ $action ] += $count; + } } - if ( $merged_filters !== $backup_globals['backup_merged_filters'] ){ + if ( $merged_filters !== $backup_globals['backup_merged_filters'] ) { $merged_filters = array_merge_recursive( $merged_filters, $backup_globals['backup_merged_filters'] ); } - if ( $wp_current_filter !== $backup_globals['backup_wp_current_filter'] ){ + if ( $wp_current_filter !== $backup_globals['backup_wp_current_filter'] ) { $wp_current_filter = array_merge_recursive( $wp_current_filter, $backup_globals['backup_wp_current_filter'] ); } } diff --git a/src/wp-settings.php b/src/wp-settings.php index 37a31c2fe7..1a241fac05 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -83,7 +83,7 @@ wp_debug_mode(); */ if ( WP_CACHE && apply_filters( 'enable_loading_advanced_cache_dropin', true ) ) { // For an advanced caching plugin to use. Uses a static drop-in because you would only want one. - _backup_plugin_globals(); + _backup_plugin_globals( true ); WP_DEBUG ? include( WP_CONTENT_DIR . '/advanced-cache.php' ) : @include( WP_CONTENT_DIR . '/advanced-cache.php' ); _restore_plugin_globals(); } diff --git a/tests/phpunit/tests/actions.php b/tests/phpunit/tests/actions.php index b02e2adcc9..fd45ffd6af 100644 --- a/tests/phpunit/tests/actions.php +++ b/tests/phpunit/tests/actions.php @@ -332,7 +332,7 @@ class Tests_Actions extends WP_UnitTestCase { * @ticket 36819 */ function test_backup_plugin_globals_returns_filters() { - $backup = _backup_plugin_globals(); + $backup = _backup_plugin_globals( true ); $this->assertArrayHasKey( 'backup_wp_filter', $backup ); $this->assertArrayHasKey( 'backup_wp_actions', $backup ); $this->assertArrayHasKey( 'backup_wp_current_filter', $backup ); @@ -343,14 +343,14 @@ class Tests_Actions extends WP_UnitTestCase { * @ticket 36819 */ function test_backup_plugin_globals_returns_filters_from_first_time_called() { - $backup = _backup_plugin_globals(); + $backup = _backup_plugin_globals( true ); $a = new MockAction(); $tag = rand_str(); add_action($tag, array(&$a, 'action')); - $new_backup = _backup_plugin_globals(); + $new_backup = _backup_plugin_globals( false ); $this->assertEquals( $backup, $new_backup ); } @@ -361,7 +361,7 @@ class Tests_Actions extends WP_UnitTestCase { global $wp_actions; $original_actions = $wp_actions; - _backup_plugin_globals(); + _backup_plugin_globals( true ); $wp_actions = array(); @@ -378,7 +378,7 @@ class Tests_Actions extends WP_UnitTestCase { global $wp_filter; $original_filter = $wp_filter; - $backup = _backup_plugin_globals(); + $backup = _backup_plugin_globals( true ); $a = new MockAction(); $tag = rand_str(); @@ -391,6 +391,26 @@ class Tests_Actions extends WP_UnitTestCase { $this->assertNotEquals( $GLOBALS['wp_filter'], $original_filter ); } + /** + * @ticket 36819 + */ + function test_applied_actions_are_counted_after_restore() { + global $wp_actions; + + $action_name = 'this_is_a_fake_action_name'; + $this->assertArrayNotHasKey( $action_name, $wp_actions ); + + do_action( $action_name ); + + $this->assertEquals( 1, $wp_actions[ $action_name ] ); + + _backup_plugin_globals( true ); + do_action( $action_name ); + _restore_plugin_globals(); + + $this->assertEquals( 2, $wp_actions[ $action_name ] ); + } + function apply_testing_filter() { $this->apply_testing_filter = true;