Classic Theme Structure

SkillAI & models

Build or audit a modern classic PHP WordPress theme structure for WP 7.1 without FSE/block-theme assumptions. Covers required `style.css` + `index.php`, `functions.php` as bootstrap, `after_setup_theme`, `wp_enqueue_scripts`, `get_theme_file_uri/path`, `wp_head`, `wp_body_open`, `wp_footer`, recommended `assets/`, `inc/`, `template-parts/`, `page-templates/`, `languages/`, child-theme-safe paths, theme supports, menus, sidebars, and what belongs in a plugin instead of a theme. Use when scaffolding/reviewing a non-FSE theme, converting static HTML to a theme, or deciding where theme files/hooks belong.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Classic Theme Structure skill

What this skill tells your AI

The instructions your AI receives, as published by lonsdale201/wp-agent-skills in theme-development/classic-theme-structure/SKILL.md and read by ahel’s review.

Use this when creating or reviewing a classic PHP WordPress theme. This skill deliberately avoids FSE/block-theme architecture: no templates/*.html as the primary rendering layer, no Site Editor assumptions, and no Gutenberg/block development workflow.

The target is a secure, maintainable classic theme for WP 7.1.

When to Use This Skill

  • Scaffolding a new classic theme.
  • Converting static HTML/CSS into a WordPress theme.
  • Reviewing a theme folder for bad structure, missing hooks, direct asset tags, or business logic in functions.php.
  • The work mentions style.css, index.php, functions.php, header.php, footer.php, template-parts, after_setup_theme, wp_enqueue_scripts, or classic theme files.

Runtime Minimum vs Practical Minimum

WordPress recognizes a classic theme with:

  • style.css in the theme root, with a valid theme header.
  • index.php in the theme root, as the final template fallback.

For real projects, also include:

  • functions.php for bootstrap/hooks.
  • header.php and footer.php.
  • 404.php, page.php, single.php, archive.php, search.php.
  • comments.php if comments are supported.
  • screenshot.png for admin display and distribution.

Do not create a block theme by accident. A classic theme's fallback template is root index.php, not templates/index.html.

Recommended Folder Layout

mytheme/
|-- style.css
|-- functions.php
|-- index.php
|-- header.php
|-- footer.php
|-- 404.php
|-- page.php
|-- single.php
|-- archive.php
|-- search.php
|-- comments.php
|-- screenshot.png
|-- assets/
|   |-- css/
|   |-- js/
|   |-- images/
|   `-- fonts/
|-- inc/
|   |-- setup.php
|   |-- enqueue.php
|   |-- template-tags.php
|   |-- template-functions.php
|   `-- customizer.php
|-- template-parts/
|   |-- content.php
|   |-- content-page.php
|   |-- content-none.php
|   `-- content-search.php
|-- page-templates/
|   `-- full-width.php
`-- languages/

Keep root templates thin. Put repeatable PHP helpers in inc/, repeatable markup in template-parts/, and static assets in assets/.

style.css Header

style.css must live in the theme root. WordPress parses its header through WP_Theme.

/*
Theme Name: MyTheme
Theme URI: https://example.com/mytheme
Author: Example Team
Description: A classic PHP WordPress theme.
Version: 1.0.0
Requires at least: 7.1
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: mytheme
Domain Path: /languages
*/

Tested up to is not a style.css theme header parsed by WP_Theme; do not copy the plugin/readme field into this file. Record release testing in the distribution metadata or project documentation instead.

For a child theme, add Template: parent-theme-folder-name.

functions.php as Bootstrap

functions.php loads on frontend and admin. In a child theme, the child functions.php loads before the parent functions.php.

Use it as a bootstrap, not as a 2,000-line application file:

