Theme Requirements and Standards
Learning Objectives
- Understand WordPress.org theme directory requirements
- Learn WordPress coding standards for themes
- Master security best practices for theme development
- Understand accessibility requirements
- Learn about licensing and GPL compliance
Introduction
Creating a WordPress theme that meets professional standards requires following established guidelines for code quality, security, accessibility, and licensing. Let's explore the requirements that ensure your theme is robust, secure, and ready for distribution.
Minimum Theme Requirements
Every WordPress theme must have at least these two files:
1. style.css - The Main Stylesheet
/*
Theme Name: Twenty Twenty-Five
Theme URI: https://wordpress.org/themes/twentytwentyfive/
Author: the WordPress team
Author URI: https://wordpress.org/
Description: Our default theme for 2025 is designed to be flexible, versatile and applicable to any website.
Requires at least: 6.0
Tested up to: 6.4
Requires PHP: 7.4
Version: 1.0
License: GPL v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: twentytwentyfive
Tags: blog, custom-background, custom-colors, custom-logo, custom-menu, editor-style, featured-images, footer-widgets, block-patterns, rtl-language-support, sticky-post, threaded-comments, translation-ready, accessibility-ready
*/
2. index.php - The Main Template File
<?php
/**
* The main template file
*
* This is the most generic template file in a WordPress theme
* and one of the two required files for a theme (the other being style.css).
*/
get_header();
?>
<main id="primary" class="site-main">
<?php
if ( have_posts() ) :
// Start the Loop
while ( have_posts() ) :
the_post();
// Include the Post-Format-specific template
get_template_part( 'template-parts/content', get_post_format() );
endwhile;
// Posts navigation
the_posts_navigation();
else :
// If no content, include the "No posts found" template
get_template_part( 'template-parts/content', 'none' );
endif;
?>
</main>
<?php
get_sidebar();
get_footer();
WordPress Coding Standards
WordPress has specific coding standards for PHP, HTML, CSS, and JavaScript:
PHP Coding Standards
<?php
// ✅ CORRECT: Using WordPress coding standards
// Naming Conventions
function my_theme_enqueue_scripts() { // snake_case for functions
$theme_version = '1.0.0'; // snake_case for variables
// Proper spacing around operators
if ( is_single() && ! is_attachment() ) {
wp_enqueue_script(
'my-theme-single', // kebab-case for handles
get_template_directory_uri() . '/assets/js/single.js',
array( 'jquery' ), // Dependencies
$theme_version,
true // Load in footer
);
}
}
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_scripts' );
// ❌ INCORRECT: Not following standards
function myThemeEnqueueScripts(){ // Should use snake_case
$themeVersion="1.0.0"; // Missing spaces
if(is_single()&&!is_attachment()) // Missing spaces
{ // Brace should be on same line
wp_enqueue_script('my_theme_single',...); // Should use kebab-case
}
}
HTML Standards
<!-- ✅ CORRECT: Semantic HTML5 -->
<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">
<time datetime="<?php echo get_the_date( 'c' ); ?>">
<?php echo get_the_date(); ?>
</time>
</div>
</header>
<div class="entry-content">
<?php the_content(); ?>
</div>
</article>
<!-- ❌ INCORRECT: Non-semantic HTML -->
<div class="post">
<div class="title"><?php the_title(); ?></div>
<div class="content"><?php the_content(); ?></div>
</div>
CSS Standards
/* ✅ CORRECT: Following CSS standards */
.site-header {
background-color: #ffffff;
padding: 1.5rem 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.site-header .site-title {
font-size: 1.875rem;
font-weight: 700;
margin: 0;
}
/* Media Queries */
@media screen and (min-width: 768px) {
.site-header {
padding: 2rem 0;
}
}
/* ❌ INCORRECT: Not following standards */
.site-header{background:#fff;padding:1.5rem 0} /* Everything on one line */
.site-header .site-title{font-size:30px} /* Using px instead of rem */
Security Requirements
Security is paramount in theme development. Follow these essential practices:
Data Validation and Sanitization
<?php
// ✅ CORRECT: Escaping output
?>
<h1><?php echo esc_html( get_the_title() ); ?></h1>
<a href="<?php echo esc_url( get_permalink() ); ?>">Read More</a>
<div class="<?php echo esc_attr( $custom_class ); ?>">Content</div>
<?php
// Sanitizing input
$clean_email = sanitize_email( $_POST['email'] );
$clean_text = sanitize_text_field( $_POST['username'] );
$clean_html = wp_kses_post( $_POST['bio'] );
// ❌ INCORRECT: Direct output without escaping
?>
<h1><?php echo $title; ?></h1> <!-- Unsafe! -->
<a href="<?php echo $url; ?>">Link</a> <!-- Unsafe! -->
Nonce Verification
<?php
// Creating a form with nonce
function my_theme_render_form() {
?>
<form method="post" action="">
<?php wp_nonce_field( 'my_theme_form_action', 'my_theme_form_nonce' ); ?>
<input type="text" name="user_data" />
<button type="submit">Submit</button>
</form>
<?php
}
// Verifying nonce on submission
function my_theme_process_form() {
if ( ! isset( $_POST['my_theme_form_nonce'] ) ||
! wp_verify_nonce( $_POST['my_theme_form_nonce'], 'my_theme_form_action' ) ) {
wp_die( 'Security check failed' );
}
// Process the form data
$user_data = sanitize_text_field( $_POST['user_data'] );
}
Accessibility Requirements
Themes should be accessible to all users, including those using assistive technologies:
Accessibility Best Practices
<!-- ✅ CORRECT: Accessible navigation -->
<nav id="site-navigation" class="main-navigation" role="navigation"
aria-label="<?php esc_attr_e( 'Primary Menu', 'textdomain' ); ?>">
<button class="menu-toggle" aria-controls="primary-menu"
aria-expanded="false">
<span class="screen-reader-text">
<?php esc_html_e( 'Menu', 'textdomain' ); ?>
</span>
<span class="menu-toggle-icon" aria-hidden="true">☰</span>
</button>
<?php
wp_nav_menu( array(
'theme_location' => 'primary',
'menu_id' => 'primary-menu',
'menu_class' => 'nav-menu',
'container' => 'ul',
) );
?>
</nav>
<!-- Skip links for keyboard navigation -->
<a class="skip-link screen-reader-text" href="#content">
<?php esc_html_e( 'Skip to content', 'textdomain' ); ?>
</a>
Color Contrast Requirements
/* ✅ CORRECT: Sufficient color contrast */
.entry-content {
color: #212529; /* Dark text */
background: #ffffff; /* White background */
/* Contrast ratio: 12.63:1 - Passes WCAG AAA */
}
.entry-content a {
color: #0066cc; /* Link color */
text-decoration: underline;
/* Contrast ratio: 8.59:1 - Passes WCAG AAA */
}
/* Focus indicators */
a:focus,
button:focus,
input:focus,
textarea:focus,
select:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
Internationalization (i18n)
Make your theme translation-ready from the start:
<?php
// ✅ CORRECT: Translation-ready strings
// Simple string
esc_html_e( 'Read More', 'my-theme-textdomain' );
// String with variable
printf(
/* translators: %s: Post title */
esc_html__( 'Leave a comment on %s', 'my-theme-textdomain' ),
get_the_title()
);
// Plural forms
printf(
/* translators: %s: Number of comments */
esc_html( _n(
'%s Comment',
'%s Comments',
get_comments_number(),
'my-theme-textdomain'
) ),
number_format_i18n( get_comments_number() )
);
// Context for translators
_x( 'Read', 'past participle: books I have read', 'my-theme-textdomain' );
// ❌ INCORRECT: Hard-coded strings
echo 'Read More'; // Not translatable
echo "Posted on $date"; // Not translatable
Loading Text Domain
<?php
/**
* Load theme textdomain
*/
function my_theme_load_textdomain() {
load_theme_textdomain(
'my-theme-textdomain',
get_template_directory() . '/languages'
);
}
add_action( 'after_setup_theme', 'my_theme_load_textdomain' );
Licensing Requirements
WordPress themes must be GPL-compatible:
License Declaration
<?php
/**
* My Theme functions and definitions
*
* @package My_Theme
* @since 1.0.0
* @license GPL v2 or later
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
WordPress.org Directory Requirements
If you plan to submit your theme to WordPress.org, additional requirements apply:
Required Theme Support Features
<?php
function my_theme_setup() {
// Required: Automatic feed links
add_theme_support( 'automatic-feed-links' );
// Required: Title tag support
add_theme_support( 'title-tag' );
// Required: Post thumbnails
add_theme_support( 'post-thumbnails' );
// Required: Custom logo
add_theme_support( 'custom-logo', array(
'height' => 100,
'width' => 350,
'flex-height' => true,
'flex-width' => true,
) );
// Required: HTML5 support
add_theme_support( 'html5', array(
'comment-form',
'comment-list',
'gallery',
'caption',
'style',
'script',
'navigation-widgets',
) );
// Required: Block editor support
add_theme_support( 'wp-block-styles' );
add_theme_support( 'responsive-embeds' );
// Recommended: Custom background
add_theme_support( 'custom-background' );
// Recommended: Editor styles
add_theme_support( 'editor-styles' );
add_editor_style( 'style-editor.css' );
}
add_action( 'after_setup_theme', 'my_theme_setup' );
Theme Standards Best Practices
- Use Theme Check Plugin: Test your theme against WordPress standards
- Follow PHP Standards: PSR-2 and WordPress-specific standards
- Validate HTML: Use W3C validator for HTML5 compliance
- Test Accessibility: Use WAVE or axe DevTools
- Check Color Contrast: Ensure WCAG AA compliance minimum
- Escape Everything: Never output raw data
- Prefix Everything: Use unique prefixes for functions, classes, and globals
- Document Your Code: Use PHPDoc for all functions and classes
Practice Exercise
Let's create a standards-compliant theme header file: