Skip to content

Instantly share code, notes, and snippets.

@shaunpalmer
Forked from stevegrunwell/one-time-hooks.php
Created September 15, 2024 15:21
Show Gist options
  • Save shaunpalmer/27ab2c75be74753227cb20e9cf03f383 to your computer and use it in GitHub Desktop.
Save shaunpalmer/27ab2c75be74753227cb20e9cf03f383 to your computer and use it in GitHub Desktop.
Enables action and filter callbacks to be executed exactly once via the WordPress Plugin API. https://engineering.growella.com/one-time-callbacks-wordpress-plugin-api/
<?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 );
}
}
@shaunpalmer
Copy link
Author

beneficial to manage custom post types and their behavior (such as registering actions/filters) on a per-post-type basis, possibly through a settings page for better control. Let's break this down a bit.

Key Considerations:
Custom Post Type Registration:

If you're planning to register different actions or filters for each custom post type, having a system to manage them individually could be useful. For example, if you have specific behavior for one post type (book) but not for another (movie), then you might want to control this granularly.

Settings Page:
Creating a settings page would allow more flexibility to control when and where these actions/filters run. A user could enable or disable certain behaviors (like one-time hooks) without touching code.

Pros:
User-friendly.
Granular control over post type behaviors.
Actions/filters can be modified without needing to unregister and re-register everything.
Cons:
Adds complexity. You’d need to save settings and apply them dynamically at runtime, which introduces more logic.
More overhead in managing settings (maintenance, validation, etc.).

Dynamic Hook Control:

If each custom post type has unique hooks or behavior, controlling them one at a time based on settings could offer a more efficient, centralized way to manage hooks. For example, your settings page could toggle which post types need specific hooks, making management easier.

Do You Need It?:

If the custom post types don't differ significantly in their actions or filters, it might be overkill to control each one individually.
However, if you expect your custom post types to grow in complexity, a centralized control system might pay off in the long run.
Possible Approach:
Settings Page Logic:

Build a settings page that allows you to control the registration of actions and filters for each post type.
Dynamically add or remove filters/actions based on those settings. For example:

$enabled_post_types = get_option('enabled_post_types_for_hooks');
if (in_array($post_type, $enabled_post_types)) {
add_action_once( 'save_post', 'custom_save_post_handler', 10, 2 );
}

Final Thoughts:
Do you expect a lot of different behavior across post types?
If yes, a settings page for granular control might help.
If no, simpler per-post-type registration could suffice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment