Better names for Statamic fields and variables

Over the last couple months I've been building a site with Statamic, a flat-file PHP CMS. Unlike most content management systems, Statamic does not use a database, keeping instead the site's content in plain files. This makes it easy to keep the content in version control and to edit with a text editor.

One of the adverse side effects of this approach is that naming is even harder than usual. If you want to change a field's name, for example, you have to find-and-replace it throughout all the templates and all of the content. This makes common field names like title, photo, summary rather unwieldy for the purpose.

Following BEM, I've developed a simple approach to naming fields and other variables in Statamic that makes them easier to find and understand.

A better naming convention

BEM-inspired approaches to naming CSS classes are becoming more popular. I've used it in my last few projects with, admittedly, uneven results. But after I began working with Statamic, it soon became clear that it would be a useful approach for naming Statamic fields and other variables.

BEM stands for block, element, modifier, and is used to articulate the relationship between the three types of CSS classes required to mark up a single component.

.block { }
.block__element { }
.block__element--modifier { }

This is not the place to do yet another recap of BEM. The part that is relevant concerns the suffixes: __element and --modifier.

Statamic doesn't allow hyphens to be used in field names, but underscores are fine. Which is lucky, because all we'll be doing is using the double underscore to indicate a descendant relationship between a block and an element.

block__element

A simple example

Let's say you have a "Profile" fieldset, which is defined in profile.yaml.

Instead of using photo and job as the names for those fields, you would use profile__photo and profile__job.

title: Profile

fields:

    profile__photo:
        display: Photo
        type: file
        allowed: [png, gif, jpg, jpeg]
        ...

    profile__job:
        display: Job title
        type: text

This approach has two advantages:

  1. If you need to find (or find-and-replace) a field across the project, the specificity of the name makes it hard to mix up with regular content. You might mention a "photo" in a blog post, but unless you're writing this post, it's unlikely that you would ever refer to "profile__photo".

  2. It makes it easier to figure out what the context is. This is useful when you're looking at dense templates or are using partials within partials.

    There is no ambiguity about where this value is coming from:

    {% raw %}<p></p>{% endraw %}

    It also allows you write more complex markup, while maintaining clarity:

    {% raw %}<p></p>{% endraw %}

    (If the blog has a summary it will be displayed; otherwise the page's summary will be displayed instead.)

Grids & replicators

When using grids or replicators my current practice is to keep using the double underscore to delineate any descendant relationship.

Let's say that in my profile example I also wanted to have a list of websites, defined using a grid, with a title and URL for each row.

profile__websites:
    display: Websites
    type: grid

    fields:

        profile__website__title:
            display: Website
            type: text

        profile__website__url:
            display: URL
            type: text

To maintain findability the block (i.e., the grid) is plural, while the elements inside it (i.e., the fields inside the grid) are singular. This allows you to search for:

  • the block (profile__websites)
  • the elements (profile__website__)
  • the block and the elements (profile__website)
  • a specific element (profile__website__title)

Replicators are a bit more complicated, but the same idea holds:

profile__bio:
    type: replicator

    sets:

        profile__bio__quotes:
            display: Quote

            fields:

                profile__bio__quote__text:
                    display: Text
                    type: textarea

                profile__bio__quote__author:
                    display: Author
                    type: text

As the above snipper shows, this approach also makes it easier to parse the different levels in your fieldsets.

Other uses

In general, the block__element convention is useful to make sure variables are findable and that their context is apparent.

Cache

An easy way to keep an eye on the keys for the new cache tag is to prefix them with cache__. Then you can just search for cache__profile to find all the places where changing the profile entries should bust the cache.

Partials

If you're passing a parameter into a partial, you can prefix it with par__:

{% raw %}{% endraw %}

Before establishing this usage I was sometimes left wondering where a value was coming from, especially if I was using the partial in multiple places. Now the context is clear.

Conclusion

If you're already sold on BEM, you should find the reasoning behind this approach congenial. If not, a lot of the arguments levelled against using BEM in CSS can also be used here.

At first all this seems like it would be a lot of work to write and tiresome to read. But I've been using this approach for a few weeks and have found that the significant gains in findability and clarity outweigh the verbosity.

Did you enjoy this post? Tweet or email me.