Page builders exist for a reason — they let non-developers build pages fast. But a lot of client sites end up on Elementor or Divi even when a developer is already building the theme, and the result is often 40+ extra database queries per page just to render layout that plain PHP templates could handle directly.

When a hand-coded theme actually makes sense

If the client (or you) will never touch page layout after launch — the design is finished, content changes happen through the editor but the structure doesn’t — a lightweight custom theme is usually worth the extra build time. If the client needs to rearrange sections themselves regularly, a page builder or block theme is the more honest choice, and fighting that need with a rigid custom theme just creates support tickets later.

A minimal theme structure

my-theme/
├── style.css          // theme header + minimal reset
├── functions.php
├── index.php
├── header.php
├── footer.php
├── single.php
├── page.php
└── template-parts/
    └── content.php

Enqueueing assets properly

add_action('wp_enqueue_scripts', function() {
    wp_enqueue_style('theme-style', get_stylesheet_uri(), [], filemtime(get_template_directory() . '/style.css'));
    wp_enqueue_script('theme-script', get_template_directory_uri() . '/js/main.js', [], filemtime(get_template_directory() . '/js/main.js'), true);
});

Using filemtime() as the version number means the browser cache busts automatically on every deploy, without you having to remember to bump a version string manually.

What you give up

No drag-and-drop layout editing, no visual page builder for the client. If that’s actually needed post-launch, this isn’t the right approach — a block theme using core Gutenberg patterns splits the difference better, giving structure without the query overhead of a full third-party builder.