Actions

Actions let you execute code at specific points in WordPress. They don’t return values — they fire and trigger side effects.

wp_head

head-meta

Outputs content in the <head> section

wp_head is the print slot inside document head. Use it for meta tags and inline snippets — not for enqueueing CSS or JS files.

Signature

do_action( 'wp_head' );

Example

add_action( 'wp_head', function() {
    echo '<meta name="theme-color" content="#0073aa">';
} );

Common Use Cases

  • Enqueue custom meta tags
  • Output inline styles or scripts
  • Add Open Graph / SEO tags
  • Insert tracking pixels
since 1.5.0wp-includes/general-template.php

wp_footer

head-meta

Fires before </body> closing tag

wp_footer is the last print slot on the front-end. Deferred scripts, analytics, and widgets that must load after content belong here.

Signature

do_action( 'wp_footer' );

Example

add_action( 'wp_footer', function() {
    echo '<script>console.log("Footer loaded");</script>';
} );

Common Use Cases

  • Inject deferred JavaScript
  • Add analytics snippets
  • Load chat widgets
  • Output footer-specific markup
since 1.5.1wp-includes/general-template.php

init

bootstrap

Runs after WordPress has finished loading

init is the default place to register post types, taxonomies, and rewrite-related APIs. It fires after plugins are loaded and before headers go out.

Signature

do_action( 'init' );

Example

add_action( 'init', function() {
    register_post_type( 'book', [
        'public' => true,
        'label'  => 'Books',
    ] );
} );

Common Use Cases

  • Register custom post types
  • Register custom taxonomies
  • Start sessions
  • Load text domains (plugins)
since 0.71wp-settings.php

wp_enqueue_scripts

enqueue

The correct hook to enqueue frontend assets

Queue front-end CSS and JS here. WordPress prints the tags during wp_head / wp_footer — do not echo link or script tags yourself.

Signature

do_action( 'wp_enqueue_scripts' );

Example

add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_style( 'my-style', get_stylesheet_uri() );
    wp_enqueue_script( 'my-script', get_template_directory_uri() . '/js/main.js', [], '1.0', true );
} );

Common Use Cases

  • Enqueue theme stylesheet
  • Load JavaScript libraries
  • Conditionally load assets per page
  • Pass PHP data to JS via wp_localize_script
  • Migrate off bundled jQuery (deprecated direction in core) toward vanilla JS or a bundler
since 2.1.0wp-includes/script-loader.php

save_post

save-crud

Fires after a post is saved or updated

save_post runs after WordPress writes the post row. Use it for caches, sync, and derived data — and always guard against autosave, revisions, and infinite loops.

Signature

do_action( 'save_post', int $post_id, WP_Post $post, bool $update );

Example

add_action( 'save_post', function( $post_id, $post ) {
    if ( $post->post_type !== 'book' ) {
        return;
    }
    delete_transient( 'book_list_' . $post_id );
}, 10, 2 );

Common Use Cases

  • Clear caches after post update
  • Send admin email notifications
  • Sync data to external APIs
  • Auto-generate related records
  • Queue heavy sync/recalculation work instead of running it inline on large tables
since 1.5.0wp-includes/post.php

admin_init

admin

Fires at the beginning of every admin page

admin_init is the admin counterpart to init: settings, redirects, and capability checks that must not run on the front-end.

Signature

do_action( 'admin_init' );

Example

add_action( 'admin_init', function() {
    register_setting( 'my_options_group', 'my_option_name' );
} );

Common Use Cases

  • Register plugin settings
  • Redirect non-admin users
  • Handle admin form submissions
  • Add admin notices conditionally
since 2.0.0wp-admin/admin.php

plugins_loaded

bootstrap

Fires once all active plugins have loaded

plugins_loaded is the earliest point where every active plugin's functions and classes are guaranteed to exist — use it for cross-plugin checks, not for registering WordPress objects.

Signature

do_action( 'plugins_loaded' );

Example

add_action( 'plugins_loaded', function() {
    if ( class_exists( 'WooCommerce' ) ) {
        require_once __DIR__ . '/integrations/woocommerce.php';
    }
} );

Common Use Cases

  • Check if another plugin/class exists
  • Load plugin translations
  • Bootstrap plugin dependencies
  • Set up autoloaders
