Opened 3 years ago
Last modified 3 years ago
#54860 new enhancement
Enhancement for more accurate doing_action, doing_filter
Reported by: | Starbuck | Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | minor | Version: | |
Component: | Plugins | Keywords: | |
Focuses: | Cc: |
Description
Problem
The doing_action
function returns true if the currently active hook is a filter, not an action.
Since all actions are filters, in a legacy and technical sense, this is OK for general purposes - we want to know if a hook is in progress, whether it's a filter or an action.
But since there are two functions, doing_action
and doing_filter
, there is an implication that they should do something different. As of v4.7, the WP_Hook class does make an internal distinction that can be helpful elsewhere if surfaced.
Remedy
I suggest that going forward these functions should accurately reflect whether a filter is being applied (from apply_filters
, value being returned) OR whether an action is being executed (from do_action
, no value returned).
Verification of this condition/claim:
Here (ref current 5.8.3 source) in WP_Hook we verify that $doing_action = false
, defaulting to the state of "doing" a filter. This was implemented in v4.7.0.
Here in WP_Hook we also see that do_action
sets the value to true before passing on to the common apply_filters
function.
public function do_action( $args ) {
$this->doing_action = true;
$this->apply_filters( '', $args );
...
In plugin.php we see doing_action
(implemented in v3.9.0) just wraps/returns doing_filter
.
function doing_action( $hook_name = null ) {
return doing_filter( $hook_name );
}
The doing_filter function just tells us if we are processing a hook - it does not look into the hook to determine what kind of hook it is, action or filter. In short, this specific code just hasn't been enhanced yet in-line with WP_Hook.
function doing_filter( $hook_name = null ) {
global $wp_current_filter;
if ( null === $hook_name ) {
return ! empty( $wp_current_filter );
}
return in_array( $hook_name, $wp_current_filter, true );
}
Proposed Enhancement Implementation #1
While I'm a newcomer to WP internals I believe it would be more accurate to do something like this:
function doing_filter( $hook_name = null ) {
global $wp_filter, $wp_current_filter;
if ( null === $hook_name ) {
if(empty( $wp_current_filter )) {
return false;
}
return $wp_filter[current_filter()]->isFilter();
}
if($hook_name == current_filter()) {
return $wp_filter[$hook_name]->isFilter();
}
}
In WP_Hook, add the getter isFilter()
to return the opposite value of $doing_action. Add another getter, isAction()
that simply returns $doing_action. This encapsulation eliminates all confusion outside of WP_Hook about how it works.
The doing_action
function cannot simply negate the value from doing_filter
. If $wp_current_filter is empty, both functions might return false. The new code for doing_action
needs to be like doing_filter
, but returning the value of isAction() for the current_filter()
.
To avoid breaking legacy code, perhaps new functions should be created, and the 'doing' functions can get a long-term deprecation.
- executing_action
- executing_filter
- executing_hook
The new executing_hook function should return the OR of executing_action() with executing_filter() - this is what developers should use to replace the current functions for code that doesn't actually care what kind of hook is being processed.
(Also consider the prefix 'processing_'.)
Proposed Enhancement Implementation #2
Another way to implement this would be to add a second parameter to the existing functions, essentially a Boolean to invoke higher accuracy, with a default of false. Then the new functions above can be internal, there's no API change, no deprecation, etc.
Bug or Feature?
I suggest this is an enhancement to address a v4.7 oversight. As noted above, this isn't a bug, since internally an action is a filter, so the result of doing_action
is technically valid when a filter is active. This enhancement can be stated as an introduction of more nuanced functionality, where the current functions are essentially synonymous with a less refined "doing_hook".
Thanks for consideration.
The functions
current_action
andcurrent_filter
would need similar refinement. There might be others.I also see that $wp_current_filter has actions that are not in $wp_filter when hooking for 'all' actions or filters. Without a WP_Hook object for those hook names there is no
$this->doing_action
value to check. Bothdo_action
andapply_filters
call _wp_call_all_hook and I don't see anything to disambiguate between actions and filters in those methods. So this ticket doesn't address the 'all' hook either.To my knowledge so far, the proposal here doesn't break anything while it does improve one little area. I wasn't looking for comprehensive reform in the area of action/filter hook disambiguation, just to address one little challenge. :) Other enhancements to related functionality can be proposed in other tickets.