If you’re customizing a WordPress theme, mastering hooks, filters and actions, is the closest thing you’ll get to a superpower. Hooks let you change behavior, adjust markup, and inject assets without hacking core or scattering fragile edits across templates. This cheat sheet walks you through the key WordPress filters and actions for theme customization, when to use them, and the timing quirks that trip people up. Keep it handy as you build or refine your theme so your changes stay clean, upgrade-safe, and fast.
How WordPress Hooks Work
Actions Vs. Filters
Actions let you run custom code at a specific point in the WordPress lifecycle, enqueue scripts, register menus, output markup. Think: “Do something now.” Filters let you modify data before it’s used, tweak classes, change titles, alter HTML attributes. Think: “Change this value first.”
You’ll attach callbacks with add_action( 'hook_name', 'callback', $priority, $accepted_args ) and add_filter( 'hook_name', 'callback', $priority, $accepted_args ). Actions don’t return anything: filters must return the modified value.
Hook Priority And Accepted Arguments
Priority controls order when multiple callbacks run on the same hook. Lower numbers run earlier. Default is 10. Use earlier priorities (5–9) to set broad defaults: use later priorities (11–20) to finely adjust after other callbacks ran. Also, some hooks pass multiple arguments, e.g., the_content passes the content: nav_menu_link_attributes passes attributes, item, args, depth. Make sure your callback signature matches, and set $accepted_args accordingly.
Where To Add Hooked Code (Functions.php, Child Theme, Or Plugin)
For theme-specific functionality like registering menus, your theme’s functions.php is fine. But if a customization should persist across theme switches, custom post types, shortcodes, login tweaks, put it in a small site-specific plugin. Using a child theme is the safest way to customize a parent theme: add your hooks in the child’s functions.php so you keep parent updates intact.
Timing Caveats And Conditional Tags
Not all conditionals are true at all times. For example, is_singular() or is_front_page() won’t be reliable before the main query is set. If you’re filtering queries, use pre_get_posts. If you need to conditionally enqueue assets for a template, hook into wp_enqueue_scripts and check conditionals there. For admin customizations, use admin-specific hooks like admin_enqueue_scripts. Always ask: “Has WordPress loaded what I need yet?” before calling conditionals.
Core Theme Setup And Asset Actions
after_setup_theme
This action fires early, after the theme is initialized. Use it to add theme supports (thumbnails, HTML5 markup, responsive embeds), register nav menus, and set image sizes. It’s your theme’s declaration of capabilities and should stay idempotent, no output here, just configuration.
wp_enqueue_scripts
Your primary frontend asset gate. Enqueue CSS and JS here with dependencies and versions to leverage browser caching. Use wp_register_style/script and wp_enqueue_style/script. Localize scripts if you need to pass data to JS. For block themes, you may still use this for legacy assets, but prefer theme.json where appropriate.
widgets_init
Register sidebars (widget areas) for classic themes. Even if you’re moving toward block widgets, many sites still rely on registered sidebars. Name and describe them clearly to keep your widget UI sane.
wp_head And wp_footer
These actions output crucial head and footer markup, styles, scripts, meta, preload tags, and analytics. Never remove them from your templates. If you need to add small snippets (e.g., verification meta), hook with late priority to wp_head or wp_footer rather than editing header.php or footer.php directly.
Output And Markup Filters You’ll Use Daily
body_class And post_class
Use these filters to add contextual classes for styling and JS hooks. Append device, layout, or feature flags to body_class. Add taxonomies, post format, or custom states to post_class. Keep class names BEM-friendly and predictable.
the_content And the_title
the_content is your most flexible markup filter: wrap images, inject callouts, add reading-time badges, or sanitize embedded iframes. Be respectful, avoid heavy DOM manipulation that can slow rendering. the_title is ideal for prefix/suffix logic (e.g., adding icons to certain post types) or fixing edge cases like empty titles.
document_title_parts And language_attributes
Modern themes use document_title_parts to shape the <title> tag, reorder site name and tagline, add separators, or strip redundancy on the homepage. language_attributes lets you refine the <html> attributes, useful for adding dir in RTL contexts or injecting accessibility-related attributes carefully.
excerpt_length And excerpt_more
Control presentation in archives. Adjust excerpt_length for your layout (e.g., 24–36 words for grid cards feels scannable). Customize excerpt_more to an accessible, descriptive link, consider appending a screen-reader-only post title so “Read more” isn’t ambiguous.
nav_menu_css_class And nav_menu_link_attributes
Powerful for navigation states and accessibility. Add an is-active class for current items, inject aria-current="page", or add rel attributes for external links. Keep it consistent across menu locations so your CSS isn’t a tangle.
Customizer And Theme Mods
customize_register
Here you define customizer panels, sections, settings, and controls. Use sanitize_callback for every setting to keep inputs clean. Group related options (colors, typography, header) so users don’t hunt through a maze.
customize_preview_init
Enable live preview by enqueueing a small postMessage script that listens for changes and updates the DOM without a full refresh. This makes your theme feel polished and encourages tinkering.
theme_mod_$name And pre_set_theme_mod
Theme mods are persistent, theme-scoped options. Filter theme_mod_$name to dynamically override a value, perhaps to enforce a minimum contrast ratio for accessibility. Use pre_set_theme_mod to validate or transform values before saving. For portability, map mods to CSS variables so changes cascade predictably.
Templates, Queries, And The Loop
template_include
This filter lets you swap the template path at runtime. Handy for loading a custom template for a specific taxonomy, device, or feature flag without duplicating half your theme. Always return a valid file path and avoid infinite loops.
pre_get_posts
The right way to change the main query. Want to include a custom post type in search? Adjust posts per page on archives? Use pre_get_posts, check is_main_query() and .is_admin(), then modify query vars. Don’t use query_posts(), it breaks pagination and clobbers the global query.
loop_start And loop_end
These actions run around The Loop. They’re perfect for wrapping grid containers, injecting ad slots, or resetting counters without editing template files. Keep output minimal and cache-friendly.
the_archive_title And the_archive_description
Tidy up archive headings. Remove “Category:” or “Tag:” prefixes for cleaner UI, or add explanatory text to author archives. If you add markup, keep headings semantic, don’t demote H1s arbitrarily.
Media, Performance, And Accessibility Hooks
wp_get_attachment_image_attributes
Filter the attributes on images generated by wp_get_attachment_image(). Add loading="lazy" (WordPress does this by default for many cases), decoding="async", or high-DPR srcset fine-tuning. You can also add sizes rules tailored to your layout for real performance gains.
upload_mimes
Expand or restrict allowed file types, SVGs, WebPs, or custom fonts. If you allow SVG, sanitize it and consider limiting to trusted roles for security.
script_loader_tag And style_loader_tag
Perfect for adding defer, async, type="module", nomodule, or Subresource Integrity (SRI) attributes to enqueued assets. Pair with dependency management so you don’t break inline scripts that expect synchronous execution.
wp_resource_hints
Add preconnect, preload, or dns-prefetch hints for fonts and third-party CDNs. Target only critical resources: excessive hints can backfire. Preload fonts you actually use above the fold and specify as and type correctly.
body_open And comment_class
body_open fires right after the opening <body> tag, ideal for tag managers, skip links, or consent banners that must appear early. comment_class lets you mark author comments, pending comments, or even inject aria attributes for better screen reader context.
Conclusion
You don’t need to memorize every hook in WordPress, just the ones that move your theme forward. Use actions to set up capabilities and place assets. Use filters to refine output, tighten accessibility, and polish performance. Be mindful of timing, return values, and where your code lives (child theme or plugin) so your customizations survive updates. Keep this cheat sheet nearby, and you’ll ship cleaner, faster, more maintainable WordPress theme customizations without touching a single core file.

No responses yet