WordPress Theme Development Skill
Overview
Comprehensive guide for developing WordPress themes following best practices. Covers both classic PHP-based themes and modern FSE (Full Site Editing) block themes. Core principle: Build accessible, performant, and WordPress-standards-compliant themes.
When to Use
Use when:
- Building new WordPress themes (classic or block)
- Creating child themes
- Implementing template hierarchy
- Adding customizer options
- Setting up FSE templates and template parts
- Troubleshooting theme issues
Don't use for:
- Plugin development (use wp-plugin-development)
- Block development specifically (use wp-gutenberg-blocks)
- Security auditing (use wp-security-review)
Theme Types Overview
| Type | Description | Key Files | |------|-------------|-----------| | Classic Theme | PHP templates, customizer | style.css, functions.php, templates/.php | | Block Theme | FSE, theme.json based | style.css, theme.json, templates/.html, parts/*.html | | Hybrid Theme | Mix of both approaches | All of the above | | Child Theme | Extends parent theme | style.css, functions.php |
Classic Theme Structure
theme-name/
├── assets/
│ ├── css/
│ │ ├── style.css # Compiled styles
│ │ └── editor-style.css # Editor styles
│ ├── js/
│ │ ├── main.js # Main scripts
│ │ └── navigation.js # Nav scripts
│ ├── images/
│ └── fonts/
├── inc/
│ ├── customizer.php # Customizer settings
│ ├── template-functions.php # Template helpers
│ ├── template-tags.php # Template tags
│ ├── theme-setup.php # Theme setup
│ └── walker-nav.php # Custom walkers
├── template-parts/
│ ├── header/
│ │ ├── site-branding.php
│ │ └── site-navigation.php
│ ├── footer/
│ │ ├── footer-widgets.php
│ │ └── site-info.php
│ ├── content/
│ │ ├── content.php
│ │ ├── content-page.php
│ │ ├── content-single.php
│ │ └── content-none.php
│ └── components/
│ ├── post-meta.php
│ └── pagination.php
├── languages/
│ └── theme-name.pot
├── 404.php
├── archive.php
├── comments.php
├── footer.php
├── front-page.php
├── functions.php
├── header.php
├── index.php
├── page.php
├── screenshot.png # 1200x900px
├── search.php
├── sidebar.php
├── single.php
├── style.css
└── readme.txt
Block Theme Structure
theme-name/
├── assets/
│ ├── css/
│ │ └── custom.css
│ ├── js/
│ └── fonts/
├── parts/
│ ├── header.html
│ ├── footer.html
│ └── sidebar.html
├── patterns/
│ ├── hero.php
│ ├── featured-posts.php
│ └── call-to-action.php
├── styles/
│ ├── blue.json # Color variations
│ └── dark.json
├── templates/
│ ├── 404.html
│ ├── archive.html
│ ├── front-page.html
│ ├── home.html
│ ├── index.html
│ ├── page.html
│ ├── search.html
│ └── single.html
├── functions.php
├── screenshot.png
├── style.css
├── theme.json
└── readme.txt
Required Files
style.css Header
/*
Theme Name: Theme Name
Theme URI: https://example.com/theme
Author: Your Agency
Author URI: https://youragency.com
Description: A custom WordPress theme with modern features.
Version: 1.0.0
Requires at least: 6.0
Tested up to: 6.5
Requires PHP: 8.0
License: GPL v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: theme-name
Tags: block-patterns, block-styles, custom-colors, custom-logo, editor-style, full-site-editing, wide-blocks
Theme Name is based on starter theme components.
*/
functions.php Setup
<?php
/**
* Theme functions and definitions.
*
* @package Theme_Name
*/
if ( ! defined( 'THEME_NAME_VERSION' ) ) {
define( 'THEME_NAME_VERSION', '1.0.0' );
}
/**
* Theme setup.
*/
function theme_name_setup() {
// Make theme available for translation.
load_theme_textdomain( 'theme-name', get_template_directory() . '/languages' );
// Add default posts and comments RSS feed links.
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' );
set_post_thumbnail_size( 1200, 630, true );
// Add custom image sizes.
add_image_size( 'theme-name-featured', 1920, 1080, true );
add_image_size( 'theme-name-card', 600, 400, true );
// Register navigation menus.
register_nav_menus(
array(
'primary' => esc_html__( 'Primary Menu', 'theme-name' ),
'footer' => esc_html__( 'Footer Menu', 'theme-name' ),
'social' => esc_html__( 'Social Menu', 'theme-name' ),
)
);
// HTML5 markup support.
add_theme_support(
'html5',
array(
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
'style',
'script',
'navigation-widgets',
)
);
// Custom logo support.
add_theme_support(
'custom-logo',
array(
'height' => 100,
'width' => 400,
'flex-width' => true,
'flex-height' => true,
)
);
// Custom background support.
add_theme_support(
'custom-background',
array(
'default-color' => 'ffffff',
'default-image' => '',
)
);
// Block editor support.
add_theme_support( 'wp-block-styles' );
add_theme_support( 'align-wide' );
add_theme_support( 'responsive-embeds' );
// Editor color palette.
add_theme_support(
'editor-color-palette',
array(
array(
'name' => esc_html__( 'Primary', 'theme-name' ),
'slug' => 'primary',
'color' => '#0066cc',
),
array(
'name' => esc_html__( 'Secondary', 'theme-name' ),
'slug' => 'secondary',
'color' => '#6c757d',
),
array(
'name' => esc_html__( 'Dark', 'theme-name' ),
'slug' => 'dark',
'color' => '#212529',
),
array(
'name' => esc_html__( 'Light', 'theme-name' ),
'slug' => 'light',
'color' => '#f8f9fa',
),
)
);
// Editor font sizes.
add_theme_support(
'editor-font-sizes',
array(
array(
'name' => esc_html__( 'Small', 'theme-name' ),
'slug' => 'small',
'size' => 14,
),
array(
'name' => esc_html__( 'Normal', 'theme-name' ),
'slug' => 'normal',
'size' => 16,
),
array(
'name' => esc_html__( 'Large', 'theme-name' ),
'slug' => 'large',
'size' => 20,
),
array(
'name' => esc_html__( 'Huge', 'theme-name' ),
'slug' => 'huge',
'size' => 32,
),
)
);
}
add_action( 'after_setup_theme', 'theme_name_setup' );
/**
* Set content width.
*/
function theme_name_content_width() {
$GLOBALS['content_width'] = apply_filters( 'theme_name_content_width', 1200 );
}
add_action( 'after_setup_theme', 'theme_name_content_width', 0 );
/**
* Register widget areas.
*/
function theme_name_widgets_init() {
register_sidebar(
array(
'name' => esc_html__( 'Sidebar', 'theme-name' ),
'id' => 'sidebar-1',
'description' => esc_html__( 'Add widgets here.', 'theme-name' ),
'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', 'theme-name' ),
'id' => 'sidebar-footer',
'description' => esc_html__( 'Footer widget area.', 'theme-name' ),
'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', 'theme_name_widgets_init' );
/**
* Enqueue scripts and styles.
*/
function theme_name_scripts() {
// Main stylesheet.
wp_enqueue_style(
'theme-name-style',
get_stylesheet_uri(),
array(),
THEME_NAME_VERSION
);
// Additional styles.
wp_enqueue_style(
'theme-name-main',
get_template_directory_uri() . '/assets/css/main.css',
array( 'theme-name-style' ),
THEME_NAME_VERSION
);
// Main script.
wp_enqueue_script(
'theme-name-script',
get_template_directory_uri() . '/assets/js/main.js',
array(),
THEME_NAME_VERSION,
array(
'in_footer' => true,
'strategy' => 'defer',
)
);
// Navigation script.
wp_enqueue_script(
'theme-name-navigation',
get_template_directory_uri() . '/assets/js/navigation.js',
array(),
THEME_NAME_VERSION,
array(
'in_footer' => true,
'strategy' => 'defer',
)
);
// Localize script data.
wp_localize_script(
'theme-name-script',
'themeNameData',
array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'theme_name_nonce' ),
)
);
// Comment reply script.
if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
wp_enqueue_script( 'comment-reply' );
}
}
add_action( 'wp_enqueue_scripts', 'theme_name_scripts' );
/**
* Enqueue editor styles.
*/
function theme_name_editor_styles() {
add_editor_style(
array(
'assets/css/editor-style.css',
)
);
}
add_action( 'after_setup_theme', 'theme_name_editor_styles' );
/**
* Include required files.
*/
require get_template_directory() . '/inc/template-tags.php';
require get_template_directory() . '/inc/template-functions.php';
require get_template_directory() . '/inc/customizer.php';
Template Hierarchy
Template Selection Priority
# Single Post
single-{post-type}-{slug}.php
single-{post-type}.php
single.php
singular.php
index.php
# Page
page-{slug}.php
page-{id}.php
page.php
singular.php
index.php
# Category Archive
category-{slug}.php
category-{id}.php
category.php
archive.php
index.php
# Custom Post Type Archive
archive-{post-type}.php
archive.php
index.php
# Taxonomy Archive
taxonomy-{taxonomy}-{term}.php
taxonomy-{taxonomy}.php
taxonomy.php
archive.php
index.php
# Author Archive
author-{nicename}.php
author-{id}.php
author.php
archive.php
index.php
# Date Archive
date.php
archive.php
index.php
# Search Results
search.php
index.php
# 404 Error
404.php
index.php
# Front Page
front-page.php
home.php (if showing posts)
page.php (if showing page)
index.php
# Blog Home
home.php
index.php
Template Parts Usage
<?php
// In single.php.
get_header();
while ( have_posts() ) :
the_post();
// Load template part based on post format.
get_template_part( 'template-parts/content/content', get_post_format() );
// Previous/next navigation.
get_template_part( 'template-parts/components/post-navigation' );
// Comments.
if ( comments_open() || get_comments_number() ) {
comments_template();
}
endwhile;
get_sidebar();
get_footer();
<?php
// template-parts/content/content-single.php.
?>
<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">
<?php theme_name_posted_on(); ?>
<?php theme_name_posted_by(); ?>
</div>
</header>
<?php theme_name_post_thumbnail(); ?>
<div class="entry-content">
<?php
the_content();
wp_link_pages(
array(
'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'theme-name' ),
'after' => '</div>',
)
);
?>
</div>
<footer class="entry-footer">
<?php theme_name_entry_footer(); ?>
</footer>
</article>
Template Tags
Custom Template Tags (inc/template-tags.php)
<?php
/**
* Custom template tags for this theme.
*
* @package Theme_Name
*/
if ( ! function_exists( 'theme_name_posted_on' ) ) :
/**
* Prints HTML with meta information for the current post-date/time.
*/
function theme_name_posted_on() {
$time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>';
if ( get_the_time( 'U' ) !== get_the_modified_time( 'U' ) ) {
$time_string = '<time class="entry-date published" datetime="%1$s">%2$s</time><time class="updated" datetime="%3$s">%4$s</time>';
}
$time_string = sprintf(
$time_string,
esc_attr( get_the_date( DATE_W3C ) ),
esc_html( get_the_date() ),
esc_attr( get_the_modified_date( DATE_W3C ) ),
esc_html( get_the_modified_date() )
);
printf(
'<span class="posted-on">%s</span>',
'<a href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . $time_string . '</a>'
);
}
endif;
if ( ! function_exists( 'theme_name_posted_by' ) ) :
/**
* Prints HTML with meta information for the current author.
*/
function theme_name_posted_by() {
printf(
'<span class="byline">%s</span>',
'<span class="author vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">' . esc_html( get_the_author() ) . '</a></span>'
);
}
endif;
if ( ! function_exists( 'theme_name_post_thumbnail' ) ) :
/**
* Displays an optional post thumbnail.
*/
function theme_name_post_thumbnail() {
if ( post_password_required() || is_attachment() || ! has_post_thumbnail() ) {
return;
}
if ( is_singular() ) :
?>
<div class="post-thumbnail">
<?php the_post_thumbnail( 'theme-name-featured' ); ?>
</div>
<?php
else :
?>
<a class="post-thumbnail" href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
<?php
the_post_thumbnail(
'theme-name-card',
array(
'alt' => the_title_attribute( array( 'echo' => false ) ),
)
);
?>
</a>
<?php
endif;
}
endif;
if ( ! function_exists( 'theme_name_entry_footer' ) ) :
/**
* Prints HTML with meta information for the categories, tags and comments.
*/
function theme_name_entry_footer() {
// Hide category and tag text for pages.
if ( 'post' === get_post_type() ) {
$categories_list = get_the_category_list( esc_html__( ', ', 'theme-name' ) );
if ( $categories_list ) {
printf(
'<span class="cat-links">%s%s</span>',
esc_html__( 'Posted in ', 'theme-name' ),
$categories_list
);
}
$tags_list = get_the_tag_list( '', esc_html__( ', ', 'theme-name' ) );
if ( $tags_list ) {
printf(
'<span class="tags-links">%s%s</span>',
esc_html__( 'Tagged ', 'theme-name' ),
$tags_list
);
}
}
if ( ! is_single() && ! post_password_required() && ( comments_open() || get_comments_number() ) ) {
echo '<span class="comments-link">';
comments_popup_link(
sprintf(
/* translators: %s: post title */
esc_html__( 'Leave a Comment on %s', 'theme-name' ),
'<span class="screen-reader-text">' . get_the_title() . '</span>'
)
);
echo '</span>';
}
edit_post_link(
sprintf(
/* translators: %s: Name of current post */
esc_html__( 'Edit %s', 'theme-name' ),
'<span class="screen-reader-text">' . get_the_title() . '</span>'
),
'<span class="edit-link">',
'</span>'
);
}
endif;
Customizer Implementation
Customizer Settings (inc/customizer.php)
<?php
/**
* Theme Customizer settings.
*
* @package Theme_Name
*/
/**
* Register customizer settings.
*
* @param WP_Customize_Manager $wp_customize Theme Customizer object.
*/
function theme_name_customize_register( $wp_customize ) {
// Theme Options Panel.
$wp_customize->add_panel(
'theme_name_options',
array(
'title' => esc_html__( 'Theme Options', 'theme-name' ),
'description' => esc_html__( 'Configure theme settings.', 'theme-name' ),
'priority' => 130,
)
);
// Header Section.
$wp_customize->add_section(
'theme_name_header',
array(
'title' => esc_html__( 'Header', 'theme-name' ),
'panel' => 'theme_name_options',
'priority' => 10,
)
);
// Header Layout Setting.
$wp_customize->add_setting(
'header_layout',
array(
'default' => 'default',
'sanitize_callback' => 'theme_name_sanitize_select',
'transport' => 'refresh',
)
);
$wp_customize->add_control(
'header_layout',
array(
'label' => esc_html__( 'Header Layout', 'theme-name' ),
'section' => 'theme_name_header',
'type' => 'select',
'choices' => array(
'default' => esc_html__( 'Default', 'theme-name' ),
'centered' => esc_html__( 'Centered', 'theme-name' ),
'minimal' => esc_html__( 'Minimal', 'theme-name' ),
),
)
);
// Sticky Header Toggle.
$wp_customize->add_setting(
'sticky_header',
array(
'default' => false,
'sanitize_callback' => 'theme_name_sanitize_checkbox',
'transport' => 'refresh',
)
);
$wp_customize->add_control(
'sticky_header',
array(
'label' => esc_html__( 'Enable Sticky Header', 'theme-name' ),
'section' => 'theme_name_header',
'type' => 'checkbox',
)
);
// Footer Section.
$wp_customize->add_section(
'theme_name_footer',
array(
'title' => esc_html__( 'Footer', 'theme-name' ),
'panel' => 'theme_name_options',
'priority' => 20,
)
);
// Footer Copyright Text.
$wp_customize->add_setting(
'footer_copyright',
array(
'default' => '',
'sanitize_callback' => 'wp_kses_post',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
'footer_copyright',
array(
'label' => esc_html__( 'Copyright Text', 'theme-name' ),
'description' => esc_html__( 'Enter custom copyright text for the footer.', 'theme-name' ),
'section' => 'theme_name_footer',
'type' => 'textarea',
)
);
// Selective refresh for footer copyright.
$wp_customize->selective_refresh->add_partial(
'footer_copyright',
array(
'selector' => '.site-info',
'render_callback' => 'theme_name_customize_partial_copyright',
)
);
// Typography Section.
$wp_customize->add_section(
'theme_name_typography',
array(
'title' => esc_html__( 'Typography', 'theme-name' ),
'panel' => 'theme_name_options',
'priority' => 30,
)
);
// Body Font Size.
$wp_customize->add_setting(
'body_font_size',
array(
'default' => 16,
'sanitize_callback' => 'absint',
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
'body_font_size',
array(
'label' => esc_html__( 'Body Font Size (px)', 'theme-name' ),
'section' => 'theme_name_typography',
'type' => 'number',
'input_attrs' => array(
'min' => 12,
'max' => 24,
'step' => 1,
),
)
);
}
add_action( 'customize_register', 'theme_name_customize_register' );
/**
* Sanitize select input.
*
* @param string $input Input value.
* @param object $setting Setting object.
* @return string Sanitized value.
*/
function theme_name_sanitize_select( $input, $setting ) {
$input = sanitize_key( $input );
$choices = $setting->manager->get_control( $setting->id )->choices;
return ( array_key_exists( $input, $choices ) ? $input : $setting->default );
}
/**
* Sanitize checkbox.
*
* @param bool $checked Whether checked.
* @return bool
*/
function theme_name_sanitize_checkbox( $checked ) {
return ( ( isset( $checked ) && true === $checked ) ? true : false );
}
/**
* Render copyright partial.
*/
function theme_name_customize_partial_copyright() {
$copyright = get_theme_mod( 'footer_copyright' );
if ( $copyright ) {
echo wp_kses_post( $copyright );
} else {
printf(
/* translators: %s: Site name */
esc_html__( '© %1$s %2$s', 'theme-name' ),
esc_html( gmdate( 'Y' ) ),
esc_html( get_bloginfo( 'name' ) )
);
}
}
/**
* Enqueue customizer preview script.
*/
function theme_name_customize_preview_js() {
wp_enqueue_script(
'theme-name-customizer',
get_template_directory_uri() . '/assets/js/customizer.js',
array( 'customize-preview' ),
THEME_NAME_VERSION,
true
);
}
add_action( 'customize_preview_init', 'theme_name_customize_preview_js' );
/**
* Output customizer CSS.
*/
function theme_name_customizer_css() {
$body_font_size = get_theme_mod( 'body_font_size', 16 );
$css = "
body {
font-size: {$body_font_size}px;
}
";
wp_add_inline_style( 'theme-name-style', $css );
}
add_action( 'wp_enqueue_scripts', 'theme_name_customizer_css' );
Child Theme Setup
style.css
/*
Theme Name: Theme Name Child
Theme URI: https://example.com/theme-child
Description: Child theme for Theme Name
Author: Your Agency
Author URI: https://youragency.com
Template: theme-name
Version: 1.0.0
License: GPL v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: theme-name-child
*/
/* Custom styles below */
functions.php
<?php
/**
* Child theme functions.
*
* @package Theme_Name_Child
*/
/**
* Enqueue parent and child theme styles.
*/
function theme_name_child_enqueue_styles() {
$parent_style = 'theme-name-style';
// Parent theme stylesheet.
wp_enqueue_style(
$parent_style,
get_template_directory_uri() . '/style.css',
array(),
wp_get_theme( 'theme-name' )->get( 'Version' )
);
// Child theme stylesheet.
wp_enqueue_style(
'theme-name-child-style',
get_stylesheet_uri(),
array( $parent_style ),
wp_get_theme()->get( 'Version' )
);
}
add_action( 'wp_enqueue_scripts', 'theme_name_child_enqueue_styles' );
Accessibility Requirements
Skip Link
<!-- In header.php, right after <body> -->
<a class="skip-link screen-reader-text" href="#primary">
<?php esc_html_e( 'Skip to content', 'theme-name' ); ?>
</a>
/* Skip link styles */
.skip-link {
position: absolute;
left: -9999rem;
top: 2.5rem;
z-index: 999999999;
padding: 0.5rem 1rem;
background-color: #000;
color: #fff;
}
.skip-link:focus {
left: 1rem;
}
Accessible Navigation
<nav id="site-navigation" class="main-navigation" aria-label="<?php esc_attr_e( 'Primary Navigation', 'theme-name' ); ?>">
<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false">
<span class="screen-reader-text"><?php esc_html_e( 'Menu', 'theme-name' ); ?></span>
<span class="hamburger"></span>
</button>
<?php
wp_nav_menu(
array(
'theme_location' => 'primary',
'menu_id' => 'primary-menu',
'container' => false,
)
);
?>
</nav>
Screen Reader Text
.screen-reader-text {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}
.screen-reader-text:focus {
background-color: #f1f1f1;
border-radius: 3px;
box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
clip: auto !important;
clip-path: none;
color: #21759b;
display: block;
font-size: 0.875rem;
font-weight: 700;
height: auto;
left: 5px;
line-height: normal;
padding: 15px 23px 14px;
text-decoration: none;
top: 5px;
width: auto;
z-index: 100000;
}
Security Best Practices
// ❌ BAD: Unescaped output.
echo $title;
echo get_the_title();
// ✅ GOOD: Always escape output.
echo esc_html( $title );
echo esc_html( get_the_title() );
// ❌ BAD: Unescaped URLs.
<a href="<?php echo $url; ?>">
// ✅ GOOD: Escape URLs.
<a href="<?php echo esc_url( $url ); ?>">
// ❌ BAD: Unescaped attributes.
<input value="<?php echo $value; ?>">
// ✅ GOOD: Escape attributes.
<input value="<?php echo esc_attr( $value ); ?>">
// ❌ BAD: Using include with user input.
include $_GET['template'];
// ✅ GOOD: Validate template names.
$allowed = array( 'header', 'footer', 'sidebar' );
$template = sanitize_file_name( $_GET['template'] );
if ( in_array( $template, $allowed, true ) ) {
get_template_part( $template );
}
Performance Optimization
Lazy Load Images
// WordPress 5.5+ handles lazy loading automatically.
// For older versions or custom implementation:
function theme_name_lazy_load_images( $content ) {
return str_replace( '<img ', '<img loading="lazy" ', $content );
}
add_filter( 'the_content', 'theme_name_lazy_load_images' );
Defer Non-Critical CSS
function theme_name_defer_styles( $html, $handle ) {
$defer_handles = array( 'theme-name-print', 'theme-name-animations' );
if ( in_array( $handle, $defer_handles, true ) ) {
$html = str_replace(
"rel='stylesheet'",
"rel='preload' as='style' onload=\"this.rel='stylesheet'\"",
$html
);
}
return $html;
}
add_filter( 'style_loader_tag', 'theme_name_defer_styles', 10, 2 );
Preload Key Assets
function theme_name_preload_assets() {
// Preload main font.
echo '<link rel="preload" href="' . esc_url( get_template_directory_uri() ) . '/assets/fonts/main.woff2" as="font" type="font/woff2" crossorigin>';
}
add_action( 'wp_head', 'theme_name_preload_assets', 1 );
Theme Check Compliance
Before release, ensure:
- [ ] Passes Theme Check plugin (no errors)
- [ ] Passes Theme Sniffer (PHP coding standards)
- [ ] All strings are translation-ready
- [ ] Uses proper prefixing for functions, classes, options
- [ ] Includes screenshot.png (1200x900px)
- [ ] Includes readme.txt with proper format
- [ ] No bundled plugins (recommend instead)
- [ ] GPL-compatible license
- [ ] Escapes all output
- [ ] Sanitizes all input
- [ ] Uses proper enqueue functions
- [ ] Supports core WordPress features
Severity Definitions
| Severity | Description | |----------|-------------| | Critical | Theme won't work, security vulnerability | | Warning | Theme Check failure, accessibility issue | | Info | Best practice suggestion, optimization |