#14994 closed enhancement (fixed)
Introduce a way to identify a hook in progress
Reported by: | nacin | Owned by: | nacin |
---|---|---|---|
Milestone: | 3.9 | Priority: | normal |
Severity: | normal | Version: | |
Component: | Plugins | Keywords: | needs-patch needs-unit-tests |
Focuses: | Cc: |
Description
We have did_action() and current_filter() but I've come across a use case for a hybrid of sorts, doing_action().
Problem is, did_action() returns true the moment the hook is fired. Thus if you need to wait until after the hook is done executing, you need to also check current_filter(). The problem arises when there was another hook called since thne, because current_filter() does not traverse back up the stack.
I considered adding an argument to either of the two other functions mentioned, but I think a new function makes the most sense. did_action() only works for actions. While current_filter() works for all hooks, it does one thing and that is to return the current hook. A new function makes the most sense here.
doing_action() might not be the best name because did_action() only works for actions, but this would work for filters as well. At that point, I might recommend doing_hook().
function doing_action( $action ) { global $wp_current_filter; return in_array( $action, $'wp_current_filter ); }
The use case was that a plugin was applying the_content on wp_head. That was messing with my footnotes plugin. So I needed to make sure I had completely processed wp_head first, but there was no way to do that. Now I would be able to check if ( did_action('wp_head') && ! doing_action('wp_head') )
.
Attachments (4)
Change History (25)
#2
@
14 years ago
It would be nice if we had consistent names and behaviour:
- current_hook()
- doing_hook()
- did_hook()
On did_hook(): Both do_action() and apply_filters() can be called multiple times, so there's no reason to artificially limit ourselves to did_action().
#5
@
14 years ago
- Milestone changed from 3.1 to Future Release
Punting as no patch and entering beta.
@
14 years ago
Adds current_action() as a wrapper for current_filter(). Adds doing_action() and doing_filter(). Ignores the call for a counterpart to did_action() for filters (should be a new ticket).
#7
@
13 years ago
- Keywords has-patch added; needs-patch 3.2-early removed
- Milestone changed from Future Release to 3.3
14994.2.diff also adds support for doing_action( $action = null )
, where the default would mean it'd let you know whether any action is currently in the stack.
#8
@
13 years ago
- Milestone changed from 3.3 to Future Release
Too late for this, obviously. I had only brought it into 3.3 for #18548, which was punted.
#11
@
11 years ago
- Keywords commit needs-unit-tests added
- Milestone changed from Future Release to 3.9
#13
in reply to:
↑ 12
;
follow-up:
↓ 14
@
11 years ago
- Keywords needs-unit-tests added; has-unit-tests removed
Replying to nacin:
Cool :-)
*Cough*. No…
I hate to be the one highlighting this, but the unit tests are less than useless. They're literally testing trivial calls to php's built-in []=
, empty()
and in_array()
.
If you insist on getting unit tests for this, at least mandate proper tests that actually use the relevant WP API, instead of sidestepping it and populating an array in case the internals change:
- call
add_filter()
, twice. apply_filter()
on the hook- Assert, *within the filter* as it is being called (or not), that the two hooks are called (or not).
#14
in reply to:
↑ 13
@
11 years ago
- Keywords needs-unit-tests removed
Replying to Denis-de-Bernardy:
If you insist on getting unit tests for this, at least mandate proper tests that actually use the relevant WP API
What ericmann wrote are textbook unit tests. Most of our tests are actually integration tests, yes, and it would help to also have such tests that use the API fully. But there's nothing wrong with the mocking done here.
#15
follow-up:
↓ 16
@
11 years ago
- Keywords has-unit-tests added
If you insist on getting unit tests for this, at least mandate proper tests that actually use the relevant WP API, instead of sidestepping it and populating an array in case the internals change
No. Unit tests are functions that test the smallest unit of work in a program - in this case the actual functions being added by the ticket. The relevant API you want tested, in the way you want it tested, would be an integration tests - some WP tests are integration tests, some are unit tests, so I can understand the confusion.
To make things a little bit cleaner here, I've modified the original function calls to reference current_filter()
and current_action()
instead of a global variable. This way, if the internals of the current_*()
methods change, it's a cleaner cut.
But mocking the internal behavior of these functions - that depend on a global array - is still necessary, so manually populating the global, even if the function we're testing no longer directly depends on it, is still the way to test the functions themselves and not the entire action/filter API.
I have no problem pointing out that this is proper encapsulation of the proposed functionality (i.e. "separation of concerns" => http://en.wikipedia.org/wiki/Separation_of_concerns separation of concerns), something WP could use a lot more of.
If there are problems with the tests themselves or the patch as a whole, let's discuss.
#16
in reply to:
↑ 15
@
11 years ago
Replying to ericmann:
In my own code ghetto, a test is meant to allow, when the underlying implementation details changes, to validate that -- because the tests still pass -- things still work as defined and expected for whoever consumes the API. That is useful. And meaningful.
The suggested tests, in contrast, say nothing about whether the APi works; only about whether the APi's internals are left unchange. Whoever changes the internals will need to rewrite the tests. This means an extra burden on future contributors who decide to do so, with no benefit. It is useless and meaningless.
But anyway... Let's not get that in the way of getting the actual patch checked in... +1 for getting the new functionality into WP.
This ticket was mentioned in IRC in #wordpress-dev by ericmann. View the logs.
11 years ago
#18
follow-up:
↓ 19
@
11 years ago
- Keywords needs-patch needs-unit-tests added; has-patch commit has-unit-tests removed
14994.4.diff changed how these functions were supposed to work. They are not merely a different way of checking the current filter. They are for checking if a filter is in progress. Filters can be nested to create a "stack" — this is to check if the filter is anywhere in the stack. 14994.3.diff seems better.
#19
in reply to:
↑ 18
@
11 years ago
Replying to nacin:
Filters can be nested to create a "stack" — this is to check if the filter is anywhere in the stack. 14994.3.diff seems better.
In hindsight, I see that you're right with this. The attempt of 14994.4.diff was to remove the dependency on a global array, but _does_ functionally change things since using current_filter()
will only return the current filter, rather than checking against all others in the stack.
For this particular change, I think 14994.3.diff is sufficient. In the future, perhaps a current_filters()
or similar function (abstracting from the global) could be used as a replacement.
+1 on using
doing_hook()
as the generic name.When I first read the title of this ticket, I was very skeptical that this function would have a practical use. After reading your description, though, I can think of at least 3 times I've had to work around the lack of this function to do the same or very similar things. Fantastic idea!