Common WordPress Hooks Reference
Introduction
This is a quick reference guide to the most frequently used WordPress hooks. These are the hooks you'll use in 90% of your WordPress development work.
Hook Categories
WordPress hooks are organized by functionality:
WORDPRESS HOOKS STRUCTURE
=========================
Initialization Hooks
├── plugins_loaded
├── init
├── after_setup_theme
└── wp_loaded
Template Hooks
├── wp_head
├── wp_footer
├── get_header
├── get_sidebar
└── get_footer
Content Hooks (Filters)
├── the_title
├── the_content
├── the_excerpt
└── body_class
Script/Style Hooks
├── wp_enqueue_scripts
├── admin_enqueue_scripts
└── login_enqueue_scripts
Admin Hooks
├── admin_menu
├── admin_init
├── save_post
└── admin_notices
User Hooks
├── user_register
├── wp_login
└── wp_logout
Initialization Hooks
plugins_loaded
Type: Action
When: After all plugins are loaded
Use: Plugin initialization, check for other plugins
add_action('plugins_loaded', 'my_plugin_init');
function my_plugin_init() {
// Check if another plugin is active
if (class_exists('WooCommerce')) {
// Initialize WooCommerce integration
}
// Load text domain for translations
load_plugin_textdomain('my-plugin', false, dirname(plugin_basename(__FILE__)) . '/languages');
}
init
Type: Action
When: WordPress initialization complete
Use: Register post types, taxonomies, shortcodes
add_action('init', 'my_custom_init');
function my_custom_init() {
// Register custom post type
register_post_type('book', [
'public' => true,
'label' => 'Books',
'has_archive' => true,
]);
// Register custom taxonomy
register_taxonomy('genre', 'book', [
'label' => 'Genres',
'hierarchical' => true,
]);
// Register shortcode
add_shortcode('my_shortcode', 'my_shortcode_handler');
}
after_setup_theme
Type: Action
When: After theme is loaded
Use: Theme setup, add theme support
add_action('after_setup_theme', 'my_theme_setup');
function my_theme_setup() {
// Add theme support
add_theme_support('post-thumbnails');
add_theme_support('custom-logo');
add_theme_support('title-tag');
// Register navigation menus
register_nav_menus([
'primary' => 'Primary Menu',
'footer' => 'Footer Menu',
]);
}
wp_loaded
Type: Action
When: Everything is loaded (WordPress, plugins, theme)
Use: Operations requiring everything to be ready
add_action('wp_loaded', 'my_custom_operation');
function my_custom_operation() {
// Everything is loaded, safe to use any WordPress function
if (is_user_logged_in()) {
// Do something for logged-in users
}
}
Frontend Template Hooks
wp_head
Type: Action
When: Inside <head> section before </head>
Use: Add meta tags, inline CSS, tracking codes
add_action('wp_head', 'add_custom_meta_tags');
function add_custom_meta_tags() {
?>
<meta name="author" content="John Doe">
<meta name="description" content="<?php echo get_the_excerpt(); ?>">
<link rel="preconnect" href="https://fonts.googleapis.com">
<?php
}
wp_footer
Type: Action
When: Before closing </body> tag
Use: Add scripts, analytics, modals, pop-ups
add_action('wp_footer', 'add_analytics_code');
function add_analytics_code() {
?>
<script>
// Google Analytics
gtag('config', 'GA_MEASUREMENT_ID');
</script>
<?php
}
get_header
Type: Action
When: After header.php is loaded
Use: Modify header output
add_action('get_header', 'my_header_customization');
function my_header_customization() {
// Add something after header
echo '<div class="site-announcement">Special Offer!</div>';
}
get_sidebar
Type: Action
When: After sidebar.php is loaded
Use: Modify sidebar
add_action('get_sidebar', 'add_sidebar_ad');
function add_sidebar_ad() {
echo '<div class="sidebar-ad">Advertisement</div>';
}
get_footer
Type: Action
When: After footer.php is loaded
Use: Modify footer
add_action('get_footer', 'add_footer_widgets');
function add_footer_widgets() {
dynamic_sidebar('footer-widgets');
}
Content Filters
the_title
Type: Filter
When: Post/page title is displayed
Parameters: $title, $post_id
Use: Modify post titles
add_filter('the_title', 'customize_title', 10, 2);
function customize_title($title, $post_id) {
// Add emoji to product titles
if (get_post_type($post_id) === 'product') {
$title = '🛍️ ' . $title;
}
return $title;
}
the_content
Type: Filter
When: Post content is displayed
Parameters: $content
Use: Modify post content
add_filter('the_content', 'add_content_footer');
function add_content_footer($content) {
// Only on single posts
if (is_single()) {
$footer = '<div class="content-footer">';
$footer .= '<p>Share this article!</p>';
$footer .= '</div>';
$content .= $footer;
}
return $content;
}
the_excerpt
Type: Filter
When: Post excerpt is displayed
Parameters: $excerpt
Use: Modify excerpt
add_filter('the_excerpt', 'custom_excerpt');
function custom_excerpt($excerpt) {
return $excerpt . ' <a href="' . get_permalink() . '">Read More →</a>';
}
excerpt_length
Type: Filter
When: Excerpt length is determined
Parameters: $length
Use: Change excerpt word count
add_filter('excerpt_length', 'custom_excerpt_length');
function custom_excerpt_length($length) {
return 30; // Change from default 55 to 30 words
}
excerpt_more
Type: Filter
When: Excerpt "more" indicator is displayed
Parameters: $more
Use: Change [...] text
add_filter('excerpt_more', 'custom_excerpt_more');
function custom_excerpt_more($more) {
return '... <a href="' . get_permalink() . '" class="read-more">Continue Reading</a>';
}
CSS Class Filters
body_class
Type: Filter
When: Body CSS classes are output
Parameters: $classes (array)
Use: Add custom body classes
add_filter('body_class', 'custom_body_classes');
function custom_body_classes($classes) {
// Add logged-in class
if (is_user_logged_in()) {
$classes[] = 'user-logged-in';
}
// Add browser-specific class
if (strpos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
$classes[] = 'safari';
}
return $classes;
}
post_class
Type: Filter
When: Post CSS classes are output
Parameters: $classes, $class, $post_id
Use: Add custom post classes
add_filter('post_class', 'custom_post_classes', 10, 3);
function custom_post_classes($classes, $class, $post_id) {
// Add featured class if post has thumbnail
if (has_post_thumbnail($post_id)) {
$classes[] = 'has-featured-image';
}
return $classes;
}
Script and Style Hooks
wp_enqueue_scripts
Type: Action
When: Frontend scripts/styles should be enqueued
Use: Add CSS/JS files to frontend
add_action('wp_enqueue_scripts', 'enqueue_custom_assets');
function enqueue_custom_assets() {
// Enqueue stylesheet
wp_enqueue_style(
'custom-style',
get_template_directory_uri() . '/css/custom.css',
[],
'1.0.0'
);
// Enqueue script
wp_enqueue_script(
'custom-script',
get_template_directory_uri() . '/js/custom.js',
['jquery'],
'1.0.0',
true
);
// Pass data to JavaScript
wp_localize_script('custom-script', 'myData', [
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('my-nonce'),
]);
}
admin_enqueue_scripts
Type: Action
When: Admin scripts/styles should be enqueued
Parameters: $hook (current admin page)
Use: Add CSS/JS to admin area
add_action('admin_enqueue_scripts', 'enqueue_admin_assets');
function enqueue_admin_assets($hook) {
// Only load on our custom page
if ($hook !== 'toplevel_page_my-plugin') {
return;
}
wp_enqueue_style('my-admin-style', plugins_url('css/admin.css', __FILE__));
wp_enqueue_script('my-admin-script', plugins_url('js/admin.js', __FILE__));
}
login_enqueue_scripts
Type: Action
When: Login page scripts/styles should be enqueued
Use: Customize login page
add_action('login_enqueue_scripts', 'custom_login_styles');
function custom_login_styles() {
?>
<style>
#login h1 a {
background-image: url('<?php echo get_template_directory_uri(); ?>/images/logo.png');
width: 200px;
height: 100px;
background-size: contain;
}
</style>
<?php
}
Admin Hooks
admin_menu
Type: Action
When: Admin menu is being constructed
Use: Add admin menu pages
add_action('admin_menu', 'add_custom_admin_page');
function add_custom_admin_page() {
add_menu_page(
'My Plugin Settings', // Page title
'My Plugin', // Menu title
'manage_options', // Capability
'my-plugin-settings', // Menu slug
'render_my_plugin_page', // Callback function
'dashicons-admin-generic', // Icon
20 // Position
);
add_submenu_page(
'my-plugin-settings', // Parent slug
'Advanced Settings', // Page title
'Advanced', // Menu title
'manage_options', // Capability
'my-plugin-advanced', // Menu slug
'render_advanced_page' // Callback
);
}
function render_my_plugin_page() {
?>
<div class="wrap">
<h1>My Plugin Settings</h1>
<form method="post" action="options.php">
<?php
settings_fields('my-plugin-settings');
do_settings_sections('my-plugin-settings');
submit_button();
?>
</form>
</div>
<?php
}
admin_init
Type: Action
When: Admin area is initialized
Use: Register settings, redirect, check permissions
add_action('admin_init', 'register_my_settings');
function register_my_settings() {
// Register setting
register_setting('my-plugin-settings', 'my_option');
// Add settings section
add_settings_section(
'my-settings-section',
'General Settings',
'my_settings_section_callback',
'my-plugin-settings'
);
// Add settings field
add_settings_field(
'my-field',
'My Setting',
'my_field_callback',
'my-plugin-settings',
'my-settings-section'
);
}
function my_settings_section_callback() {
echo '<p>Configure your settings below:</p>';
}
function my_field_callback() {
$value = get_option('my_option', '');
echo '<input type="text" name="my_option" value="' . esc_attr($value) . '">';
}
save_post
Type: Action
When: Post is saved
Parameters: $post_id, $post, $update
Use: Save custom data, trigger actions
add_action('save_post', 'save_custom_metadata', 10, 3);
function save_custom_metadata($post_id, $post, $update) {
// Don't save during autosave
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
// Check user permissions
if (!current_user_can('edit_post', $post_id)) {
return;
}
// Check nonce
if (!isset($_POST['my_nonce']) || !wp_verify_nonce($_POST['my_nonce'], 'my_action')) {
return;
}
// Save custom field
if (isset($_POST['custom_field'])) {
update_post_meta($post_id, '_custom_field', sanitize_text_field($_POST['custom_field']));
}
// Clear cache when post is updated
if ($update) {
delete_transient('homepage_posts');
}
}
admin_notices
Type: Action
When: Admin notices should be displayed
Use: Show admin messages
add_action('admin_notices', 'show_custom_notice');
function show_custom_notice() {
$screen = get_current_screen();
if ($screen->id === 'edit-post') {
?>
<div class="notice notice-info is-dismissible">
<p>Welcome to the post editor!</p>
</div>
<?php
}
}
User Hooks
user_register
Type: Action
When: New user is registered
Parameters: $user_id
Use: Set up new user data, send welcome email
add_action('user_register', 'setup_new_user', 10, 1);
function setup_new_user($user_id) {
// Add custom user meta
add_user_meta($user_id, 'registration_date', current_time('mysql'));
// Send welcome email
$user = get_userdata($user_id);
wp_mail(
$user->user_email,
'Welcome to our site!',
'Thank you for registering...'
);
// Add to mailing list
subscribe_to_newsletter($user->user_email);
}
wp_login
Type: Action
When: User logs in
Parameters: $user_login, $user
Use: Track logins, redirect, update data
add_action('wp_login', 'track_user_login', 10, 2);
function track_user_login($user_login, $user) {
// Update last login time
update_user_meta($user->ID, 'last_login', current_time('mysql'));
// Log the login
error_log("User {$user_login} logged in");
// Increment login count
$login_count = get_user_meta($user->ID, 'login_count', true);
update_user_meta($user->ID, 'login_count', $login_count + 1);
}
wp_logout
Type: Action
When: User logs out
Use: Clean up session data, track logouts
add_action('wp_logout', 'handle_user_logout');
function handle_user_logout() {
$user_id = get_current_user_id();
// Update logout time
update_user_meta($user_id, 'last_logout', current_time('mysql'));
// Clear custom session data
delete_user_meta($user_id, 'temp_session_data');
}
Comment Hooks
comment_post
Type: Action
When: Comment is posted
Parameters: $comment_id, $comment_approved
Use: Process comments, notifications
add_action('comment_post', 'notify_on_comment', 10, 2);
function notify_on_comment($comment_id, $comment_approved) {
if ($comment_approved === 1) {
$comment = get_comment($comment_id);
$post = get_post($comment->comment_post_ID);
// Notify post author
wp_mail(
get_the_author_meta('user_email', $post->post_author),
'New comment on your post',
"Someone commented on: {$post->post_title}"
);
}
}
comment_text
Type: Filter
When: Comment text is displayed
Parameters: $comment_text
Use: Modify comment display
add_filter('comment_text', 'highlight_admin_comments');
function highlight_admin_comments($comment_text) {
$comment = get_comment();
if (user_can($comment->user_id, 'administrator')) {
$comment_text = '<div class="admin-comment">' . $comment_text . '</div>';
}
return $comment_text;
}
Widget Hooks
widgets_init
Type: Action
When: Widgets are initialized
Use: Register widget areas, custom widgets
add_action('widgets_init', 'register_custom_sidebars');
function register_custom_sidebars() {
// Register sidebar
register_sidebar([
'name' => 'Footer Sidebar',
'id' => 'footer-sidebar',
'before_widget' => '<div class="widget">',
'after_widget' => '</div>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
]);
// Register custom widget
register_widget('My_Custom_Widget');
}
Query Hooks
pre_get_posts
Type: Action
When: Before posts are queried
Parameters: $query (WP_Query object)
Use: Modify queries
add_action('pre_get_posts', 'modify_main_query');
function modify_main_query($query) {
// Only modify main query on frontend
if (!is_admin() && $query->is_main_query()) {
// Show 20 posts on blog page
if ($query->is_home()) {
$query->set('posts_per_page', 20);
}
// Exclude category from blog
if ($query->is_home()) {
$query->set('cat', '-5'); // Exclude category ID 5
}
}
}
Quick Reference Tables
Most Common Actions
| Hook | When | Common Use |
|---|---|---|
init | WordPress loaded | Register CPTs, taxonomies |
wp_enqueue_scripts | Enqueue time (frontend) | Add CSS/JS |
admin_enqueue_scripts | Enqueue time (admin) | Add admin CSS/JS |
wp_head | In <head> | Meta tags, CSS |
wp_footer | Before </body> | Scripts, analytics |
admin_menu | Building admin menu | Add admin pages |
save_post | Post saved | Save metadata |
user_register | User registered | Welcome email |
wp_login | User logged in | Track login |
Most Common Filters
| Hook | What It Filters | Common Use |
|---|---|---|
the_title | Post title | Modify titles |
the_content | Post content | Add content |
the_excerpt | Post excerpt | Customize excerpt |
body_class | Body CSS classes | Add classes |
post_class | Post CSS classes | Conditional classes |
excerpt_length | Excerpt word count | Change length |
login_redirect | Login redirect URL | Custom redirect |
upload_mimes | Allowed file types | Add file types |
Summary
This reference covers the most essential WordPress hooks. Remember:
- Actions: Use to execute code at specific points
- Filters: Use to modify data before it's used
- Check the WordPress Developer Reference for complete documentation
- Use appropriate hooks for your specific needs
- Always check if you're in the right context (frontend/admin/etc.)