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:

FilePurpose
style.cssMust 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.phpThe 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');
Note: This is real, correct WordPress theme code meant to be copied into your own 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:

ConceptWhat it means
Parent themeThe original, complete theme (e.g. a downloaded theme like Astra or Twenty Twenty-Four).
Child themeA 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.

Next up: Template Hierarchy explains exactly which template file WordPress picks for any given page — the rule system that decides between index.php and all the more specific templates you can add.