since 1.5.0wp-settings.php

wp_loaded

bootstrap

Fires once WordPress, plugins, and theme are fully loaded

wp_loaded runs after every init callback has finished — use it when your code depends on things other plugins register on init.

Signature

do_action( 'wp_loaded' );

Example

add_action( 'wp_loaded', function() {
    if ( ! post_type_exists( 'book' ) ) {
        return;
    }
    flush_rewrite_rules();
} );

Common Use Cases

  • Read config set by other plugins on init
  • Conditional logic that depends on registered post types/taxonomies
  • Late-stage bootstrap checks
since 3.0.0wp-settings.php

after_setup_theme

bootstrap

Fires after the theme is loaded, before init

after_setup_theme is where themes declare support for core features — post thumbnails, menus, HTML5 markup — before WordPress finishes bootstrapping.

Signature

do_action( 'after_setup_theme' );

Example

add_action( 'after_setup_theme', function() {
    add_theme_support( 'post-thumbnails' );
    add_theme_support( 'title-tag' );
    register_nav_menus( [ 'primary' => 'Primary Menu' ] );
} );

Common Use Cases

  • Declare add_theme_support() features
  • Register nav menu locations
  • Set content width
  • Load theme text domain
since 2.6.0wp-settings.php

widgets_init

bootstrap

Fires when it's time to register widgets and sidebars

widgets_init is exclusively for register_sidebar() and register_widget() calls — nothing else belongs here.

Signature

do_action( 'widgets_init' );

Example

add_action( 'widgets_init', function() {
    register_sidebar( [
        'name' => 'Footer Widgets',
        'id'   => 'footer-widgets',
        'before_widget' => '<div class="widget %2$s">',
        'after_widget'  => '</div>',
    ] );
} );

Common Use Cases

  • Register sidebar/widget areas
  • Register custom WP_Widget classes
  • Unregister default widgets
since 2.2.0wp-includes/widgets.php

admin_enqueue_scripts

enqueue

The correct hook to enqueue admin-only assets

admin_enqueue_scripts is the admin equivalent of wp_enqueue_scripts — always check $hook_suffix so you don't load your CSS/JS on every admin screen.

Signature

do_action( 'admin_enqueue_scripts', string $hook_suffix );

Example

add_action( 'admin_enqueue_scripts', function( $hook_suffix ) {
    if ( 'post.php' !== $hook_suffix ) {
        return;
    }
    wp_enqueue_script( 'my-admin-js', plugins_url( 'admin.js', __FILE__ ), [ 'jquery' ], '1.0', true );
} );

Common Use Cases

  • Enqueue admin CSS/JS scoped to one screen
  • Load a color picker or media uploader script
  • Pass data to admin JS via wp_localize_script
since 2.8.0wp-admin/admin-header.php

template_redirect

loop-content

Fires right before WordPress decides which template to load

template_redirect is the standard place to short-circuit a request — custom redirects, maintenance mode, or blocking access — after the query is known but before any template file loads.

Signature

do_action( 'template_redirect' );

Example

add_action( 'template_redirect', function() {
    if ( is_page( 'old-page' ) ) {
        wp_safe_redirect( home_url( '/new-page/' ), 301 );
        exit;
    }
} );

Common Use Cases

  • Custom redirects based on conditional tags
  • Block access / maintenance mode
  • Serve a custom response instead of a template (e.g. JSON)
  • Force login on specific pages
since 1.5.0wp-includes/template-loader.php

pre_get_posts

loop-content

Modify any WP_Query before it runs

pre_get_posts fires for every query — main and secondary. Always check is_main_query() (and is_admin()) or you'll silently break widgets, related-post queries, and REST requests.

Signature

do_action( 'pre_get_posts', WP_Query $query );

Example

add_action( 'pre_get_posts', function( $query ) {
    if ( ! is_admin() && $query->is_main_query() && is_post_type_archive( 'book' ) ) {
        $query->set( 'posts_per_page', 24 );
    }
} );

Common Use Cases

  • Change posts_per_page for an archive
  • Include/exclude post types from search
  • Reorder posts on a custom query
  • Restrict a query by taxonomy or meta
since 2.0.0wp-includes/class-wp-query.php

