In this article, you’ll examine WordPress theme types and learn how to add block theme features to a classic theme, blending the best of both to create a powerful and flexible hybrid theme.
Table of Contents
Theme types
There are two primary theme types: classic themes and block themes.
An overview of block themes
In January 2022, WordPress 5.9 was released, and with it came the Site Editor. This new functionality allowed developers to create themes entirely from blocks while also allowing users more control over various areas of their sites, such as the header and footer, without having to write a single line of code.
A new method to apply styles globally across the site was also introduced, managed through a theme.json
file. Block themes simplify the creation of templates by leveraging a visual, block-based approach, allowing for the design of complex layouts directly in the editor. These features empower non-developers to make site-wide changes quickly and intuitively, while giving developers the flexibility to implement advanced functionality and create highly customizable themes.
An overview of classic themes
Classic themes are traditional PHP, HTML, CSS, and JavaScript based themes that date back nearly two decades to 2005, when WordPress 1.5 first introduced the theme system. They rely primarily on PHP to provide advanced functionality, which makes them a great option for developers who need to create themes with highly customized logic and integrations. Unfortunately, this dependency makes them far less accessible to non-developers as even the smallest of changes often require direct editing to the template files. While classic themes support the block editor, they do not support the Site Editor, which requires all parts of its templates to be block markup.
Key differences
Both theme types have several differences and understanding them is important to help you choose the right theme type for your project. Despite their differences, they also share a lot of functionality that you can gradually adopt over time.
The main differences between the theme types are:
- Site editor: Block themes are designed for the Site Editor which gives users more control over the look and feel of their templates, a feature that classic themes do not support.
- Templates: Classic themes leverage PHP files, allowing for highly customized templates through code. Block themes require HTML files made up of block-based markup and can be easily created right in the editor.
- Global styles: Classic themes have limited support for a
theme.json
file that can be expanded as more block theme features become available in classic themes.
Despite all the differences in functionality and how users work with each, one key difference makes a classic theme a block theme: the inclusion of a /templates/index.html
file. When this file is in place, WordPress will view it as a block theme.
Hybrid themes
Somewhere between a classic theme and a block theme, there’s a third approach that doesn’t get as much attention but is gaining more support with each WordPress release. That is the concept of a hybrid theme, one rooted in the traditional approach of a classic theme but able to leverage most of the modern features of a block theme.
Since WordPress 5.9, more and more block theme features have been made available to use in classic themes, allowing developers to gradually adopt these new features and use a mix of PHP or HTML files without making the full leap into a block theme. This is what is referred to as a hybrid theme, and throughout the rest of this article, each feature will be explored in detail.
Getting setup
To make things easier to follow along, you can clone an accompanying GitHub repository that uses underscores as a starting point. The repository contains a few new files that allow you to quickly test out hybrid theme functionality.
functions-hybrid.php
/assets/js/hybrid-theme.js
/assets/css/hybrid-theme.css
The functions-hybrid.php
file includes the two block asset enqueues that load the necessary CSS and JS files. If you are using your own theme while following along, here are the enqueues found in the example repository.
// Enqueue script into block editor
function hybrid_theme_enqueue_scripts() {
wp_enqueue_script(
'hybrid-theme-scripts',
get_template_directory_uri() . '/assets/js/hybrid-theme.js',
array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' ),
null,
true
);
}
add_action( 'enqueue_block_editor_assets', 'hybrid_theme_enqueue_scripts' );
// Enqueue styles in block editor and front end
function hybrid_theme_enqueue_styles() {
wp_enqueue_style(
'hybrid-theme-styles',
get_template_directory_uri() . '/assets/css/hybrid-theme.css',
array(),
filemtime( get_template_directory() . '/assets/css/hybrid-theme.css' )
);
add_editor_style( 'assets/css/hybrid-theme.css' );
}
add_action( 'enqueue_block_assets', 'hybrid_theme_enqueue_styles' );
Now that you’re ready, let’s explore the block features that can be used in a classic theme and how to set them up.
If you’d like to skip ahead and see the theme with examples the repository has a branch that contains a version of the theme with most of the following examples added.
Global styles
The Global Styles and Settings API was introduced in WordPress 5.8, and developers could start controlling settings, tools, and styles in their themes through a theme.json file. Initially this feature only had partial support for classic themes, but over time, the support has expanded with each new release.
To leverage this feature, simply create a theme.json
file at the root of your theme. Here’s an example to get you started.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"layout": {
"contentSize": "768px",
"wideSize": "1024px"
},
"color": {
"palette": [
{
"slug": "primary",
"color": "#DE7D0D",
"name": "Primary"
},
{
"slug": "secondary",
"color": "#7C0DDE",
"name": "Secondary"
}
]
},
"typography": {
"fontFamilies": [
{
"slug": "default",
"name": "Default",
"fontFamily": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
}
]
}
}
}
In this example, you are adding layout sizes, a basic color palette and setting the default font. There are plenty of resources out there, so I won’t go into detail on what you can and can’t do with a theme.json file, but if you want to explore that more I’d encourage you to check out the resources available in the Theme Handbook.
Block theme supports
There are several theme supports you can add to a classic theme to include both block theme features, and block functionality. Read more about theme supports in the WordPress Developer Resources.
responsive-embeds
– adds support for responsive embedseditor-styles
– adds support for loading a stylesheet in the block editordisable-custom-colors
– disables the color picker for blocksdisable-custom-font-sizes
– disables the custom font size for typography
The following theme supports will not work when a theme.json
file is in place (because they can be done in your theme.json
file, more about this below).
align-wide
– adds support for full and wide alignments in the editorcustom-line-height
– adds typography option to customize line heightcustom-spacing
– adds support for custom padding on blockscustom-units
– adds support for custom measurementseditor-color-palette
– adds support for creating custom color paletteseditor-gradient-presets
– adds support for creating custom gradient presetseditor-font-sizes
– adds support for creating custom font sizes for typography
function hybrid_add_theme_supports() {
add_theme_support( 'responsive-embeds' );
add_theme_support( 'disable-custom-colors' );
add_theme_support( 'disable-custom-gradients' );
add_theme_support( 'disable-custom-font-sizes' );
// Cannot use alongside a theme.json file
add_theme_support( 'align-wide' );
add_theme_support( 'custom-line-height' );
add_theme_support( 'custom-spacing' );
add_theme_support( 'custom-units', array( 'rem', 'em', 'px', 'vw', 'vh' ) );
add_theme_support(
'editor-color-palette',
array(
array(
'name' => __( 'Dusty Blue', 'hybrid-theme' ),
'slug' => 'dusty-blue',
'color' => '#367cb3',
),
array(
'name' => __( 'Faded Brown', 'hybrid-theme' ),
'slug' => 'faded-brown',
'color' => '#7a6a53',
),
)
);
add_theme_support(
'editor-gradient-presets',
array(
array(
'name' => __( 'Dusty to Faded', 'hybrid-theme' ),
'gradient' => 'linear-gradient(135deg, #367cb3 0%, #7a6a53 100%)',
'slug' => 'dusty-to-faded',
),
)
);
add_theme_support(
'editor-font-sizes',
array(
array(
'name' => 'Small',
'slug' => 'small',
'size' => 12
),
array(
'name' => 'Medium',
'slug' => 'medium',
'size' => 18
),
)
);
}
add_action( 'after_setup_theme','hybrid_add_theme_supports' );
Theme supports in theme.json
There’s a much easier and more efficient way to add these theme supports. In fact, you already set up a couple of them in earlier sections of this article when you created a theme.json
file. The example below adds support for everything listed above except for the responsive-embeds
support.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"layout": {
"contentSize": "1024px",
"wideSize": "1280px", // align-wide
},
"typography": {
"customFontSize": false, // disable-custom-font-sizes
"lineHeight": true, // custom-line-height
"defaultFontSizes": false,
// editor-font-sizes
"fontSizes": [
{
"name": "Regular",
"slug": "regular",
"size": "16px"
},
{
"name": "Very Big",
"slug": "very-big",
"size": "36px"
}
]
},
"color": {
"custom": false, // disable-custom-colors
"customGradient": false, // disable-custom-gradients
// editor-color-palette
"palette": [
{
"name": "Primary",
"slug": "primary",
"color": "#DE7D0D"
},
{
"name": "Secondary",
"slug": "secondary",
"color": "#7C0DDE"
},
{
"name": "Dusty Blue",
"slug": "dusty-blue",
"color": "#367cb3"
},
{
"name": "Faded Brown",
"slug": "faded-brown",
"color": "#7a6a53"
}
],
// editor-gradient-presets
"gradients": [
{
"name": "Dusty to Faded",
"slug": "dusty-to-faded",
"gradient": "linear-gradient(135deg, #367cb3 0%, #7a6a53 100%)"
}
]
},
"spacing": {
"units": [ "px", "em", "rem", "%" ] // custom-units
},
// custom-spacing (done on a per block basis)
"blocks": {
"core/columns": {
"spacing": {
"padding": true,
"margin": true
}
}
}
}
}
Block variations
The Block Variations API was introduced in WordPress 5.4 and provides developers with an easy way to create variations of existing blocks with unique starting attributes. There are a couple of steps to adding a block variation in a classic theme, but they are simple and straightforward.
Add a block variation by pasting the code below into the /js/hybrid-theme.js
. In this example, you are creating a variation on the Paragraph block called Intro Paragraph that sets new defaults for the font size, sets the drop cap to true, and uses a unique placeholder.
wp.blocks.registerBlockVariation('core/paragraph', {
name: 'intro-paragraph',
title: 'Intro Paragraph',
description: 'A paragraph with large text and a drop cap.',
attributes: {
fontSize: 'medium',
dropCap: true,
placeholder: 'Write an introduction.',
},
});
Add the new Intro Paragraph
block variation to a page and you should see something that looks like this screenshot.
Block style variations
WordPress 5.3 introduced us to block style variations, allowing developers more flexibility in creating alternate styles for blocks that could be quickly selected in the editor. There are options that can be leveraged in JavaScript or PHP to register block style variations, but the preferred method as of WordPress 6.6 is to use a JSON file similar to your theme.json
file.
In your theme create /styles/block/blue-heading.json
and paste the following code to add a Dark Blue Bg option to both the Heading and Paragraph blocks.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"slug": "dark-blue-bg",
"title": "Dark Blue Bg",
"blockTypes": [ "core/heading", "core/paragraph" ],
"styles": {
"color": {
"background": "#2860a6",
"text": "#ffffff"
},
"spacing": {
"padding": {
"top": "0.5em",
"right": "1em",
"bottom": "0.5em",
"left": "1em"
}
}
}
}
Add a Heading
block to a page and select the Dark Blue Bg
style variation to and you see something that looks like this screenshot.
For a more in-depth look at Block Style Variations see this post on the WordPress Developer Blog.
Templates and template parts
When WordPress 5.9 introduced Site Editing and Block Themes, it also included the ability to use block templates and parts in classic themes. By simply adding a new theme support, you could start creating template parts such as a header and footer using block markup in an HTML file. You could even take it a bit further and create full templates leveraging blocks.
There are a couple of aspects to what you can do with block templates and template parts in your classic theme. Before you can use either, you must add block template parts theme support by pasting the following into your functions-hybrid.php
file.
function hybrid_add_template_parts_support() {
add_theme_support( 'block-template-parts' );
}
add_action( 'after_setup_theme', 'hybrid_add_template_parts_support' );
Block template parts
You can now start creating block template parts that can be used in your PHP templates. Each template part must use an HTML file that contains block markup. All files also must live in a /parts
folder at the root of the theme.
Create /parts/footer.html
and paste in the following block markup.
<!-- wp:group {"backgroundColor":"vivid-cyan-blue","layout":{"inherit":true,"type":"constrained"}} -->
<div class="wp-block-group has-vivid-cyan-blue-background-color has-background">
<!-- wp:group {"style":{"spacing":{"padding":"20px 30px"}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"space-between"}} -->
<div class="wp-block-group" style="padding:20px 30px">
<!-- wp:paragraph {"align":"left","style":{"elements":{"link":{"color":{"text":"var:preset|color|white"}}}},"textColor":"white","fontSize":"medium"} -->
<p class="has-text-align-left has-white-color has-text-color has-link-color has-medium-font-size">Proudly Powered by <a href="https://wordpress.org" rel="nofollow">WordPress</a></p>
<!-- /wp:paragraph -->
<!-- wp:loginout {"style":{"spacing":{"padding":"10px 12px"}},"backgroundColor":"white"} /--></div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
To use your new template part inside your theme’s footer, take the following code and paste it into your footer.php
file either after the existing footer
code, or replacing it entirely.
<?php block_template_part( 'footer' ); ?>
Repeat these steps for any other block template parts you want to create in your theme, and in the block_template_part
function, swap out `footer` for the name of the new file you have created.
Once you have setup your footer block and refresh the frontend of your site you should see a footer like this screenshot.
Let’s add another one; this time a header.html
file. Create the new file and paste in the following code.
<!-- wp:group {"align":"full","style":{"color":{"background":"#e5f5ff"}}, {"spacing":{"padding":"10px 30px"}},"layout":{"type":"default"}} -->
<div class="wp-block-group alignfull" style="background-color:#e5f5ff;padding:10px 30px">
<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:group {"align":"wide","style":{"spacing":{"padding":{"top":"var:preset|spacing|30","bottom":"var:preset|spacing|30"}}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"space-between"}} -->
<div class="wp-block-group alignwide" style="padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30)">
<!-- wp:site-title {"level":0} /-->
<!-- wp:group {"style":{"spacing":{"blockGap":"var:preset|spacing|10"}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"right"}} -->
<div class="wp-block-group">
<!-- wp:navigation {"overlayBackgroundColor":"base","overlayTextColor":"contrast","layout":{"type":"flex","justifyContent":"right","flexWrap":"wrap"}} /-->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
For now, don’t use the block_template_part
function in your header.php
file. You’ll use this one to build a full block template below.
Block templates
Now that you have a couple of block template parts setup you can use those to create your first block template. For this example, you will replace the single PHP template file with an HTML one.
Adding this block template is as easy as creating a new HTML file in your theme at /templates/page.html
. Paste the following block markup into the new HTML file.
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","style":{"spacing":{"margin":{"top":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<main class="wp-block-group" style="margin-top:var(--wp--preset--spacing--60)">
<!-- wp:group {"align":"full","style":{"spacing":{"padding":{"top":"var:preset|spacing|60","bottom":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-group alignfull" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)">
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-featured-image {"aspectRatio":"3/2"} /-->
<!-- wp:post-content {"align":"full","layout":{"type":"constrained"}} /-->
<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|60","bottom":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-group" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)">
<!-- wp:post-terms {"term":"post_tag","separator":" ","className":"is-style-post-terms-1"} /-->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->
At the top and the bottom of this HTML file you will see references to the template parts that you created in the previous section. This example is a modified version of the page.html
file used in the Twenty Twenty-Five theme.
Once you have this in place and view a page on the frontend you will see something similar to this screenshot.
Patterns
Introduced in WordPress 5.5 for both classic and block themes, patterns are predefined block layouts that developers can register or users can create. These layouts can then be used to quickly insert new content and configure. Read more about patterns.
To add patterns to a classic theme, create a /patterns
folder and add a PHP file that includes a file header. Here’s an example of a pattern that you can use as a starting point: it uses a Heading, Paragraph, and Button block. Create a file named pattern-example.php
in the /patterns
folder and paste in the following code.
<?php
/**
* Title: Pattern Example
* Slug: hybrid-theme/pattern-example
* Categories: hybrid-patterns
*/
?>
<!-- wp:heading -->
<h2 class="wp-block-heading">Hybrid Theme Pattern</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sollicitudin dolor a ipsum consequat, et pharetra risus dignissim. Interdum et malesuada fames ac ante ipsum primis in faucibus.</p>
<!-- /wp:paragraph -->
<!-- wp:buttons -->
<div class="wp-block-buttons"><!-- wp:button -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="#">Link</a></div>
<!-- /wp:button --></div>
<!-- /wp:buttons -->
In the example I am using a category named hybrid-patterns. To create custom categories for patterns, add the following code to your theme’s functions.php
file.
function hybrid_register_pattern_categories() {
register_block_pattern_category(
'hybrid-patterns',
array( 'label' => __( 'Hybrid Patterns', 'hybrid-theme' ) )
);
}
add_action( 'init', 'hybrid_register_pattern_categories' );
Once you have everything in place your new pattern will become available to use on your page like the following screenshot.
Conclusion
It’s apparent that block themes are the future, and as WordPress evolves, so do the features that long-time classic theme designers and developers have available. While I’m excited to dive deeper into the world of block themes, I’m equally excited to experiment more with what can be done in a hybrid theme, and I hope this article inspires you to take some time and experiment as well.
Props to @ndiego, @bph and @greenshady for feedback and review on this post.
Resources
Related documentation
- Work with Themes – https://wordpress.org/documentation/article/work-with-themes/
- Block Themes – https://wordpress.org/documentation/article/block-themes/
- Site Editor – https://wordpress.org/documentation/article/site-editor/
- Work with patterns in the site editor – https://wordpress.org/documentation/article/site-editor-patterns/
- Comparing patterns, template parts and synced patterns – https://wordpress.org/documentation/article/comparing-patterns-template-parts-and-reusable-blocks/
Courses and tutorials
- Intro to the Site Editor – https://learn.wordpress.org/tutorial/intro-to-the-site-editor-and-template-editor/
- Converting a classic theme to a block theme – https://learn.wordpress.org/lesson/converting-a-classic-theme-to-a-block-theme/
- Use theme.json in classic themes – https://learn.wordpress.org/lesson/theme-json-in-classic-themes/
- Using block template parts in classic themes – https://learn.wordpress.org/tutorial/using-block-template-parts-in-classic-themes/
- Develop your first low-code block theme – https://learn.wordpress.org/course/develop-your-first-low-code-block-theme/
- Intermediate theme developer – https://learn.wordpress.org/course/intermediate-theme-developer/
Leave a Reply