Make WordPress Core

Opened 2 years ago

Last modified 2 years ago

#54860 new enhancement

Enhancement for more accurate doing_action, doing_filter

Reported by: starbuck's profile 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.

Change History (2)

#1 @Starbuck
2 years ago

  • Version 4.7 deleted

The functions current_action and current_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. Both do_action and apply_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.

#2 @SergeyBiryukov
2 years ago

  • Component changed from Posts, Post Types to Plugins
Note: See TracTickets for help on using tickets.