wp_insert_post

save-crud

Fires immediately after a post is inserted or updated in the database

wp_insert_post looks like save_post but fires from every wp_insert_post() call, including programmatic inserts that never touch the block editor.

Signature

do_action( 'wp_insert_post', int $post_id, WP_Post $post, bool $update );

Example

add_action( 'wp_insert_post', function( $post_id, $post, $update ) {
    if ( 'book' !== $post->post_type || $update ) {
        return;
    }
    wp_mail( get_option( 'admin_email' ), 'New book added', get_the_title( $post_id ) );
}, 10, 3 );

Common Use Cases

  • Notify on new post creation (not updates)
  • React to programmatic/import inserts
  • Sync newly created posts to an external system
since 1.2.0wp-includes/post.php

transition_post_status

save-crud

Fires whenever a post's status changes

transition_post_status is the only hook that reliably tells you a status changed — including the old value — which save_post cannot do.

Signature

do_action( 'transition_post_status', string $new_status, string $old_status, WP_Post $post );

Example

add_action( 'transition_post_status', function( $new_status, $old_status, $post ) {
    if ( 'publish' === $new_status && 'publish' !== $old_status ) {
        wp_mail( get_option( 'admin_email' ), 'Post published', get_the_title( $post ) );
    }
}, 10, 3 );

Common Use Cases

  • Detect draft-to-publish transitions
  • Log status change history
  • Trigger workflows on unpublish/trash
  • Build scheduled-publish notifications
since 2.3.0wp-includes/post.php

admin_menu

admin

Fires before the admin menu is rendered — register menu pages here

admin_menu is exclusively for add_menu_page() / add_submenu_page() calls; anything else belongs on admin_init.

Signature

do_action( 'admin_menu' );

Example

add_action( 'admin_menu', function() {
    add_menu_page( 'My Plugin', 'My Plugin', 'manage_options', 'my-plugin', 'my_plugin_render_page', 'dashicons-admin-generic', 66 );
} );

Common Use Cases

  • Register top-level or submenu admin pages
  • Remove default menu items for non-admins
  • Reorder menu items
since 1.5.0wp-admin/menu.php

admin_notices

admin

Fires to print admin notices at the top of admin pages

admin_notices runs on every admin screen — always check current_user_can() or a specific screen ID so your notice doesn't nag every user on every page.

Signature

do_action( 'admin_notices' );

Example

add_action( 'admin_notices', function() {
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }
    echo '<div class="notice notice-warning"><p>Please configure My Plugin.</p></div>';
} );

Common Use Cases

  • Show setup/configuration warnings
  • Confirm a settings save succeeded
  • Prompt for a plugin update or license key
  • Surface validation errors after form submit
since 3.1.0wp-admin/admin-header.php

wp_login

auth

Fires after a user has successfully logged in

wp_login fires only on a successful authentication — pair it with wp_login_failed to cover both outcomes.

Signature

do_action( 'wp_login', string $user_login, WP_User $user );

Example

add_action( 'wp_login', function( $user_login, $user ) {
    update_user_meta( $user->ID, 'last_login', current_time( 'mysql' ) );
}, 10, 2 );

Common Use Cases

  • Track last login time
  • Redirect users by role after login
  • Log login events for security auditing
  • Trigger welcome logic on first login
since 1.5.1wp-includes/user.php

user_register

auth

Fires immediately after a new user is registered

user_register fires right after wp_insert_user() writes the row — the account exists but you're still inside the registration request, which matters for redirects and emails.

Signature

do_action( 'user_register', int $user_id, array $userdata );

Example

add_action( 'user_register', function( $user_id ) {
    $user = new WP_User( $user_id );
    $user->set_role( 'subscriber' );
    wp_mail( $user->user_email, 'Welcome!', 'Thanks for registering.' );
} );

Common Use Cases

  • Send welcome emails
  • Assign a default role
  • Sync new users to a CRM/mailing list
  • Set default user meta on signup
since 2.0.0wp-includes/user.php

rest_api_init

rest-api

Fires when the REST API is initialized — register custom routes here

rest_api_init is the register_rest_route() equivalent of init — it only fires on REST requests, not every page load.

Signature

do_action( 'rest_api_init', WP_REST_Server $wp_rest_server );

