The Case For Minimal WordPress Setups: A Contrarian View On Theme Frameworks

About The Author

Kevin Leary is a WordPress consultant in Boston, Massachusetts. He specializes in custom WordPress websites for mid-to-large-sized businesses and has extensive … More about Kevin ↬

Email Newsletter

Weekly tips on front-end & UX.
Trusted by 200,000+ folks.

Modern frameworks are supposed to help speed up development while providing modern tools and a developer-friendly workflow. In theory, this is great and makes a lot of sense. In reality, Kevin Leary has found that they cause far more problems than they solve. This ultimately leads to the big question: why are modern theme frameworks so popular, and do they really benefit developers in the long run?

When it comes to custom WordPress development, theme frameworks like Sage and Genesis have become a go-to solution, particularly for many agencies that rely on frameworks as an efficient starting point for client projects. They promise modern standards, streamlined workflows, and maintainable codebases. At face value, these frameworks seem to be the answer to building high-end, bespoke WordPress websites. However, my years of inheriting these builds as a freelance developer tell a different story — one rooted in the reality of long-term maintenance, scalability, and developer onboarding.

As someone who specializes in working with professional websites, I’m frequently handed projects originally built by agencies using these frameworks. This experience has given me a unique perspective on the real-world implications of these tools over time. While they may look great in an initial pitch, their complexities often create friction for future developers, maintenance teams, and even the businesses they serve.

This is not to say frameworks like Sage or Genesis are without merit, but they are far from the universal “best practice” they’re often touted to be.

Below, I’ll share the lessons I’ve learned from inheriting and working with these setups, the challenges I’ve faced, and why I believe a minimal WordPress approach often provides a better path forward.

Why Agencies Use Frameworks

Frameworks are designed to make WordPress development faster, cleaner, and optimized for current best practices. Agencies are drawn to these tools for several reasons:

  • Current code standards
    Frameworks like Sage adopt PSR-2 standards, composer-based dependency management, and MVC-like abstractions.
  • Reusable components
    Sage’s Blade templating encourages modularity, while Genesis relies on hooks for extensive customization.
  • Streamlined design tools
    Integration with Tailwind CSS, SCSS, and Webpack (or newer tools like Bud) allows rapid prototyping.
  • Optimized performance
    Frameworks are typically designed with lightweight, bloat-free themes in mind.
  • Team productivity
    By creating a standardized approach, these frameworks promise efficiency for larger teams with multiple contributors.

On paper, these benefits make frameworks an enticing choice for agencies. They simplify the initial build process and cater to developers accustomed to working with modern PHP practices and JavaScript-driven tooling. But whenever I inherit these projects years later, the cracks in the foundation begin to show.

The Reality of Maintaining Framework-Based Builds

While frameworks have their strengths, my firsthand experience reveals recurring issues that arise when it’s time to maintain or extend these builds. These challenges aren’t theoretical — they are issues I’ve encountered repeatedly when stepping into an existing framework-based site.

1. Abstraction Creates Friction

One of the selling points of frameworks is their use of abstractions, such as Blade templating and controller-to-view separation. While these patterns make sense in theory, they often lead to unnecessary complexity in practice.

For instance, Blade templates abstract PHP logic from WordPress’s traditional theme hierarchy. This means errors like syntax issues don’t provide clear stack traces pointing to the actual view file — rather, they reference compiled templates. Debugging becomes a scavenger hunt, especially for developers unfamiliar with Sage’s structure.

Take puck.news, a popular news outlet with millions of monthly visitors. When I first inherited their Sage-based theme, I had to bypass their Lando/Docker environment to use my own minimal Nginx localhost setup. The theme was incompatible with standard WordPress workflows, and I had to modify build scripts to support a traditional installation. Once I resolved the environment issues, I realized their build process was incredibly slow, with hot module replacement only partially functional (Blade template changes wouldn’t reload). Each save took 4–5 seconds to compile.

Faced with a decision to either upgrade to Sage 10 or rebuild the critical aspects, I opted for the latter. We drastically improved performance by replacing the Sage build with a simple Laravel Mix process. The new build process was reduced from thousands of lines to 80, significantly improving developer workflow. Any new developer could now understand the setup quickly, and future debugging would be far simpler.

2. Inflexible Patterns

While Sage encourages “best practices,” these patterns can feel rigid and over-engineered for simple tasks. Customizing basic WordPress features — like adding a navigation menu or tweaking a post query — requires following the framework’s prescribed patterns. This introduces a learning curve for developers who aren’t deeply familiar with Sage, and slows down progress for minor adjustments.

Traditional WordPress theme structures, by contrast, are intuitive and widely understood. Any WordPress developer, regardless of background, can jump into a classic theme and immediately know where to look for templates, logic, and customizations. Sage’s abstraction layers, while well-meaning, limit accessibility to a smaller, more niche group of developers.

3. Hosting Compatibility Issues

