A Platform for
Modern
WordPress Developers

What are WordPress Action Hooks? A Practical Guide
Introduction
If you have ever wanted to learn WordPress action hooks deeply, then this practical guide is exactly for this purpose.
You will learn:
- What action hooks really are and how they work.
- The difference between actions and filters (and why it matters).
- Real-world examples you can use today.
- Advanced techniques like creating custom hooks, debugging, and handling priorities.
- Practice Projects and Resources to master it practically
- Best practices that professional developers rely on.
In simple terms, hooks are points in the WordPress lifecycle where you can attach your own code.
(This guide is all about WordPress action hooks; if you want to understand the Hooks concept and its types first, then read more in our dedicated hooks guide.)
By the end, you will be ready to use action hooks not just for small additions but to build flexible, professional-grade WordPress solutions.
What Are Action Hooks?
Imagine WordPress as a large machine that executes a series of steps every time someone loads a page.
At specific points in that process, WordPress pauses and says: “Hey, do you want to add something here?” Those pause points are called action hooks.
In technical terms, an action hook is a spot in the WordPress lifecycle where developers can insert custom code.
Think of them as “checkpoints” or “plug-in” slots where you can attach extra functionality without editing WordPress core files.
Why does this matter?
Almost everything in WordPress, from displaying a new admin page to registering custom post types, relies on hooks. In fact, plugins and themes are built on top of them.
Mastering hooks means you are no longer limited by what WordPress gives you. Instead, you can unlock limitless possibilities for customization.
For example,
If you want to add a simple message in the footer, you don’t edit or hack the footer file. Instead, you just use the wp_footer action hook like this:
// Hook
add_action( 'wp_footer', 'custom_footer' );
// Callback Function
function custom_footer() {
echo '<p>Hello from the footer!</p>';
};This tiny snippet tells WordPress: “When you reach the footer checkpoint, run my custom function.”
That’s the beauty of action hooks. You can attach your code exactly where it belongs.
How to Add an Action Hook (Step-by-Step Breakdown)
At their core, action hooks are simple. You write a function (called a callback) and then tell WordPress when to run it.
The process always follows two steps:
- Create a callback function: This is where you define what should happen or what you want to do.
- Attach it to a hook – You will use the
add_action()function to connect your callback to a specific WordPress hook.
The add_action() function has four parameters:
$hook_name→ The exact hook where you want to insert code.$callback→ The function name that should run.$priority→ The order in which your function runs (default is 10).$accepted_args→ The number of arguments your function can receive.
Basic structure looks like this:
add_action( $hook_name, $callback_function, $priority, $accepted_args );For example, let’s say you want to add custom text inside a <head> section of your site. You’d use the wp_head action hook like this:
function my_custom_head_text() {
echo 'Custom note added in head';
}
add_action( 'wp_head', 'my_custom_head_text' );When WordPress reaches the wp_head checkpoint, it executes your function without touching the core.
Where & When to Use Action Hooks (Themes vs Plugins)
Once you know how hooks work, the next question is: where do I actually put them for use?
The simplest option is inside your theme’s functions.php file.
This works great for quick edits, like adding a footer message, inserting a script, or any other addition.
But there’s one drawback to it.
If you switch themes, those changes are lost. So, if your edit’s scope is just for one theme, then there is no problem with this way.
Another way or the best practice is to place your hooks inside a plugin. Plugins make your customizations reusable, portable, and safe even if the theme has changed.
In short, you can call hooks wherever you want, either in themes, plugins, or in main or any callable sub-file of themes or plugins.
Here are two common use cases:
Add the Google Analytics script with wp_head:
add_action( 'wp_head', function() {
echo "<script>/* Google Analytics code Snippet here */</script>";
});Enqueue CSS/JS with wp_enqueue_scripts:
function my_enqueue_scripts() {
wp_enqueue_style( 'custom-style', get_stylesheet_uri() );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );Knowing where to place hooks is just as important as knowing how they work.
Real-World Examples of Action Hooks (Bring Hooks to Life)
Now that you know what action hooks are and where to place them.
Let’s look at how they power real-world WordPress functionality.
These examples show how developers use hooks to extend WordPress without hacking the core.
1. wp_login → Track User Login Activity
function log_user_login( $user_login ) {
error_log( "User $user_login logged in at " . date('Y-m-d H:i:s') );
}
add_action( 'wp_login', 'log_user_login' );This hook fires when a user logs in. Our function writes a log entry with the username and timestamp, which will be helpful for tracking user activity.
2. admin_menu → Add Custom Menu in Dashboard
function add_custom_admin_menu() {
add_menu_page( 'Custom Menu', 'My Menu', 'manage_options', 'my-menu', null );
}
add_action( 'admin_menu', 'add_custom_admin_menu' );The admin_menu hook lets you add new menu items to the dashboard. Here, we create a “My Menu” link that site admins can see and use.
3. save_post → Send Notification When a Post Publishes
function notify_on_publish( $post_id ) {
wp_mail( 'admin@example.com', 'New Post Published', 'Post ID: ' . $post_id );
}
add_action( 'save_post', 'notify_on_publish' );Every time a post is saved or published, this hook runs. In this case, it sends an email to the site admin with the post ID.
4. init → Register a Custom Post Type
function my_register_books() {
register_post_type( 'book', [ 'public' => true, 'label' => 'Books' ] );
}
add_action( 'init', 'my_register_books' );The init hook fires when WordPress finishes loading. Here, we use it to register a new custom post type “Books,” which now appears in the admin menu.
These examples show the power of hooks, whether it’s adding features, automating tasks, or customizing admin screens; hooks make it seamless.
How to Find WordPress Action Hooks You Can Use
One of the first challenges beginners face is: “How do I even know which hooks exist?”
Luckily, WordPress gives us multiple ways to discover them.
1. Official Documentation (Most Reliable)
The Plugin API/Action Reference in the WordPress Codex lists hundreds of action hooks properly organized in categories with clear descriptions.
This is the go-to source for finding official information about Action Hooks.
2. Search the WordPress Source Code
Under the hood, action hooks are created with the do_action() function.
By searching the WordPress source code for do_action, you can see exactly where hooks are placed.
This method is great when you want to understand hooks at the code level.
3. Debugging Plugins (Beginner-Friendly)
Tools like Query Monitor make hooks visible as they fire on your site.
Instead of digging through files, you can watch hooks in action and know exactly where to attach your code.
Hook Priority & Multiple Actions with one Hook (Controlling Execution Order)
Sometimes, more than one function is hooked into the same action hook.
That’s where priority comes in, which is an optional parameter of the add_action() function.
By default, WordPress assigns a priority of 10, meaning all functions run in the order they were added. But you can adjust this number to control when your function executes.
For example, here are two functions hooked into wp_footer:
function footer_message_one() {
echo '<p>First message</p>';
}
add_action( 'wp_footer', 'footer_message_one', 5 );
function footer_message_two() {
echo '<p>Second message</p>';
}
add_action( 'wp_footer', 'footer_message_two', 15 );Here, footer_message_one runs before footer_message_two because its priority is higher (5). The smaller the number, the higher the priority given to it.
This is especially useful when multiple plugins or themes try to use the same hook. By adjusting priority, you control the order of execution and prevent conflicts.
Passing Arguments to Action Hooks (Working with Dynamic Data)
One of the most powerful features of action hooks is that they can pass useful data (arguments) to your callback function.
This means you are not just running code blindly, but you get access to details like post IDs, user information, or even database query objects.
For example, the save_post hook automatically passes the ID of the post being saved:
function log_saved_post( $post_id ) {
error_log( "Post $post_id saved successfully!" );
}
add_action( 'save_post', 'log_saved_post' );Here, every time a post is saved, the ID is logged because of this action hook.
So, the fourth parameter in add_action() is $accepted_args, which tells WordPress how many arguments your function expects.
This is used for the purpose of passing arguments to callback functions
For instance, save_post can pass three values: $post_id, $post, and $update.
function detailed_log( $post_id, $post, $update ) {
error_log( "Post {$post->post_title} updated: " . ($update ? 'Yes' : 'No') );
}
add_action( 'save_post', 'detailed_log', 10, 3 );This way, you can capture more detailed information directly from hooks.
Creating Your Own Custom Action Hook (Make Your Code Extensible)
So far, we have been using WordPress’s built-in hooks.
But you can also create your own custom hooks.
This is especially useful when you are developing your own plugins or themes that you want others (or even your future self) to extend without editing the original code.
The syntax is simple:
do_action( 'my_custom_hook', $variable );This line acts as a trigger point. Anywhere you place it, other developers can “hook into” it with their own functions at the same point where you add this line.
For example, let’s say you are building a form plugin. After a user submits the form, you could fire a custom hook like this:
do_action( 'my_plugin_after_form_submit', $user_id );Now, any developer can attach custom functions to run after form submission, like sending an email, logging activity, or awarding points.
Creating custom hooks makes your code more modular, extendable, flexible, and developer-friendly.
Action Hook Related Functions (Complete Toolkit for Developers)
When you start building advanced plugins or themes, it’s not enough to just add functions to hooks. But you will also want to inspect, remove, or control their execution flow.
WordPress provides several built-in functions for managing action hooks.
1. do_action() – Trigger a Hook
This function is used to create a custom hook and executes all callbacks attached to this specific action hook.
Without it, the hook won’t run. Developers place do_action() inside their code to create extensibility points.
// Fire a custom action so other plugins/themes can hook into it.
do_action( 'my_custom_hook' );Think of it as broadcasting an event that others can listen to.
2. add_action() – Attach a Callback
Registers your callback function to a hook so it executes when the hook is fired.
You can also control priority and how many arguments your function accepts.
function greet_on_init() {
echo "Hello, WordPress!";
}
add_action( 'init', 'greet_on_init', 10, 0 );This is the entry point for adding functionality to WordPress events.
3. has_action() – Check if Hook Has Functions
Sometimes you want to verify if a hook already has callbacks before attaching another one.
This is used to avoid duplicates or conflicts.
if ( has_action( 'init', 'greet_on_init' ) ) {
echo 'The greet_on_init function is already hooked!';
}Helpful for debugging or conditionally attaching/removing actions.
4. do_action_ref_array() – Pass Arguments as Array
Similar to do_action(), but instead of passing arguments individually, you provide them as an array.
Useful when you don’t know the argument count at runtime.
$args = [ 'Admin 1', 'Admin 2' ];
do_action_ref_array( 'user_registered', $args );Ideal for dynamic arguments or when arguments are stored in an array.
5. remove_action() – Remove a Specific Callback
Sometimes you need to unhook a function that WordPress or another plugin has already added.
remove_action( 'init', 'greet_on_init' );This gives you control over third-party code that interferes with your logic.
6. remove_all_actions() – Clear All Functions from a Hook
Removes every single function attached to a hook. Use with caution, as it wipes out both your code and third-party callbacks.
remove_all_actions( 'wp_footer' );Useful in cases where you want a completely clean slate.
7. current_action() – See Which Hook is Running
Returns the name of the hook currently executing. Helpful when debugging inside a shared callback.
function check_hook() {
echo 'Currently running: ' . current_action();
}
add_action( 'init', 'check_hook' );Great when your function is hooked to multiple actions, but you need to behave differently depending on the hook.
8. did_action() – Count How Many Times a Hook Fired
Tracks how many times a specific hook has already run.
add_action( 'init', function() {
echo 'Init ran ' . did_action( 'init' ) . ' times.';
});Perfect for testing hook execution order or preventing duplicate runs.
9. doing_action() – Is a Hook Running Now?
Checks whether a given hook is currently executing.
if ( doing_action( 'init' ) ) {
echo 'Init is in progress!';
}Useful for conditional logic that should only run while a hook is active.
Together, these functions give you total mastery over hooks. You can add, remove, inspect, and control execution flow.
Think of them as your ultimate toolkit and power tools when scaling from beginner WordPress development to advanced plugin architecture.
Advanced Use Cases of Action Hooks
Once you have mastered the fundamentals, the real power of action hooks comes alive in advanced scenarios.
These techniques separate beginner-level customizations from advanced plugin and theme development.
Activation & Deactivation Hooks
Run setup/cleanup tasks when your plugin activates or deactivates:
register_activation_hook( __FILE__, 'my_plugin_activate' );
register_deactivation_hook( __FILE__, 'my_plugin_deactivate' );Essential for database setup, flushing rewrite rules, or cleanup.
Removing Actions
Sometimes you don’t want a default WordPress feature (or another plugin’s function) to run. So, remove_action() lets you surgically disable it:
// Removes WP version tag
remove_action( 'wp_head', 'wp_generator' );Great for cleaning up markup or overriding default functions.
Removing All Callbacks
Need a completely fresh start? remove_all_actions() wipes a hook clean:
remove_all_actions( 'wp_footer' );Useful when you want full control over an area, like the footer.
Determining the Current Hook
When the same function is attached to multiple hooks, current_action() helps you detect which one is running:
function my_logger() {
error_log( 'Now running: ' . current_action() );
}
add_action( 'init', 'my_logger' );
add_action( 'wp_footer', 'my_logger' );Helps in multi-hook functions.
Checking How Many Times a Hook Has Run
did_action() counts executions:
echo did_action( 'init' ); // 1 (after init runs once)Perfect for avoiding duplicate logic.
Debugging with the “all” Hook
The special hook fires on every single action.
add_action( 'all', function( $hook ) {
error_log( "Hook fired: $hook" );
});Powerful for debugging, but don’t leave it active in production.
Conditional Actions
Attach hooks only on certain pages or templates:
if ( is_page( 'contact' ) ) {
add_action( 'wp_footer', 'add_tracking_code' );
}Keeps your code lightweight and context-aware.
Dynamic Hooks
WordPress often builds hook names dynamically. Example:
do_action( "save_post_{$post->post_type}", $post->ID );Let’s you target specific post types with precision.
Nested Hooks
You can even add/remove hooks inside other hooks:
add_action( 'init', function() {
remove_action( 'wp_footer', 'old_footer_code' );
});Useful for conditional overrides or runtime changes.
By combining these techniques, you move from simply “using WordPress” to controlling WordPress at its core, giving you unmatched flexibility for custom solutions.
Debugging Action Hooks
Even experienced developers get stuck when a hook doesn’t seem to fire. That’s why learning to debug action hooks is essential.
First, enable debugging in your wp-config.php:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );This way, you will capture hook-related errors in the debug.log.
Next, use the special all hook to watch every hook WordPress fires:
add_action( 'all', function( $hook ) {
error_log( "Hook triggered: $hook" );
});This is like turning on “night vision” to see what’s happening under the hood.
For more structured debugging, tools like Query Monitor and Debug Bar let you inspect hooks in real time from the WordPress dashboard.
Example: if save_post isn’t running, log it:
add_action( 'save_post', fn($id) => error_log("save_post fired for $id") );With these techniques, you’ll quickly track down why a hook isn’t behaving as expected.
Common & Useful Action Hooks
By now, you understand how hooks work, but which ones should you actually use in real projects?
Let’s cover the most commonly used action hooks that every WordPress developer relies on:
Front-end hooks:
wp_head→ Insert code or scripts in the<head>section.wp_footer→ Add scripts, tracking codes, or custom HTML before the closing</body>.wp_enqueue_scripts→ Safely load CSS and JavaScript files.
Admin hooks:
admin_menu→ Create custom menus inside the WordPress dashboard.admin_init→ Run code when the admin area initializes (great for registering settings).
Content hooks:
save_post→ Perform actions whenever a post is saved or updated.the_post→ Modify or extend post content before it’s displayed.
Login/User hooks:
wp_login→ Trigger actions on successful login (e.g., log activity).user_register→ Run code when a new user account is created.
For a complete list, check the WordPress Action Hook Reference.
Practice Projects to Master Action Hooks
Now, you fully understand the action hooks, so it’s time to build small and practical projects to gain hands-on experience. Here are four ideas to get you started:
- Custom Post Type Registration – Use the
inithook to create a new post type (e.g., “Recipes”). - Post Save Notification – With
save_post, send yourself an email whenever a new post is published. - User Login Tracker – Hook into
wp_loginto log usernames and login times for basic activity tracking. - Dashboard Custom Menu – Use
admin_menuto add a custom settings page inside the WordPress admin and also add sub-pages under this admin page.
These mini-projects reinforce your understanding and prepare you for real-world plugin development.
Best Practices for Using Action Hooks
To keep your code clean, conflict-free, and developer-friendly, follow these best practices:
- Prefix your functions (e.g.,
myplugin_custom_action) to avoid naming collisions with themes or plugins. - Keep functions small and modular, focusing on one task for easier debugging and reusability.
- Document your custom hooks with comments so other developers (or your future self) understand how to use them.
- Use priority carefully when attaching functions to avoid overwriting critical actions.
- Remove hooks when they are no longer needed because this keeps your site lightweight and prevents unexpected behavior.
Additional Resources
If you want to go deeper into WordPress action hooks, here’s a curated list of resources you can bookmark:
- Hooks – WP Developer Handbook – The official guide to understand action hooks.
- WordPress Codex – Action Hooks Reference – Organized references of available hooks.
- WordPress Code Reference – Searchable source for all core functions, classes, and hooks.
- Adam R Brown’s Hooks Index – Community-maintained index of every WordPress hook.
- Query Monitor Plugin – A must-have debugging tool to inspect hooks in real time.
- Popular WP Blogs & Tutorials – Sites like WPBeginner, Torque, and WPShout regularly publish developer-friendly guides.
With these resources, you will never feel “stuck” when working with hooks.
Conclusion & Next Steps
Action hooks are truly the backbone of WordPress extensibility.
From injecting a simple line of text in your footer to building enterprise-grade plugins, they give you the power to customize WordPress without ever touching the core files.
Once you have mastered them, the platform feels limitless because you are no longer constrained.
Instead, you can do anything from simple edits to custom features and ultimately theme and plugin development.
But this is only half the story. If action hooks perform tasks, then filter hooks modify data. To become a complete WordPress developer, you will need to explore filters next.
So, read our guide on WordPress Filter Hooks to understand the full picture of hooks.
👉 Want more? Subscribe to our newsletter and get exclusive tutorials, strategies, developer resources, and the latest WordPress news delivered right to your inbox.


