Theme Development Basics
A WordPress theme controls everything about how your site looks and how content is
laid out on the page. Technically, a theme is nothing more than a folder inside
wp-content/themes/ containing a handful of PHP and CSS files that follow a few conventions
WordPress expects. This page builds a minimal, working theme from scratch.
1. The Two Required Files
WordPress will only recognize a folder in wp-content/themes/ as an activatable theme if it
contains at least these two files:
| File | Purpose |
|---|---|
style.css | Must start with a special comment header that declares the theme's metadata — this is how WordPress identifies and lists the theme in the admin. |
index.php | The fallback template — if no more specific template matches (see the next lesson), this file renders the page. |
2. The style.css Header Block
Even though it's a CSS file, style.css must open with a comment block WordPress parses to
populate the Appearance → Themes screen:
/*
Theme Name: My First Theme
Theme URI: https://example.com/my-first-theme
Author: Sonu Kumar Pandit
Author URI: https://codingwithsonu.com
Description: A minimal starter theme used for learning WordPress theme development.
Version: 1.0
License: GPL v2 or later
Text Domain: my-first-theme
*/
body {
font-family: sans-serif;
line-height: 1.6;
}
Only Theme Name is strictly required, but filling in the rest is good practice, especially
if you ever plan to distribute the theme publicly.
3. Standard Template Files
Beyond the two required files, nearly every real-world theme splits repeated markup into its own files so it isn't duplicated across every template:
header.php— the opening<html>,<head>, and site navigation, shared by every page.footer.php— the closing markup, widget areas, and closing</html>tag.sidebar.php— a reusable sidebar widget area.functions.php— not a template at all, but a special file WordPress auto-loads for every request (explained below).
These pieces are pulled into any template file with three matching functions:
<?php get_header(); ?>
// ... page-specific content and the Loop go here ...
<?php get_sidebar(); ?>
<?php get_footer(); ?>
get_header() includes header.php, get_sidebar() includes
sidebar.php, and get_footer() includes footer.php — each one also
supports an optional name argument (e.g. get_header('shop') to load
header-shop.php) for theme variants.
4. functions.php: Your Theme's "Plugin"
functions.php runs automatically on every page load, just like a plugin would. It's the
standard place to register features and hook into WordPress rather than editing core. Two very common
jobs done here are registering navigation menu locations and widget (sidebar) areas:
<?php
function my_theme_setup() {
register_nav_menus([
'primary' => 'Primary Navigation',
'footer' => 'Footer Menu',
]);
}
add_action('after_setup_theme', 'my_theme_setup');
function my_theme_widgets() {
register_sidebar([
'name' => 'Main Sidebar',
'id' => 'sidebar-1',
'before_widget' => '<div class="widget">',
'after_widget' => '</div>',
]);
}
add_action('widgets_init', 'my_theme_widgets');
functions.php — this tutorial site doesn't run WordPress itself, so it isn't executed live on this page.5. Declaring Theme Support with add_theme_support()
Many WordPress core features (featured images, custom logos, the modern block editor's title field) are
opt-in per theme. You turn them on inside functions.php with add_theme_support(),
usually inside the same setup function used above:
<?php
function my_theme_setup() {
add_theme_support('post-thumbnails'); // enables featured images
add_theme_support('title-tag'); // lets WordPress manage <title>
add_theme_support('custom-logo');
}
add_action('after_setup_theme', 'my_theme_setup');
Without add_theme_support('post-thumbnails'), calling the_post_thumbnail() in
a template (from the previous Loop lesson) simply won't output anything, even if an image was set —
this trips up a lot of first-time theme authors.
6. A Full Minimal Working Theme
Putting it together, here is a genuinely minimal but functional theme's index.php, reusing
the Loop from the previous lesson:
<?php get_header(); ?>
<main>
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<article>
<h2><?php the_title(); ?></h2>
<?php the_excerpt(); ?>
</article>
<?php endwhile; endif; ?>
</main>
<?php get_sidebar(); get_footer(); ?>
Along with the style.css header block and the functions.php shown above, this
is enough for WordPress to list, activate, and correctly render your own custom theme.
7. Parent Themes vs Child Themes
Once a theme grows popular, you'll often want to customize it without losing your changes when the original author releases an update. This is exactly what a child theme solves:
| Concept | What it means |
|---|---|
| Parent theme | The original, complete theme (e.g. a downloaded theme like Astra or Twenty Twenty-Four). |
| Child theme | A separate, small theme folder that declares the parent via a Template: line in its own style.css, and only contains the specific files you want to override. |
Because a child theme's files simply override the parent's matching files (WordPress checks the child theme first, then falls back to the parent), you get to safely customize appearance and behavior while the parent theme continues to receive updates safely.
index.php and all the more specific templates you can add.