Building a Professional WordPress Starter Theme with Bedrock, Sage & Tailwind
Introduction
After months of working with different WordPress themes and setups, I decided to build my own starter theme using the Bedrock stack. This isn’t just another theme—it’s a complete architectural approach to WordPress development that aligns more closely with how modern web applications are built.
In this post, I’ll walk you through what I built, why I made these decisions, and why this approach scales far better than traditional WordPress development.
The Problem with Traditional WordPress Development
When I first started building WordPress sites, I leaned on themes like Understrap and Underscores. They’re solid for getting started, but as projects grew, the cracks started to show:
- Plugin dependencies scattered with no version control
- Template files cluttered with PHP logic
- No consistent styling system—everything felt ad hoc
- Difficult handover between developers
- No reliable deployment pipeline
The core issue? These setups weren’t designed for scale. They work for small projects, but once complexity increases, maintenance becomes painful.
Enter the Bedrock Stack
Bedrock rethinks how a WordPress project is structured. Instead of the traditional flat setup, it introduces a cleaner, more secure architecture:
├── config/ # Configuration (outside web root)
├── web/ # Web root
│ ├── app/ # Replaces wp-content
│ ├── wp/ # WordPress core
│ └── index.php # Entry point
├── vendor/ # Composer dependencies
└── .env # Environment variables
This separation is more than just tidy—it’s safer. Sensitive configuration files are kept outside the public directory, reducing exposure in case of server vulnerabilities.
Why Composer Changes Everything
One of the biggest upgrades is Composer integration. Instead of manually installing plugins, everything is defined and version-controlled:
{
"require": {
"roots/wordpress": "^6.0",
"roots/acorn": "^6.0",
"wpackagist-plugin/wordpress-seo": "^23.0"
}
}
This gives you:
- Locked dependency versions
- One-command updates (
composer update) - Easy rollbacks
- Fast onboarding for new developers
- Full visibility into project dependencies
For client work, this eliminates guesswork and makes maintenance far more predictable.
Blade Templates: Clean Code That Scales
Sage 10 introduces Blade templating, borrowed from Laravel. Instead of mixing logic and markup, you get a clear separation of concerns.
Traditional WordPress:
<?php if (have_posts()): while (have_posts()): the_post(); ?>
<article>
<h1><?php the_title(); ?></h1>
<div><?php the_content(); ?></div>
</article>
<?php endwhile; endif; ?>
Blade approach:
@extends('layouts.app')
@section('content')
@while(have_posts())
@php(the_post())
<article>
<h1>{{ get_the_title() }}</h1>
<div>{{ get_the_content() }}</div>
</article>
@endwhile
@endsection
The result is cleaner, more readable, and easier to scale. Developers familiar with modern PHP frameworks can jump in without needing deep WordPress-specific knowledge.
ACF Pro Blocks: Gutenberg Without the Overhead
Instead of building Gutenberg blocks with React, I used ACF Pro to create flexible, server-rendered blocks:
acf_register_block_type([
'name' => 'hero',
'title' => 'Hero',
'render_callback' => function ($block) {
echo \Roots\view('blocks.hero', [
'block' => $block,
])->render();
},
]);
This approach keeps things simple:
- Blocks render with Blade templates
- No React complexity
- Faster development workflow
- Easier collaboration with frontend developers
It’s a practical balance between flexibility and maintainability.
Tailwind CSS: Consistency Without the Bloat
Tailwind CSS provides a utility-first approach to styling. Instead of overriding bulky frameworks, you build exactly what you need:
<h1 class="font-display text-4xl font-semibold text-ink">
Hello World
</h1>
Design tokens keep everything consistent:
:root {
--font-display: 'Playfair Display', serif;
--color-ink: #1a1a1a;
--color-accent: #8b2500;
}
Update a value once, and it reflects across the entire project. This creates a cohesive design system without unnecessary overhead.
Deployment: From Local to Production
This setup includes a GitHub Actions workflow that automates deployment. When changes are pushed:
- Dependencies are installed
- Assets are built
- Files are deployed to the server
- Cache is cleared
No more manual uploads or inconsistent environments—everything is streamlined and repeatable.
Comparing the Architectures
| Aspect | Underscores | Understrap | This Stack |
|---|---|---|---|
| PHP Dependencies | Manual | Manual | Composer |
| Template Engine | PHP | PHP + Bootstrap | Blade |
| CSS Framework | None | Bootstrap | Tailwind |
| Block System | Core | Core | ACF Pro |
| Security | Standard | Standard | Enhanced |
| Deployment | Manual | Manual | Automated |
| Scalability | Low | Medium | High |
| Developer Experience | Basic | Good | Excellent |
When to Use This Approach
This stack works best for:
- Client projects that will evolve over time
- Agency workflows
- Portfolio projects showcasing professional development practices
- Long-term, maintainable websites
It may be overkill for:
- Simple blogs
- Quick prototypes
- Very low-budget builds
Conclusion
This starter theme represents a shift from traditional WordPress development to a more modern, scalable approach.
It brings together better structure, cleaner code, improved security, and a smoother developer experience—all while still leveraging WordPress as a powerful CMS.
For developers looking to level up their workflow, this architecture offers a solid foundation that can handle real-world complexity without falling apart.
Tech Stack: WordPress, Bedrock, Sage 10, Tailwind CSS v4, ACF Pro, Vite, GitHub Actions