Custom Templates
Complete reference for customTemplates in theme.json.
Overview
The customTemplates array registers custom page/post templates that users can select in the editor.
{
"customTemplates": [
{
"name": "blank",
"title": "Blank",
"postTypes": ["page", "post"]
},
{
"name": "full-width",
"title": "Full Width",
"postTypes": ["page"]
}
]
}
Template Definition
Each template object:
| Property | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Template file name (without extension) |
title |
string | Yes | Display name in editor template selector |
postTypes |
array | No | Post types this template is available for |
File Structure
Templates are stored in the templates/ directory:
theme-root/
├── theme.json
├── templates/
│ ├── index.html # Required fallback
│ ├── single.html # Single post
│ ├── page.html # Pages
│ ├── archive.html # Archives
│ ├── blank.html # Custom: Blank template
│ ├── full-width.html # Custom: Full width template
│ └── landing-page.html # Custom: Landing page template
└── parts/
├── header.html
└── footer.html
Registration
Basic Template
{
"customTemplates": [
{
"name": "blank",
"title": "Blank"
}
]
}
With corresponding templates/blank.html:
<!-- wp:post-content /-->
Template with Post Types
{
"customTemplates": [
{
"name": "full-width",
"title": "Full Width",
"postTypes": ["page"]
}
]
}
Only available when editing pages.
Multiple Post Types
{
"customTemplates": [
{
"name": "no-title",
"title": "No Title",
"postTypes": ["page", "post"]
}
]
}
Available for both pages and posts.
All Post Types
Omit postTypes to make available for all:
{
"customTemplates": [
{
"name": "blank",
"title": "Blank"
}
]
}
Template Content Examples
Blank Template
templates/blank.html:
<!-- wp:post-content {"layout":{"type":"constrained"}} /-->
Minimal template with just the content.
Full Width Template
templates/full-width.html:
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<!-- wp:group {"tagName":"main","layout":{"type":"default"}} -->
<main class="wp-block-group">
<!-- wp:post-content {"layout":{"type":"default"}} /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
No width constraints on content.
Landing Page Template
templates/landing-page.html:
<!-- wp:group {"tagName":"main","style":{"spacing":{"padding":{"top":"0","bottom":"0"}}},"layout":{"type":"default"}} -->
<main class="wp-block-group" style="padding-top:0;padding-bottom:0">
<!-- wp:post-content {"layout":{"type":"default"}} /-->
</main>
<!-- /wp:group -->
No header/footer, full-width, no padding.
Page with Sidebar Template
templates/page-sidebar.html:
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
<!-- wp:columns {"style":{"spacing":{"blockGap":{"left":"var:preset|spacing|60"}}}} -->
<div class="wp-block-columns">
<!-- wp:column {"width":"70%"} -->
<div class="wp-block-column" style="flex-basis:70%">
<!-- wp:post-content /-->
</div>
<!-- /wp:column -->
<!-- wp:column {"width":"30%"} -->
<div class="wp-block-column" style="flex-basis:30%">
<!-- wp:template-part {"slug":"sidebar"} /-->
</div>
<!-- /wp:column -->
</div>
<!-- /wp:columns -->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
Single Post – No Featured Image
templates/single-no-image.html:
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
<!-- wp:group {"layout":{"type":"constrained","contentSize":"720px"}} -->
<div class="wp-block-group">
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-date /-->
<!-- wp:post-content /-->
<!-- wp:post-terms {"term":"post_tag"} /-->
</div>
<!-- /wp:group -->
<!-- wp:comments /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
Complete theme.json Example
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"customTemplates": [
{
"name": "blank",
"title": "Blank",
"postTypes": ["page", "post"]
},
{
"name": "full-width",
"title": "Full Width",
"postTypes": ["page"]
},
{
"name": "landing-page",
"title": "Landing Page",
"postTypes": ["page"]
},
{
"name": "page-sidebar",
"title": "Page with Sidebar",
"postTypes": ["page"]
},
{
"name": "single-no-image",
"title": "Post - No Featured Image",
"postTypes": ["post"]
},
{
"name": "single-narrow",
"title": "Post - Narrow Content",
"postTypes": ["post"]
},
{
"name": "portfolio-item",
"title": "Portfolio Item",
"postTypes": ["portfolio"]
}
]
}
Custom Post Type Templates
For custom post types:
{
"customTemplates": [
{
"name": "product-full",
"title": "Product - Full Width",
"postTypes": ["product"]
},
{
"name": "event-single",
"title": "Event Detail",
"postTypes": ["event"]
}
]
}
Note: The custom post type must already be registered in WordPress for the template to appear.
How Users Select Templates
- Edit a page/post in the block editor
- Open the document settings sidebar (right panel)
- Find "Template" section
- Click the template name to open selector
- Choose from available templates
Templates appear based on:
- Whether template’s
postTypesincludes current post type - If
postTypesis omitted, template appears for all post types
Template Hierarchy
Custom templates exist alongside WordPress’s template hierarchy:
1. Custom template (if selected)
↓
2. Standard hierarchy (single-{post-type}.html, single.html, etc.)
↓
3. index.html (fallback)
When a user selects a custom template, it overrides the standard hierarchy for that specific post/page.
Best Practices
Naming Conventions
{
"customTemplates": [
{ "name": "page-blank", "title": "Page - Blank" },
{ "name": "page-full-width", "title": "Page - Full Width" },
{ "name": "page-sidebar-left", "title": "Page - Sidebar Left" },
{ "name": "page-sidebar-right", "title": "Page - Sidebar Right" },
{ "name": "single-minimal", "title": "Post - Minimal" },
{ "name": "single-featured", "title": "Post - Large Featured Image" },
{ "name": "archive-grid", "title": "Archive - Grid Layout" }
]
}
Descriptive Titles
Good titles:
- "Landing Page (No Header/Footer)"
- "Full Width – No Sidebar"
- "Blog Post – Featured Image Hero"
Bad titles:
- "Template 1"
- "Custom"
- "New Layout"
Limit Template Count
Aim for 3-6 custom templates. Too many creates confusion.
Document Templates
Include template descriptions in theme documentation so users understand when to use each.
PHP Access
Check if a custom template is being used:
// Get current template
$template = get_page_template_slug();
// Check for specific template
if ( 'blank' === get_page_template_slug() ) {
// This page uses the blank template
}
Get all registered custom templates:
$theme = wp_get_theme();
$templates = $theme->get_page_templates();
// Returns array: ['blank' => 'Blank', 'full-width' => 'Full Width', ...]
Relationship with templateParts
Custom templates typically use template parts:
<!-- templates/full-width.html -->
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:post-content /-->
<!-- wp:template-part {"slug":"footer"} /-->
Define template parts in templateParts:
{
"customTemplates": [
{ "name": "full-width", "title": "Full Width" }
],
"templateParts": [
{ "name": "header", "area": "header", "title": "Header" },
{ "name": "footer", "area": "footer", "title": "Footer" }
]
}
See template-parts.md for details.