Craft: A CMS for developers
As a software engineer, I thrive and thoroughly enjoy working on fully custom software products, applications conceived to model and help in the execution of some business process and that are built from the ground up by a team of developers.
Such projects are often complex and expensive, though, and for some clients, they can be overkill. Some clients come up with requirements that are better served by off-the-shelf software solutions. One group of such solutions are content management systems (CMS). As a rule of thumb, if a client wants a website whose main purpose is to showcase some content, their brand or image, and custom business logic requirements are limited, then chances are that a CMS will fit the bill nicely.
Lately we’ve been using the Craft CMS for a client that meets the aforementioned criteria, and I gotta say, I’ve been pleasantly surprised by the developer experience it offers.
Unlike most of the technology and products we discuss in our blog, Craft CMS is not Open Source or Free Software. The source code is readily available in GitHub for anybody to use, study, and modify, but commercial use of it is restricted and certain features are exclusive to a so-called “Pro” edition. Learn more by reading their license and their pricing structure.
The features that we will discuss in this article are all part of the no-charge “Solo” edition of Craft CMS 3 that can be used for noncommercial websites.
In this article I’m going to talk through a few of the key aspects of Craft that make me think that it’s really a CMS made for developers. Let’s get started:
Craft is easy to get up and running
Craft is just a PHP application. And it is as typical as modern PHP applications go, capable of being initially set up with Composer and of running on top of a MySQL database (it also supports Postgres!) and the Apache web server. It can all be done via console too, if that’s how you roll.
If you already have a box with Apache, PHP, MySQL and Composer, it all amounts to little more than creating a MySQL database for Craft, composer install
ing the Craft package, sorting out some permissions, running php craft setup
, following the prompts, and finally, configuring a virtual host in Apache to serve the web
directory from inside where Craft was installed.
All of this is explained in Craft’s official documentation.
Craft is easy to put in containers
For ease of development and project bootstrapping, I’ve created a containerized setup with Docker and Docker Compose that encapsulates some infrastructure tailored to my development needs. You can get the relevant files here.
If you want to follow along, clone that repo, and you’ll end up with this file structure (as shown by the tree
command):
.
├── apache_config
│ └── 000-default.conf
├── docker-compose.yml
├── Dockerfile
└── README.md
1 directory, 4 files
This setup includes two containers: one for running Apache and Craft, and another for running MySQL. The apache_config/000-default.conf
contains some Apache VirtualHost configuration for serving the site. docker-compose.yml
defines the whole infrastructure: both containers, a network that they use to talk to each other, and a volume to persist MySQL database files. The Dockerfile
is the definition of the image for the container that runs Apache and Craft.
Feel free to explore the files; I’ve made sure to comment them so that they are easy to understand and modify as you see fit.
Note: If you want to run this setup, be sure to change the ServerAdmin
value in apache_config/000-default.conf
, and the USER
, UID
, and GID
values in docker-compose.yml
under services > web > build > args
according to your environment and user account information.
If you have Docker and Docker Compose installed in your machine, you can go to the directory just created by the git clone
and:
-
Run
docker-compose up
to set up the infrastructure. You will see Docker and Docker Compose creating the image defined inDockerfile
and the containers defined indocker-compose.yml
. Then the logs of the various containers will start showing. It you want to run this in the background, usedocker-compose up -d
instead and it will give you control of the terminal immediately after it’s done. -
Run
docker-compose exec web bash
to connect to theweb
container. This is the container that has Craft’s code and is running Apache. You’ll be “logged into” the container and be placed in/var/www
. This is the directory where we will install Craft. -
Once in there, run
composer create-project craftcms/craft ./install
to install Craft with Composer. In other words, it will download all of the files that Craft needs to run. You should see something like this at the end:> @php craft setup/welcome ______ .______ ___ _______ .___________. / || _ \ / \ | ____|| | | ,----'| |_) | / ^ \ | |__ `---| |----` | | | / / /_\ \ | __| | | | `----.| |\ \----./ _____ \ | | | | \______|| _| `._____/__/ \__\ |__| |__| A N E W I N S T A L L ______ .___ ___. _______. / || \/ | / | | ,----'| \ / | | (----` | | | |\/| | \ \ | `----.| | | | .----) | \______||__| |__| |_______/ Generating an application ID ... done (CraftCMS--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) Generating a security key ... done (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) Welcome to Craft CMS! Run the following command if you want to setup Craft from your terminal: /var/www/install/craft setup
-
After that’s done, use this bit of bash black magic:
(shopt -s dotglob; mv -v ./install/* .)
This command moves all the files that composer just downloaded into
/var/www/install
out from there and into/var/www
. Thenrmdir install
to remove theinstall
directory because we no longer need it. -
Now do
php craft setup
to use Craft’s CLI to set up the site, its configuration, and its database structure. Just follow the prompts. When it asks you for database configuration, choosemysql
as the database driver, setmysql
as the database server name (because that’s the name we’ve given it in ourdocker-compose.yml
), and use the environment variables defined indocker-compose.yml
around lines 14 to 17 for the rest of the values. You can change these to whatever you want as long as you make sure that it coincides with how you defined your MySQL database container in thedocker-compose.yml
file. The prompts should look something like this:Which database driver are you using? [mysql,pgsql,?]: mysql Database server name or IP address: [127.0.0.1] mysql Database port: [3306] Database username: [root] craft Database password: Database name: craft_demo Database table prefix: Testing database credentials ... success! Saving database credentials to your .env file ... done
-
Next, sort out some Craft file permission requirements with this command:
chmod -R o+w config storage web/cpresources
These are directories that Craft needs write access to.
-
Now start up Apache with
sudo service apache2 start
.
And that’s it! Open a browser to localhost
or 127.0.0.1
and you should see your Craft 3 homepage:
You can start playing with the control panel or the templates/index.twig
right away.
Craft’s design makes sense
When it comes to content modeling, Craft offers a set of abstractions that make sense. The main concepts to understand are sections and entries. Entries are the main pieces of content. An “article” in a news site or a “post” in a blog. Sections are the way Craft groups entries together. They are useful when your site has multiple streams of content. You can, for example, have a site where you publish news, opinion pieces, and random thoughts. With Craft, that would translate neatly into three separate sections, each one with its own type of entries.
Craft also allows you to set up custom fields for every type of entry. For example, the entries on your news section may need to include a link to the original source of the news, while your opinion pieces need a short description instead. You can configure your entries using custom fields so that they include the data that makes sense for your use case.
Let’s see what that looks like in concrete terms. Now that we have a Craft instance running in localhost
, go to localhost/admin
in your browser. You should see Craft’s control panel. Click on the “Settings” option in the navigation bar to the left of the screen, then select the “Sections” item under “Content”:
Next, click on the “+ New Section” button by the top of the screen and you’ll be shown the section creation form. We will create a “News” section so let’s fill in the form like this:
The “Name” and “Handle” fields are pretty self explanatory. The “Section Type” is a concept we haven’t discussed yet. “Channel” is the most appropriate for a news section, which is a stream of multiple entries with the same structure.
There are other types: “Single” is a type which you would use for entries that are unique, like a home or contact page. For sections of type “Single”, there’s generally one single entry that fits in them. This is unlike “Channels” which fit multiple entries. The other section type is “Structure”, which also accommodates multiple entries, but rather than a stream of ever-growing content, it’s more appropriate for similar entries that share a certain theme. A “Structure” section type is appropriate for things like services offered or projects in a portfolio.
Learn all about entries, sections, section types, and more in Craft’s official docs.
Now that we’ve filled the form, click the “Save and edit entry types” button. This has created our new “News” section and defined the “entry type” that this section will be able to contain. The control panel now shows this:
In Craft, a section can contain multiple types of entries. For our purposes with the news section, though, just the default one is enough. Click on it, and you’ll see an editor where you can select fields that make up that entry type:
The editor I mentioned before is below the “Field Layout” title. Here’s where we can pick and choose which fields make up the entries for the “News” section. We have a fresh installation of Craft though, so we don’t have any fields. Let’s create a few by going to Settings > Fields.
This is where we can define new fields to be used for our entries throughout the site. Click the “+ New Field” button near the top of the screen and you’ll be presented with the field creation form where you can specify all manner of details. For now, we just care about “Name”, “Handle” and “Field Type”. Let’s create three fields:
- One named “Heading” with a type of “Plain Text”.
- One named “Body” with a type of “Plain Text”.
- One named “Source” with a type of “URL”.
You should end up with something like this in the control panel’s “Fields” page (localhost/admin/settings/fields
):
Now, if we go back to our “News” section’s default entry type at http://localhost/admin/settings/sections/1/entrytypes/1
or Settings > Sections > News > Entry Types > News…
You can see how the new fields that we just created are present in the “Field Layout” panel. In order to make these fields available for our “News” entries, we just need to drag them into the box named “Content” inside the greyish area.
Click the “Save” button at the top, and that’s all it takes to set up a “Channel” section, an entry type for it, and a few fields.
Now that we’ve set up the blueprints for them, let’s actually create a few entries in the “News” section. To do so, click on the “Entries” link in the navigation bar to the left which should’ve revealed itself by now, and you’ll see this screen:
If you’re used to CMS back ends, this is pretty familiar. In this screen you can create new entries and browse existing ones.
Click the big red “+ New Entry” button and select “News” in the resulting pop-up menu. You should see a form with the fields that we defined in the “Field Layout” panel during previous steps. Feel free to create a few news entries. I’ve created these two:
Craft gives you complete freedom over your front end
Most CMSs can be thought of as having two components: a front end and a back end. The back end is where content is authored and the front end is where the style and structure in which the content is presented. In Craft, most of the effort has gone into creating a solid, highly customizable back end.
As we’ve just seen, Craft comes out of the box with a back end control panel where site administrators and content creators can author new content. As far as front end goes though, Craft has nothing. For a developer well versed in front end web technologies, this is freeing and transformative.
Craft makes no assumption and makes no decision for you when it comes to developing your site’s look and feel. It gets out of your way and lets you do your job. There’s no concept of “theme”. There’s no obscure framework to learn and integrate into. There’s no proprietary templating language to struggle with. In Craft, you are completely free to write HTML, CSS and JS as you see fit to obtain your desired effect for your site.
You can develop templates using the tried and true Twig templating engine, which, if you have some experience with PHP, you’ve most likely already encountered and worked with. All the content created in the back end is exposed to the Twig templates via objects. Let’s see how.
First we need to specify a template for our sections. Continuing with our example, let’s assign a template to our “News” section. Go to Settings > Sections > News and scroll down to find the “Site Settings” area. In the table there, type news
into the “Template” column. Now go to the template
directory where craft was installed and create a new news.twig
file. The contents can be simple, like this:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ entry.title }} - My Craft Demo</title>
</head>
<body>
<h1>{{ entry.heading }}</h1>
<p>{{ entry.body }}</p>
<p><a href="{{ entry.source }}">Source</a></p>
</body>
</html>
The only noteworthy aspect of this template is how we are injecting the data that we defined in the back end into this template. We use double curly brackets to reference the entry
variable. This is provided to Twig by Craft and contains all the fields that we defined for our entries in the “News” section.
With that done, save and visit any of the entries you created and you’ll see something like this:
As you can see, this entry’s URL is localhost/news/i-just-learned-that-craft-uses-twig
. Yours will obviously differ depending on the title (and slug) that you gave them.
What this example lacks in complexity, it more than makes up for in potential. This is a plain old HTML document that we’ve created, with a Twig template, of course. This is the complete freedom that I like about Craft. From this point on, you can do whatever you want in terms of front end development: use whatever CSS or JavaScript framework or library you want, organize your template files in a way that makes sense to you, your team, and your website, etc. The sky is the limit.
That’s good for individual news pages. But now let’s try to link to them from the homepage. To do so, we need to edit the templates/index.twig
file. Around line 174, remove the <ul>
that’s there along with all its <li>
s and put this instead:
{% set entries = craft.entries().section('news').all() %}
<ul>
{% for entry in entries %}
<li><a href="{{ entry.url }}">{{ entry.title }}</a></li>
{% endfor %}
</ul>
Here, we leverage Twig’s templating engine capabilities, sprinkled with some of Craft’s features to obtain a list of all the entries in our “News” section. Then, we iterate over them to render links.
Effectively, Craft enhances what you can do with Twig by exposing an API for accessing the data that exists in the CMS back end.
If you’re familiar with any sort of templating language like those included in most web application frameworks like Ruby on Rails, Symfony, ASP.NET Core MVC, etc., you’ll probably feel right at home with this.
Here’s what the homepage looks like now:
You can click on any of the links and they will take you to the specific entry page.
You can learn more about querying entries in Craft’s official documentation.
Craft is cool 🕶️
So, in conclusion, I’ve found that Craft is a cool tool to have in the toolbox. It is a full-fledged CMS with tons of customization opportunities for how to model and organize the content and data of your site. When it comes to developing the front end, though, it gets out of your way and lets you do your job. That, to me, is a big win.
Comments