WordPress theme development transforms design concepts into functional WordPress interfaces through template files, functions.php, style.css, and template hierarchy. From basic index.php and style.css requirements to advanced custom templates, post types integration, and theme customization APIs, custom themes provide complete design control beyond pre-built options. This comprehensive guide teaches theme file structure, template hierarchy, WordPress loops, navigation menus, widget areas, and modern theme development workflows.
Theme File Structure
Minimum Required Files:
mytheme/
├── style.css (required)
├── index.php (required)
├── screenshot.png (recommended)
Complete Theme Structure:
mytheme/
├── style.css
├── index.php
├── functions.php
├── header.php
├── footer.php
├── sidebar.php
├── single.php
├── page.php
├── archive.php
├── search.php
├── 404.php
├── comments.php
├── screenshot.png
├── template-parts/
│ ├── content.php
│ └── content-none.php
├── inc/
│ ├── custom-header.php
│ └── template-tags.php
├── js/
│ └── custom.js
├── css/
│ └── custom.css
└── languages/
└── mytheme.pot
Style.css Header
Required Theme Metadata:
/*
Theme Name: My Custom Theme
Theme URI: https://example.com/my-theme
Author: Your Name
Author URI: https://example.com
Description: A custom WordPress theme built from scratch
Version: 1.0.0
Requires at least: 6.0
Tested up to: 6.4
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: mytheme
Tags: custom-background, custom-logo, custom-menu, featured-images, threaded-comments
*/Only Theme Name required, but all recommended.
Index.php Template
Basic index.php Structure:
<?php get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main">
<?php
if (have_posts()) :
while (have_posts()) :
the_post();
?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<h2 class="entry-title">
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</h2>
</header>
<div class="entry-content">
<?php the_excerpt(); ?>
</div>
<footer class="entry-footer">
<span class="posted-on"><?php echo get_the_date(); ?></span>
<span class="byline"> by <?php the_author(); ?></span>
</footer>
</article>
<?php
endwhile;
the_posts_navigation();
else :
?>
<p><?php esc_html_e('No posts found', 'mytheme'); ?></p>
<?php endif; ?>
</main>
</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>Header.php Template
Standard Header Structure:
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo('charset'); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="profile" href="https://gmpg.org/xfn/11">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<div id="page" class="site">
<a class="skip-link screen-reader-text" href="#primary"><?php esc_html_e('Skip to content', 'mytheme'); ?></a>
<header id="masthead" class="site-header">
<div class="site-branding">
<?php
if (has_custom_logo()) :
the_custom_logo();
else :
?>
<h1 class="site-title">
<a href="<?php echo esc_url(home_url('/')); ?>"><?php bloginfo('name'); ?></a>
</h1>
<p class="site-description"><?php bloginfo('description'); ?></p>
<?php endif; ?>
</div>
<nav id="site-navigation" class="main-navigation">
<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false">
<?php esc_html_e('Menu', 'mytheme'); ?>
</button>
<?php
wp_nav_menu(array(
'theme_location' => 'primary',
'menu_id' => 'primary-menu',
));
?>
</nav>
</header>
<div id="content" class="site-content">Footer.php Template
Standard Footer Structure:
</div><!-- #content -->
<footer id="colophon" class="site-footer">
<div class="site-info">
<a href="<?php echo esc_url(__('https://wordpress.org/', 'mytheme')); ?>">
<?php printf(esc_html__('Proudly powered by %s', 'mytheme'), 'WordPress'); ?>
</a>
<span class="sep"> | </span>
<?php printf(esc_html__('Theme: %1$s by %2$s.', 'mytheme'), 'My Custom Theme', '<a href="https://example.com">Your Name</a>'); ?>
</div>
</footer>
</div><!-- #page -->
<?php wp_footer(); ?>
</body>
</html>Functions.php Setup
Essential Functions:
<?php
/**
* Theme Functions
*/
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
/**
* Theme Setup
*/
function mytheme_setup() {
// Add default posts and comments RSS feed links to head
add_theme_support('automatic-feed-links');
// Let WordPress manage the document title
add_theme_support('title-tag');
// Enable support for Post Thumbnails
add_theme_support('post-thumbnails');
// Register navigation menus
register_nav_menus(array(
'primary' => esc_html__('Primary Menu', 'mytheme'),
'footer' => esc_html__('Footer Menu', 'mytheme'),
));
// Switch default core markup to HTML5
add_theme_support('html5', array(
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
'style',
'script',
));
// Add theme support for selective refresh for widgets
add_theme_support('customize-selective-refresh-widgets');
// Add support for custom logo
add_theme_support('custom-logo', array(
'height' => 100,
'width' => 400,
'flex-height' => true,
'flex-width' => true,
));
// Add support for custom background
add_theme_support('custom-background', array(
'default-color' => 'ffffff',
));
// Add support for Block Editor styles
add_theme_support('wp-block-styles');
// Add support for full and wide align images
add_theme_support('align-wide');
// Add support for editor styles
add_theme_support('editor-styles');
// Enqueue editor styles
add_editor_style('style-editor.css');
// Add support for responsive embeds
add_theme_support('responsive-embeds');
}
add_action('after_setup_theme', 'mytheme_setup');
/**
* Set content width
*/
function mytheme_content_width() {
$GLOBALS['content_width'] = apply_filters('mytheme_content_width', 800);
}
add_action('after_setup_theme', 'mytheme_content_width', 0);
/**
* Enqueue scripts and styles
*/
function mytheme_scripts() {
// Main stylesheet
wp_enqueue_style('mytheme-style', get_stylesheet_uri(), array(), '1.0.0');
// Custom stylesheet
wp_enqueue_style('mytheme-custom', get_template_directory_uri() . '/css/custom.css', array(), '1.0.0');
// Custom JavaScript
wp_enqueue_script('mytheme-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '1.0.0', true);
// Comment reply script
if (is_singular() && comments_open() && get_option('thread_comments')) {
wp_enqueue_script('comment-reply');
}
}
add_action('wp_enqueue_scripts', 'mytheme_scripts');
/**
* Register widget areas
*/
function mytheme_widgets_init() {
register_sidebar(array(
'name' => esc_html__('Sidebar', 'mytheme'),
'id' => 'sidebar-1',
'description' => esc_html__('Add widgets here.', 'mytheme'),
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
));
register_sidebar(array(
'name' => esc_html__('Footer', 'mytheme'),
'id' => 'footer-1',
'description' => esc_html__('Add footer widgets here.', 'mytheme'),
'before_widget' => '<div id="%1$s" class="widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
));
}
add_action('widgets_init', 'mytheme_widgets_init');Single.php Template
Single Post Template:
<?php get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main">
<?php
while (have_posts()) :
the_post();
?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<?php the_title('<h1 class="entry-title">', '</h1>'); ?>
<div class="entry-meta">
<span class="posted-on">
<?php echo get_the_date(); ?>
</span>
<span class="byline">
by <?php the_author_posts_link(); ?>
</span>
<span class="cat-links">
<?php the_category(', '); ?>
</span>
</div>
</header>
<?php if (has_post_thumbnail()) : ?>
<div class="post-thumbnail">
<?php the_post_thumbnail('large'); ?>
</div>
<?php endif; ?>
<div class="entry-content">
<?php
the_content();
wp_link_pages(array(
'before' => '<div class="page-links">' . esc_html__('Pages:', 'mytheme'),
'after' => '</div>',
));
?>
</div>
<footer class="entry-footer">
<?php the_tags('<span class="tags-links">', ', ', '</span>'); ?>
</footer>
</article>
<?php
// Previous/next post navigation
the_post_navigation(array(
'prev_text' => '<span class="nav-subtitle">' . esc_html__('Previous:', 'mytheme') . '</span> <span class="nav-title">%title</span>',
'next_text' => '<span class="nav-subtitle">' . esc_html__('Next:', 'mytheme') . '</span> <span class="nav-title">%title</span>',
));
// Comments
if (comments_open() || get_comments_number()) :
comments_template();
endif;
endwhile;
?>
</main>
</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>Page.php Template
Static Page Template:
<?php get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main">
<?php
while (have_posts()) :
the_post();
?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<?php the_title('<h1 class="entry-title">', '</h1>'); ?>
</header>
<div class="entry-content">
<?php
the_content();
wp_link_pages(array(
'before' => '<div class="page-links">' . esc_html__('Pages:', 'mytheme'),
'after' => '</div>',
));
?>
</div>
<?php if (comments_open() || get_comments_number()) : ?>
<?php comments_template(); ?>
<?php endif; ?>
</article>
<?php endwhile; ?>
</main>
</div>
<?php get_footer(); ?>Archive.php Template
Archive Listing Template:
<?php get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main">
<?php if (have_posts()) : ?>
<header class="page-header">
<?php
the_archive_title('<h1 class="page-title">', '</h1>');
the_archive_description('<div class="archive-description">', '</div>');
?>
</header>
<?php
while (have_posts()) :
the_post();
get_template_part('template-parts/content', 'excerpt');
endwhile;
the_posts_navigation();
else :
get_template_part('template-parts/content', 'none');
endif;
?>
</main>
</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>Template Parts
template-parts/content-excerpt.php:
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<?php the_title(sprintf('<h2 class="entry-title"><a href="%s">', esc_url(get_permalink())), '</a></h2>'); ?>
<div class="entry-meta">
<span class="posted-on"><?php echo get_the_date(); ?></span>
<span class="byline"> by <?php the_author(); ?></span>
</div>
</header>
<?php if (has_post_thumbnail()) : ?>
<div class="post-thumbnail">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail('medium'); ?>
</a>
</div>
<?php endif; ?>
<div class="entry-summary">
<?php the_excerpt(); ?>
</div>
<footer class="entry-footer">
<a href="<?php the_permalink(); ?>" class="read-more">
<?php esc_html_e('Read More', 'mytheme'); ?>
</a>
</footer>
</article>Sidebar.php Template
Widget Area Sidebar:
<?php
if (!is_active_sidebar('sidebar-1')) {
return;
}
?>
<aside id="secondary" class="widget-area">
<?php dynamic_sidebar('sidebar-1'); ?>
</aside>Search.php Template
Search Results Template:
<?php get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main">
<?php if (have_posts()) : ?>
<header class="page-header">
<h1 class="page-title">
<?php printf(esc_html__('Search Results for: %s', 'mytheme'), '<span>' . get_search_query() . '</span>'); ?>
</h1>
</header>
<?php
while (have_posts()) :
the_post();
get_template_part('template-parts/content', 'search');
endwhile;
the_posts_navigation();
else :
?>
<section class="no-results not-found">
<header class="page-header">
<h1 class="page-title"><?php esc_html_e('Nothing Found', 'mytheme'); ?></h1>
</header>
<div class="page-content">
<p><?php esc_html_e('Sorry, but nothing matched your search terms. Please try again with different keywords.', 'mytheme'); ?></p>
<?php get_search_form(); ?>
</div>
</section>
<?php endif; ?>
</main>
</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>Conclusion
WordPress theme development creates custom designs through template hierarchy, functions.php configuration, and modular template parts. Build themes from scratch using required style.css and index.php files, expand functionality through header.php, footer.php, single.php, page.php templates, register navigation menus and widget areas, enqueue stylesheets and scripts properly, and follow WordPress coding standards. Custom themes provide unlimited design flexibility and complete control over WordPress site appearance and functionality.
External Links
- WordPress Theme Handbook
- Template Hierarchy
- Theme Development Checklist
- WordPress Coding Standards
- Underscores Starter Theme
Call to Action
Custom themes need reliable backups. Backup Copilot Pro protects your WordPress theme files and database automatically. Safeguard your development work—start your free 30-day trial today!

