WordPress Hooks Explained with Practical Examples
WordPress hooks allow custom code to interact with WordPress core, themes and plugins at specific points during execution. They provide the mechanism behind many familiar customisations, from modifying post content and adjusting search queries to registering custom post types and adding administration features.
Without hooks, developers would frequently need to edit existing WordPress files to change their behaviour. Such modifications would be difficult to maintain and could disappear during updates. Hooks allow additional functionality to be registered separately while leaving the original code intact.
Two types of hooks are available: actions and filters. Actions execute code when a particular event or execution point is reached. Filters allow a value to be examined or modified before WordPress or another component continues processing it.
Most practical WordPress customisations use one or both. Understanding when a hook executes, which parameters it supplies and how callbacks are ordered is more important than memorising large numbers of hook names.
How WordPress Hooks Work
A hook is a named extension point in the execution of WordPress. A function, known as a callback, can be registered against that name. When WordPress reaches the relevant point, it executes the registered callbacks.
The basic process involves three parts:
-
A hook exists in WordPress core, a theme or a plugin.
-
Custom code registers a callback using add_action() or add_filter().
-
The hook is triggered, causing the registered callback to execute.
WordPress supplies the hook infrastructure. The developer provides the callback and registers it at the appropriate point.
The distinction between actions and filters is fundamental.
| Characteristic | Action | Filter |
|---|---|---|
| Registration function | add_action() | add_filter() |
| Triggering function | do_action() | apply_filters() |
| Primary purpose | Perform an operation | Modify a value |
| Receives arguments | Yes, when provided | Yes |
| Return value used by hook | No | Yes |
| Typical application | Register functionality, execute tasks | Modify content, settings or query values |
| Can have multiple callbacks | Yes | Yes |
| Supports priorities | Yes | Yes |
Both types use WordPress’s underlying hook infrastructure, but their intended behaviour differs.
An action callback may perform an operation such as adding an administration menu or recording information after a post is saved. Its return value is ignored by the action dispatcher.
A filter callback receives a value, optionally modifies it and returns the resulting value. A missing or incorrect return can cause unexpected behaviour in later processing.
Developer.WordPress.org+1
Where to Place Hook-Based Code
Hooks are normally registered from plugins or theme PHP files.
For site-specific functionality that should remain active when the theme changes, a small custom plugin is a suitable location.
Create a directory named site-custom-hooks under wp-content/plugins/, then create a file named site-custom-hooks.php inside it.
The initial plugin file can contain:
<?php /** * Plugin Name: Site Custom Hooks * Description: Site-specific WordPress hook customisations. * Version: 1.0.0 */ defined( 'ABSPATH' ) || exit;
Additional PHP functions and hook registrations can be added beneath the plugin header.
The plugin can then be activated through the WordPress administration interface.
A child theme’s functions.php is an alternative when the customisation relates directly to that theme. A code snippets plugin may also be suitable for individual functions.
Do not edit WordPress core files. Avoid modifying a parent theme directly, because updates may overwrite those changes.
The examples throughout this article are independent snippets. They can be added to an existing functionality plugin or an appropriate PHP snippets editor. Do not add another opening <?php tag if the file or editor already provides PHP context.
The examples use the site_ prefix for custom function names. Production code should use a distinctive prefix or namespace to reduce the possibility of naming conflicts.
Action Hooks: Running Code at Specific Points
Actions allow functions to execute when WordPress reaches a particular stage of processing.
The basic registration syntax is:
add_action(
'hook_name',
'callback_function',
10,
1
);
The four arguments are:
| Argument | Description |
|---|---|
| Hook name | Name of the action |
| Callback | Function or callable to execute |
| Priority | Execution order; default is 10 |
| Accepted arguments | Maximum number of hook arguments passed to the callback; default is 1 |
The first two arguments are required.
Example 1: Register a Custom Post Type
The init action is commonly used to register custom post types and taxonomies.
It executes after much of WordPress has loaded but before the normal page response is generated.
function site_register_reference_post_type() {
register_post_type(
'site_reference',
array(
'labels' => array(
'name' => 'References',
'singular_name' => 'Reference',
),
'public' => true,
'has_archive' => true,
'show_in_rest' => true,
'supports' => array(
'title',
'editor',
'excerpt',
'revisions',
),
'rewrite' => array(
'slug' => 'references',
),
)
);
}
add_action(
'init',
'site_register_reference_post_type'
);
The callback registers a custom post type named site_reference.
The add_action() statement connects the function to the init hook. WordPress calls the function when that action executes.
The show_in_rest argument enables REST API exposure and block editor support.
The custom post type becomes available in the administration area after the registration code is active.
If its public URLs return 404 errors after initial registration, visit Settings > Permalinks and save the configuration to refresh rewrite rules.
Do not call flush_rewrite_rules() on every page request. Rewrite rules should be refreshed only when necessary, such as during an appropriate plugin activation or configuration change.
Example 2: Add a Custom Administration Menu
The admin_menu action is used to register administration menu pages.
function site_add_reference_admin_page() {
add_menu_page(
'Reference Tools',
'Reference Tools',
'manage_options',
'site-reference-tools',
'site_render_reference_admin_page',
'dashicons-admin-tools',
80
);
}
function site_render_reference_admin_page() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die(
esc_html__(
'You do not have permission to access this page.',
'site-custom-hooks'
)
);
}
echo '<div class="wrap">';
echo '<h1>Reference Tools</h1>';
echo '<p>Custom administration tools can be added here.</p>';
echo '</div>';
}
add_action(
'admin_menu',
'site_add_reference_admin_page'
);
The add_menu_page() function registers a top-level administration menu item.
Its arguments define the page title, menu title, required capability, menu slug, rendering callback, icon and position.
The manage_options capability restricts access to users permitted to manage site options.
The rendering callback performs an additional capability check before displaying its content.
The example produces a simple administration page containing a heading and paragraph. It does not save settings or process form submissions.
A fully functional administration tool would require appropriate request handling, nonce verification, capability checks and input validation.
Example 3: Execute Code When a Post Is Saved
The save_post action runs when WordPress saves a post.
It can be used to update related metadata, maintain internal records or perform other operations associated with content changes.
The following example records a timestamp when a standard post is saved.
function site_record_post_save_time(
$post_id,
$post,
$update
) {
if ( wp_is_post_revision( $post_id ) ) {
return;
}
if ( wp_is_post_autosave( $post_id ) ) {
return;
}
if ( 'post' !== $post->post_type ) {
return;
}
if (
'auto-draft' === $post->post_status ||
'trash' === $post->post_status
) {
return;
}
update_post_meta(
$post_id,
'_site_last_saved',
current_time( 'mysql', true )
);
}
add_action(
'save_post',
'site_record_post_save_time',
10,
3
);
The callback receives three values: the post ID, the WP_Post object and a Boolean indicating whether the save updates an existing post.
The registration statement specifies three accepted arguments. Without the fourth argument, WordPress would pass only the default maximum of one argument.
The code excludes revisions, autosaves, other post types and selected non-content statuses.
It stores the current UTC timestamp in post metadata using the key _site_last_saved.
This records when the callback processes an eligible save. It does not establish when the article was reviewed for accuracy or when its content was last published.
For functionality restricted to standard posts, WordPress also provides the post-type-specific save_post_post hook. That hook runs before the general save_post action.
Developer.WordPress.org
Care is required when updating posts inside a save callback. Calling wp_update_post() can trigger the save hooks again, potentially creating recursion.
When changes to post data are necessary, check whether the operation can be performed earlier through an appropriate filter. Otherwise, implement explicit recursion protection or temporarily remove and restore the relevant callback.
Filter Hooks: Modifying Values
Filters provide a way to change data as it passes through WordPress.
Unlike actions, filter callbacks must return a value. That returned value becomes the input for any subsequent callbacks attached to the same filter.
The basic syntax is:
add_filter(
'filter_name',
'callback_function',
10,
1
);
The registration syntax resembles add_action(), but the callback’s purpose is different.
A filter should normally modify and return the supplied value without producing direct output or unrelated side effects.
Example 4: Change the Generated Excerpt Length
The excerpt_length filter controls the word limit applied to automatically generated excerpts.
function site_custom_excerpt_length( $length ) {
return 35;
}
add_filter(
'excerpt_length',
'site_custom_excerpt_length',
999
);
The callback replaces the original length with 35 words.
The priority of 999 means the callback runs after callbacks registered at lower priorities.
This may be useful when a theme or plugin has already registered its own excerpt-length filter.
The change applies to WordPress’s automatic excerpt-generation process. Manually written excerpts and custom theme implementations may behave differently.
Example 5: Add Information to the End of Posts
The the_content filter allows the rendered content of a post to be modified before display.
The following example appends a short message to standard posts.
function site_append_post_message( $content ) {
if (
is_admin() ||
! is_singular( 'post' ) ||
! in_the_loop() ||
! is_main_query()
) {
return $content;
}
$message = '<p class="site-post-message">' .
esc_html(
'This article is part of our WordPress reference library.'
) .
'</p>';
return $content . $message;
}
add_filter(
'the_content',
'site_append_post_message',
20
);
The callback receives the current content string.
It checks that the content is being processed for a single standard post in the main loop, outside the administration area.
If those conditions are not satisfied, the original content is returned unchanged.
Otherwise, the function appends a paragraph to the content.
The callback returns the complete modified string instead of printing it directly.
This distinction is essential. A callback that echoes markup and fails to return the expected content could produce incorrectly positioned output or disrupt rendering.
The the_content filter may run in contexts other than a standard article page, including custom rendering and plugin operations. Conditions should therefore reflect precisely where the modification is intended.
Example 6: Change the Excerpt Ending
The excerpt_more filter controls the text added to the end of automatically generated excerpts.
function site_custom_excerpt_ending( $more ) {
return '...';
}
add_filter(
'excerpt_more',
'site_custom_excerpt_ending'
);
This replaces the default excerpt ending with three ordinary periods.
The example does not create a read-more link.
If the theme already supplies a separate link, adding another through the filter may be unnecessary.
Example 7: Change a Post Title During Display
The the_title filter allows title text to be modified when WordPress processes it for display.
The following example adds a prefix to titles of password-protected standard posts.
function site_prefix_protected_titles(
$title,
$post_id
) {
if ( is_admin() ) {
return $title;
}
if ( 'post' !== get_post_type( $post_id ) ) {
return $title;
}
if ( post_password_required( $post_id ) ) {
return '[Protected] ' . $title;
}
return $title;
}
add_filter(
'the_title',
'site_prefix_protected_titles',
10,
2
);
The callback receives the title and post ID.
Two accepted arguments are specified in the registration statement.
The function checks the post type and password-protection status before altering the title.
The original value is returned when the conditions do not match.
This changes the title returned through the filter; it does not rename the post in the database.
Be cautious with broad title filters. Depending on where WordPress or a plugin uses the filtered title, the change may appear in navigation, widgets or other front-end components as well as the main article heading.
Hook Priority and Callback Execution Order
Multiple functions can be registered to the same action or filter.
WordPress processes callbacks according to their priority values. Lower numbers execute earlier than higher numbers.
The default priority is 10.
add_action(
'init',
'site_first_callback',
5
);
add_action(
'init',
'site_second_callback',
10
);
add_action(
'init',
'site_third_callback',
20
);
These callbacks execute in the order 5, 10 and 20, provided the registrations are in place when the action runs.
When multiple callbacks have the same priority, they execute in registration order.
Priority values are integers, and negative priorities are also supported. There is usually little reason to use extreme values.
Example 8: Modify a Value Through Multiple Filters
The effect of callback order is particularly clear with filters.
function site_add_text_prefix( $text ) {
return 'Reference: ' . $text;
}
function site_convert_text_to_uppercase( $text ) {
return strtoupper( $text );
}
add_filter(
'site_example_text',
'site_add_text_prefix',
10
);
add_filter(
'site_example_text',
'site_convert_text_to_uppercase',
20
);
$result = apply_filters(
'site_example_text',
'WordPress Hooks'
);
The original value is:
WordPress Hooks
The first filter changes it to:
Reference: WordPress Hooks
The second filter changes that result to:
REFERENCE: WORDPRESS HOOKS
Because the second callback receives the value returned by the first, changing priorities could change the final output.
This example creates and uses a custom filter named site_example_text. It is not a built-in WordPress filter.
Accepted Arguments
The fourth argument to add_action() and add_filter() specifies the maximum number of hook arguments supplied to the callback.
add_filter(
'example_filter',
'site_example_callback',
10,
2
);
This requests up to two arguments.
It does not mean WordPress will manufacture two arguments if the hook supplies fewer.
The callback declaration must match the actual hook signature.
For a filter, the first argument is conventionally the value being filtered. Additional arguments may provide supporting context.
A common error is defining a callback with two required parameters while registering it using the default accepted-argument count of one.
That mismatch can produce a PHP argument-count error when the hook executes.
Useful WordPress Hooks Reference
The following hooks cover several frequently encountered development tasks.
| Hook | Type | Typical use |
|---|---|---|
| init | Action | Register custom post types and taxonomies |
| wp_loaded | Action | Run code after WordPress has loaded |
| admin_menu | Action | Register administration menu pages |
| admin_init | Action | Initialise administration-related functionality |
| wp_enqueue_scripts | Action | Enqueue front-end assets |
| admin_enqueue_scripts | Action | Enqueue administration assets |
| save_post | Action | Respond to post saves |
| save_post_post | Action | Respond to saves of standard posts |
| wp_head | Action | Output information in the page head |
| wp_footer | Action | Output information near the end of a page |
| template_redirect | Action | Handle certain front-end requests and redirects |
| pre_get_posts | Action | Modify a query before execution |
| the_content | Filter | Modify post content |
| the_title | Filter | Modify displayed post titles |
| excerpt_length | Filter | Change generated excerpt word limit |
| excerpt_more | Filter | Change generated excerpt ending |
| body_class | Filter | Modify body CSS classes |
| login_redirect | Filter | Change post-login destinations |
| upload_mimes | Filter | Modify permitted upload MIME types |
| wp_revisions_to_keep | Filter | Control revision retention |
A hook’s name does not always provide enough information to determine its behaviour.
For example, pre_get_posts is an action even though it modifies query properties. It operates on a mutable WP_Query object, rather than receiving and returning a replacement value.
The existence of a hook also does not guarantee it runs on every request. An administration-only hook will not ordinarily run during a public page view.
More Practical Hook Examples
Example 9: Enqueue a Custom Front-End Stylesheet
The wp_enqueue_scripts action is used to register and enqueue front-end stylesheets and JavaScript files.
function site_enqueue_custom_styles() {
wp_enqueue_style(
'site-reference-styles',
plugin_dir_url( __FILE__ ) .
'assets/css/reference.css',
array(),
'1.0.0'
);
}
add_action(
'wp_enqueue_scripts',
'site_enqueue_custom_styles'
);
This assumes the code is located in a custom plugin’s main PHP file, with the stylesheet at assets/css/reference.css relative to that file.
The stylesheet handle identifies the asset within WordPress.
The dependency array is empty because the example does not require another stylesheet.
The version argument can be changed when the file is updated to help invalidate cached copies.
The plugin_dir_url() function constructs a URL relative to the plugin file. It should not be copied unchanged into a child theme, where theme-specific directory functions are more appropriate.
Example 10: Enqueue JavaScript Only in the Administration Area
The admin_enqueue_scripts action is intended for assets used by WordPress administration screens.
Its callback receives a hook suffix identifying the current administration page.
function site_enqueue_dashboard_script( $hook_suffix ) {
if ( 'index.php' !== $hook_suffix ) {
return;
}
wp_enqueue_script(
'site-dashboard-script',
plugin_dir_url( __FILE__ ) .
'assets/js/dashboard.js',
array(),
'1.0.0',
array(
'strategy' => 'defer',
'in_footer' => true,
)
);
}
add_action(
'admin_enqueue_scripts',
'site_enqueue_dashboard_script'
);
The script is loaded only on the standard dashboard screen, whose hook suffix is index.php.
This avoids loading unnecessary JavaScript throughout the administration area.
The example assumes a modern WordPress version supporting the array-based script-loading options.
The specified JavaScript file must exist in the expected directory.
For a custom administration page, use the hook suffix returned by the relevant menu-registration function where possible.
Example 11: Modify the Main Search Query
The pre_get_posts action provides access to the WP_Query object before its database query runs.
The following example restricts the main public search query to standard posts.
function site_search_standard_posts_only( $query ) {
if (
is_admin() ||
! $query->is_main_query() ||
! $query->is_search()
) {
return;
}
$query->set(
'post_type',
'post'
);
}
add_action(
'pre_get_posts',
'site_search_standard_posts_only'
);
The callback does not return a replacement query. It modifies the supplied object.
The is_admin() check excludes administration requests.
The is_main_query() check prevents changes to secondary queries generated by widgets, shortcodes or other components.
The query object’s is_search() method determines whether the current query is a search query.
This distinction matters because global conditional functions can refer to a different query context from the object supplied to the callback.
Developer.WordPress.org
On a website selling digital products, restricting search to standard posts may be undesirable because it excludes pages and other post types. The example should therefore be used only when that behaviour is intentional.
Example 12: Add a Custom Body Class
The body_class filter allows CSS classes to be added to the HTML body element when a theme uses the standard WordPress body-class mechanism.
function site_add_body_class( $classes ) {
if ( is_singular( 'post' ) ) {
$classes[] = 'site-single-article';
}
return $classes;
}
add_filter(
'body_class',
'site_add_body_class'
);
The callback receives an array of classes and returns the modified array.
On single standard post pages, the additional class can be used in CSS:
.site-single-article .entry-content {
line-height: 1.75;
}
The CSS selector assumes the theme has an .entry-content container.
The PHP filter only adds the body class. It does not create or style the content wrapper.
This technique is useful for applying page-specific styling without modifying every article individually.
Creating Custom WordPress Hooks
Developers are not limited to hooks provided by WordPress core.
A custom plugin can expose its own actions and filters, allowing other code to extend its behaviour without modifying the original plugin.
The two functions used to trigger custom hooks are do_action() and apply_filters().
Example 13: Create and Trigger a Custom Action
Suppose a plugin needs to notify other components when an internal operation has completed.
It can expose a custom action:
function site_complete_reference_operation( $reference_id ) {
// Perform the operation here.
do_action(
'site_reference_operation_completed',
$reference_id
);
}
Another component can register a callback:
function site_log_reference_operation( $reference_id ) {
error_log(
'Reference operation completed: ' .
absint( $reference_id )
);
}
add_action(
'site_reference_operation_completed',
'site_log_reference_operation',
10,
1
);
When site_complete_reference_operation() is called, it performs its operation and then triggers the custom action.
Any callbacks already registered to site_reference_operation_completed execute at that point.
The logging example is suitable for controlled debugging; it should not be left generating unnecessary production logs.
The initial function is an integration example, not a complete reference-management system.
A custom action runs only when code explicitly triggers it. Registering the callback does not cause the operation to occur automatically.
Use distinctive hook names to avoid collisions with WordPress core or unrelated plugins.
Example 14: Create a Custom Filter
A custom filter is useful when another component should be able to alter a value before it is used.
function site_get_reference_heading() {
$heading = 'WordPress Reference Library';
return apply_filters(
'site_reference_heading',
$heading
);
}
Other code can modify the heading:
function site_change_reference_heading( $heading ) {
return 'Technical WordPress Resources';
}
add_filter(
'site_reference_heading',
'site_change_reference_heading'
);
Calling site_get_reference_heading() now returns the modified value.
Unlike an action, the filter’s return value is essential. The original function uses the result of apply_filters() rather than ignoring it.
Custom filters can also pass additional context:
$heading = apply_filters(
'site_reference_heading',
$heading,
$reference_id
);
Callbacks can then request two arguments, allowing them to make decisions using the reference ID.
Filters should have a predictable value type. If the calling code expects a string, callback developers should avoid returning an array or object unless the API explicitly permits it.
Removing and Inspecting Registered Hooks
WordPress also provides functions for removing callbacks and checking hook state.
| Function | Purpose |
|---|---|
| remove_action() | Remove a registered action callback |
| remove_filter() | Remove a registered filter callback |
| remove_all_actions() | Remove all callbacks from an action |
| remove_all_filters() | Remove all callbacks from a filter |
| has_action() | Check whether callbacks are registered |
| has_filter() | Check whether filter callbacks are registered |
| did_action() | Count how many times an action has fired |
| doing_action() | Check whether an action is currently executing |
| current_filter() | Obtain the name of the currently executing hook |
| doing_filter() | Check whether a filter is currently executing |
Example 15: Remove an Existing Callback
Suppose a plugin has registered the following callback:
add_action(
'wp_footer',
'site_display_footer_message',
10
);
The callback can be removed with:
remove_action(
'wp_footer',
'site_display_footer_message',
10
);
The hook name, callback identity and priority must match the original registration.
The removal must also occur at the appropriate point during WordPress execution. Removing a callback before it has been registered will not prevent a later registration.
For callbacks belonging to a third-party plugin, inspect its registration point before deciding when to remove them.
Anonymous functions require particular care. A new anonymous function with identical code is not the same callback instance as the original, so it cannot be used to remove the original registration.
Checking Whether a Callback Is Registered
The has_action() and has_filter() functions are useful when investigating plugin conflicts.
$priority = has_action(
'wp_footer',
'site_display_footer_message'
);
if ( false !== $priority ) {
error_log(
'Footer callback registered at priority ' .
(string) $priority
);
}
When a specific callback is supplied, has_action() returns its priority or false if it is not registered.
The strict comparison matters because priority zero is valid and should not be mistaken for an absent callback.
Checking Whether an Action Has Already Fired
The did_action() function returns the number of times a named action has executed.
if ( did_action( 'init' ) > 0 ) {
// The init action has already fired.
}
This is useful when diagnosing code that registers a callback after its intended hook has already run.
However, it should not routinely be used to compensate for incorrect plugin loading or hook registration.
The better solution is usually to register the callback at the correct stage of execution.
Hook Timing and Common Development Mistakes
Hook timing can determine whether otherwise correct code works.
A function registered against init will normally execute during WordPress initialisation. The same function registered against wp_footer will run much later, and only when the relevant template calls that hook.
Some WordPress APIs are intended for particular stages of execution. Registering a custom post type should occur on init; registering a front-end stylesheet should normally occur on wp_enqueue_scripts.
An action also may not execute in every context. A script attached to an administration hook should not be expected to run on a public page.
| Problem | Likely cause | Specific check |
|---|---|---|
| Callback never executes | Wrong hook or registration too late | Confirm when the hook fires |
| PHP argument-count error | Incorrect accepted-argument count | Compare hook signature with callback |
| Filter unexpectedly returns empty content | Missing return statement | Ensure the modified value is returned |
| Custom output appears twice | Callback registered multiple times | Inspect active registrations |
| Custom code affects unrelated pages | Missing conditional checks | Restrict execution context |
| Callback cannot be removed | Wrong priority or callback identity | Match original registration |
| Changes are overwritten | Another filter runs later | Inspect hook priority |
| Post save causes repeated execution | Recursive update | Review calls to wp_update_post() |
| Admin functionality missing | Front-end hook used | Check administration-specific hooks |
| Theme-dependent feature disappears | Code placed in theme | Move persistent functionality into a plugin |
| JavaScript or CSS does not load | Incorrect enqueue hook or file path | Inspect registered assets and URLs |
| Query changes affect widgets | Main-query checks missing | Inspect the supplied WP_Query object |
Debugging Hook Execution
Temporary logging can help establish whether a callback executes.
function site_debug_init_execution() {
if (
defined( 'WP_DEBUG' ) &&
WP_DEBUG
) {
error_log(
'Custom init callback executed'
);
}
}
add_action(
'init',
'site_debug_init_execution'
);
This example uses PHP’s error_log() function. Where the message is written depends on the PHP and server logging configuration.
If WordPress debug logging is configured, relevant output may be available in the configured debug log.
Do not assume that logging to wp-content/debug.log is always enabled or that the path is publicly inaccessible.
Debug logging should be configured carefully and should not expose passwords, authentication tokens, personal information or other sensitive values.
For a recurring event such as init, unrestricted logging can generate substantial output. Remove temporary diagnostic callbacks once the investigation is complete.
Hooks and Security
Hooks are extension points, not security boundaries.
Registering an action does not automatically establish that the current user has permission to perform its operation.
A callback that changes settings, processes requests or modifies protected data must perform the necessary authorisation checks.
The current_user_can() function is used to check WordPress capabilities. Nonces can help protect relevant requests against cross-site request forgery, but they do not replace capability checks.
Input from HTTP requests should be validated and sanitised according to its intended use. Output must be escaped for the context in which it appears.
Filters also require care. A filter may run in several contexts, and unexpectedly returning malformed data can cause failures in unrelated components.
When writing reusable hooks, document the types and meanings of the arguments supplied to callbacks. A consistent hook API makes a plugin easier to extend and reduces compatibility problems.
WordPress Hooks Quick Reference
| Task | Appropriate function or hook |
|---|---|
| Register a callback for an event | add_action() |
| Register a value-modifying callback | add_filter() |
| Execute a custom action | do_action() |
| Apply a custom filter | apply_filters() |
| Control callback execution order | Priority argument |
| Receive additional hook arguments | Accepted-arguments parameter |
| Remove an action callback | remove_action() |
| Remove a filter callback | remove_filter() |
| Check callback registration | has_action() or has_filter() |
| Check whether an action fired | did_action() |
| Register a custom post type | init |
| Add an administration menu | admin_menu |
| Load public CSS or JavaScript | wp_enqueue_scripts |
| Load administration assets | admin_enqueue_scripts |
| Respond to post updates | save_post |
| Modify displayed content | the_content |
| Change excerpt length | excerpt_length |
| Modify a main query | pre_get_posts |
| Add body CSS classes | body_class |
| Modify an existing plugin’s behaviour | Its documented actions or filters |
When selecting a hook, check its purpose, execution context, available arguments and timing. These details determine whether a callback will operate reliably.
For site-specific customisations, keeping hook registrations in a small functionality plugin makes the code easier to maintain independently of the active theme. More substantial plugins should use consistently named callbacks, documented custom hooks and appropriate checks around any operation that modifies data.