Example

add_action( 'rest_api_init', function() {
    register_rest_route( 'my-plugin/v1', '/books', [
        'methods'  => 'GET',
        'callback' => 'my_plugin_get_books',
        'permission_callback' => '__return_true',
    ] );
} );

Common Use Cases

  • Register custom REST routes
  • Expose extra fields on existing endpoints via register_rest_field
  • Add custom REST authentication logic
since 4.4.0wp-includes/rest-api.php

wp_logout

auth

Fires after a user logs out

wp_logout is the mirror of wp_login — use it to clear per-user cookies, caches, or add custom redirect logic.

Signature

do_action( 'wp_logout', int $user_id );

Example

add_action( 'wp_logout', function( $user_id ) {
    delete_transient( 'user_session_' . $user_id );
} );

Common Use Cases

  • Clear custom cookies or transients on logout
  • Log a security/audit event
  • Redirect to a custom page after logout
  • Invalidate a cached per-user fragment
since 1.5.1wp-includes/pluggable.php

comment_post

comments

Fires immediately after a comment is inserted

comment_post fires right after a new comment saves — the standard place to trigger notifications or moderation logic.

Signature

do_action( 'comment_post', int $comment_id, int|string $comment_approved, array $comment_data );

Example

add_action( 'comment_post', function( $comment_id, $approved ) {
    if ( 1 === $approved ) {
        wp_mail( get_option( 'admin_email' ), 'New comment', 'A comment was just approved.' );
    }
}, 10, 2 );

Common Use Cases

  • Send custom notification emails
  • Auto-flag suspicious comments for review
  • Sync comments to an external system
  • Award points/badges for commenting
since 1.2.0wp-includes/comment.php

wp_insert_comment

comments

Fires right after a comment row is written to the database

wp_insert_comment is the lower-level sibling of comment_post — it fires for every comment insert, including ones triggered programmatically, not just front-end submissions.

Signature

do_action( 'wp_insert_comment', int $id, WP_Comment $comment );

Example

add_action( 'wp_insert_comment', function( $id, $comment ) {
    error_log( 'New comment #' . $id . ' on post ' . $comment->comment_post_ID );
}, 10, 2 );

Common Use Cases

  • React to comments created via REST API or import scripts, not just the comment form
  • Sync a WP_Comment object right after creation
  • Trigger downstream logic that needs the full comment object rather than raw array data
since 2.8.0wp-includes/comment.php

enqueue_block_editor_assets

enqueue

Loads scripts/styles inside the block editor only

enqueue_block_editor_assets is the block-editor-only counterpart to wp_enqueue_scripts — it never runs on the public front-end.

Signature

do_action( 'enqueue_block_editor_assets' );

Example

add_action( 'enqueue_block_editor_assets', function() {
    wp_enqueue_script(
        'my-block-editor-script',
        get_template_directory_uri() . '/js/editor.js',
        [ 'wp-blocks', 'wp-element', 'wp-editor' ],
        '1.0'
    );
} );

Common Use Cases

  • Load custom block registration JS
  • Add editor-only CSS for custom blocks
  • Register a Gutenberg sidebar plugin
  • Load third-party editor extensions
since 5.0.0wp-includes/script-loader.php

before_delete_post

save-crud

Fires right before a post is permanently deleted

before_delete_post is your last chance to act while the post (and its data) still exists — right after this, wp_delete_post() removes the row for good.

Signature

do_action( 'before_delete_post', int $post_id, WP_Post $post );

Example

add_action( 'before_delete_post', function( $post_id, $post ) {
    if ( 'book' !== $post->post_type ) {
        return;
    }
    global $wpdb;
    $wpdb->delete( $wpdb->prefix . 'book_ratings', [ 'post_id' => $post_id ] );
}, 10, 2 );

Common Use Cases

  • Clean up custom database rows tied to a post
  • Delete associated generated/uploaded files
  • Sync the deletion to an external system
  • Log permanent deletions for an audit trail
since 1.2.0wp-includes/post.php

enqueue_block_assets

enqueue

Loads scripts/styles in both the block editor and the front-end

enqueue_block_assets is the one enqueue hook that runs in both places — the block editor and the public front-end — making it the right spot for a block's own shared styling.

Signature

