ExpressionEngine is fantastic at handling traditional web layouts. Let's start by clarifying what I mean by traditional web layouts. Every developer has received a series of PSDs and an accompanying sitemap made up of the following:

ExpressionEngine, it would seem, is quite literally built to manage this kind of content and, at the time that the architecture for EE’s content model was developed, the aforementioned structure was the norm.

What Are Modular Page Layouts?

More and more, we're seeing designs that are based on modular content elements which can be arranged in any order, on any given page. Consider these wireframes made up of the following content elements:

Modular Wireframes

Wireframe Layout, Example 1

Modular Wireframes

Wireframe Layout, Example 2

The standard ExpressionEngine field-group/channel/template architecture isn't going to work for this type of design because we don't know which content elements should appear on any given page or in what order.

How to Build Modular Page Layouts in ExpressionEngine

Let's use the wireframe above as an example of how we could build our modular page layouts. Let's say our example site has five main sections:

Each section is going to be made up of pages that consist of some combination of the content elements described above.

Channel Structure

Our channel structure is going to be a little different than a typical ExpressionEngine build. We are going to create channels for each of the main sections of our site, prefixed with "-pages-".

We will end up with the following channels:

We are also going to create channels for each of our content element types, prefixed with "-element-".

Our content element channels will be named:

Channel Field Groups

-element- Channels

The channel field groups for our -element- channels are going to, as you would imagine, be unique to the needs of each content element type. A nice benefit of this approach is that we can make each of the content elements a bit more flexible without making the entire experience too daunting for our end user. For example, let's consider the Call to Action channel. It will likely be made up of the following fields:

However, to make it a bit more flexible, we would likely add an additional field for Layout (P&T Switch) with the following options:

ExpressionEngine Element Entry

ExpressionEngine Element Entry

You can imagine how this same type of flexibility could be added to each of the -element- channels to allow a level of creativity for the end user as they assemble pages.

Additionally, we always include fields for:

This allows us to apply custom classes or IDs on the containing html for our content element. This way, if we need to do something a little special for a particular element, it's simply a matter of adjusting the CSS and targeting that element.

-pages- Channels

Unlike the -element- channels which are unique to the needs of their respective content element, all of the -pages- channels will be exactly the same. In fact, they can even use the same channel fields group if you'd like. In this example, we'll use one channel fields group to keep things simple. It will be made up of the following fields:

ExpressionEngine Pages Entry

ExpressionEngine Pages Entry

At this point, I think you can see where I'm going with this. The end user will create content elements based on their needs in their respective channels. They will then create pages by simply using Playa to drag/drop the appropriate elements in the correct order. As you can imagine, another great benefit of this approach is that you can very easily distribute a single content element onto multiple pages. This, of course, will make updating syndicated content much faster.

Playa Links

I mentioned above, we will include Playa Links fieldtypes in all of the -element- and -pages- channel field groups. Without using Playa links, if a user wanted to update content on a particular page, their workflow might look something like this:

This is cumbersome and not the kind of experience we like to create for our ExpressionEngine users. We developed Playa Links to solve this very problem.

ExpressionEngine Playa Links

ExpressionEngine Playa Links

The Playa Links field which is used on the -pages- channels will create direct links to the related -elements- being used. The Playa Links field in the -elements- channels will alert the editor of which -pages- entries the content element they're editing is being included in.

Better Pages

Since we are only using one template in this example, we'll be making use of EllisLab's first-party Pages Module. This will give our end users the ability to determine the full URL of the page they are creating without having to adhere to strict template/url_title patterns.

In order to make this experience just a little better however, we'll use Better Pages to limit the choice of templates down to the only one that is appropriate in this case. This will be the pages/index template.

Templates and Snippets

-element- Snippets

We will keep all of our -element- template code in snippets and our one -pages- template in an actual template file (pages/index). We use Snippet Sync to manage all of our snippets as flat files and get them into Git. The other benefit of Snippet Sync is that it allows us to keep all of our -element- snippets in their own directory, so we'll create the following files:

If you don't use Snippet Sync, you should really check it out. It's a fantastic add-on and part of our core build.

-pages- Template

Each of the -element- snippets will be unique to the site we are developing but the approach for the -pages- template will be somewhat standard and worthy of delving deeper into. Let's take a look at the template code:

Standard exp:channel:entries Tag

You'll see that we begin with a standard exp:channel:entries tag. The only difference here is that we have listed all the possible -pages- channels for it to respond to.

Elements Playa Field

The code actually starts to get interesting at line 10 where we enter the Playa loop which will work its way through the different elements we have assigned to this page.

Switchee To The Rescue (again)

I'm pretty sure that every ExpressionEngine developer has been saved by Mark Croxton's free Switchee plugin at least once. Here is another great example of its usefulness.

On line 11 we pass Switchee the short channel name of the current -element- channel entry that is being handled by the Playa loop. We have to also remember to instruct Switchee to parse inward.

Within Switchee's tag pair, we will set up a case for each of the possible -element- channels and then include the appropriate snippet for that -element-.

One Template to Rule Them All

That's really all there is to it. We've successfully built out a modular page layout which we can use across all the different sections of our site, using only one template, while still retaining the solid content architecture which makes ExpressionEngine so effective.

CE Cache

You use Causing Effect's CE Cache for every site you build, right? Right? I'm going to go ahead and assume the answer is yes because you absolutely should be. What we've done above can be somewhat heavy from a template processing perspective and you can mitigate any performance hits by using Aaron's incredible add-on.

It's All About the Add-ons

I think it is worth mentioning that this is a perfect example of what makes ExpressionEngine so great. Although the core of ExpressionEngine is robust, it's the incredible Add-on community that allows developers to handle tricky situations like these. To be clear, this approach wouldn't even be possible without the following add-ons: