Hooks (Actions / Filters)
WordPress hooks are extension points: add_action runs your callback at a named event; add_filter transforms a value as it passes through the system. Hooks are how every plugin, theme, and admin tweak modifies WP without forking it.
Real action + filter recipes
EXAMPLE
<?php
// 1) Action — run at a named moment
add_action('init', function () {
register_post_type('product', [
'public' => true,
'label' => 'Products',
'supports' => ['title', 'editor', 'thumbnail', 'excerpt'],
'show_in_rest' => true, // enables Gutenberg + REST API
]);
});
// 2) Action — enqueue scripts/styles on the front-end
add_action('wp_enqueue_scripts', function () {
wp_enqueue_style(
'theme',
get_stylesheet_directory_uri() . '/style.css',
[],
wp_get_theme()->get('Version'),
);
wp_enqueue_script(
'app',
get_stylesheet_directory_uri() . '/app.js',
['wp-element'],
wp_get_theme()->get('Version'),
true, // in footer
);
});
// 3) Action — admin notice on Settings page
add_action('admin_notices', function () {
if (!current_user_can('manage_options')) return;
echo '<div class="notice notice-warning is-dismissible"><p>Don’t forget to set your API key.</p></div>';
});
// 4) Filter — transform a value
add_filter('the_content', function ($content) {
if (!is_singular('post')) return $content;
return $content . '<p class="share"><a href="#">Share this post</a></p>';
}, 20);
// 5) Filter — change excerpt length
add_filter('excerpt_length', fn() => 30);
add_filter('excerpt_more', fn($more) => ' …');
// 6) Filter — modify the WP_Query for the main loop
add_action('pre_get_posts', function ($q) {
if (is_admin() || !$q->is_main_query()) return;
if (is_home()) {
$q->set('posts_per_page', 12);
$q->set('post_type', ['post', 'product']);
}
});
// 7) Filter — sanitise/transform incoming form data on save
add_filter('pre_update_option_site_url', fn($v) => esc_url_raw(trim($v)));
// 8) Hook priority + acceptable args
add_filter('the_title', 'my_title_filter', 10, 2);
function my_title_filter($title, $post_id) {
return get_post_type($post_id) === 'product' ? '🛒 ' . $title : $title;
}
// 9) Remove a hook — defuse a plugin's bad behaviour
remove_action('wp_head', 'wp_generator'); // hide WP version
remove_filter('the_content', 'wpautop'); // turn off auto-paragraphs
// 10) Run code once per request — protect against double-firing
add_action('save_post_product', function ($post_id, $post, $update) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if ($post->post_status !== 'publish') return;
// safe to do work here
}, 10, 3);
// 11) Discovery — find every hook a page fires
// Tools: Query Monitor (plugin), `wp hook list` (WP-CLI), `do_action_ref_array` calls in source
// 12) Custom hook — let other code extend YOURS
do_action('my_plugin_after_user_signup', $user_id);
$message = apply_filters('my_plugin_welcome_subject', 'Welcome to ' . get_bloginfo('name'));
Why it matters
Hooks are how WordPress stays small. Any plugin that wants to extend behaviour should be using add_action / add_filter — never editing core files. The cost: read your hooks list with Query Monitor to know what’s actually firing.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Actions — do something at a moment.
add_action('init', 'my_init');
// Filters — transform a value.
add_filter('the_title', fn($t) => strtoupper($t));
Try it Yourself »
Exercise
Hook type that lets you modify a value.
Starts with F.
Discussion
Loading…