do_action( 'enqueue_block_assets' );

Example

add_action( 'enqueue_block_assets', function() {
    wp_enqueue_style( 'my-block-style', get_template_directory_uri() . '/css/block.css' );
} );

Common Use Cases

  • Load a custom block's CSS so it looks right in the editor and on the front-end
  • Share fonts/variables between editor preview and rendered output
  • Avoid duplicating enqueue code across wp_enqueue_scripts and enqueue_block_editor_assets
since 5.0.0wp-includes/script-loader.php

Filters

Filters let you modify data before WordPress uses or displays it. They always receive a value and must return it (modified or not).

apply_filters( $hook, $value, …$args )

the_content

loop-content

Filters post content before display

the_content is the last chance to change post HTML before it reaches the template. Always return the string — filters that echo will break the page.

Signature

apply_filters( 'the_content', string $content );

Example

add_filter( 'the_content', function( $content ) {
    if ( is_single() ) {
        $content .= '<p><strong>Thanks for reading!</strong></p>';
    }
    return $content;
} );

Common Use Cases

  • Append/prepend content to posts
  • Transform shortcodes manually
  • Add schema markup to content
  • Strip or sanitize specific HTML
since 0.71wp-includes/post-template.php

the_title

loop-content

Filters the post title

the_title changes how a title is displayed, not the value in the database. Guard with post ID so menus and admin lists are not rewritten by accident.

Signature

apply_filters( 'the_title', string $title, int $id );

Example

add_filter( 'the_title', function( $title, $id ) {
    if ( get_post_type( $id ) === 'book' ) {
        return 'Book: ' . $title;
    }
    return $title;
}, 10, 2 );

Common Use Cases

  • Prefix/suffix titles by post type
  • Truncate long titles
  • Add icons or labels to titles
  • Translate titles dynamically
since 0.71wp-includes/post-template.php

wp_title

head-meta

Filters the document <title> tag

wp_title is the classic document-title filter. Modern themes should prefer document_title_parts — this hook remains for older title tags.

Signature

apply_filters( 'wp_title', string $title, string $sep, string $seplocation );

Example

add_filter( 'wp_title', function( $title, $sep ) {
    return $title . $sep . get_bloginfo( 'name' );
}, 10, 2 );

Common Use Cases

  • Customize SEO page titles on legacy themes
  • Append site name to titles
  • Set title format for specific pages
  • Override title for 404 pages
since 0.71wp-includes/general-template.php

body_class

head-meta

Filters the CSS classes on <body>

body_class lets CSS target context without extra wrappers. Return the array — do not echo class names.

Signature

apply_filters( 'body_class', string[] $classes, string[] $css_class );

Example

add_filter( 'body_class', function( $classes ) {
    if ( is_user_logged_in() ) {
        $classes[] = 'user-logged-in';
    }
    return $classes;
} );

Common Use Cases

  • Add role-based body classes
  • Target specific page templates via CSS
  • Add device detection classes
  • Inject A/B test variant classes
since 2.8.0wp-includes/post-template.php

excerpt_length

loop-content

Controls the auto-generated excerpt word count

excerpt_length only affects auto excerpts, not the Excerpt box in the editor. Return an integer word count.

Signature

apply_filters( 'excerpt_length', int $number );

Example

add_filter( 'excerpt_length', function( $length ) {
    return 30;
} );

Common Use Cases

  • Shorten excerpts for card layouts
  • Lengthen excerpts for search results
  • Vary length by post type
  • Control reading time estimates
since 2.7.0wp-includes/formatting.php

login_url

auth

Filters the login page URL

login_url is how membership and white-label sites hide wp-login.php. Return a full URL, not a path fragment.

Signature

apply_filters( 'login_url', string $login_url, string $redirect, bool $force_reauth );

Example

add_filter( 'login_url', function( $url ) {
    return home_url( '/my-login/' );
} );

Common Use Cases

  • Custom login page URL
  • Hide wp-login.php from bots
  • Membership site login flow
  • White-label WordPress projects
since 2.8.0wp-includes/general-template.php

the_excerpt

loop-content

Filters the displayed post excerpt

the_excerpt filters the final excerpt string, whether it was typed manually or auto-generated — use excerpt_length/excerpt_more to shape the auto version instead.

