How I’d Like “Single-Page” Themes to Work

Layers | WordPress single-page themes

Today’s article gets quite technical, but the intent is very simple. So let’s start with that:

What We’re Going For

To restate the video, the intent is to create:

  1. A “single-page” layout,
  2. that does look “single-page” (for example, has different full-width backgrounds for different page sections),
  3. that really does reside in a single WordPress post,
  4. that has a simple and flexible editing experience, and
  5. that can have an arbitrarily large or small number of sections.

I think the solution the video shows off—which creates several custom fields, including a TinyMCE text editor window, for each desired page section—gets all of the above right!

As such, I’m wishing that more single-page themes adopted it instead of the alternatives.

The Alternatives

In order of badness, here’s how themes commonly create a “single-page” effect:

Theme Options Madness

David and I were very recently traumatized by a theme whose page section types are baked into an almost totally unusable morass of theme options:


With themes like this, you can “drag-and-drop” page sections, but you can do almost nothing that you’d expect to do with actual pages—like add images.

If you create single-page themes this way, you are hurting WordPress, and the people and wapuu who use it.

Shortcodes Madness

This was the approach I first considered for the project shown in the video: simply separate sections by shortcodes.

The advantage of this approach is that everything is inside one editing experience in the main TinyMCE window. The disadvantage, though, is that that editing experience quickly drowns in shortcodes:


If you’ve tried to develop on top of sites that use commercial “page builder” themes, you know how frustrating this can be.

Combine-Page-Content Sorcery

Many “one-page” themes I’ve worked with do something like “pull in the content of any Page that is a child Page of Home.” So you edit those Pages individually, and the theme itself pulls them into a single page for display on the front end.

This isn’t too bad, but it does mean a lot of switching between Pages—when what would be nice is editing sections on a single Page.

Bespoke Page Builders

I can’t comment on page builders in general, but I do know that I find myself resisting them. They seem like a learning curve and a source of complexity—which sections served through TinyMCE windows that mimic the functionality of the post’s main content, plus simple custom fields to change details about those sections, generally do not.

The Intuition Behind this Solution

Our solution works as follows:

It Uses CMB2 for the Heavy Lifting

This solution leans heavily on CMB2, the GitHub project (and plugin) that simplifies creating custom fields and other user data.

In particular, we’re using CMB2’s pre-made ability to register repeating field groups: “As many as needed” of a certain type of custom field.

The only intuitive leap in the current solution was: “What if the repeating custom field type was a block of content, edited through TinyMCE?” (CMB2 calls this type “wysiwyg.”) As it turns out, this works.

You’ll Need to Edit Theme Files to Display the Data

As-is, the plugin only lets you save the data. So your theme files will need to change to accommodate “arbitrarily many TinyMCE fields of content” saved to the current post as post meta.

Basic Sections Markup

These fields are organized into sections. The basic pattern for a section, with the markup I’ve chosen, is:

<section class="page-section <?php echo get_post_meta( get_the_ID(), '_wpshout_main_wysiwyg_background', true ); ?>">
	<div class="section-content">
		<!-- Content goes here -->

The content inside the section-content div can come from one of two places:

  1. the_content(), for the main TinyMCE window
  2. get_post_meta() inside a foreach loop of the additional sections

Looping Through the Array of Additional Sections

That loop looks something like:

$wysiwygs = get_post_meta( get_the_ID(), '_wpshout_wysiwyg', true );

if (is_array($wysiwygs)) :
	foreach( $wysiwygs as $key => $wysiwyg ) : ?>

		<section class="page-section<?php if( $wysiwyg['color'] ) { echo ' ' . $wysiwyg['color']; } ?>">
			<div class="section-content">
				<h2><?php if( $wysiwyg['title'] ) { echo $wysiwyg['title']; } ?></h2>
				<?php echo wpautop( $wysiwyg['content'] ); ?>
	<?php endforeach;

You’ll see all of this put together in sample-template-page.php in the plugin ZIP file or GitHub repository for this solution.


The crucial CSS to style the sections looks like:

.page-section {
	padding: 3em 0;

.section-content {
	max-width: 920px;
	margin: 0 auto;

This gives the “full-width with boxed content” appearance we’re going for.

The backgrounds themselves are handled by CSS classes. For example: {
	background: #5d88a8;
	color: #fff;

These classes are added with get_post_meta(), in the foreach loop that goes through each custom section.

Try it Out!

You can play with this code in two ways:

Plugin Zip File

Here’s the functionality above, wrapped into a plugin. This plugin already includes CMB2, so it will create custom fields on every Page-type post by default. After that, it’s up to you to style your site, and alter your template files, to get the effect you’re looking for.

GitHub Repository

Here’s a GitHub repository with the same files and a quick readme:

In this case, if you download the GitHub repo and install it as a plugin, the plugin will not work without you also including CMB2. Instructions for doing that are in the repo’s readme.

Toward Better Single-Page Layouts

This article is intended as a “gist” toward a better way of doing single-page layouts. Theme developers: What do you think? More fun than theme options, right? We’d love to hear from you in the comments below!

Image credit: 16:9clue