WordPress.org

Make WordPress Core

Ticket #41422: 41422.diff

File 41422.diff, 5.9 KB (added by bobbingwide, 2 years ago)

logic to support replacement and restore of filter functions

  • src/wp-includes/plugin.php

    diff --git a/src/wp-includes/plugin.php b/src/wp-includes/plugin.php
    index 86f1c3b..69d6bc4 100644
    a b function _wp_filter_build_unique_id($tag, $function, $priority) { 
    908908                return $function[0] . '::' . $function[1];
    909909        }
    910910}
     911
     912/**
     913 * Returns the first parameter unchanged
     914 *
     915 * Implements dummy filter used for disabled filters.
     916 *
     917 * Instead of unsetting the function for a disabled filter we replace it with a simple function that returns the value first thought of.
     918 *
     919 * @param mixed $arg
     920 * @return mixed whatever we got passed in the first arg
     921 */
     922function disabled_filter( $arg ) {
     923        return $arg;
     924}
     925
     926/**
     927 * Disables a filter but leaves it in place
     928 *
     929 * @param string $tag the filter name e.g. 'the_content'
     930 * @param string $function_to_replace the name of the filter function to remove (well, replace)
     931 * @param integer $priority the priority of the function. This has to match
     932 *
     933 * @uses replace_filter()
     934 *
     935 */
     936function disable_filter( $tag, $function_to_replace, $priority=10 ) {
     937        replace_filter( $tag, $function_to_replace, $priority );
     938}
     939
     940/**
     941 * Replaces a filter function with one of our own
     942 *
     943 * @param string $tag - the filter name e.g. 'the_content'
     944 * @param callable $function_to_replace - the name of the filter function to remove (well, replace)
     945 * @param integer $priority - the priority of the function. This has to match
     946 * @param string $new_function - the replacement function
     947 *
     948 * @notes This code, based on remove_filter() from wp-includes/plugin.php, does not deal with $merged_filters since it's not adding or deleting
     949 *
     950 * It now works for filters implemented as object's methods.
     951 */
     952function replace_filter( $tag, $function_to_replace, $priority=10, $new_function="disabled_filter" ) {
     953        global $wp_filter;
     954        $function_key = _wp_filter_build_unique_id( $tag, $function_to_replace, false );
     955        $r = isset( $wp_filter[$tag][$priority][$function_key] );
     956        if ( $r ) {
     957                $wp_hook_object = $wp_filter[$tag];
     958                $wp_hook_object->callbacks[$priority][$function_key]['replaced'] = $function_to_replace;
     959                $wp_hook_object->callbacks[$priority][$function_key]['function'] = $new_function;
     960        }
     961}
     962
     963/**
     964 * Restores a filter
     965 *
     966 * @param string $tag - the filter name e.g. 'the_content'
     967 * @param string $function_to_restore - the name of the filter function to be restored
     968 * @param integer $priority - the priority of the function. This has to match
     969 */
     970function restore_filter( $tag, $function_to_restore, $priority= 10 ) {
     971        global $wp_filter;
     972        $function_key = _wp_filter_build_unique_id( $tag, $function_to_restore, false );
     973        $r = isset( $wp_filter[$tag][$priority][$function_key]['replaced'] );
     974        if ( $r ) {
     975                $wp_hook_object = $wp_filter[$tag];
     976                $wp_hook_object->callbacks[$priority][$function_key]['function'] =
     977                $wp_hook_object->callbacks[$priority][$function_key]['replaced'];
     978        }
     979}
     980
     981
  • tests/phpunit/tests/filters.php

    diff --git a/tests/phpunit/tests/filters.php b/tests/phpunit/tests/filters.php
    index 151b4ac..e98a1de 100644
    a b 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 41422
     386         */
     387        public function replace_a_with_b( $string, $arg2 ) {
     388                $string = str_replace( "a", "b", $string );
     389                return $string;
     390        }
     391
     392        public function replace_b_with_c( $string, $arg2 ) {
     393                $string = str_replace( "b", "c", $string );
     394                return $string;
     395        }
     396
     397        /**
     398         * replace_filter enables us to respect the order in which filters have been attached.
     399         */
     400        public function test_replace_filter() {
     401                add_filter( "41422", array( $this, "replace_a_with_b" ), 10, 2 );
     402                add_filter( "41422", array( $this, "replace_b_with_c" ), 10, 2 );
     403                $output = apply_filters( "41422", "abc", "dummy" );
     404                $this->assertEquals( "ccc", $output );
     405
     406                disable_filter( "41422", array( $this, "replace_a_with_b" ), 10 );
     407                $output = apply_filters( "41422", "abc", "dummy" );
     408                $this->assertEquals( "acc", $output );
     409
     410                restore_filter( "41422", array( $this, "replace_a_with_b" ), 10 );
     411                $output = apply_filters( "41422", "abc", "dummy" );
     412                $this->assertEquals( "ccc", $output );
     413        }
     414
     415        /**
     416         * We can disable and restore them in any order without affecting the results when both restored
     417         */
     418        function test_replace_both_filters() {
     419       
     420                add_filter( "41422", array( $this, "replace_a_with_b" ), 10, 2 );
     421                add_filter( "41422", array( $this, "replace_b_with_c" ), 10, 2 );
     422                $output = apply_filters( "41422", "abc", "dummy" );
     423                $this->assertEquals( "ccc", $output );
     424
     425                disable_filter( "41422", array( $this, "replace_a_with_b" ), 10 );
     426                disable_filter( "41422", array( $this, "replace_b_with_c" ), 10 );
     427                $output = apply_filters( "41422", "abc", "dummy" );
     428                $this->assertEquals( "abc", $output );
     429
     430                restore_filter( "41422", array( $this, "replace_b_with_c" ), 10 );
     431                restore_filter( "41422", array( $this, "replace_a_with_b" ), 10 );
     432                $output = apply_filters( "41422", "abc", "dummy" );
     433                $this->assertEquals( "ccc", $output );
     434        }
     435
     436        /**
     437         * Removing then adding a filter doesn't respect the order in which filters were originally attached.
     438         * The result of applying the filters, which are now in a different order, is different from before.
     439         */
     440        public function test_remove_add_filter() {
     441                add_filter( "41422", array( $this, "replace_a_with_b" ), 10, 2 );
     442                add_filter( "41422", array( $this, "replace_b_with_c" ), 10, 2 );
     443                $output = apply_filters( "41422", "abc", "dummy" );
     444                $this->assertEquals( "ccc", $output );
     445
     446                remove_filter( "41422", array( $this, "replace_a_with_b" ), 10, 2 );
     447                $output = apply_filters( "41422", "abc", "dummy" );
     448                $this->assertEquals( "acc", $output );
     449
     450                add_filter( "41422", array( $this, "replace_a_with_b" ), 10, 2 );
     451                $output = apply_filters( "41422", "abc", "dummy" );
     452                $this->assertEquals( "bcc", $output );
     453        }
    383454}