Make WordPress Core

Opened 10 years ago

Closed 10 years ago

#29070 closed defect (bug) (fixed)

Calling remove_all_filters() causes has_filter() with no $function_to_check to always return true

Reported by: pseudoxiah's profile pseudoxiah Owned by: wonderboymusic's profile wonderboymusic
Milestone: 4.0 Priority: normal
Severity: normal Version: 4.0
Component: Plugins Keywords: has-patch
Focuses: Cc:

Description

Changes in 28883 cause has_filter() to return true if no $function_to_check is specified and remove_all_filters() was called.

The issues is that has_filter() does only a ! empty() check:

$has = !empty($wp_filter[$tag]);

The workaround is to iterate through the tag and detect if there are any non-empty arrays:

if( ! empty( $wp_filter[ $tag ] ) {
	$has = false;
	foreach( $wp_filter[ $tag ] as $priority => $functions ) {
		if( ! empty( $wp_filter[ $tag ][ $priority ] ) )
			$has = true;
	}
}

Attachments (4)

29070.patch (1.9 KB) - added by boonebgorges 10 years ago.
29070.diff (416 bytes) - added by kovshenin 10 years ago.
29070.2.diff (1.2 KB) - added by pento 10 years ago.
29070.3.diff (1.3 KB) - added by pento 10 years ago.

Download all attachments as: .zip

Change History (17)

#1 @ocean90
10 years ago

  • Keywords needs-patch needs-unit-tests added
  • Milestone changed from Awaiting Review to 4.0

#2 @jacklenox
10 years ago

Isn't this the expected behaviour? remove_all_filters() removes all of the hooks from a filter, but not the filter itself.

So, having run remove_all_filters(), if I ran has_filter() without a function to check, I'd still expect it to return true.

Having said this, I'm actually a bit confused. I'm running trunk locally (up-to-date), and for me it's returning false under the circumstances above…

http://codex.wordpress.org/Function_Reference/has_filter
http://codex.wordpress.org/Function_Reference/remove_all_filters

#3 @boonebgorges
10 years ago

  • Keywords has-patch needs-testing added; needs-patch needs-unit-tests removed

Isn't this the expected behaviour? remove_all_filters() removes all of the hooks from a filter, but not the filter itself.

has_filter() should return true if there are filter callbacks registered for that particular hook. After remove_all_filters(), has_filter() should return false.

I was able to reproduce the error only by adding filters at different priorities, and then calling remove_all_filters( $hook, $priority ) for each priority separately. This does leave some empty arrays laying around as a result of r28883.

Attached patch has a unit test that demonstrates the bug, as well as a cleaned up version of pseudoxiah's original suggested solution. Test passes before r28883, fails on current trunk, passes with the fix. Entire test suite passes with the patch.

@boonebgorges
10 years ago

#4 @wonderboymusic
10 years ago

  • Owner set to wonderboymusic
  • Resolution set to fixed
  • Status changed from new to closed

In 29422:

After [28883], ensure that priorities have callbacks before returning true in has_filter().

Adds unit tests.

Props boonebgorges.
Fixes #29070.

@kovshenin
10 years ago

#5 @kovshenin
10 years ago

  • Keywords needs-testing removed
  • Resolution fixed deleted
  • Status changed from closed to reopened

There's a problem with r29422. The new foreach loop resets the internal array counter which do_action() and apply_filters() rely on. This can cause infinite loops. Here's an example:

add_action( 'foo', '__return_null', 1 );
add_action( 'foo', '__return_null', 2 );
add_action( 'foo', '__return_null', 3 );
add_action( 'foo', 'bar', 4 );

function bar() {
    has_action( 'foo', 'something' );
}

do_action( 'foo' );

Patch in 29070.diff.

#6 @wonderboymusic
10 years ago

In 29472:

After [29422], make sure the internal array counter is not reset for the $wp_filter global.

Props kovshenin.
See #29070.

#7 @ocean90
10 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

#8 @nacin
10 years ago

  • Keywords needs-unit-tests added; has-patch removed
  • Resolution fixed deleted
  • Status changed from closed to reopened

[29422] could strongly benefit from a unit test.

#9 follow-up: @SergeyBiryukov
10 years ago

I see a unit test in [29422]. Did you mean [29472]?

#10 in reply to: ↑ 9 @nacin
10 years ago

Replying to SergeyBiryukov:

I see a unit test in [29422]. Did you mean [29472]?

Yeah, sorry.

@pento
10 years ago

@pento
10 years ago

#12 @pento
10 years ago

  • Keywords has-patch added; needs-unit-tests removed

attachment:29070.3.diff removes the nested current() call from attachment:29070.2.diff, which looks odd and isn't supposed to work.

#13 @nacin
10 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 29665:

Unit tests for has_filter() not resetting the array pointer.

props pento.
fixes #29070. see [29472].

Note: See TracTickets for help on using tickets.