[wp-trac] [WordPress Trac] #40393: Using remove_action within an action callback skips over execution of other callbacks with lower priority

WordPress Trac noreply at wordpress.org
Fri Apr 7 16:01:07 UTC 2017


#40393: Using remove_action within an action callback skips over execution of other
callbacks with lower priority
--------------------------+-----------------------------
 Reporter:  weeblrpress   |      Owner:
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  Plugins       |    Version:  4.7.3
 Severity:  normal        |   Keywords:
  Focuses:                |
--------------------------+-----------------------------
 Description:

 When remove_action is used by an action callback to remove itself from the
 list of callbacks, this results in all callbacks hooked with the
 immediately lower priority to be skipped by apply_filters.

 Here is simple code to demonstrate:

 {{{#!php
 <?php

 class Sample {

     public function test()
         {
                 add_action('custom_action', array($this, 'callback_1'),
 1);
                 add_action('custom_action', array($this, 'callback_2'));
                 add_action('custom_action', array($this, 'callback_3'),
 20);

                 echo '<h1>First Run</h1>';
                 echo '<pre>';
                 do_action('custom_action');
                 echo '</pre>';
                 echo '<h1>Second Run</h1>';
                 echo '<pre>';
                 do_action('custom_action');
                 echo '</pre>';
         }

         public function callback_1()
         {
                 echo "Callback 1\n";
         }

         public function callback_2()
         {
                 echo "Callback 2\n";
                 remove_action('custom_action', array($this,
 'callback_2'));
         }

         public function callback_3()
         {
                 echo "Callback 3 - Priority 20\n";
         }
 }

 $runner = new Sample;
 $runner->test();

 }}}

 The output is:

 First Run
 Callback 1
 Callback 2

 Second Run
 Callback 1
 Callback 3 - Priority 20

 The expected output should be:

 First Run
 Callback 1
 Callback 2
 Callback 3 - Priority 20

 Second Run
 Callback 1
 Callback 3 - Priority 20

 The net effect of this issue is that a plugin using remove_action in that
 way will break another, totally unrelated plugin, if they both add actions
 on same tag, with different prorities.

 WooCommerce is using this method, it uses remove_action inside a
 pre_get_posts action callback. This broke our Accelerated Mobile Pages
 plugin when doing AMP pages for WooCommerce.
 This was reported to
 [https://github.com/woocommerce/woocommerce/issues/14092 WooCommerce
 here], but it was then suggested it was a core issue.

 '''Additional notes''':

 - all callbacks must '''object methods'''. The problem does not occur if
 callbacks are functions.

 - the callback using remove_action must be the only registered callback
 for that priority level

 {{{#!php
 <?php
 add_action('custom_action', array($this, 'callback_1'));
 add_action('custom_action', array($this, 'callback_2'));
 add_action('custom_action', array($this, 'callback_3'), 20);
 add_action('custom_action', array($this, 'callback_4'), 20);
 }}}

 will not cause the issue, all callbacks are executed.

 {{{#!php
 <?php
 add_action('custom_action', array($this, 'callback_1'), 5);
 add_action('custom_action', array($this, 'callback_2'));
 add_action('custom_action', array($this, 'callback_3'), 20);
 }}}

 will cause the issue, callback_3 is not executed.

 - only the next priority level is removed (but all callbacks for that
 level are removed):

 {{{#!php
 <?php
 add_action('custom_action', array($this, 'callback_1'), 1);
 add_action('custom_action', array($this, 'callback_2'));
 add_action('custom_action', array($this, 'callback_3'), 15);
 add_action('custom_action', array($this, 'callback_4'), 20);
 }}}

 will cause callback_3 to be skipped and callback_4 to be executed normally

 {{{#!php
 <?php
 add_action('custom_action', array($this, 'callback_1'), 1);
 add_action('custom_action', array($this, 'callback_2'));
 add_action('custom_action', array($this, 'callback_3'), 20);
 add_action('custom_action', array($this, 'callback_4'), 20);
 }}}

 will cause both callback_3 and callback_4 to be skipped


 '''Related''': the following tickets are related, even duplicates, but are
 marked as fixed, which is why I am opening this ticket:
 [https://core.trac.wordpress.org/ticket/33144 #33144],
 [https://core.trac.wordpress.org/ticket/21169 21169],
 [https://core.trac.wordpress.org/ticket/37679 37679]

--
Ticket URL: <https://core.trac.wordpress.org/ticket/40393>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list