
GeneratePress is built around WordPress action hooks, and that single design decision is what makes it a developer's theme rather than a page-builder substitute. Instead of editing template files (which breaks on the next update) or stuffing everything into a builder, you attach your code to a named insertion point and let the theme render it in exactly the right place. This guide maps the hook system, shows you the three ways to attach code, and walks through real add_action snippets you can paste into a child theme today.
You can copy content.php or header.php into a child theme and edit the markup directly. Don't, unless you have no other option. Template overrides freeze your copy in time: when GeneratePress ships a markup or accessibility change, your override silently keeps serving the old version, and you inherit every bug the theme later fixes. Hooks sidestep all of that. Your code lives outside the template, the theme keeps full control of its own structure, and updates flow through cleanly. A hooked function is also trivial to disable, version, and move to a different location later.
Performance-wise, hooks cost essentially nothing. An add_action callback is a function reference that fires once during render. The myth that "more hooks = slower site" comes from heavy plugins doing real work on every hook, not from the hook mechanism itself. GeneratePress stays lightweight (a clean install ships well under 30KB of CSS/JS), and adding a handful of your own callbacks won't change that.
You have three places to put hooked code, and choosing the right one matters more than people admit.
functions.php with add_action. The purist's choice. Code lives in version control, ships with your deploy, and is reviewable in a PR. Best for agency work, anything you'll maintain long-term, and logic that belongs to the site's build rather than its content. Downside: a PHP fatal error here can white-screen the site, so edit through a proper deploy, not the WordPress file editor.add_action code, but managed in the admin with per-snippet on/off toggles and error guarding that deactivates a broken snippet instead of crashing the site. Best when a non-developer client needs to flip things on and off, or when you want isolation between unrelated tweaks.A practical rule: if it's logic, use functions.php; if it's content with conditional placement, use a Hook Element; if a client needs the switch, use a snippets plugin.
GeneratePress follows a consistent generate_before_* / generate_after_* naming convention, which makes the locations easy to reason about once you've seen the page top to bottom.
wp_body_open — WordPress core, but the first thing inside <body>. The correct home for tag-manager noscript, skip links, or a site-wide banner.generate_before_header / generate_after_header — wrap the header block. generate_after_header is the classic spot for a hero section or full-width announcement strip below the logo.generate_inside_navigation — drop a button, search field, or CTA inside the primary nav bar.generate_before_content / generate_after_content — surround the article container. generate_after_content is where author boxes, related-post grids, and post-footer CTAs belong.generate_after_entry_title — fires right after the post title, ideal for reading-time estimates or a byline meta line.generate_before_main_content / generate_after_main_content — broader wrappers around the main content area, useful on archives.generate_before_right_sidebar / generate_after_left_sidebar — inject sticky CTAs or ad units into the sidebar columns.generate_before_footer / generate_after_footer — the footer-CTA band and pre-copyright content live here.Each of these goes in a child theme's functions.php (or a snippet). They're complete and runnable as-is.
1. A CTA box after every blog post. Note the is_singular('post') guard so it doesn't appear on pages.
add_action( 'generate_after_content', function () {
if ( ! is_singular( 'post' ) ) {
return;
}
echo '<div class="post-cta">
<h3>Enjoyed this?</h3>
<p>Get the next guide in your inbox.</p>
<a class="button" href="/subscribe/">Subscribe</a>
</div>';
} );
2. A site-wide announcement bar below the header.
add_action( 'generate_after_header', function () {
echo '<div class="announce-bar">Free shipping this week — code SHIP26</div>';
} );
3. Inject an ad or callout after the third paragraph. This one isn't a region hook — it's the core the_content filter, which is how you reach inside the article body where no GeneratePress hook fires.
add_filter( 'the_content', function ( $content ) {
if ( ! is_singular( 'post' ) || ! in_the_loop() || ! is_main_query() ) {
return $content;
}
$ad = '<div class="inline-ad">Your unit here</div>';
$paras = explode( '</p>', $content );
if ( count( $paras ) >= 3 ) {
$paras[2] .= '</p>' . $ad;
unset( $paras[2] ); // already appended below
}
return implode( '</p>', $paras );
}, 20 );
Two ways to scope output. In code, lean on conditional tags: is_singular(), is_page('contact'), is_post_type_archive('product'), is_front_page(), and category/tag checks. Always guard early and return rather than nesting your whole callback in an if. In Hook Elements, the same scoping happens in the Display Rules panel — "Location: All Posts", plus an Exclude rule to carve out specific IDs. The GUI rules are easier for clients; the code conditions are more precise and composable. They're equivalent in power for the common cases.
This is where hooks earn their keep for developers. Every add_action accepts a priority argument (default 10). When two callbacks share a hook, lower numbers fire first. If your announcement bar needs to render before something else GeneratePress attaches to generate_after_header, give it a priority of 5.
More powerfully, GeneratePress builds its own header, navigation, and footer by hooking its internal functions onto these same actions — which means you can unhook them. To strip and replace the default navigation, for example:
// Remove GP's navigation from after the header...
remove_action( 'generate_after_header', 'generate_add_navigation_after_header', 5 );
// ...and place your own version before it instead
add_action( 'generate_before_header', 'my_custom_nav', 5 );
The catch with remove_action is that the priority must match the one used to add it, or the removal silently no-ops. When a remove_action "does nothing," a wrong priority is almost always why.
generate_* hooks don't fire. Confirm you're on the classic theme before relying on them.add_action works for everyone — but the GUI placement tool is a GP Premium feature.esc_html(), esc_url(), or wp_kses_post() before echoing.Once the region map and the three attachment methods are second nature, GeneratePress stops feeling like a theme you configure and starts feeling like a framework you build on — update-safe, version-controlled, and exactly as custom as the project needs.
Site
Tools
We do not sell your email. We do not spam.
© 2026 RevealTheme. All rights reserved.