Signature

apply_filters( 'the_excerpt', string $post_excerpt );

Example

add_filter( 'the_excerpt', function( $excerpt ) {
    return '<div class="excerpt-wrap">' . $excerpt . '</div>';
} );

Common Use Cases

  • Wrap excerpts in custom markup
  • Append a 'read more' link consistently
  • Strip shortcodes left in excerpts
since 0.71wp-includes/post-template.php

excerpt_more

loop-content

Filters the '[…]' string appended to auto-generated excerpts

excerpt_more only changes the trailing string on auto-generated excerpts — it does nothing to a manually written excerpt.

Signature

apply_filters( 'excerpt_more', string $more_string );

Example

add_filter( 'excerpt_more', function() {
    return ' <a href="' . get_permalink() . '">Read more →</a>';
} );

Common Use Cases

  • Replace the ellipsis with a Read More link
  • Localize the trailing string
  • Add an icon after trimmed excerpts
since 1.8.0wp-includes/formatting.php

post_class

loop-content

Filters the CSS classes on a single post's wrapper element

post_class runs once per post inside the loop — unlike body_class, which runs once per page — so keep the callback fast if you're looping many posts.

Signature

apply_filters( 'post_class', string[] $classes, string[] $css_class, int $post_id );

Example

add_filter( 'post_class', function( $classes, $css_class, $post_id ) {
    if ( has_post_thumbnail( $post_id ) ) {
        $classes[] = 'has-thumbnail';
    }
    return $classes;
}, 10, 3 );

Common Use Cases

  • Add a class for featured-image presence
  • Highlight sticky or featured posts
  • Add taxonomy-term-based classes
  • Alternate row classes for grid layouts
since 2.7.0wp-includes/post-template.php

document_title_parts

head-meta

Filters the parts that build the <title> tag on modern themes

document_title_parts is the modern replacement for wp_title — it works with an array of parts, not a raw string, so you edit pieces instead of parsing text.

Signature

apply_filters( 'document_title_parts', array $title );

Example

add_filter( 'document_title_parts', function( $title ) {
    if ( is_singular( 'book' ) ) {
        $title['title'] .= ' | Book Review';
    }
    return $title;
} );

Common Use Cases

  • Customize SEO page titles per post type
  • Remove the tagline/site name segment
  • Add dynamic segments (category, search term)
  • Override the title on 404 pages
since 4.4.0wp-includes/general-template.php

wp_nav_menu_items

loop-content

Filters the HTML list items of a rendered nav menu

wp_nav_menu_items lets you append or alter menu markup without editing the menu in the admin — useful for injecting a login/cart link at the end.

Signature

apply_filters( 'wp_nav_menu_items', string $items, stdClass $args );

Example

add_filter( 'wp_nav_menu_items', function( $items, $args ) {
    if ( 'primary' !== $args->theme_location ) {
        return $items;
    }
    $items .= is_user_logged_in()
        ? '<li><a href="' . wp_logout_url() . '">Log out</a></li>'
        : '<li><a href="' . wp_login_url() . '">Log in</a></li>';
    return $items;
}, 10, 2 );

Common Use Cases

  • Append a login/cart/search item to a menu
  • Inject a CTA button into navigation
  • Conditionally add items by user role
since 3.0.0wp-includes/nav-menu-template.php

wp_mail_from

admin

Filters the from-address used by wp_mail()

wp_mail_from fixes the wordpress@yourdomain.com sender WordPress uses by default — pair it with wp_mail_from_name to fully brand outgoing mail.

Signature

apply_filters( 'wp_mail_from', string $from_email );

Example

add_filter( 'wp_mail_from', function() {
    return 'no-reply@example.com';
} );
add_filter( 'wp_mail_from_name', function() {
    return get_bloginfo( 'name' );
} );

Common Use Cases

  • Fix deliverability by using a real domain address
  • Brand transactional emails with the site name
  • Route different email types from different addresses
since 2.2.3wp-includes/pluggable.php

upload_mimes

media

Filters the list of file types allowed for upload

upload_mimes controls what get_allowed_mime_types() and the uploader accept — adding a type here does not make it safe by itself; WordPress still runs its own file-content checks.

Signature