When working with Sage, issues with hosting environments are inevitable. For example, Sage’s use of Laravel Blade compiles templates into cached PHP files, often stored in directories like /wp-content/cache. Strict file system rules on managed hosting platforms, like WP Engine, can block these writes, leading to white screens or broken templates after deployment.

This was precisely the issue I faced with paperlessparts.com, which was running a Sage theme on WP Engine. Every Git deployment resulted in a white screen of death due to PHP errors caused by Blade templates failing to save in the intended cache directory. The solution, recommended by WP Engine support, was to use the system’s /tmp directory. While this workaround prevented deployment errors, it undermined the purpose of cached templates, as temporary files are cleared by PHP’s garbage collection. Debugging and implementing this solution consumed significant time — time that could have been avoided had the theme been designed with hosting compatibility in mind.

4. Breaking Changes And Upgrade Woes

Upgrading from Sage 9 to Sage 10 — or even from older versions of Roots — often feels like a complete rebuild. These breaking changes create friction for businesses that want long-term stability. Clients, understandably, are unwilling to pay for what amounts to refactoring without a visible return on investment. As a result, these sites stagnate, locked into outdated versions of the framework, creating problems with dependency management (e.g., Composer packages, Node.js versions) and documentation mismatches.

One agency subcontract I worked on recently gave me insight into Sage 10’s latest approach. Even on small microsites with minimal custom logic, I found the Bud-based build system sluggish, with watch processes taking over three seconds to reload.

For developers accustomed to faster workflows, this is unacceptable. Additionally, Sage 10 introduced new patterns and directives that departed significantly from Sage 9, adding a fresh learning curve. While I understand the appeal of mirroring Laravel’s structure, I couldn’t shake the feeling that this complexity was unnecessary for WordPress. By sticking to simpler approaches, the footprint could be smaller, the performance faster, and the maintenance much easier.

The Cost Of Over-Engineering

The issues above boil down to one central theme: over-engineering.

Frameworks like Sage introduce complexity that, while beneficial in theory, often outweighs the practical benefits for most WordPress projects.

When you factor in real-world constraints — like tight budgets, frequent developer turnover, and the need for intuitive codebases — the case for a minimal approach becomes clear.

Minimal WordPress setups embrace simplicity:

  • No abstraction for abstraction’s sake
    Traditional WordPress theme hierarchy is straightforward, predictable, and accessible to a broad developer audience.
  • Reduced tooling overhead
    Avoiding reliance on tools like Webpack or Blade removes potential points of failure and speeds up workflows.
  • Future-proofing
    A standard theme structure remains compatible with WordPress core updates and developer expectations, even a decade later.

In my experience, minimal setups foster easier collaboration and faster problem-solving. They focus on solving the problem rather than adhering to overly opinionated patterns.

Real World Example

Like many things, this all sounds great and makes sense in theory, but what does it look like in practice? Seeing is believing, so I’ve created a minimal theme that exemplifies some of the concepts I’ve described here. This theme is a work in progress, and there are plenty of areas where it needs work. It provides the top features that custom WordPress developers seem to want most in a theme framework.

Modern Features

Before we dive in, I’ll list out some of the key benefits of what’s going on in this theme. Above all of these, working minimally and keeping things simple and easy to understand is by far the largest benefit, in my opinion.

  • A watch task that compiles and reloads in under 100ms;
  • Sass for CSS preprocessing coupled with CSS written in BEM syntax;
  • Native ES modules;
  • Composer package management;
  • Twig view templating;
  • View-controller pattern;
  • Namespaced PHP for isolation;
  • Built-in support for the Advanced Custom Fields plugin;
  • Global context variables for common WordPress data: site_url, site_description, site_url, theme_dir, theme_url, primary_nav, ACF custom fields, the_title(), the_content().

Templating Language

Twig is included with this theme, and it is used to load a small set of commonly used global context variables such as theme URL, theme directory, site name, site URL, and so on. It also includes some core functions as well, like the_content(), the_title(), and others you’d routinely often use during the process of creating a custom theme. These global context variables and functions are available for all URLs.

While it could be argued that Twig is an unnecessary additional abstraction layer when we’re trying to establish a minimal WordPress setup, I chose to include it because this type of abstraction is included in Sage. But it’s also for a few other important reasons:

  • Old,
  • Dependable, and
  • Stable.

You won’t need to worry about any future breaking changes in future versions, and it’s widely in use today. All the features I commonly see used in Sage Blade templates can easily be handled with Twig similarly. There really isn’t anything you can do with Blade that isn’t possible with Twig.

Blade is a great templating language, but it’s best suited for Laravel, in my opinion. BladeOne does provide a good way to use it as a standalone templating engine, but even then, it’s still not as performant under pressure as Twig. Twig’s added performance, when used with small, efficient contexts, allows us to avoid the complexity that comes with caching view output. Compile-on-the-fly Twig is very close to the same speed as raw PHP in this use case.

Most importantly, Twig was built to be portable. It can be installed with composer and used within the theme with just 55 lines of code.