<?php
/**
 * Theme bootstrap.
 *
 * @package MyTheme
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

define( 'MYTHEME_VERSION', wp_get_theme()->get( 'Version' ) );

require_once get_template_directory() . '/inc/setup.php';
require_once get_template_directory() . '/inc/enqueue.php';
require_once get_template_directory() . '/inc/template-tags.php';
require_once get_template_directory() . '/inc/template-functions.php';

Use get_template_directory() for parent-theme code includes. Use get_theme_file_path() when child themes should be able to override a file.

Do not put custom post types, business rules, payment logic, CRM sync, or data migrations in a theme. If the feature should survive a theme switch, build a plugin.

Theme Setup

Register theme support and theme-owned features on after_setup_theme.

<?php
/**
 * Setup theme defaults.
 *
 * @package MyTheme
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

add_action( 'after_setup_theme', 'mytheme_setup' );

function mytheme_setup(): void {
    load_theme_textdomain( 'mytheme', get_template_directory() . '/languages' );

    add_theme_support( 'title-tag' );
    add_theme_support( 'post-thumbnails' );
    add_theme_support( 'automatic-feed-links' );
    add_theme_support(
        'html5',
        array( 'search-form', 'comment-form', 'comment-list', 'gallery', 'caption', 'script', 'style' )
    );

    register_nav_menus(
        array(
            'primary' => __( 'Primary Menu', 'mytheme' ),
            'footer'  => __( 'Footer Menu', 'mytheme' ),
        )
    );
}

Register widget areas on widgets_init, not in global scope:

add_action( 'widgets_init', 'mytheme_register_sidebars' );

function mytheme_register_sidebars(): void {
    register_sidebar(
        array(
            'name'          => __( 'Sidebar', 'mytheme' ),
            'id'            => 'sidebar-1',
            'before_widget' => '<section id="%1$s" class="widget %2$s">',
            'after_widget'  => '</section>',
            'before_title'  => '<h2 class="widget-title">',
            'after_title'   => '</h2>',
        )
    );
}

Assets

Never hardcode <link> or <script> tags in templates. Enqueue assets on wp_enqueue_scripts.

add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_assets' );

function mytheme_enqueue_assets(): void {
    wp_enqueue_style(
        'mytheme-style',
        get_stylesheet_uri(),
        array(),
        MYTHEME_VERSION
    );

    $script = 'assets/js/main.js';
    $path   = get_theme_file_path( $script );

    wp_enqueue_script(
        'mytheme-main',
        get_theme_file_uri( $script ),
        array(),
        file_exists( $path ) ? filemtime( $path ) : MYTHEME_VERSION,
        array(
            'strategy'  => 'defer',
            'in_footer' => true,
        )
    );
}

Use child-theme-safe helpers:

NeedFunction
Active theme stylesheet URLget_stylesheet_uri()
Child override first, then parent URLget_theme_file_uri( 'assets/js/main.js' )
Child override first, then parent pathget_theme_file_path( 'inc/file.php' )
Parent theme URL onlyget_parent_theme_file_uri( 'assets/css/base.css' )
Parent theme path onlyget_template_directory() . '/inc/file.php'

Required Hooks in Templates

header.php must include:

  • language_attributes() on <html>.
  • bloginfo( 'charset' ) or equivalent charset meta.
  • wp_head() before </head>.
  • body_class() on <body>.
  • wp_body_open() immediately after <body>.

footer.php must include wp_footer() before </body>.

Without these, plugins and WordPress core cannot enqueue scripts/styles, inject metadata, render admin bar assets, or hook accessibility integrations correctly.

Structural Rules

  • Prefix global functions with the theme slug, or use a unique namespace for non-template helper code.
  • Do not close PHP-only files with ?>.
  • Use lowercase, hyphenated file names for ordinary files.
  • Use require_once for mandatory includes.
  • Use get_template_part( 'template-parts/content', 'page', $args ) instead of global variables for reusable markup.
  • Keep templates focused on presentation. Query manipulation belongs in hooks such as pre_get_posts, and portable site features belong in plugins.

What This Skill Does Not Cover

  • Block themes, FSE, theme.json, block templates, block patterns, and Site Editor workflows.
  • Deep template hierarchy decisions; use classic-template-hierarchy.
  • Detailed escaping/security review; use classic-theme-security-standards and wp-security-audit.

References

Signals

GitHub stars
22
Forks
2
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
classic-theme-structure
Source
github.com/lonsdale201/wp-agent-skills