apply_filters( 'upload_mimes', array $mime_types, WP_User|int|null $user );

Example

add_filter( 'upload_mimes', function( $mimes ) {
    $mimes['svg'] = 'image/svg+xml';
    return $mimes;
} );

Common Use Cases

  • Allow SVG or other blocked file types
  • Restrict uploads to a smaller set of types by role
  • Add support for a niche file format
since 2.0.0wp-includes/functions.php

comment_text

comments

Filters the displayed text of a single comment

comment_text is where you'd add nofollow to links, auto-linkify text, or moderate content on display — it doesn't change what's stored in the database.

Signature

apply_filters( 'comment_text', string $comment_text, WP_Comment|null $comment, array $args );

Example

add_filter( 'comment_text', function( $comment_text, $comment ) {
    if ( $comment && ! $comment->user_id ) {
        $comment_text .= '<span class="guest-badge">Guest</span>';
    }
    return $comment_text;
}, 10, 2 );

Common Use Cases

  • Add badges/labels to comment output
  • Auto-link mentions or hashtags in comments
  • Strip disallowed markup on display
since 0.71wp-includes/comment-template.php

template_include

loop-content

Filters the final template file path WordPress is about to load

template_include is the very last stop in the template hierarchy — return an absolute path to a PHP file and WordPress loads exactly that, bypassing the rest of the hierarchy.

Signature

apply_filters( 'template_include', string $template );

Example

add_filter( 'template_include', function( $template ) {
    if ( is_singular( 'book' ) ) {
        $custom = plugin_dir_path( __FILE__ ) . 'templates/single-book.php';
        if ( file_exists( $custom ) ) {
            return $custom;
        }
    }
    return $template;
} );

Common Use Cases

  • Ship custom templates from a plugin
  • Override a theme's template for a specific condition
  • Serve a completely custom page (landing pages, builders)
since 1.5.0wp-includes/template-loader.php

admin_footer_text

admin

Filters the text shown in the bottom-left of every admin page

admin_footer_text is a lightweight branding hook — agencies commonly use it to replace WordPress's default footer credit with their own support link.

Signature

apply_filters( 'admin_footer_text', string $text );

Example

add_filter( 'admin_footer_text', function() {
    return 'Managed by Acme Agency — <a href="https://example.com/support">Get support</a>';
} );

Common Use Cases

  • White-label the admin footer for clients
  • Add a support/help link
  • Show the current plugin/theme version
since 2.8.0wp-admin/includes/template.php

script_loader_tag

enqueue

Filters the final <script> tag markup for an enqueued script

script_loader_tag is how you add async/defer or a nonce to a specific enqueued script without touching the theme's enqueue logic wholesale.

Signature

apply_filters( 'script_loader_tag', string $tag, string $handle, string $src );

Example

add_filter( 'script_loader_tag', function( $tag, $handle ) {
    if ( 'my-script' !== $handle ) {
        return $tag;
    }
    return str_replace( ' src', ' defer src', $tag );
}, 10, 2 );

Common Use Cases

  • Add async/defer to specific scripts
  • Add a nonce or crossorigin attribute
  • Remove type="text/javascript" for cleaner markup
since 4.1.0wp-includes/class-wp-scripts.php

render_block

loop-content

Filters the final HTML output of every rendered block

render_block runs for every block on the page, core and custom alike — check $block['blockName'] or it will touch content you didn't intend to change.

Signature

apply_filters( 'render_block', string $block_content, array $block );

Example

add_filter( 'render_block', function( $block_content, $block ) {
    if ( 'core/image' !== $block['blockName'] ) {
        return $block_content;
    }
    return str_replace( '<img', '<img loading="lazy"', $block_content );
}, 10, 2 );

Common Use Cases

  • Modify markup of one specific block type
  • Inject wrapper markup around blocks
  • Add tracking attributes to CTA blocks
since 5.0.0wp-includes/class-wp-block.php

rest_prepare_post

rest-api

Filters the REST API response for a single post before it's sent

rest_prepare_post lets you add or remove fields on the /wp/v2/posts response without touching register_rest_field — useful for last-mile shaping of what the API returns.

Signature

apply_filters( 'rest_prepare_post', WP_REST_Response $response, WP_Post $post, WP_REST_Request $request );

