[wp-trac] [WordPress Trac] #17817: do_action/apply_filters/etc. recursion on same filter kills underlying call

WordPress Trac wp-trac at lists.automattic.com
Thu Jun 16 18:04:05 UTC 2011


#17817: do_action/apply_filters/etc. recursion on same filter kills underlying call
--------------------------+-----------------------------
 Reporter:  kernfel       |      Owner:
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  General       |    Version:
 Severity:  minor         |   Keywords:
--------------------------+-----------------------------
 Affects @wp-includes/plugin.php: do_action, do_action_ref_array,
 apply_filters, apply_filters_ref_array, _wp_call_all_hook

 When calling a specific hook from a function that was called through that
 same hook, the remaining hooked functions from the first iteration will be
 discarded.[[BR]]
 This is due to the handling of the array of registered functions using
 internal array pointers instead of a more robust approach.

 In my example, this problem arose when I tried to programmatically delete
 a menu in reaction to the removal of a category. I hooked into the
 delete_term action to do so, upon which another function hooked into
 delete_term would no longer fire.[[BR]]
 The obvious workaround is to adjust the priorities accordingly, but it
 shouldn't be necessary.


 The current implementation as in apply_filters is:
 {{{
 reset( $wp_filter[ $tag ] );

 if ( empty($args) )
         $args = func_get_args();

 do {
         foreach( (array) current($wp_filter[$tag]) as $the_ )
                 if ( !is_null($the_['function']) ){
                         $args[1] = $value;
                         $value = call_user_func_array($the_['function'],
 array_slice($args, 1, (int) $the_['accepted_args']));
                 }

 } while ( next($wp_filter[$tag]) !== false );
 }}}

 Using the following method instead, both iterations would develop
 properly:
 {{{
 if ( empty($args) )
         $args = func_get_args();

 foreach ( $wp_filter[$tag] as $filters )
         foreach( (array) $filters as $the_ )
                 if ( !is_null($the_['function']) ){
                         $args[1] = $value;
                         $value = call_user_func_array($the_['function'],
 array_slice($args, 1, (int) $the_['accepted_args']));
                 }
 }}}

-- 
Ticket URL: <http://core.trac.wordpress.org/ticket/17817>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software


More information about the wp-trac mailing list