[wp-trac] [WordPress Trac] #27488: Problem with action hook recursion causing later callbacks not to be called
WordPress Trac
noreply at wordpress.org
Sat Mar 22 14:19:12 UTC 2014
#27488: Problem with action hook recursion causing later callbacks not to be called
--------------------------+-----------------------------
Reporter: PolyMe | Owner:
Type: defect (bug) | Status: new
Priority: normal | Milestone: Awaiting Review
Component: General | Version: 3.8.1
Severity: normal | Keywords:
Focuses: |
--------------------------+-----------------------------
Calling an action hook from within the first action hook callback for an
action hook that contains 2+ callbacks will cause the additional callbacks
not to be called for the initial action calls.
Bug was discovered using the following example code...
{{{#!php
function add_more_meta( $meta_id, $post_id, $meta_key, $_meta_value ) {
if ( 'initial_meta' !== $meta_key ) {
return;
}
echo "Updating 'some_key'<br>\n";
update_post_meta( $post_id, 'some_key', 'some_value' . rand( 0,
9999 ) );
echo "'some_key' updated<br>\n";
}
function echo_meta( $meta_id, $post_id, $meta_key, $_meta_value ) {
echo "echoing...$meta_key<br>\n";
echo get_post_meta( $post_id, $meta_key, true ) . "<br>\n";
}
add_action( 'updated_post_meta', 'add_more_meta', 5, 4 );
add_action( 'updated_post_meta', 'echo_meta', 10, 4 );
$post_id = 1;
update_post_meta( $post_id, 'initial_meta', 'initial_meta_value' . rand(
0, 9999 ) );
}}}
In the above example, the updated_post_meta action hook is called within
another updated_post_meta action hook callback.
Because the code that calls the action hooks, uses an array pointed on the
global variable, the secondary action hook call, moves the pointer, so
that when execution returns to the original callback, it thinks that it
has completed all the callbacks.
The fix...
Instead of using the $wp_filter global array, by copying the array to a
variable with function scope, this pointer is not reset by subsequent
calls to the action hook.
Update the code at the bottom of the do_action() function as follows...
Before...
{{{#!php
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 );
}}}
After...
{{{#!php
$callbacks = $wp_filter[$tag];
reset( $wp_filter[ $tag ] );
do {
foreach( (array) current($callbacks) as $the_ )
if ( !is_null($the_['function']) )
call_user_func_array($the_['function'],
array_slice($args, 0, (int) $the_['accepted_args']));
} while ( next($callbacks) !== false );
}}}
This will also need updating in the following functions...
* apply_filters()
* apply_filters_ref_array()
* do_action_ref_array()
I'll now look at preparing a patch to fix this.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/27488>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list