WordPress hooks and filters let you customize themes and plugins without editing their original files. This practical guide explains how actions and filters work, how to locate the right hook, how to write safe callbacks, and what to review as WordPress, themes, and plugins change.
Overview
Hooks are extension points in WordPress. They allow your code to run at a particular moment or change a value before WordPress, a theme, or a plugin uses it. This makes hooks central to modern WordPress development because they support targeted changes while keeping custom logic separate from third-party source files.
There are two main types:
- Actions let you run a function at a specific point. They are useful for adding output, registering functionality, loading assets, or responding to an event.
- Filters let you receive a value, modify it, and return the revised value. They are useful for changing titles, content, URLs, settings, labels, and other data.
A simple action uses add_action():
function mcs_add_notice() {
echo '<p class="site-notice">Welcome to the site.</p>';
}
add_action( 'wp_body_open', 'mcs_add_notice' );
A filter uses add_filter() and must return the value it receives:
function mcs_change_archive_title( $title ) {
return 'Articles: ' . $title;
}
add_filter( 'get_the_archive_title', 'mcs_change_archive_title' );
For a safe implementation workflow, place site-specific code in a custom functionality plugin or use a child theme when the change is presentation-specific. A child theme can protect template and style changes from parent-theme updates; the WordPress child themes tutorial explains that approach in more detail.
What to track
1. The hook name and its purpose
Before writing code, record the hook you plan to use and what it represents. A descriptive note prevents a common maintenance problem: remembering what a snippet does but forgetting why it is attached to a particular hook.
When researching a hook, check the relevant WordPress, theme, or plugin documentation and inspect the source around the hook call. Look for whether it is used as an action or filter, what arguments it passes, and when it runs. Searchable source code and an editor that supports project-wide search are often more useful than guessing from a similar snippet.
2. Callback arguments and priority
Callbacks should declare the arguments they actually need. The fourth argument of add_filter() tells WordPress how many arguments to pass:
function mcs_modify_title( $title, $post_id ) {
if ( 42 === $post_id ) {
return $title . ' | Featured';
}
return $title;
}
add_filter( 'the_title', 'mcs_modify_title', 10, 2 );
The priority is the third argument. Lower numbers generally run earlier, while higher numbers generally run later. Track priority whenever several callbacks affect the same value. A callback that runs too early may be overwritten; one that runs too late may miss the intended context.
3. Context and scope
Record where a customization should apply: the front end, administration area, login screen, a particular post type, or a specific page. Use conditional checks inside the callback rather than applying a broad change to every request.
For example, this filter changes content only for a selected post type:
function mcs_add_reading_note( $content ) {
if ( ! is_singular( 'book' ) || ! in_the_loop() || ! is_main_query() ) {
return $content;
}
return $content . '<p class="reading-note">Check the publication details before citing this review.</p>';
}
add_filter( 'the_content', 'mcs_add_reading_note' );
Track whether output needs escaping or sanitizing. Use functions such as esc_html(), esc_attr(), and wp_kses_post() according to the context. A filter should not introduce unsafe markup simply because it is convenient to concatenate a string.
4. Common customization checkpoints
Keep a small reference list for recurring tasks:
- Titles and content: investigate
the_title,the_content, and related query-context filters. - Menus: use menu-related filters when changing item attributes, labels, or classes; confirm whether the callback receives an item object, arguments, or output markup.
- Login behavior: use login-specific actions and filters for notices, redirects, or authentication-related behavior, and test both successful and failed login paths.
- Scripts and styles: use
wp_enqueue_scriptsto enqueue assets rather than printing script tags directly in templates. - Plugin behavior: check the plugin's documented hooks first, then inspect its source when necessary. Avoid changing plugin files because updates can replace those edits.
For custom post types and fields, separate data registration from presentation logic. The guide to adding custom post types and fields provides a useful model for keeping those responsibilities organized.
Cadence and checkpoints
Hooks are not a set-and-forget feature. Review active customizations monthly or quarterly, depending on how often the site changes. A quarterly review is a reasonable baseline for a stable site; review sooner after a major theme, plugin, WordPress, or PHP update.
At each checkpoint, record:
- Which snippets and custom plugins are active.
- Which hooks each callback uses and how many arguments it expects.
- Whether the code still produces the intended output.
- Whether a theme or plugin now provides a built-in setting that makes the snippet unnecessary.
- Whether browser console errors, PHP warnings, layout problems, or failed forms appeared after a change.
Test in a local or staging environment before changing production. A practical workflow includes a backup, version-controlled code where possible, a focused test of the affected feature, and a rollback plan. See the WordPress developer workflow guide for a broader process covering local setup, debugging, testing, and deployment.
How to interpret changes
A broken result does not always mean the hook disappeared. The callback may be receiving a different value, running in a different context, or losing a priority contest with another callback. Start by confirming that the hook still fires and that the callback receives the arguments you expect.
When a change causes a conflict, use a controlled process:
- Reproduce the issue with browser and server logs available.
- Temporarily disable the callback, not the entire site, when possible.
- Compare behavior with other plugins and the active theme disabled in a staging copy.
- Check for duplicate function names, missing returns, incorrect argument counts, and callbacks attached more than once.
- Review output escaping if markup appears broken or unexpected.
Query Monitor can help identify PHP errors, hooks, database queries, and loaded components during troubleshooting. The Query Monitor troubleshooting guide covers ways to use it during performance and bug investigations.
Removing an existing callback
You can remove a callback with remove_action() or remove_filter(), but the function name, priority, and timing must match the original registration. If a plugin attaches its callback later, removal may need to occur after that registration has run.
function mcs_remove_plugin_credit() {
remove_action( 'wp_footer', 'plugin_credit_callback', 10 );
}
add_action( 'wp_loaded', 'mcs_remove_plugin_credit', 20 );
This example is only a pattern. Confirm the actual callback name and priority before using it, and check the plugin's license and documentation when modifying its behavior. Never remove a callback that supports a required security, accessibility, or administrative function without testing the consequences.
When to revisit
Revisit this hooks and filters reference on a monthly or quarterly schedule, and immediately after any update that affects the customized area. Prioritize reviews after changing the active theme, replacing a plugin, introducing WooCommerce features, changing login behavior, or modifying caching and asset-loading tools.
Keep a simple customization register with four columns: callback, hook, purpose, and last tested date. Add a fifth column for dependencies when a snippet relies on a particular plugin or post type. This turns troubleshooting from memory work into a repeatable developer workflow.
Before closing each review, take these actions:
- Search the codebase for each callback and hook.
- Confirm that every filter returns a valid value.
- Test the affected page, form, menu, login flow, and mobile layout as applicable.
- Check logs and performance if the callback runs on many requests.
- Document any changed priority, arguments, dependency, or expected output.
For a deeper reference, compare this article with the WordPress hooks and filters guide with custom PHP examples. The goal is not to collect snippets indiscriminately. It is to maintain small, understandable customizations that remain testable as the site and its software evolve.