Advanced Custom Fields: Building a Client Friendly “Page Builder”, Part 1

Tutorial, WordPress

There are very few subjects debated so hotly in the WordPress world as the ones regarding “Page Builders”. For the unfamiliar, a page builder allows the end user to set up content without needing knowledge of code.  While – to the end user – the allure of being able to have full control over design and content is nice, most developers shy away from them due to the resources needed to give that sort of power. Page bloat – loading of unnecessary scripts that drives up load time – is usually a problem with such plugins. Even caching plugins can only do so much to curb the bloat.

Over the years, I’ve tried to find a nice, happy medium – something that was “developmentally sound”, but that would allow at least some customization of the content beyond just being able to enter text.

A few years ago, I got a primer from Tammy Hart about Advanced Custom Fields – specifically, the “Flexible Content” fields.  Flexible Content fields allow a user to select from predefined options, fill in blanks, and the code renders based on what content is selected.  Given the combination of options available in ACF, there is a way to build something that resembles a page builder – the ability to have different types of content – without the “page bloat”.

Note: I only recommend paid plugins when the cost is outweighed by the benefits. This plugins has been in my toolkit for several years, so I absolutely recommend it for any developer wanting to extend their capabilities.  You can purchase it here: https://www.advancedcustomfields.com/pro/. The free version will not work, as you need the Pro version for the “Flexible Content” add-on.

Page Builder Overview

This is the first in a series of posts. The first post will be the initial setup of the “module loop” and a sample module.  The second post will contain sample modules used in many modern page builders. The final post will be a few “tricks” I’ve learned – global (sitewide) modules, defining module locations with hooks, and other similar aspects.

The Initial Module Loop

Once you’ve purchased and installed the plugin, a new option (“Custom Fields”) will show up on the left side.  Clicking on it reveals a page that shows any field groups you’ve defined.

Add a new field group, give the group a name, and admire all of the options you have to set. Luckily, we can avoid most of them in favor of setting the essentials.

Yes, there’s a lot of options – ranging from input boxes to date pickers.  For this tutorial, we’re going to focus on the “Flexible Content” option.  Selecting it gives you the basics – the title, the slug, and the ability to define your modules.

I’ve called mine “Modules” since we’re thinking about this in a “page builder” mindset. We want something people can define a row and content, add in some text, and call it a day.  For our first module, we’ll do something very simple: A WYSIWYG editor that runs the full container width.

Keep in mind that your code may look similar, but ultimately you need to implement this code in your own way, with your own framework. I’m just providing the basics.

The big things to note are that our modules have a “module” slug, and our content block has a “content” slug. We’ll need these as we write our code.

Publish the field group, and let’s swap over to our codebase.

The Page Builder Code

I’m going to define these modules as a “function”. I do this for a few reasons: 1) It keeps our actual content templates free of bloat, and 2) it allows me to re-use the function multiple times – something I do for clients that need modules in different places.  An example: one client I wrote for has these modules either above, below, or replacing their content on a page.

function insert_modules() { ?>
<section id="modules">
<?php
    if( have_rows('modules') ):
       while ( have_rows('modules') ) : the_row();
          if( get_row_layout() == 'full_width_content' ): ?>
             <section class="module full_width_content_module">
                <div class="container">
                <?php the_sub_field('content'); ?>
                </div>
             </section>
          <?php endif;
       endwhile;
    else :
       echo "<div class='container'>No Modules Defined!</div>";
    endif;
 ?>
</section>
<?php }

So, let’s look through this:

The first line defines the use of a function. This lets us re-use it later, vs just being able to use it once.

Then, the actual HTML markup for the function. I’m setting up a section (named modules) so I can keep things in line.

Then things get interesting: we’re using an if-then statement to check for any defined “modules”.  If there aren’t any, it falls back to an error message.

Inside of our “loop”, we then query for what “type” of module we’re display, and use that code.  We’ve defined one module – the full width content. If there’s a match on the module type, it runs the code inside (and pulls the relative custom field data).

In our next post, we’re going to set up a few different types of modules (and add them to our “module loop”). We’ll explore what some of the more popular content types are on a site, and see if there’s a way to duplicate those without all of the bloat a “page builder” has.

Drop your questions in the comments below, or if you have any module ideas for the next post, leave those as well!