Locastic Oct 25

Modern WordPress boilerplate setup

6 min read –

In my last article where I talked about how component-based architecture became the cornerstone of frontend development, I mentioned that my next post is going to go over our own current setup at Locastic that we use to bring CBA to WordPress based websites.

Most of our work at the frontend department in Locastic consists of using frontend frameworks (Angular and React) to make web and mobile applications, which means our team is familiar with working with components and organizing our projects around them.

However, sometimes standard CMS websites are what our clients need.

We usually use WordPress as a base for our website projects, because it is very intuitive for our clients to use and because it gives us so many ready-made features and solutions either straight out of the box or by installing some of its countless available plugins.

The problem WordPress leaves us with is that by default it gives us no direct way to use modern component-based architecture to build our frontend with.

Luckily, as developers we are always happy to solve problems, so we developed our own custom component based starter-theme for developing WordPress based websites.

We are already seeing the benefits of using the first version of our boilerplate as a starter theme for our newest projects so we decided to share it with the community in the hope that other people might find it useful as well and maybe chip in with their ideas or contributions to develop it further.

In the rest of this post, I am going to go over the different parts of the starter theme and explain the different problems they solve.

The first secret ingredient in our boilerplate is the Timber plugin

To start off, let’s get one of the major issues of WordPress for frontend developers out of the way.

WordPress is built with PHP, and that often means that when making WordPress websites we write our markup in the same place where we query our database and write our business logic. This breaks a ton of best practices, results in messy code and bad developer experience which turns off a lot of developers away from WordPress.

There is a better way to get around these issues, we start off by installing a plugin called Timber which gives us the option to separate our markup in to twig files to create views which provides us with a very simple MVC architecture, we write our views with twig, we have PHP files (controllers) that render our views with the data fetched from the database and we use a combination of custom post types and advanced custom fields to build our models.

Structure and hierarchy

Bred Frost popularised the idea of atomic design, referring to the composable nature of UI elements.

Bred suggests we split our codebase in low-level primitives – “atoms” which we combine to make “molecules”, “organisms” , “templates” and “pages”.

We divide our own structure similarly into these categories:

  1. Components
  2. Layouts
  3. Templates/Views
  4. Pages

1. Components

Components are the smallest building blocks, each component is a self-contained part with its own structure, styling and logic. Buttons, cards, banners, form elements, pop-ups, and similar elements are all components.

2. Layouts

We use layouts to abstract and reuse different patterns used across the design.

A layout can represent something as the following; main+sidebar, vertical item list, equal column width grid, alternate 1/3 – 2/3, 2/3 – 1-3 … grid. We can distinguish the classes that are used for layout purpose by prefixing them like this;

 .l-class-name 

Besides using the layout classes to get the sizing and the positions right, we can also build layout twig files with slots, then when we create a particular view, we extend that layout with the contents of the view placed in their respective slots inside the layout.

3. Templates/Views

Our templates work similarly to basic WordPress templates used to display different types of pages. A homepage-template.php file would be the most basic example of a template file, the .php file is used to fetch and process the data and perform any needed logic and its assigned a view .twig file which it renders using the prepared data.

4. Pages

WordPress renders the pages from templates with the data fetched from the database, each page has it’s unique id and can be targeted to add additional page-specific styles or scripts.

Working with assets

Most of the styles and scripts can be saved alongside the twig files they correspond to. Different components, layouts, and pages can each have their own styles and scripts associated with them.

components
--|card
--|--|card-markup.twig
--|--|card-styles.sss
--|--|card-script.js

We also have the separate scripts and styles folders which hold the index.js and index.sss (SugarSS with postCSS) files, along with some global files as well.

All the assets are managed with webpack.

The scripts can be included from any of the structural levels, for example, you can define scripts that will be added once a certain component or a layout is loaded.

{{ fn("addScript", "componentScript") }}

There can be 10 card components on a single page but the script will only load once.

We plan to add something similar to work with CSS as well, but CSS costs us less performance-wise, so it’s not really as important as the ability to code-split our scripts and deliver them in chunks when needed.

However the boilerplate is configured to use a postCSS plugin postcss-critical-css which saves the browser from having to parse any unneeded render-blocking CSS before showing something to the user.

Both WordPress and its plugins sometimes come with assets files we don’t necessarily need.

You can list all of the enqueued assets using the print_scripts_styles.php helper located inside the /includes/helpers folder.

Once you notice an asset that you don’t need to load on the frontend you can remove it by including and using the remove_unwanted_scripts.php or remove_unwanted_styles.php helpers.

Grid system

The boilerplate comes with a built-in custom grid system that uses column and gutter variables to define the sizes and spacings.

.sidebar
    width: calc(3 * $col + 2 * $gutter)
    margin-left: calc($col + $gutter)

You can change the grid settings in detail by modifying the variables inside the styles/vars.sss file.

$site-width: 1200px
$number-of-cols: 12

$gutter: 20px
$outer-gutter: 20px

$gutters: $number-of-cols * $gutter

$col: calc(($site-width - $gutters) / $number-of-cols)

...

Pattern lab

All components and layouts are symlinked to Pattern Lab which means we get a living styleguide straight out of the box. The only thing we need to do is to provide the data used in the templates inside a .json file.

Here is an example of data used to provide data for a post-card component:

{
    "post":{
        "title": "Blog title",
        "excerpt": "Lorem ipsum",
        "featured_image": "https://picsum.photos/300/200",
        "link": "#"
    }
}

And then used inside the .twig file like this:

<article class="post-card">
    <img src="{{post.featured_image}}"/>
    <h2>{{post.title}}</h2>
    <p>{{post.excerpt}}</p>
    <a href="{{post.link}}">Read more</a>
</div>

Future plans

I am personally very excited about how good has the boilerplate performed for us so far and proven that WordPress sites can be built with modern methodologies without going headless and using a .js framework.

We have a couple of features on the todo list at the moment; we will add a setup for using visual regression testing for both the actual site and the pattern library, get code splitting for styles to work with critical CSS, add Swup.jspage transitions by default and start building a separate repo of ready-made components and layouts that can be used with the boilerplate to jump-start each new project even further.

You can clone the repo from here: https://github.com/Locastic/wp-cba-boilerplate

If you decide to give it a try, there is a readme.md file inside the repo which covers more details, but if you get stuck or have any questions, feel free to drop a comment below or even contact me directly with a question.