There is a moment every WordPress designer knows. You have installed yet another multipurpose theme with 40 demo sites, a page builder and a settings panel with more tabs than a web browser. You only wanted a clean blog with your client's colours, and now you are fighting the theme to remove things you never asked for. The site is slow, and every update feels risky.
Building your own theme sounds like a big leap from there, but it is closer than you think. A classic WordPress theme is a handful of PHP template files and a stylesheet. Starting from a clean starter theme, you can have a fast, tailored design that does exactly what the site needs and nothing else. This guide explains how classic themes are put together and a practical path from a starter theme to a finished design.
What a theme actually is
A WordPress theme controls how content is displayed. It does not store content; posts, pages and settings live in the database. That separation is what lets you change the design without losing anything.
At minimum, a classic theme needs just two files: style.css with a header comment WordPress recognises, and index.php. Everything else builds on those.
/*
Theme Name: Acme Studio
Author: Acme
Description: A lightweight custom theme for Acme Studio.
Version: 1.0.0
License: GPL v2 or later
Text Domain: acme-studio
*/The core template files
| File | What it does |
|---|---|
style.css | Theme header and main styles |
functions.php | Theme setup, features, asset loading |
index.php | The fallback template for everything |
header.php | The top of every page, including the head section |
footer.php | The bottom of every page |
sidebar.php | The sidebar and its widgets |
single.php | A single blog post |
page.php | A static page |
archive.php | Category, tag, date and author listings |
404.php | The "page not found" screen |
Two function calls are essential: wp_head() just before the closing head tag in header.php, and wp_footer() just before the closing body tag in footer.php. Plugins rely on them to add their scripts and styles, and many plugins break without them.
The template hierarchy, simply explained
When someone visits a URL, WordPress looks for the most specific template available and falls back step by step until it finds one. For a single blog post it checks roughly: a template for that specific post, then single-post.php, then single.php, then singular.php, then index.php.
This is powerful. You can start with only index.php and add more specific templates as the design needs them. A starter theme without page.php or archive.php still works perfectly: pages and listings simply use index.php until you create those files, usually by copying index.php and adjusting the layout. A custom post type called book automatically uses single-book.php if it exists, which is how custom content gets its own layout; our guide to WordPress custom post types covers this in detail.
functions.php: where the theme is set up
functions.php switches features on and loads assets. A typical setup function:
function acme_studio_setup() {
add_theme_support( 'title-tag' );
add_theme_support( 'post-thumbnails' );
add_theme_support( 'custom-logo' );
add_theme_support( 'html5', array( 'search-form', 'comment-form', 'gallery', 'caption' ) );
}
add_action( 'after_setup_theme', 'acme_studio_setup' );title-tag lets WordPress (and SEO plugins) manage the page title, post-thumbnails enables featured images, custom-logo adds a logo option, and html5 switches core markup to modern HTML. Stylesheets and scripts are loaded with wp_enqueue_style() and wp_enqueue_script() on the wp_enqueue_scripts hook, never hard-coded into the header.
Starting from a starter theme
Writing every file from nothing is a good exercise, but for real projects, a starter theme saves hours. The WordPress Theme Generator creates a clean classic theme with your name, description, author, version, text domain and license already filled in. It includes the core templates (index, header, footer, sidebar, single and 404), reusable template parts for posts, a main JavaScript file, and a README. Every function and constant is prefixed with your theme slug so it will not clash with plugins.
You can also choose optional extras:
- Widget areas: a primary sidebar and a footer widget area.
- Customizer settings: a Theme Options panel with an accent colour, applied through a CSS variable, and a footer text field.
- A starter custom post type in
inc/post-types.php, with a note that long-lived content belongs in a plugin.
It downloads as a ZIP containing the theme folder, ready for Appearance → Themes → Add New → Upload Theme.
A practical path to a finished design
1. Work locally
Install WordPress on your own computer with a local development tool, and put the theme in wp-content/themes. You can edit files and refresh instantly, without risking a live site.
2. Start with the global styles
The generated stylesheet uses CSS variables such as --color-primary, --color-text and --spacing-base in :root. Set your brand colours, fonts and spacing there first; the whole theme picks them up.
3. Build the header and footer
These appear on every page, so getting them right early gives the whole site its character. Keep wp_head() and wp_footer() in place.
4. Style the content
Most of a site's pages are posts and pages. Make body text comfortable to read, with a sensible line length, clear headings and good spacing, before adding decorative touches.
5. Add specific templates only when needed
A homepage layout, a portfolio archive, a landing page template: add them as the design requires, following the template hierarchy.
6. Keep it fast
A custom theme is a chance to be lighter than any multipurpose theme. Load only the CSS and JavaScript you use, size images properly, and give them dimensions to avoid layout shifts. Check the result with the Core Web Vitals Checker; our Core Web Vitals guide explains what to fix first.
What belongs in a theme and what does not
Themes should handle presentation. Features that must survive a redesign, such as custom post types, shortcodes, contact forms and integrations, belong in a plugin. If a client switches themes in three years, their content and functionality should stay intact. The WordPress Plugin Generator is a quick way to start that companion plugin, and our guide to creating your first WordPress plugin explains the basics.
Security and good habits
Themes print a lot of data, so escaping matters: use esc_html() for text, esc_attr() for attributes and esc_url() for links whenever you output something that could come from a user or the database. The WordPress Functions Reference has quick examples.
A few more habits worth adopting early: put the theme in version control from the first day, keep the text domain matching the theme folder name so translations work, and prefer a child theme when you only need to adjust someone else's theme rather than building your own.
Your own theme, your own pace
A custom theme does not need to be ambitious. Start with a clean starter, set your colours and fonts, build the header, footer and post templates, and add more only when the site needs it. The result is a site that loads quickly, does exactly what it should, and never makes you fight settings you did not ask for.