Example

add_filter( 'rest_prepare_post', function( $response, $post ) {
    $response->data['reading_time'] = ceil( str_word_count( $post->post_content ) / 200 );
    return $response;
}, 10, 2 );

Common Use Cases

  • Add computed/derived fields to the REST response
  • Strip sensitive fields from public API output
  • Reshape data for a headless front-end
since 4.7.0wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

wp_get_attachment_image_attributes

media

Filters the HTML attributes of an image rendered by wp_get_attachment_image()

wp_get_attachment_image_attributes touches every image WordPress renders through its own media functions — including inside blocks and thumbnails — so scope changes carefully.

Signature

apply_filters( 'wp_get_attachment_image_attributes', array $attr, WP_Post $attachment, string|array $size );

Example

add_filter( 'wp_get_attachment_image_attributes', function( $attr ) {
    $attr['loading'] = 'lazy';
    $attr['decoding'] = 'async';
    return $attr;
} );

Common Use Cases

  • Add loading="lazy" or fetchpriority attributes
  • Override alt text site-wide
  • Add custom data-* attributes for a lightbox script
since 2.8.0wp-includes/media.php

cron_schedules

cron

Registers custom cron interval schedules

cron_schedules is the only way to add a custom recurring interval — WordPress ships with hourly, twicedaily, and daily only.

Signature

apply_filters( 'cron_schedules', array $schedules );

Example

add_filter( 'cron_schedules', function( $schedules ) {
    $schedules['every_fifteen_minutes'] = [
        'interval' => 15 * MINUTE_IN_SECONDS,
        'display'  => 'Every 15 Minutes',
    ];
    return $schedules;
} );

Common Use Cases

  • Add a custom recurring interval (e.g. every 15 minutes)
  • Register a weekly or non-standard interval
  • Match a plugin's own scheduled task frequency
  • Support finer-grained sync/polling than core's daily/hourly options
since 2.1.0wp-includes/cron.php

authenticate

auth

The core WordPress login/authentication filter

authenticate is the chain that decides whether login credentials are valid — every auth method, from core's own password check to SSO plugins, hooks into this same filter.

Signature

apply_filters( 'authenticate', WP_User|WP_Error|null $user, string $username, string $password );

Example

add_filter( 'authenticate', function( $user, $username ) {
    if ( 'blocked_user' === $username ) {
        return new WP_Error( 'blocked', 'This account is disabled.' );
    }
    return $user;
}, 30, 3 );

Common Use Cases

  • Add a second authentication factor before allowing login
  • Block specific usernames or patterns
  • Integrate an SSO/external identity provider
  • Log failed or suspicious login attempts
since 2.8.0wp-includes/user.php

rest_pre_dispatch

rest-api

Short-circuits a REST API request before routing

rest_pre_dispatch lets you intercept a REST API request before WordPress even matches it to a route — the earliest point to block or fake a response.

Signature

apply_filters( 'rest_pre_dispatch', mixed $result, WP_REST_Server $server, WP_REST_Request $request );

Example

add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) {
    if ( str_starts_with( $request->get_route(), '/my-plugin/v1' ) && ! is_user_logged_in() ) {
        return new WP_Error( 'forbidden', 'Login required', [ 'status' => 401 ] );
    }
    return $result;
}, 10, 3 );

Common Use Cases

  • Block REST API access globally or per-route before any processing
  • Serve a cached response without running the real route logic
  • Rate-limit or IP-block at the earliest possible point
  • Mock or A/B test an endpoint's response
since 4.4.0wp-includes/rest-api/class-wp-rest-server.php

manage_posts_columns

admin

Adds or removes columns on the admin post list table

manage_posts_columns controls what shows up in wp-admin's post list table — add a custom column here, then fill it with manage_posts_custom_column.

Signature

apply_filters( 'manage_posts_columns', string[] $columns );

Example

add_filter( 'manage_posts_columns', function( $columns ) {
    $columns['word_count'] = 'Word Count';
    return $columns;
} );

Common Use Cases

  • Show custom field values in the post list at a glance
  • Remove default columns you don't need (Author, Comments)
  • Control column display order
  • Build a lightweight custom dashboard view
since 2.5.0wp-admin/includes/class-wp-posts-list-table.php