Now, in a real project, this would probably be more than 55 lines, but either way, it is, without a doubt, much easier to understand and work with than Blade. Blade was built for use in Laravel, and it’s just not nearly as portable. It will be significantly easier to identify issues, track them down with a direct stack trace, and fix them with Twig.

The view context in this theme is deliberately kept sparse, during a site build you’ll add what you specifically need for a particular site. A lean context for your views helps with performance and workflow.

Models & Controllers

The template hierarchy follows the patterns of good ol’ WordPress, and while some developers don’t like this, it is undoubtedly the most widely accepted and commonly understood standard. Each standard theme file uses a model where you define your data structures with PHP and hand off the theme as the context to a .twig view file.

Developers like the structure of separating server-side logic from a template, and in a classic MVC/MVVC pattern, we have our model, view, and controller. Here, I’m using the standard WordPress theme templates as models.

Currently, template files include some useful basics. You’re likely familiar with these standard templates, but I’ll list them here for posterity:

  • 404.php: Displays a custom “Page Not Found” message when a visitor tries to access a page that doesn’t exist.
  • archive.php: Displays a list of posts from a particular archive, such as a category, date, or tag archive.
  • author.php: Displays a list of posts by a specific author, along with the author’s information.
  • category.php: Displays a list of posts from a specific category.
  • footer.php: Contains the footer section of the theme, typically including closing HTML tags and widgets or navigation in the footer area.
  • front-page.php: The template used for the site’s front page, either static or a blog, depending on the site settings.
  • functions.php: Adds custom functionality to the theme, such as registering menus and widgets or adding theme support for features like custom logos or post thumbnails.
  • header.php: Contains the header section of the theme, typically including the site’s title, meta tags, and navigation menu.
  • index.php: The fallback template for all WordPress pages is used if no other more specific template (like category.php or single.php) is available.
  • page.php: Displays individual static pages, such as “About” or “Contact” pages.
  • screenshot.png: An image of the theme’s design is shown in the WordPress theme selector to give users a preview of the theme’s appearance.
  • search.php: Displays the results of a search query, showing posts or pages that match the search terms entered by the user.
  • single.php: Displays individual posts, often used for blog posts or custom post types.
  • tag.php: Displays a list of posts associated with a specific tag.

Extremely Fast Build Process For SCSS And JavaScript

The build is curiously different in this theme, but out of the box, you can compile SCSS to CSS, work with native JavaScript modules, and have a live reload watch process with a tiny footprint. Look inside the bin/*.js files, and you’ll see everything that’s happening.

There are just two commands here, and all web developers should be familiar with them:

  1. Watch
    While developing, it will reload or inject JavaScript and CSS changes into the browser automatically using a Browsersync.
  2. Build
    This task compiles all top-level *.scss files efficiently. There’s room for improvement, but keep in mind this theme serves as a concept.

Now for a curveball: there is no compile process for JavaScript. File changes will still be injected into the browser with hot module replacement during watch mode, but we don’t need to compile anything.

WordPress will load theme JavaScript as native ES modules, using WordPress 6.5’s support for ES modules. My reasoning is that many sites now pass through Cloudflare, so modern compression is handled for JavaScript automatically. Many specialized WordPress hosts do this as well. When comparing minification to GZIP, it’s clear that minification provides trivial gains in file reduction. The vast majority of file reduction is provided by CDN and server compression. Based on this, I believe the benefits of a fast workflow far outweigh the additional overhead of pulling in build steps for webpack, Rollup, or other similar packaging tools.

We’re fortunate that the web fully supports ES modules today, so there is really no reason why we should need to compile JavaScript at all if we’re not using a JavaScript framework like Vue, React, or Svelte.

A Contrarian Approach

My perspective and the ideas I’ve shared here are undoubtedly contrarian. Like anything alternative, this is bound to ruffle some feathers. Frameworks like Sage are celebrated in developer circles, with strong communities behind them. For certain use cases — like large-scale, enterprise-level projects with dedicated development teams — they may indeed be the right fit.

For the vast majority of WordPress projects I encounter, the added complexity creates more problems than it solves. As developers, our goal should be to build solutions that are not only functional and performant but also maintainable and approachable for the next person who inherits them.

Simplicity, in my view, is underrated in modern web development. A minimal WordPress setup, tailored to the specific needs of the project without unnecessary abstraction, is often the leaner, more sustainable choice.

Conclusion

Inheriting framework-based projects has taught me invaluable lessons about the real-world impact of theme frameworks. While they may impress in an initial pitch or during development, the long-term consequences of added complexity often outweigh the benefits. By adopting a minimal WordPress approach, we can build sites that are easier to maintain, faster to onboard new developers, and more resilient to change.

Modern tools have their place, but minimalism never goes out of style. When you choose simplicity, you choose a codebase that works today, tomorrow, and years down the line. Isn’t that what great web development is all about?

Smashing Editorial (gg, yk)