Skip to main content

Recommended functions.php Patterns

warning

Child theme code runs on every request. A fatal error or heavy logic will impact the entire site.

PatternWhat it looks likeWhy it helps
Modular includesrequire_once .../inc/*.phpPrevents functions.php bloat
Scoped hooksOne file for hooks, one for filtersEasier debugging
Prefixes/namespacesUnique identifiersAvoid collisions
Guard railsABSPATH guard, early returnsSafer execution

Why It Matters

  • Maintainability: teams can navigate code faster.
  • Safety: smaller files reduce error surface.
  • Deployability: modular child themes are easier to test and review.

How It Works

functions.php is the entry point for child theme code. It should bootstrap only: includes, constants, and hooks.

flowchart TD
F[functions.php] --> INC[inc/*.php includes]
INC --> ENQ[Enqueues]
INC --> HOOKS[Hooks]
INC --> FIL[Filters]
HOOKS --> OUT[Site output]

Practical Walkthrough

Step 1: Create a Minimal inc/ Layout

create-inc-layout.sh
cd /var/www/html
mkdir -p wp-content/themes/generatepress-child/inc
touch wp-content/themes/generatepress-child/inc/enqueue.php
touch wp-content/themes/generatepress-child/inc/hooks.php
touch wp-content/themes/generatepress-child/inc/filters.php

Step 2: Bootstrap Includes from functions.php

wp-content/themes/generatepress-child/functions.php
<?php

if ( ! defined( 'ABSPATH' ) ) {
exit;
}

require_once get_stylesheet_directory() . '/inc/enqueue.php';
require_once get_stylesheet_directory() . '/inc/hooks.php';
require_once get_stylesheet_directory() . '/inc/filters.php';

Step 3: Put Enqueues in inc/enqueue.php

wp-content/themes/generatepress-child/inc/enqueue.php
<?php

add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_style( 'generatepress-parent', get_template_directory_uri() . '/style.css' );
} );

Step 4: Verify Your Child Theme Structure

verify-child-theme-structure.sh
cd /var/www/html/wp-content/themes/generatepress-child
ls
ls inc

Practical Examples

Example 1: Prefix a Custom Function

wp-content/themes/generatepress-child/inc/hooks.php
<?php

function gp_child_notice() {
echo '<div class="gp-child-notice">Hello</div>';
}
add_action( 'generate_before_header', 'gp_child_notice' );

Example 2: Keep Debug Code Behind a Flag

Use a constant or environment flag so debug output does not ship accidentally.

wp-content/themes/generatepress-child/functions.php
<?php

define( 'GP_CHILD_DEBUG', false );
wp-content/themes/generatepress-child/inc/hooks.php
<?php

if ( defined( 'GP_CHILD_DEBUG' ) && GP_CHILD_DEBUG ) {
add_action( 'wp_footer', function() {
echo '<!-- GP child debug enabled -->';
} );
}

Example 3: Put Filters in inc/filters.php

wp-content/themes/generatepress-child/inc/filters.php
<?php

add_filter( 'body_class', function( $classes ) {
$classes[] = 'gp-child';
return $classes;
} );

Best Practices

PracticeWhy
Keep functions.php as a bootstrap onlyEasier audits
Use require_once (not require)Prevents double include bugs
Prefer hooks/filters over template copiesUpdate safety
Escape outputSecurity
Keep heavy logic out of hooksProtects performance
Avoid hard-coded pathsUse get_stylesheet_directory() helpers

Troubleshooting

SymptomCauseFix
Fatal error after deployMissing include fileConfirm paths and re-deploy
Hook runs twiceIncluded twiceEnsure require_once and no duplicates
White screenSyntax errorCheck /usr/local/lsws/logs/error.log
"Cannot redeclare" errorsFunction loaded twiceUse unique prefixes/namespaces and remove duplicates

Hands-On

  1. Split your child theme into inc/enqueue.php, inc/hooks.php, and inc/filters.php.
  2. Add one hook in inc/hooks.php.
  3. Confirm it renders, then remove it.
  4. Add one filter in inc/filters.php and confirm it changes output (body class).

Quick Reference

functions-php-patterns-cheatsheet.sh
cd /var/www/html/wp-content/themes/generatepress-child
ls
ls inc

What's Next