Claude Skill

classic-theme-structure

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`,

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download lonsdale201-wp-agent-skills-theme-development_classic-theme-structure-52f6020.zip · 3 KB
Part of lonsdale201/wp-agent-skills — 226 skills

Install

skills CLI npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/theme-development/classic-theme-structure
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
Git git clone https://github.com/Lonsdale201/wp-agent-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Classic Theme Structure

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:

Need Function
Active theme stylesheet URL get_stylesheet_uri()
Child override first, then parent URL get_theme_file_uri( 'assets/js/main.js' )
Child override first, then parent path get_theme_file_path( 'inc/file.php' )
Parent theme URL only get_parent_theme_file_uri( 'assets/css/base.css' )
Parent theme path only get_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 wp-security-audit.

References

Files (wp-agent-skills)
  • SKILL.md 9.3 KB
    ---
    name: classic-theme-structure
    description: 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.
    metadata:
      wp-skills-author: "Soczó Kristóf"
      wp-skills-contact: "mailto:lonsdale201@hotmail.com"
      wp-skills-plugin: "wordpress"
      wp-skills-plugin-version-tested: "7.1"
      wp-skills-wp-version-tested: "7.1"
      wp-skills-php-min: "7.4"
      wp-skills-last-updated: "2026-08-20"
    ---
    
    # Classic Theme Structure
    
    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
    
    ```text
    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`.
    
    ```css
    /*
    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
    <?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
    <?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:
    
    ```php
    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`.
    
    ```php
    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:
    
    | Need | Function |
    |---|---|
    | Active theme stylesheet URL | `get_stylesheet_uri()` |
    | Child override first, then parent URL | `get_theme_file_uri( 'assets/js/main.js' )` |
    | Child override first, then parent path | `get_theme_file_path( 'inc/file.php' )` |
    | Parent theme URL only | `get_parent_theme_file_uri( 'assets/css/base.css' )` |
    | Parent theme path only | `get_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 `wp-security-audit`.
    
    ## References
    
    - Official documentation: <https://developer.wordpress.org/themes/classic-themes/>
    - Official documentation: <https://developer.wordpress.org/themes/releasing-your-theme/required-theme-files/>
    - Official documentation: <https://developer.wordpress.org/themes/classic-themes/basics/main-stylesheet-style-css/>
    - Official documentation: <https://developer.wordpress.org/themes/core-concepts/custom-functionality/>
    - Official documentation: <https://developer.wordpress.org/themes/core-concepts/including-assets/>
    - Verified source paths:
      - `wp-includes/template-loader.php`
      - `wp-includes/template.php`
      - `wp-includes/general-template.php`
      - `wp-includes/theme.php`
      - `wp-includes/link-template.php`
      - `wp-includes/functions.wp-scripts.php`
      - `wp-includes/functions.wp-styles.php`
      - `wp-includes/class-wp-theme.php`
      - `wp-content/themes/storefront/`
      - `wp-content/themes/generatepress/`
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related