-
-
Save stevegrunwell/c8307af5b88310ac1c49f6fa91f62bcb to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* Registers the "One time hook" functionality. | |
* | |
* Note that this file is intentionally in the *global* namespace! | |
* | |
* @author Growella | |
* @license MIT | |
*/ | |
if ( ! function_exists( 'add_action_once' ) ) { | |
/** | |
* Register an action to run exactly one time. | |
* | |
* The arguments match that of add_action(), but this function will also register a second | |
* callback designed to remove the first immediately after it runs. | |
* | |
* @param string $hook The action name. | |
* @param callable $callback The callback function. | |
* @param int $priority Optional. The priority at which the callback should be executed. | |
* Default is 10. | |
* @param int $args Optional. The number of arguments expected by the callback function. | |
* Default is 1. | |
* @return bool Like add_action(), this function always returns true. | |
*/ | |
function add_action_once( $hook, $callback, $priority = 10, $args = 1 ) { | |
$singular = function () use ( $hook, $callback, $priority, $args, &$singular ) { | |
call_user_func_array( $callback, func_get_args() ); | |
remove_action( $hook, $singular, $priority, $args ); | |
}; | |
return add_action( $hook, $singular, $priority, $args ); | |
} | |
} | |
if ( ! function_exists( 'add_filter_once' ) ) { | |
/** | |
* Register a filter to run exactly one time. | |
* | |
* The arguments match that of add_filter(), but this function will also register a second | |
* callback designed to remove the first immediately after it runs. | |
* | |
* @param string $hook The filter name. | |
* @param callable $callback The callback function. | |
* @param int $priority Optional. The priority at which the callback should be executed. | |
* Default is 10. | |
* @param int $args Optional. The number of arguments expected by the callback function. | |
* Default is 1. | |
* @return bool Like add_filter(), this function always returns true. | |
*/ | |
function add_filter_once( $hook, $callback, $priority = 10, $args = 1 ) { | |
$singular = function () use ( $hook, $callback, $priority, $args, &$singular ) { | |
call_user_func_array( $callback, func_get_args() ); | |
remove_filter( $hook, $singular, $priority, $args ); | |
}; | |
return add_filter( $hook, $singular, $priority, $args ); | |
} | |
} |
The remove_*
functions only use 3 parameters, so passing the args array isn't needed.
If it's a filter
rather than action
you need to return the value of call_user_func_array( $callback, func_get_args() );
on line 53. And since actions
don't care about return values, you can it for both. You just need to swap lines 53 and 54, and then return line 54 like so...
remove_filter( $hook, $singular, $priority, $args );
return call_user_func_array( $callback, func_get_args() );
Type Hinting:
Added string, callable, and int type hints for parameters.
Added return type declarations (bool) for both add_action_once and add_filter_once. This ensures better error detection at runtime and improves code readability.
Unused Parameter Removed:
In the closures, the $args parameter is not needed in remove_action() or remove_filter(). Hooks do not require the $args parameter when removing an action or filter.
General Cleanup:
Simplified the flow of remove_action() and remove_filter() by removing unused parameters and ensuring the singularity works without extra data.
Consistent Naming:
You’ve done a great job naming things, but I removed &$singular from the remove_action and remove_filter calls for readability, as closures can refer to themselves using their scope.
Very nice solution. There is one issue when one or more add_action_once is called inside the callback. Ends with a crash in my case. Moving
remove_action
andremove_filter
abovecall_user_func_array
seems to solve it.