Most WordPress themes are built on top of other themes — Genesis, Underscores, Sage. There’s nothing wrong with that. But once you’ve built enough of them, you start to feel the weight of assumptions baked in by someone else. I’ve moved to starting from a blank file, and my workflow is tighter for it.
Start with style.css and nothing else
The theme header lives in style.css. Theme Name, Version, Author — that’s it. Everything else gets built deliberately, file by file. Starting blank forces me to only add what the project actually needs.
Design tokens first
Before writing a single component, I define CSS custom properties for the full design system. Colors, spacing scale, typography, transitions — all in :root. This makes the entire theme consistent and makes client revisions trivial.
:root {
--bg: #0a0a0f;
--text: #e2e8f0;
--cyan: #00d4ff;
--border: rgba(255,255,255,0.08);
--transition: 0.2s ease;
}
functions.php: only what you need
I keep functions.php organised into clearly commented sections — theme setup, asset enqueue, CPTs, admin customisations, helper functions. Each section is separated by a banner comment so you can find things at a glance.
The Customizer for client-editable content
For content that clients want to update without touching code — hero text, bio, service descriptions — I wire everything through the WordPress Customizer. The template reads values with get_theme_mod() and falls back to sensible defaults. The client gets a live preview.
Performance from the start
A few non-negotiables I build in from day one: Google Fonts loaded with display=swap, images with loading="lazy" except above-the-fold, no jQuery unless a plugin forces it, and CSS custom properties instead of Sass for zero build steps.
A blank-slate custom theme takes longer upfront than a starter theme. But the output is leaner, faster, and cheaper to maintain — no dead code, no legacy decisions to work around.