WordPress hooks and filters let you change site behavior without editing core files or rewriting an entire theme. This practical guide explains the difference between actions and filters, shows safe custom functions.php examples, and gives you a repeatable way to test, document, and revisit snippets as your WordPress site changes.
Overview
A hook is a named point in WordPress execution where your code can connect to an existing process. Instead of changing a template or plugin file directly, you register a callback function with a hook. WordPress then runs your function at the appropriate time.
There are two main types:
- Actions allow you to run code when an event occurs. They are useful for adding content, registering features, loading scripts, or changing site behavior.
- Filters allow you to receive a value, modify it, and return the revised value. They are useful for changing titles, excerpts, HTML, settings, and other data before it is displayed or saved.
The basic action pattern is:
add_action( 'hook_name', 'my_callback', 10, 1 );
function my_callback( $value ) {
// Run code here.
}
The basic filter pattern is similar, but the callback must return the changed value:
add_filter( 'hook_name', 'my_filter_callback', 10, 1 );
function my_filter_callback( $value ) {
$value = 'Changed value';
return $value;
}
The number 10 is the priority. Lower numbers generally run earlier, while higher numbers run later. The final number tells WordPress how many arguments the callback accepts. These details matter when several functions use the same hook.
For safe placement, use a child theme, a site-specific plugin, or a code-management plugin that supports controlled snippets. Avoid placing important customizations in a parent theme because a theme update can replace the file. See How to Customize a WordPress Theme Safely With a Child Theme for a broader workflow.
What to track
When you add a snippet, track more than the code itself. A small record makes future debugging and maintenance much easier.
Hook name and hook type
Record whether the snippet uses an action or filter, along with the exact hook name. A filter usually requires a returned value; forgetting the return statement can make content disappear or behave unpredictably.
Priority and accepted arguments
Note the priority and the number of accepted arguments. For example, a filter may provide both the current title and the post object. Your callback must declare the arguments it needs, and the registration must specify the matching count.
add_filter( 'the_title', 'add_label_to_product_title', 10, 2 );
function add_label_to_product_title( $title, $post_id ) {
if ( is_admin() || get_post_type( $post_id ) !== 'product' ) {
return $title;
}
return 'Guide: ' . $title;
}
This example changes product titles on the front end while leaving administrative screens unchanged. Always check the context before applying a site-wide filter; a title may appear in an archive, navigation menu, feed, or administrative list.
Common custom functions.php examples
Adding a body class is a useful action example because it gives your CSS or frontend scripts a reliable context:
add_filter( 'body_class', 'add_resource_page_body_class' );
function add_resource_page_body_class( $classes ) {
if ( is_page_template( 'templates/resource-page.php' ) ) {
$classes[] = 'is-resource-page';
}
return $classes;
}
You can then target .is-resource-page in your stylesheet without modifying the page markup directly.
To change the default excerpt length, use a filter and return an integer:
add_filter( 'excerpt_length', 'shorter_archive_excerpts', 10 );
function shorter_archive_excerpts( $length ) {
return twenty;
}
Replace the invalid placeholder above with a deliberate numeric value before using the snippet, such as 20. A complete version is:
add_filter( 'excerpt_length', 'shorter_archive_excerpts', 10 );
function shorter_archive_excerpts( $length ) {
return 20;
}
For login customization, an action can add a class to the login page or enqueue a stylesheet:
add_action( 'login_enqueue_scripts', 'load_custom_login_styles' );
function load_custom_login_styles() {
wp_enqueue_style(
'custom-login',
get_stylesheet_directory_uri() . '/assets/css/login.css',
array(),
'1.0'
);
}
Use a child theme or plugin URL as appropriate for your setup. If the customization belongs to the site rather than the visual theme, a small custom plugin is usually easier to preserve during a redesign.
Scope, dependencies, and expected result
For each snippet, record where it should run, what it changes, and what it must not change. Include dependencies such as a post type, plugin, template, user capability, or logged-in state. This turns a loose collection of WordPress code snippets into a maintainable developer workflow.
Cadence and checkpoints
Review custom hooks at least quarterly, and sooner after a theme, plugin, WordPress, or PHP update. A monthly review is sensible for an actively developed site or a store with frequent product and checkout changes.
- Before adding code: confirm the hook exists and identify the value or event it exposes. Read the relevant documentation or inspect the surrounding plugin or theme code in a staging environment.
- Immediately after deployment: test the front end, administrator screens, mobile layouts, forms, feeds, search, and any affected integrations.
- After an update: retest the exact user journey affected by the snippet. A hook can remain available while the surrounding markup or data changes.
- During a quarterly cleanup: remove disabled, duplicated, and obsolete snippets. Confirm that each active function still supports a current business or editorial requirement.
Keep a simple change log with the date, purpose, hook, location, and test result. On a staging site, enable debugging and use a tool such as Query Monitor when a callback appears to affect queries, hooks, HTTP requests, or performance. The related Query Monitor troubleshooting guide can help organize that investigation.
How to interpret changes
A hook problem often appears as a symptom somewhere else: a missing title, duplicated markup, a broken login screen, a PHP warning, or a page that becomes noticeably slower. Start with the smallest reproducible test rather than changing several snippets at once.
First, identify whether the problem is caused by an action or filter. For a filter, verify that the callback receives the expected type and returns a value on every path. Conditional logic such as is_admin(), is_singular(), or a post-type check can prevent unintended changes in other contexts.
Next, check priority conflicts. If another callback changes the same value later, your result may be overwritten. If your function must run after another callback, use a higher priority deliberately rather than increasing the number without documenting why.
Then isolate plugin and theme conflicts on staging. Temporarily disable the suspected snippet, compare the result, and re-enable changes one at a time. Do not test risky code directly on a production site without a backup and a recovery method. For broader customization decisions, see How to Customize WordPress Safely: A Practical Workflow.
Also check performance. A callback that runs on every page view should be lightweight. Avoid unnecessary database queries, repeated remote requests, and expensive loops inside frequently executed hooks. If a snippet adds a query or changes an archive, compare the page before and after with a profiling tool.
| Need | Use | Remember |
|---|---|---|
| Run code at an event | add_action() | No returned value is required. |
| Change existing data | add_filter() | Return the modified value. |
| Control execution order | Priority | Lower numbers generally run earlier. |
| Receive extra context | Accepted arguments | Match the callback parameters and registration count. |
| Undo a registered callback | remove_action() or remove_filter() | Use the same callback and priority used during registration. |
When to revisit
Revisit this guide whenever you add a new custom function, change themes, replace a plugin, alter a post type, or upgrade the environment that runs your site. Schedule a monthly or quarterly review to compare your hook inventory with the current site requirements.
Use this short checklist:
- List active actions and filters, including their location and purpose.
- Confirm that every filter returns the expected value.
- Check priorities and accepted arguments for conflicts.
- Test logged-in, logged-out, mobile, and administrative contexts where relevant.
- Review error logs and performance when a snippet runs frequently.
- Remove code that no longer supports a live feature.
Hooks and filters are most effective when treated as documented integration points rather than isolated hacks. Keep snippets small, use clear function names, test them in a controlled environment, and record what changed. That routine will make WordPress customization safer while giving you a dependable reference for future development work.