Make WordPress Core

Ticket #43621: 43621.once.diff

File 43621.once.diff, 3.4 KB (added by soulseekah, 7 years ago)

add_action_once, add_filter_once (depends on WP_Hook::previous_callback feature)

  • src/wp-includes/plugin.php

    diff --git src/wp-includes/plugin.php src/wp-includes/plugin.php
    index 879bb12..ac598ab 100644
    function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 
    115115}
    116116
    117117/**
     118 * Hook a function or method to a specific filter callback that is only run once.
     119 *
     120 * The added $function_to_add will only be run once and removed from the filter.
     121 *
     122 * @since 5.0
     123 * @see add_filter
     124 */
     125function add_filter_once( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
     126        $result = add_filter( $tag, $function_to_add, $priority, $accepted_args );
     127
     128        // Add a remove action immediately after our $function_to_add has run.
     129        add_filter( $tag, '_remove_filter_once', $priority );
     130
     131        return $result;
     132}
     133
     134/**
     135 * Callback that removes an ephemeral filter (via add_filter_once)
     136 * immediately after its execution.
     137 *
     138 * @since 5.0
     139 * @see add_filter_once
     140 * @internal
     141 */
     142function _remove_filter_once() {
     143        global $wp_filter;
     144
     145        $tag               = current_filter();
     146        $current_filter    = $wp_filter[ $tag ];
     147        $current_priority  = $current_filter->current_priority();
     148        $previous_callback = $current_filter->previous_callback();
     149
     150        // Remove the callback that has to be run once.
     151        remove_filter( $tag, $previous_callback['function'], $current_priority );
     152
     153        // Remove the remove filter :) ... Filterception.
     154        remove_filter( $tag, __FUNCTION__, $current_priority );
     155
     156        if ( func_num_args() ) {
     157                // If this is a filter return the result.
     158                return func_get_arg( 0 );
     159        }
     160}
     161
     162/**
    118163 * Check if any filter has been registered for a hook.
    119164 *
    120165 * @since 2.5.0
    function add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 
    407452}
    408453
    409454/**
     455 * Hook a function or method to a specific action callback that is only run once.
     456 *
     457 * The added $function_to_add will only be run once and removed from the action.
     458 *
     459 * @since 5.0
     460 * @see add_action
     461 */
     462function add_action_once( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
     463        return add_filter_once( $tag, $function_to_add, $priority, $accepted_args );
     464}
     465
     466/**
    410467 * Execute functions hooked on a specific action hook.
    411468 *
    412469 * This function invokes all functions attached to action hook `$tag`. It is
  • tests/phpunit/tests/filters.php

    diff --git tests/phpunit/tests/filters.php tests/phpunit/tests/filters.php
    index 03af7e5..bd9b3ec 100644
    class Tests_Filters extends WP_UnitTestCase { 
    380380                global $wp_filter;
    381381                $this->current_priority = $wp_filter['the_content']->current_priority();
    382382        }
     383
     384        /**
     385         * @ticket 43621
     386         */
     387        public function test_add_filter_once() {
     388                add_filter_once( 'test_filter_once', '__return_true' );
     389
     390                $this->assertTrue( apply_filters( 'test_filter_once', false ) );
     391                $this->assertFalse( apply_filters( 'test_filter_once', false ) );
     392        }
     393
     394        /**
     395         * @ticket 43621
     396         */
     397        public function test_add_action_once() {
     398                global $_add_action_once_counter;
     399                $_add_action_once_counter = 0;
     400
     401                add_action_once( 'test_filter_once', array( $this, '_add_action_once_increment' ) );
     402
     403                do_action( 'test_filter_once' );
     404
     405                $this->assertEquals( 1, $_add_action_once_counter );
     406
     407                do_action( 'test_filter_once' );
     408
     409                $this->assertEquals( 1, $_add_action_once_counter );
     410        }
     411
     412        public function _add_action_once_increment() {
     413                global $_add_action_once_counter;
     414                $_add_action_once_counter++;
     415        }
    383416}