Skip to main content

Extending GeneratePress via Code

GeneratePress encourages a "hooks over templates" approach. That makes customizations upgrade-safe if you keep code organized, scoped, and measurable.

Where Should This Code Live?

LocationBest forWatch-outs
Child theme (functions.php)Theme-adjacent presentation changesTied to the theme; avoid business logic
Site pluginSite features that should survive theme changesSlightly more setup, but cleaner separation
MU-plugin (wp-content/mu-plugins)Must-run essentials (security, must-have hooks)Always active; mistakes are harder to bypass
tip

If the customization is about content semantics (schema output, CPTs, REST endpoints), prefer a plugin. If it is purely visual layout, a child theme is fine.

Hooks vs Filters (Practical)

TypeYou use it when...Example
Action hookYou want to output or run logic at a point in executionAdd a banner above content
Filter hookYou want to modify a value and return itAdjust excerpt length
Action: output a lightweight notice
<?php
add_action( 'wp_footer', function () {
if ( is_admin() ) {
return;
}
echo '<div class="site-notice" role="status">New: free audit slots this week.</div>';
}, 20 );
Filter: adjust excerpt length
<?php
add_filter( 'excerpt_length', function ( $length ) {
return 22;
} );

GeneratePress Hooks You Will Actually Use

GeneratePress exposes many theme hooks. You do not need to memorize them; you need a small set you reach for consistently.

Hook (example)Typical useNotes
generate_before_headerAdd a top bar / announcementKeep it light; avoid CLS
generate_after_headerBreadcrumbs or page introEnsure only one breadcrumb source
generate_before_contentContext intro on archivesGreat for category hubs
generate_after_entry_contentPost-end CTATarget posts only
generate_before_footerTrust badges / secondary CTAAvoid duplicating global CTAs
Example: post-end CTA using a GP hook
<?php
add_action( 'generate_after_entry_content', function () {
if ( ! is_singular( 'post' ) ) {
return;
}

echo '<div class="post-cta">Want help with this? <a href="/contact/">Get in touch</a>.</div>';
} );
note

The exact hook names you use depend on your layout and GeneratePress version. When in doubt, place a temporary HTML comment marker to confirm where a hook renders.

Hook Priorities (So Output Order Stays Stable)

Multiple actions can run on the same hook. Priority controls the order.

Example: control ordering with priorities
<?php
add_action( 'wp_footer', function () {
echo '<!-- footer: first -->';
}, 5 );

add_action( 'wp_footer', function () {
echo '<!-- footer: second -->';
}, 50 );
caution

Avoid relying on priority "magic" to fix overlapping Elements. Fix overlap by tightening rules first.

A Hook-First Workflow

flowchart TD
A[Requirement] --> B[Can layout settings do it?]
B -->|Yes| C[Use GP layout controls]
B -->|No| D[Can an Element do it?]
D -->|Yes| E[Use Element + display rules]
D -->|No| F["Write small code (hook/filter)"]
F --> G[Re-test + document]
caution

Avoid dumping large blocks of PHP into a Hook Element. Prefer versioned code (child theme or plugin) for anything non-trivial.

Keep Code Predictable

Simple rules that prevent most production issues:

  • Guard your code with conditionals (is_page(), is_singular(), is_admin())
  • Escape output (esc_html, esc_url) and sanitize input
  • Use unique prefixes/namespaces to avoid collisions
  • Enqueue assets only where needed

If you need to create HTML from user inputs, escape early and escape often.

Enqueue CSS only on a specific page
<?php
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_page( 'landing-audit' ) ) {
return;
}

wp_enqueue_style(
'gp-child-landing',
get_stylesheet_directory_uri() . '/assets/css/landing.css',
[],
'1.0.0'
);
} );

Hands-On: Create a Tiny MU-Plugin

Goal: add one sitewide customization that should survive theme changes.

  1. Create wp-content/mu-plugins/gp-site.php.
  2. Add a small hook (for example, a footer notice).
  3. Confirm it appears on the frontend.
wp-content/mu-plugins/gp-site.php (example)
<?php
/**
* Plugin Name: GP Site Tweaks
* Description: Must-run site tweaks for GeneratePress sites.
*/

add_action( 'wp_footer', function () {
echo '<!-- gp-site: active -->';
}, 1 );

Troubleshooting

SymptomLikely causeFix
Custom code runs everywhereMissing conditionalsAdd explicit guards (is_singular, is_page)
Styles load on every pageEnqueue not scopedWrap enqueue in conditionals
White screen after editPHP syntax errorUse staging; check server logs; disable plugin if possible
Output appears in wrong spotWrong hook chosenMove to a nearby hook and re-test with markers
Duplicate outputElement + code both renderPick one source; remove/disable the other

Debugging: Markers Beat Guessing

When you are not sure if code runs, add a harmless marker and search for it in page source.

Debug marker (temporary)
<?php
add_action( 'wp_footer', function () {
echo '<!-- debug: gp-child-footer-marker -->';
}, 999 );

Quick Reference

  • Prefer hooks/filters over editing theme files
  • Use Elements for small, UI-driven injections
  • Put durable features into a plugin or MU-plugin

What's Next