Developer problem: "I need to create header/footer/sidebar for 15 client themes!!"
Manual approach:
- Create
header.phpin each theme - Copy/paste navigation code
- Create
footer.phpin each theme - Copy/paste widget areas
- 4 hours of repetitive work!!
My CLI approach:
- Bash script + WP-CLI
- Generate all template parts automatically
- Consistent structure across themes
- Done in 5 minutes!!
Here's how to automate WordPress template part generation with WP-CLI:
The Template Parts Problem
Block themes require:
/parts/header.html/parts/footer.html/parts/sidebar.html/parts/navigation.html
Classic themes require:
header.phpfooter.phpsidebar.phpnavigation.php
For 15 client themes:
- 60 files to create manually
- Copy/paste navigation menus
- Copy/paste widget areas
- Update theme-specific details
- Massive time waste!!
Solution: WP-CLI + Bash Automation
The CLI Workflow
# Generate all template parts for a theme
./generate-template-parts.sh my-theme
# Output:
# ✓ Created /parts/header.html
# ✓ Created /parts/footer.html
# ✓ Created /parts/sidebar.html
# ✓ Created /parts/navigation.html
# Done in 8 seconds!!
Setting Up WP-CLI
Install WP-CLI
# Download WP-CLI
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
# Make executable
chmod +x wp-cli.phar
# Move to system path
sudo mv wp-cli.phar /usr/local/bin/wp
# Verify installation
wp --version
# WP-CLI 2.10.0
Test WP-CLI Access
# Navigate to WordPress installation
cd /var/www/html
# List installed themes
wp theme list
# Output:
# +-----------------+----------+--------+---------+
# | name | status | update | version |
# +-----------------+----------+--------+---------+
# | twentytwentyfour| active | none | 1.0 |
# | my-theme | inactive | none | 1.0.0 |
# +-----------------+----------+--------+---------+
Block Theme Template Parts Generator
Script: generate-block-parts.sh
#!/bin/bash
# Usage: ./generate-block-parts.sh my-theme
THEME_SLUG=$1
THEME_DIR="/var/www/html/wp-content/themes/${THEME_SLUG}"
PARTS_DIR="${THEME_DIR}/parts"
# Validate theme exists
if [ ! -d "$THEME_DIR" ]; then
echo "Error: Theme '${THEME_SLUG}' not found!"
exit 1
fi
# Create parts directory
mkdir -p "$PARTS_DIR"
echo "Generating template parts for theme: ${THEME_SLUG}"
# Generate header.html
cat > "${PARTS_DIR}/header.html" << 'EOF'
<!-- wp:group {"align":"full","style":{"spacing":{"padding":{"top":"20px","bottom":"20px"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-group alignfull" style="padding-top:20px;padding-bottom:20px">
<!-- wp:group {"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"space-between"}} -->
<div class="wp-block-group">
<!-- wp:site-logo {"width":120} /-->
<!-- wp:group {"layout":{"type":"flex"}} -->
<div class="wp-block-group">
<!-- wp:navigation {"ref":123,"layout":{"type":"flex","setCascadingProperties":true,"justifyContent":"right"}} /-->
<!-- wp:buttons -->
<div class="wp-block-buttons">
<!-- wp:button -->
<div class="wp-block-button">
<a class="wp-block-button__link wp-element-button">Get Started</a>
</div>
<!-- /wp:button -->
</div>
<!-- /wp:buttons -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
EOF
echo "✓ Created ${PARTS_DIR}/header.html"
# Generate footer.html
cat > "${PARTS_DIR}/footer.html" << 'EOF'
<!-- wp:group {"align":"full","style":{"spacing":{"padding":{"top":"60px","bottom":"40px"}},"elements":{"link":{"color":{"text":"var:preset|color|base"}}}},"backgroundColor":"contrast","textColor":"base","layout":{"type":"constrained"}} -->
<div class="wp-block-group alignfull has-base-color has-contrast-background-color has-text-color has-background has-link-color" style="padding-top:60px;padding-bottom:40px">
<!-- wp:columns -->
<div class="wp-block-columns">
<!-- wp:column -->
<div class="wp-block-column">
<!-- wp:heading {"level":4} -->
<h4>About</h4>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>Company description goes here.</p>
<!-- /wp:paragraph -->
</div>
<!-- /wp:column -->
<!-- wp:column -->
<div class="wp-block-column">
<!-- wp:heading {"level":4} -->
<h4>Quick Links</h4>
<!-- /wp:heading -->
<!-- wp:navigation {"ref":456,"orientation":"vertical"} /-->
</div>
<!-- /wp:column -->
<!-- wp:column -->
<div class="wp-block-column">
<!-- wp:heading {"level":4} -->
<h4>Contact</h4>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>Email: info@example.com<br>Phone: (555) 123-4567</p>
<!-- /wp:paragraph -->
</div>
<!-- /wp:column -->
</div>
<!-- /wp:columns -->
<!-- wp:separator {"style":{"spacing":{"margin":{"top":"40px","bottom":"20px"}}}} -->
<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:40px;margin-bottom:20px"/>
<!-- /wp:separator -->
<!-- wp:group {"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"space-between"}} -->
<div class="wp-block-group">
<!-- wp:paragraph -->
<p>© 2026 Company Name. All rights reserved.</p>
<!-- /wp:paragraph -->
<!-- wp:social-links -->
<ul class="wp-block-social-links">
<!-- wp:social-link {"url":"https://twitter.com/","service":"twitter"} /-->
<!-- wp:social-link {"url":"https://facebook.com/","service":"facebook"} /-->
<!-- wp:social-link {"url":"https://instagram.com/","service":"instagram"} /-->
</ul>
<!-- /wp:social-links -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
EOF
echo "✓ Created ${PARTS_DIR}/footer.html"
# Generate sidebar.html
cat > "${PARTS_DIR}/sidebar.html" << 'EOF'
<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:heading {"level":3} -->
<h3>Sidebar</h3>
<!-- /wp:heading -->
<!-- wp:search {"label":"Search","showLabel":false,"buttonText":"Search"} /-->
<!-- wp:separator {"style":{"spacing":{"margin":{"top":"30px","bottom":"30px"}}}} -->
<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:30px;margin-bottom:30px"/>
<!-- /wp:separator -->
<!-- wp:latest-posts {"postsToShow":5,"displayPostDate":true,"displayFeaturedImage":true,"featuredImageSizeSlug":"thumbnail"} /-->
<!-- wp:separator {"style":{"spacing":{"margin":{"top":"30px","bottom":"30px"}}}} -->
<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:30px;margin-bottom:30px"/>
<!-- /wp:separator -->
<!-- wp:categories /-->
<!-- wp:separator {"style":{"spacing":{"margin":{"top":"30px","bottom":"30px"}}}} -->
<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:30px;margin-bottom:30px"/>
<!-- /wp:separator -->
<!-- wp:tag-cloud /-->
</div>
<!-- /wp:group -->
EOF
echo "✓ Created ${PARTS_DIR}/sidebar.html"
# Generate navigation.html
cat > "${PARTS_DIR}/navigation.html" << 'EOF'
<!-- wp:navigation {"ref":789,"layout":{"type":"flex","setCascadingProperties":true,"justifyContent":"center"}} /-->
EOF
echo "✓ Created ${PARTS_DIR}/navigation.html"
echo ""
echo "✅ All template parts generated successfully!"
echo "Location: ${PARTS_DIR}"
Make Script Executable
chmod +x generate-block-parts.sh
Run Script
./generate-block-parts.sh my-theme
[](https://www.elegantthemes.com/affiliates/idevaffiliate.php?id=53476&url=73342)
# Output:
# Generating template parts for theme: my-theme
# ✓ Created /var/www/html/wp-content/themes/my-theme/parts/header.html
# ✓ Created /var/www/html/wp-content/themes/my-theme/parts/footer.html
# ✓ Created /var/www/html/wp-content/themes/my-theme/parts/sidebar.html
# ✓ Created /var/www/html/wp-content/themes/my-theme/parts/navigation.html
#
# ✅ All template parts generated successfully!
If you're building child themes for popular themes, check out my guide on Building a Child Theme for Avada: The Right Way.
Classic Theme Template Parts Generator
Script: generate-classic-parts.sh
#!/bin/bash
# Usage: ./generate-classic-parts.sh my-classic-theme
THEME_SLUG=$1
THEME_DIR="/var/www/html/wp-content/themes/${THEME_SLUG}"
if [ ! -d "$THEME_DIR" ]; then
echo "Error: Theme '${THEME_SLUG}' not found!"
exit 1
fi
echo "Generating classic template parts for theme: ${THEME_SLUG}"
# Generate header.php
cat > "${THEME_DIR}/header.php" << 'EOF'
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo('charset'); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<div id="page" class="site">
<header id="masthead" class="site-header">
<div class="container">
<div class="site-branding">
<?php
if (has_custom_logo()) {
the_custom_logo();
} else {
?>
<h1 class="site-title">
<a href="<?php echo esc_url(home_url('/')); ?>">
<?php bloginfo('name'); ?>
</a>
</h1>
<?php
}
?>
</div>
<nav id="site-navigation" class="main-navigation">
<?php
wp_nav_menu(array(
'theme_location' => 'primary',
'menu_id' => 'primary-menu',
'container' => false,
));
?>
</nav>
</div>
</header>
<main id="primary" class="site-main">
EOF
echo "✓ Created ${THEME_DIR}/header.php"
[](https://www.elegantthemes.com/affiliates/idevaffiliate.php?id=53476&url=73342)
# Generate footer.php
cat > "${THEME_DIR}/footer.php" << 'EOF'
</main><!-- #primary -->
<footer id="colophon" class="site-footer">
<div class="container">
<div class="footer-widgets">
<div class="footer-column">
<?php dynamic_sidebar('footer-1'); ?>
</div>
<div class="footer-column">
<?php dynamic_sidebar('footer-2'); ?>
</div>
<div class="footer-column">
<?php dynamic_sidebar('footer-3'); ?>
</div>
</div>
<div class="site-info">
<p>
© <?php echo date('Y'); ?>
<a href="<?php echo esc_url(home_url('/')); ?>">
<?php bloginfo('name'); ?>
</a>.
All rights reserved.
</p>
</div>
</div>
</footer>
</div><!-- #page -->
<?php wp_footer(); ?>
</body>
</html>
EOF
echo "✓ Created ${THEME_DIR}/footer.php"
# Generate sidebar.php
cat > "${THEME_DIR}/sidebar.php" << 'EOF'
<aside id="secondary" class="widget-area">
<?php if (is_active_sidebar('sidebar-1')) : ?>
<?php dynamic_sidebar('sidebar-1'); ?>
<?php else : ?>
<section class="widget widget_search">
<?php get_search_form(); ?>
</section>
<section class="widget widget_recent_entries">
<h2 class="widget-title">Recent Posts</h2>
<?php
wp_get_archives(array(
'type' => 'postbypost',
'limit' => 5,
'format' => 'html',
'show_post_count' => true
));
?>
</section>
<section class="widget widget_categories">
<h2 class="widget-title">Categories</h2>
<ul>
<?php wp_list_categories(array(
'title_li' => '',
'show_count' => true
)); ?>
</ul>
</section>
<?php endif; ?>
</aside>
EOF
echo "✓ Created ${THEME_DIR}/sidebar.php"
# Generate navigation.php (template part)
cat > "${THEME_DIR}/navigation.php" << 'EOF'
<nav class="navigation pagination">
<h2 class="screen-reader-text">Posts navigation</h2>
<div class="nav-links">
<?php
global $wp_query;
$big = 999999999;
echo paginate_links(array(
'base' => str_replace($big, '%#%', esc_url(get_pagenum_link($big))),
'format' => '?paged=%#%',
'current' => max(1, get_query_var('paged')),
'total' => $wp_query->max_num_pages,
'prev_text' => '<span aria-hidden="true">«</span> Previous',
'next_text' => 'Next <span aria-hidden="true">»</span>',
));
?>
</div>
</nav>
EOF
echo "✓ Created ${THEME_DIR}/navigation.php"
echo ""
echo "✅ All classic template parts generated successfully!"
For optimizing classic theme performance, see my article on Avada vs Elementor: Which Page Builder Wins.
Advanced: Multi-Theme Generator
Batch Process Multiple Themes
#!/bin/bash
# generate-all-themes.sh
# Generate template parts for all client themes
THEMES=(
"client-a-theme"
"client-b-theme"
"client-c-theme"
"agency-portfolio"
"ecommerce-store"
)
for theme in "${THEMES[@]}"; do
echo ""
echo "=== Processing: $theme ==="
./generate-block-parts.sh "$theme"
# Also generate functions.php additions
./add-template-support.sh "$theme"
done
echo ""
echo "🎉 Generated template parts for ${#THEMES[@]} themes!"
Add Theme Support Automatically
#!/bin/bash
# add-template-support.sh
# Add required theme support for template parts
THEME_SLUG=$1
FUNCTIONS_FILE="/var/www/html/wp-content/themes/${THEME_SLUG}/functions.php"
if [ ! -f "$FUNCTIONS_FILE" ]; then
echo "Error: functions.php not found for theme '${THEME_SLUG}'!"
exit 1
fi
# Backup original functions.php
cp "$FUNCTIONS_FILE" "${FUNCTIONS_FILE}.backup"
# Append template part registration
cat >> "$FUNCTIONS_FILE" << 'EOF'
/**
* Register navigation menus
*/
function theme_register_nav_menus() {
register_nav_menus(array(
'primary' => __('Primary Menu', 'theme-textdomain'),
'footer' => __('Footer Menu', 'theme-textdomain'),
));
}
add_action('after_setup_theme', 'theme_register_nav_menus');
/**
* Register widget areas
*/
function theme_widgets_init() {
register_sidebar(array(
'name' => __('Sidebar', 'theme-textdomain'),
'id' => 'sidebar-1',
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
));
register_sidebar(array(
'name' => __('Footer 1', 'theme-textdomain'),
'id' => 'footer-1',
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
));
register_sidebar(array(
'name' => __('Footer 2', 'theme-textdomain'),
'id' => 'footer-2',
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
));
register_sidebar(array(
'name' => __('Footer 3', 'theme-textdomain'),
'id' => 'footer-3',
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
));
}
add_action('widgets_init', 'theme_widgets_init');
EOF
echo "✓ Added theme support to functions.php"
echo "✓ Backup created: ${FUNCTIONS_FILE}.backup"
WP-CLI Integration
Create Navigation Menus Automatically
#!/bin/bash
# create-menus.sh
# Create and assign navigation menus via WP-CLI
THEME_SLUG=$1
echo "Creating navigation menus for theme: ${THEME_SLUG}"
# Create Primary Menu
PRIMARY_MENU_ID=$(wp menu create "Primary Menu" --porcelain)
echo "✓ Created Primary Menu (ID: ${PRIMARY_MENU_ID})"
# Add menu items
wp menu item add-post $PRIMARY_MENU_ID 1 --title="Home"
wp menu item add-post $PRIMARY_MENU_ID 2 --title="About"
wp menu item add-post $PRIMARY_MENU_ID 3 --title="Services"
wp menu item add-post $PRIMARY_MENU_ID 4 --title="Blog"
wp menu item add-post $PRIMARY_MENU_ID 5 --title="Contact"
echo "✓ Added 5 menu items to Primary Menu"
# Assign menu to location
wp menu location assign $PRIMARY_MENU_ID primary
echo "✓ Assigned Primary Menu to 'primary' location"
# Create Footer Menu
FOOTER_MENU_ID=$(wp menu create "Footer Menu" --porcelain)
echo "✓ Created Footer Menu (ID: ${FOOTER_MENU_ID})"
# Add footer menu items
wp menu item add-custom $FOOTER_MENU_ID "Privacy Policy" "/privacy-policy"
wp menu item add-custom $FOOTER_MENU_ID "Terms of Service" "/terms"
wp menu item add-custom $FOOTER_MENU_ID "Sitemap" "/sitemap"
echo "✓ Added 3 menu items to Footer Menu"
# Assign footer menu
wp menu location assign $FOOTER_MENU_ID footer
echo "✓ Assigned Footer Menu to 'footer' location"
echo ""
echo "✅ Navigation menus created and assigned!"
Complete Workflow Script
#!/bin/bash
# complete-theme-setup.sh
# Complete theme setup: parts + support + menus
THEME_SLUG=$1
if [ -z "$THEME_SLUG" ]; then
echo "Usage: ./complete-theme-setup.sh <theme-slug>"
exit 1
fi
echo "========================================="
echo "Complete Theme Setup: ${THEME_SLUG}"
echo "========================================="
echo ""
# Step 1: Generate template parts
echo "Step 1: Generating template parts..."
./generate-block-parts.sh "$THEME_SLUG"
echo ""
# Step 2: Add theme support
echo "Step 2: Adding theme support..."
./add-template-support.sh "$THEME_SLUG"
echo ""
# Step 3: Create navigation menus
echo "Step 3: Creating navigation menus..."
./create-menus.sh "$THEME_SLUG"
echo ""
# Step 4: Activate theme
echo "Step 4: Activating theme..."
wp theme activate "$THEME_SLUG"
echo "✓ Theme activated"
echo ""
echo "========================================="
echo "✅ Theme setup complete!"
echo "========================================="
echo ""
echo "Next steps:"
echo "1. Visit Site Editor to customize header/footer"
echo "2. Add content to widget areas"
echo "3. Configure theme.json settings"
For more on theme comparison and setup, check out Divi vs Avada: Why ThemeForest's #1 Seller Costs 5x More Long-Term.
CI/CD Integration
GitHub Actions Workflow
.github/workflows/theme-setup.yml:
name: Theme Setup
on:
workflow_dispatch:
inputs:
theme_slug:
description: 'Theme slug to set up'
required: true
jobs:
setup-theme:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup SSH
uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Run theme setup
run: |
ssh user@server "cd /var/www/html && ./complete-theme-setup.sh ${{ github.event.inputs.theme_slug }}"
- name: Notify Slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'Theme ${{ github.event.inputs.theme_slug }} setup complete!'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
Real-World Scenario: Agency Workflow
Agency: 15 new client themes per month
Before automation:
- Create header.php manually (15 × 30 min = 7.5 hours)
- Create footer.php manually (15 × 30 min = 7.5 hours)
- Create sidebar.php manually (15 × 20 min = 5 hours)
- Create navigation menus (15 × 15 min = 3.75 hours)
- 23.75 hours per month!!
With CLI automation:
# Setup all 15 client themes
for i in {1..15}; do
./complete-theme-setup.sh "client-theme-$i"
done
# Total time: 15 × 1 minute = 15 minutes!!
Time savings: 23.75 hours → 15 minutes = 95% faster!!
ROI: Developer at $100/hr × 23.75 hours = $2,375 saved per month!!
Bottom Line
Stop manually creating template parts for every theme!!
CLI automation wins:
- Bash scripts + WP-CLI
- Generate all parts in seconds
- Consistent structure across themes
- 15 minutes vs 24 hours = massive savings!!
My agency results:
Before:
- 4 hours per theme setup
- Inconsistent template structure
- Copy/paste errors
After:
- 1 minute automated setup
- Perfect consistency across 50+ themes
- Zero copy/paste errors!!
Setup time: 2 hours to create scripts
ROI: First month saved 23+ hours = instant payoff!!
For agencies building multiple themes: Template part automation is ESSENTIAL!!
Generate 60 template files automatically vs creating them manually = 95% time savings!! 🚀
This article contains affiliate links!


Top comments (1)
This is the kind of automation most WordPress developers don’t realize they need until they’ve wasted hours copy-pasting the same files.
Using WP-CLI + bash to standardize theme parts across clients is a huge time saver and also removes human errors. Really practical workflow — especially for agencies handling multiple themes every month.