[wp-trac] [WordPress Trac] #23035: do_action() can't be nested because of global variable
WordPress Trac
noreply at wordpress.org
Fri Dec 21 09:31:13 UTC 2012
#23035: do_action() can't be nested because of global variable
-----------------------------+--------------------------
Reporter: cheeserolls | Type: defect (bug)
Status: new | Priority: normal
Milestone: Awaiting Review | Component: Plugins
Version: 3.5 | Severity: normal
Keywords: has-patch |
-----------------------------+--------------------------
wp-includes/plugin.php lines 401-408:
{{{
reset( $wp_filter[ $tag ] );
do {
foreach ( (array) current($wp_filter[$tag]) as $the_ )
if ( !is_null($the_['function']) )
call_user_func_array($the_['function'],
array_slice($args, 0, (int) $the_['accepted_args']));
} while ( next($wp_filter[$tag]) !== false );
}}}
The loop relies on the internal pointer of a global variable:
$wp_filter[$tag]
This means that an action cannot be nested inside the same action, because
nested calls to do_action will try to use the same pointer for the loop.
For example:
The WPML plugin (wordpress multilingual) maintains duplicates of posts
which haven't yet been translated. Whenever you update the main post,
WPML will also update the duplicates for you.
It does this using the 'save_post' action. When the 'save_post' action
occurs, WPML loops through the duplicated posts and saves them as well.
However, saving the duplicates, causes the 'save_post' action to be
triggered again.
$wp_filter['save_post'] is reset and looped for each of the duplicates.
When all the duplicates are done, the loop exits and we return to the
outer 'save_post' action. But the inner loop and outer loop share the
same pointer. So the outer loop thinks it is finished, and exits. Any
other 'save_post' actions that were queued up for the main post don't get
executed.
Suggest instead the following patch, to ensure that each call to do_action
gets it's own private loop:
{{{
$this_filter = $wp_filter[$tag]; // get a copy of the array to loop over
reset( $this_filter );
do {
foreach ( (array) current($this_filter) as $the_ )
if ( !is_null($the_['function']) )
call_user_func_array($the_['function'],
array_slice($args, 0, (int) $the_['accepted_args']));
} while ( next($this_filter) !== false );
}}}
--
Ticket URL: <http://core.trac.wordpress.org/ticket/23035>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software
More information about the wp-trac
mailing list