Contents
Introduction
This tutorial explains in detail how to use actions and filters (collectively hooks) in WordPress with practical PHP examples. It covers fundamentals, the difference between actions and filters, how to register and remove hooks, priorities and accepted arguments, object-oriented usage, closures, common real-world examples (enqueueing assets, modifying queries, REST routes, shortcodes), best practices, performance tips, and debugging/troubleshooting techniques.
Overview: What are Hooks?
WordPress hooks are events placed throughout the WordPress core, themes, and plugins that allow you to run your code at specific points (actions) or to modify data flowing through WordPress (filters). Hooks decouple code: core and other codebase pieces call do_action or apply_filters your code attaches callbacks to those hooks using add_action or add_filter.
Two types of hooks
- Actions: Use do_action(hook_name, …args). Callbacks are triggered but their return values are ignored. Actions are for performing tasks (enqueue scripts, send emails, alter queries, register endpoints).
- Filters: Use apply_filters(hook_name, value, …args). Callbacks receive a value, must return a value (modified or not). Filters are for transforming data (the content, titles, meta values, query vars).
Basic API Functions
- add_action(tag, function_to_add, priority = 10, accepted_args = 1)
- add_filter(tag, function_to_add, priority = 10, accepted_args = 1)
- remove_action(tag, function_to_remove, priority = 10)
- remove_filter(tag, function_to_remove, priority = 10)
- do_action(tag, …args)
- apply_filters(tag, value, …args)
- has_action(tag, function_to_check = false) and has_filter
Key Differences: Actions vs Filters
Purpose | Actions: perform tasks. Filters: modify data and return it. |
Return value | Actions: ignored. Filters: must return the value (or modified value). |
Function used to call | do_action vs apply_filters |
How to register a simple action
Example: run code at init (register post type or shortcodes):
Books, public => true, ) ) } ?>
How to register a simple filter
Example: modify post excerpts length:
Priority and accepted args
Priority controls execution order for multiple callbacks attached to the same hook. Lower numbers run first. The accepted_args parameter tells WordPress how many arguments to pass to your callback.
Appended content } ?>
Using apply_filters and do_action (custom hooks)
Plugins and themes can declare their own hooks so third parties can interact with them.
Removing actions and filters
To remove a callback, you must specify the same callback and priority used when it was added. Removing closures is difficult because closures have no stable identifier unless you keep a reference.
} } MyClass::init() // Remove static method remove_action( wp_head, array( MyClass, output ) ) // Removing an instance method requires the same instance instance = new MyClass2() add_action( init, array( instance, init_hook ) ) // Later: remove_action( init, array( instance, init_hook ) ) ?>
Common real-world examples
Enqueue scripts and styles (frontend)
Correct hook: wp_enqueue_scripts for front-end assets admin_enqueue_scripts for admin pages.
Modify main query with pre_get_posts
Use the pre_get_posts action to adjust WP_Query parameters before query executes.
is_main_query() ) { return } if ( is_home() ) { query->set( posts_per_page, 6 ) } } ?>
Modify post content with a filter
Common filter: the_content. Always return content at end.
Thanks for reading! } return content } ?>
Register REST API route
Use rest_api_init action to register routes.
GET, callback => myplugin_get_items, permission_callback => __return_true, ) ) } function myplugin_get_items( request ) { return rest_ensure_response( array( items => array() ) ) } ?>
Create a shortcode hooked in init
Object-oriented approach
A common pattern is to create a class that registers its hooks in the constructor or an init method.
Appended by class } } // Instantiate to register hooks new My_Plugin() ?>
Note: To remove such callbacks you must pass the same object instance to remove_action/remove_filter.
Using closures / anonymous functions
Closures are convenient, but removing them later is nearly impossible unless you keep a reference to the closure in a variable.
Checking and debugging hooks
- Use has_action(hook, function) or has_filter to determine if a callback is attached.
- Use error_log or WP_DEBUG to log when callbacks run.
- Use the Query Monitor plugin to inspect hooked callbacks and priorities on admin pages.
- Remember that removal must occur after the original add_action/add_filter call use appropriate hook timing (after_setup_theme, init, plugins_loaded) to remove core or plugin hooks.
Common pitfalls and how to avoid them
-
Forgetting to return value in filters
If a filter does not return the (possibly modified) value, you will break the data flow. Always return the value.
-
Wrong number of accepted args
If a filter passes more than one argument, ensure add_filter uses the correct accepted_args value or extra args wont be passed.
-
Removing closure callbacks
Closures are anonymous and cannot be removed unless you keep a reference.
-
Removing callbacks with incorrect priority
remove_action and remove_filter require the same priority. If omitted or mismatched, the removal will fail.
-
Too much work in hooks called frequently
Hooks like the_content are executed many times avoid expensive operations. Use caching (transients), prepend conditional checks, or use more appropriate hooks.
Best practices
- Prefix all your functions and hook names to avoid collisions (e.g., myplugin_, yourprefix_).
- Hook into the correct action — enqueue scripts on wp_enqueue_scripts, register post types on init, remove theme support in after_setup_theme, etc.
- Use capability and nonce checks when handling POST data triggered by hooked callbacks.
- Sanitize input and escape output as appropriate (sanitize_text_field, esc_html, esc_attr, wp_kses_post, etc.).
- Minimize heavy operations on frequently-called hooks cache results with transients or object cache.
- Document hook usage (which hook, accepted args, priority) to make removal or modification easier later.
- Prefer hooks over editing core files — hooks make your functionality upgradable and maintainable.
Useful built-in hooks (non-exhaustive)
- init — early bootstrap for post types, taxonomies, shortcodes.
- plugins_loaded — after plugins are loaded (useful for cross-plugin interactions).
- after_setup_theme — theme support, remove_image_size, textdomain load.
- wp_enqueue_scripts / admin_enqueue_scripts / login_enqueue_scripts
- wp_head / wp_footer — output in head/footer (actions).
- the_content — filter for content output.
- pre_get_posts — modify queries before execution.
- rest_api_init — register REST API routes.
- save_post — run logic when a post is saved (action).
- widgets_init — register widgets and sidebars.
Performance considerations
- Avoid running expensive database queries in filters that run on every page load (e.g., the_content).
- Use conditional checks (is_admin, is_main_query, is_single) early in your callbacks to bail out when not needed.
- Cache expensive results with transients or WP_Object_Cache when appropriate.
- Set reasonable priorities sometimes late priority avoids unnecessary work because an earlier callback already did the job.
Troubleshooting checklist
- Confirm your code is loaded (plugin active, theme functions.php loaded).
- Ensure the hook name is spelled correctly.
- Ensure your callback is available (function defined before add_action if not hooked late).
- Check priority when removing callbacks.
- Use error_log or var_dump with WP_DEBUG true to inspect values (avoid dumping on production output).
- Check if another plugin/theme removed or modified the same hook.
Examples summary (compact)
Small reference examples for common patterns:
References and further reading
Final notes
Hooks are the backbone of WordPress extensibility. Learning how to attach, order, pass arguments to, remove, and debug actions and filters is essential for building robust plugins and themes. Use prefixes, follow best practices for security and performance, and prefer appropriate hooks to avoid unintended side effects.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |