Feeds

Author

Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough
Dec 02 2020
Dec 02

You Might Also Like

Many platforms are advertising the ability to manage content in one place while publishing it to multiple channels. They provide a way to model, manage, and create content and then expose that content via an API. 

These are decoupled-only (or headless) back-ends. The only way to present your content is to create an application that consumes the API, interprets it, and renders the content in your desired format.

Contentful is one such platform, and in this article, we’ll be comparing Contentful’s capabilities to Drupal’s capabilities as decoupled content providers. We’ll be using Drupal Core’s JSON: API, which requires no additional configuration to get up and running and is the most popular way for Drupal to serve as a decoupled back-end.

We’ll cover the following:

In the end, we’ll answer the question: can Drupal do anything that Contentful can do? The answer to that is yes, and more, though it takes different paths to get there.

Content Modeling

A good CMS experience starts with content modeling capabilities. Can we accurately represent the data that we need? Can we enable content creation in a well-organized way and defined based on an overarching content strategy?

Like Drupal, Contentful offers a flexible way to create content types and relate them to each other.

Field types

Contentful offers the following field types:

  • Rich text - text formatting with entity embeds.
  • Text - short or long text.
  • Number - integer or decimal.
  • Date and time - can be date only or date with time.
  • Location - latitude and longitude.
  • Media - images, videos, and other files.
  • Boolean
  • JSON object - arbitrary data in JSON format.
  • Reference - reference other content.

How does Drupal compare to this line-up? Drupal Core contains most of these without needing to install other modules.

Drupal includes a few more format-specific field types, like Email and Link. Contentful doesn’t have these extra field types because it has a “Match a specific pattern” validation you can apply to any text field. You can use a regular expression or one of the supplied patterns (Email, URL, Phone number, etc.)

But this is only for immediate validation when creating content. These pattern validations do not change the underlying schema, and there are no distinct data types. As far as any consumer of a Contentful API is concerned, any text field, no matter the pattern validation applied, should be treated as normal text.

You could mimic the same approach in Drupal with the Field Validation module. But there are benefits to how Drupal implements data types (like Email or Link), especially for the back-end. An automated job that checked for broken links, for example, benefits from knowing that something is a link.

Rich text fields include a WYSIWYG editor similar to Drupal, and setting it up is simple and clear. It includes a toggle for most of what you would want to allow: 

  • Headings (H1 through H6)
  • Bold, italic, and underline buttons
  • Basic code formatting
  • Blockquotes
  • Hyperlinks
  • Ordered and unordered lists
  • Embeds of media or other content

What is Drupal Core missing in terms of field types and modeling?

  1. Location - This gap can be filled with the Geofield module.
  2. JSON object - For Contentful, this is the field type you can use to inject whatever data you want into a content type, and there isn’t a corresponding field type that matches what you need. Of course, it’s not very user-friendly for editors. It is very likely the Drupal landscape has the module you need for the data you want to store, but there is also the JSON Field module if you want to mimic the field type itself.

Contentful has one way of doing something, like how to include images and other media. And it works well for the 80%.

With Drupal, there are different ways to do this, even with just what is included in Drupal Core. You have to make a decision upfront, and if you want to switch later, it could be a huge development effort. You could use normal file fields and the basic image embedding offered by the built-in CKEditor.

Or you could enable the Media and Media Library modules, which will use a different type of field and a different way to embed media into rich text. And your entire paradigm changes.

Contentful’s biased approach saves you some brain cycles in figuring out how you want to accomplish some things. It just works. Drupal requires more planning and setup at the beginning. This will be a common theme for other areas of comparison as well.

What is Contentful missing in terms of field types and modeling?

The easiest way to answer this is to just point to the Drupal module ecosystem. Since it is open-source, there are a wide variety of contributions, and since Drupal encourages compatibility, many of these modules work together in interesting ways. 

However, this huge library can also be Drupal’s weakness. It can be hard to find what you are looking for if you don’t already know the correct terminology, and it tends to be less polished. There are sometimes multiple ways of doing something, and unless you have been involved in Drupal for years, you don’t know the “best” way.

Analysis paralysis.

We ran into this same problem while writing this article. What exactly do we include in this section beyond waving our hands in the direction of Drupal’s module directory?

In the end, we landed on some “must-haves” based on common usage, following the 80/20 rule.

  • Multi-value fields - Other than for its Reference and text fields, Contentful does not provide multi-value fields like Drupal. If you want multiple values for a number or location, you need to create multiple fields. That can get cumbersome for both content type setup and the eventual rendering of the content by a consumer. Grouping the related values would require naming all the fields a certain way, which leads to fragility. Drupal’s way of handling this type of data provides clarity and intention.
  • Physical addresses - Drupal’s Address module is a robust modeling of complicated data that differs from one geographic area to the next. Contentful requires you to build up an address field from multiple text fields or write a custom extension.
  • Extensible rich text editor - Drupal uses the mature CKEditor (though you can switch this out if you want), and plugins can be added to extend its functionality. Contentful’s Rich Text editor cannot be modified, though you can take their code for it and modify it to your needs. That means you miss out on any updates and improvements they might push.

Drupal’s Entity structure is also an improvement over Contentful’s entity structure. 

Contentful only has “Content” that you can model. In Drupal, Users, Media, Taxonomy Terms, and much more are entities that can have fields and complex modeling. With Users in particular, this adds some exciting possibilities for things like advanced access control, workflows, and personalization. 

Some of this will simply not be possible in Contentful.

Drupal went through its “everything is content” phase and came out the other side as a mature tool capable of modeling complex domains and requirements. It paid for this maturity with blood, sweat, and tears. Previous versions have the scars to prove it. 

Contentful will also have to learn similar lessons as it matures.

Editorial Experience

How easy is it to find, create, and manage content? Contentful’s default editorial experience looks great and is easy to use. Everything feels fluid and natural. This is one of the natural benefits of a SaaS product, as they have a given feature set and don’t need to be able to solve every editorial problem imaginable.

But this just pertains to the default Contentful Web App. 

If your team is familiar with React, you can customize the editorial experience at the level of a page, content type, field, sidebar, and dialogs. But then you lose some of the benefits of Contentful’s sensible defaults.

With some“locations,” you need to implement your own error handling, rich text data entry, and closely tracking release updates to ensure the underlying data structure has not changed. You are looking at the same development effort as a complex, medium-sized React application. Field and widget customizations have the complexity of writing an individual React component or subcomponent. The good news is that Contentful has released their field editors as open-source, so you have some guidance and/or things you can reuse when writing your own.

This is something you should keep in mind when evaluating Contentful, especially if you feel you will need unique customizations for how you manage content.

Creating content

Each field type has a good selection of widgets to choose from: text fields, drop-downs, radio buttons, URL formatters, and more. Contentful number fields even have the option to enter them as stars to mimic review sites. Long text fields (that are not rich text) have the option for Markdown entry.

You can add existing references or create a piece of content at the same time as referencing it. This can also be done in the context of a rich text field to embed content. It feels intuitive.

Content views

The default content view lists all content in the system, with easy ways to filter that list of content. You can filter by content type and the value of any field, including reference fields. 

You can save any combination of filters as its own view for quick access later. This view can be saved as a “shared view” for everyone or one for your own use. This is incredibly helpful, as it gives editors more autonomy. It’s as easy as typing in a name and clicking “save.”

Translations

Contentful allows you to add locales for content translation. You can then mark fields as translatable. Their default editorial app allows you to switch between locales when creating or editing content, displaying the proper fields.

If you want more than 10 locales, however, you will need their Enterprise tier. In addition, there is no way to translate the default editorial interface. 

If you want a localized experience for your editors, you will need to write your own editorial app.

What is Drupal Core missing in terms of the editorial experience?

  • Duplicating content - This gap can be filled with the Entity Clone module.
  • Entity usage - This gap can be filled with the Entity Usage module, though this can present some scalability issues with some setups.
  • Scheduling content - This gap can be filled with the Scheduler module.
  • Search or create an entity to reference - With a combination of Embed, Entity Embed, Entity Browser, and Inline Entity Form, you can reach functional parity with Contentful’s referencing experience. It takes some effort to set up, but it can be done without any custom code. See images below.
  • Revision comparison and restoration - This gap can be partially filled with the Diff module. However, the out-of-the-box interface is not as nice or intuitive as Contentful’s, which allows for easy field-level restoration. It is straightforward to view differences at a glance and roll back only the fields you want. Drupal has full revision rollback capabilities but is less polished.

The ability for editors to save their own views is useful and not something Drupal can do easily. Any new View, because it is stored in configuration, will require some developer time and a deployment.

What is Contentful missing in terms of the editorial experience?

Drupal has a lot of options for you to craft a good experience for your editors. While many things will not look as sleek or polished as Contentful (a problem being tackled by the Admin UI & Javascript Modernisation Initiative), you can get close. 

Not only are there administration themes looking to fill some gaps, like Gin, there is also plenty you can get done in Drupal through clicking some buttons in the user interface. Doing something similar in Contentful would mean custom development of a React application or component.

  • Form organization - The Field Group module provides custom grouping of fields that allow easy customizations of the editorial experience. This is useful for content types with a lot of fields. With Contentful, you must have a fully custom “Entry Editor.”
  • Multi-value fields - This was also a line-item for content modeling, but it also applies to the editorial experience. There are no multi-value fields for some of their data types in Contentful, so you will not be able to have a widget with checkboxes on many of the field types. Not without heavy customization, at least.
  • User roles and permissions - Drupal gives you unlimited granularity in the roles you define. Contentful limits the roles you can have. The first paid tier gives you some more predefined roles, but you must have an Enterprise-tier account to have custom roles and permissions. 
  • Editorial workflows - Drupal Core includes Content Moderation module and the Workflows module. With them, you can define an unlimited amount of arbitrary publishing states and workflows. No matter how large or varied your team, you can map your ideal workflow and implement it. Because of Contentful’s limited roles, advanced workflows are not possible unless you upgrade to the Enterprise tier.
  • Advanced views - While editors cannot easily create their own content views, Drupal’s View system can create more varied experiences, with the ability to add any field to the view, pull in relationships, and perform bulk operations. If you have a development team working on the back-end anyway, it is effortless to roll out new content views based on particular needs.
  • Translations - Drupal provides unlimited locales. You can also translate the editorial interface without any special customization and without rewriting the whole thing from scratch. Translation workflows can also be combined with more advanced editorial workflows, so Drupal translations can fit within the way your editors want to work.

More on multi-value fields. No doubt Contentful would recommend you create a new content type for anything that needs to be multi-valued. That way, editors can add one to many references to that content, and more, that content can be re-used. It helps things stay organized.

But that seems like overkill for something that just needs a single field of data, and if you need more than 48 content types, you will need the Enterprise tier. You will then be charged accordingly for the number of content types that you need.

Drupal’s flexibility, with unlimited content types and multi-value fields, is something to keep in mind.

The API

Here is the bread and butter of what Contentful offers: the content API. We’ll look at how it measures up to the API included in Drupal Core, JSON: API. For this overview, we will only look at the Content Delivery API, though both Contentful and Drupal have ways to create content through an API and ways to call and preview unpublished content. 

For our comparisons, we have created the same content model in both Contentful and Drupal 8, populated with the same data. This gives us a good sampling of data types and organization to make a good comparison. This is a simple music library.

  • Artist - A Name field, an About field that is rich text so we can include embedded entities, a Latest Album reference field that will reference an Album content type, and a Contact field that will hold an email address.
  • Album - A Title field, a Description field, a Cover Art field so we can look at Media assets and management, a Release Date field for a date/time sample, an Artist field that references an Artist content type, and a Tracks reference that references many entities of the Track content type.
  • Track - only a Title field.

Single Content Queries

This is the API response for the Abbey Road album:

Request format: 

https://cdn.contentful.com/spaces/{space_id}/environments/master/entries/{entry_id}?access_token={access_token}

{
    "sys": {
        "space": {
            "sys": {
                "type": "Link",
                "linkType": "Space",
                "id": "79u36k13bxm5"
            }
        },
        "id": "2oc0DNVizJuFLoXsG7EHwi",
        "type": "Entry",
        "createdAt": "2020-11-12T22:28:11.031Z",
        "updatedAt": "2020-11-12T22:38:16.502Z",
        "environment": {
            "sys": {
                "id": "master",
                "type": "Link",
                "linkType": "Environment"
            }
        },
        "revision": 2,
        "contentType": {
            "sys": {
                "type": "Link",
                "linkType": "ContentType",
                "id": "album"
            }
        },
        "locale": "en-US"
    },
    "fields": {
        "title": "Abbey Road",
        "releaseDate": "1969-09-26",
        "description": "Abbey Road is the eleventh studio album by the English rock band the Beatles",
        "coverArt": {
            "sys": {
                "type": "Link",
                "linkType": "Asset",
                "id": "32z3JMUzfZuUTCv8EtCumB"
            }
        },
        "tracks": [
            {
                "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "3TAx53F4EXxz3YVuGJYZql"
                }
            },
            {
                "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "26HTJnrAXT3UgQzPuQx5AA"
                }
            },
            {
                "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "1F6nqI6J96D7j4KlOQrRvQ"
                }
            },
            {
                "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "3veIx6bwvs6EuJz41308Nk"
                }
            },
            {
                "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "1Dhy3jECJdyNTYCrQgxQwk"
                }
            }
        ],
        "artist": {
            "sys": {
                "type": "Link",
                "linkType": "Entry",
                "id": "Xm0gwlpQGITlLvcyvTyyM"
            }
        }
    }
}

Here is the same data represented by Drupal’s content API.

Request format: https://example.com/jsonapi/node/{type}/{uuid}

{
    "jsonapi": {
        "version": "1.0",
        "meta": {
            "links": {
                "self": {
                    "href": "http://jsonapi.org/format/1.0/"
                }
            }
        }
    },
    "data": {
        "type": "node--album",
        "id": "df825a90-2fb8-49a1-9fda-022504bc9fb8",
        "links": {
            "self": {
                "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8?resourceVersion=id%3A7"
            }
        },
        "attributes": {
            "drupal_internal__nid": 7,
            "drupal_internal__vid": 7,
            "langcode": "en",
            "revision_timestamp": "2020-11-24T21:00:29+00:00",
            "revision_log": null,
            "status": true,
            "title": "Abbey Road",
            "created": "2020-11-24T20:54:58+00:00",
            "changed": "2020-11-24T21:00:29+00:00",
            "promote": true,
            "sticky": false,
            "default_langcode": true,
            "revision_translation_affected": true,
            "path": {
                "alias": null,
                "pid": null,
                "langcode": "en"
            },
            "field_description": "Abbey Road is the eleventh studio album by the English rock band the Beatles",
            "field_release_date": "1969-09-26T21:49:44+00:00"
        },
        "relationships": {
            "node_type": {
                "data": {
                    "type": "node_type--node_type",
                    "id": "2ba6452d-ac91-48b7-b1a8-a7ffd1ab9cec"
                },
                "links": {
                    "related": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/node_type?resourceVersion=id%3A7"
                    },
                    "self": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/relationships/node_type?resourceVersion=id%3A7"
                    }
                }
            },
            "revision_uid": {
                "data": {
                    "type": "user--user",
                    "id": "441881cb-202d-4804-9832-9f42e32e48c0"
                },
                "links": {
                    "related": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/revision_uid?resourceVersion=id%3A7"
                    },
                    "self": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/relationships/revision_uid?resourceVersion=id%3A7"
                    }
                }
            },
            "uid": {
                "data": {
                    "type": "user--user",
                    "id": "441881cb-202d-4804-9832-9f42e32e48c0"
                },
                "links": {
                    "related": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/uid?resourceVersion=id%3A7"
                    },
                    "self": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/relationships/uid?resourceVersion=id%3A7"
                    }
                }
            },
            "field_artist": {
                "data": {
                    "type": "node--artist",
                    "id": "1e3b51ea-b6b8-417b-89a0-ca14772eb223"
                },
                "links": {
                    "related": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/field_artist?resourceVersion=id%3A7"
                    },
                    "self": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/relationships/field_artist?resourceVersion=id%3A7"
                    }
                }
            },
            "field_cover_art": {
                "data": {
                    "type": "media--image",
                    "id": "f8d292a1-4557-47b0-8f0b-a059f103be24"
                },
                "links": {
                    "related": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/field_cover_art?resourceVersion=id%3A7"
                    },
                    "self": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/relationships/field_cover_art?resourceVersion=id%3A7"
                    }
                }
            },
            "field_tracks": {
                "data": [
                    {
                        "type": "node--track",
                        "id": "922b838c-b63f-42ef-acbb-4e103cf640ac"
                    },
                    {
                        "type": "node--track",
                        "id": "8f15d5d4-1163-4f7b-be98-1b27cf054546"
                    },
                    {
                        "type": "node--track",
                        "id": "6f69fe91-19a7-4a12-92d2-2f0139102072"
                    },
                    {
                        "type": "node--track",
                        "id": "dcc7e5d0-9993-4c57-8a0e-edc9980d6e09"
                    },
                    {
                        "type": "node--track",
                        "id": "923c4da6-b377-4a30-8b81-c980d34f3c92"
                    }
                ],
                "links": {
                    "related": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/field_tracks?resourceVersion=id%3A7"
                    },
                    "self": {
                        "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8/relationships/field_tracks?resourceVersion=id%3A7"
                    }
                }
            }
        }
    },
    "links": {
        "self": {
            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/album/df825a90-2fb8-49a1-9fda-022504bc9fb8"
        }
    }
}

All of the relevant data is easily accessible, though Drupal’s is a little more verbose. This is partly because Drupal’s content entities have more built-in fields by default.

Both list references with their type and their unique ID so that information can be retrieved with subsequent calls.

Contentful:

"sys": {
    "type": "Link",
    "linkType": "Entry",
    "id": "26HTJnrAXT3UgQzPuQx5AA"
}

Drupal:

{
    "type": "node--track",
    "id": "dcc7e5d0-9993-4c57-8a0e-edc9980d6e09"
},

Notice that Contentful’s response has no author or user. This is because its users are purely editorial in context and are not supposed to be part of the model. If you wanted to track authors and pass them via the API, you would need to create an Author content type and another reference field.

Both Contentful and Drupal also allow you to:

  • Resolve the referenced entities' data, so you don’t need to make subsequent API calls for each referenced entity. In our example of an album, we would get terrible performance if we made an API call for every single track. We can add an “include” parameter that puts this information in a separate array.
  • Limit the fields that are returned in a response to limit the verbosity and payload size.

Content Collections

You can pull a collection of entities that match certain criteria, and both have robust filtering mechanisms to find specific content. There are differences in implementation, but you can achieve the same result with both, filtering by any field with a wide range of operators (equal, not equal, greater than, etc.) and ordering the results based on a certain field.

Read about Contentful’s full range of search parameters here and compare them to Drupal’s JSON API filtering capabilities here.

Contentful does include some intriguing full-text search capabilities out-of-the-box that searches across all fields. Typically, a decoupled application will use a dedicated service for search, but if your search needs are rudimentary, Contentful’s default might meet your needs.

On the other hand, because of the way Drupal implements it’s filtering, you can do per-field text searches with pattern operators like 'STARTS_WITH,' 'CONTAINS,' and 'ENDS_WITH.’ This can be useful. 

You can also get a rudimentary full-text search running on Drupal with the JSON: API Search API module.

Here is a Contentful collection example, truncated to the first two results.

Request format: 

https://cdn.contentful.com/spaces/{space_id}/environments/master/entries?access_token={access_token}&content_type={type}


{
    "sys": {
        "type": "Array"
    },
    "total": 9,
    "skip": 0,
    "limit": 100,
    "items": [
        {
            "sys": {
                "space": {
                    "sys": {
                        "type": "Link",
                        "linkType": "Space",
                        "id": "79u36k13bxm5"
                    }
                },
                "id": "7w2rXd9fQfTOXuAEPcqmqB",
                "type": "Entry",
                "createdAt": "2020-11-17T19:38:08.569Z",
                "updatedAt": "2020-11-17T19:38:08.569Z",
                "environment": {
                    "sys": {
                        "id": "master",
                        "type": "Link",
                        "linkType": "Environment"
                    }
                },
                "revision": 1,
                "contentType": {
                    "sys": {
                        "type": "Link",
                        "linkType": "ContentType",
                        "id": "song"
                    }
                },
                "locale": "en-US"
            },
            "fields": {
                "title": "Please Please Me"
            }
        },
        {
            "sys": {
                "space": {
                    "sys": {
                        "type": "Link",
                        "linkType": "Space",
                        "id": "79u36k13bxm5"
                    }
                },
                "id": "7uFcbd7Q3vyG3kpibaPWfp",
                "type": "Entry",
                "createdAt": "2020-11-17T19:37:58.370Z",
                "updatedAt": "2020-11-17T19:37:58.370Z",
                "environment": {
                    "sys": {
                        "id": "master",
                        "type": "Link",
                        "linkType": "Environment"
                    }
                },
                "revision": 1,
                "contentType": {
                    "sys": {
                        "type": "Link",
                        "linkType": "ContentType",
                        "id": "song"
                    }
                },
                "locale": "en-US"
            },
            "fields": {
                "title": "Ask Me Why"
            }
        },
        ..
        .
    ]
}

And here is the Drupal JSON API example, also truncated to the first two results. 

Request format: https://example.com/jsonapi/node/{type}


{
    "jsonapi": {
        "version": "1.0",
        "meta": {
            "links": {
                "self": {
                    "href": "http://jsonapi.org/format/1.0/"
                }
            }
        }
    },
    "data": [
        {
            "type": "node--track",
            "id": "922b838c-b63f-42ef-acbb-4e103cf640ac",
            "links": {
                "self": {
                    "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/922b838c-b63f-42ef-acbb-4e103cf640ac?resourceVersion=id%3A2"
                }
            },
            "attributes": {
                "drupal_internal__nid": 2,
                "drupal_internal__vid": 2,
                "langcode": "en",
                "revision_timestamp": "2020-11-24T20:58:56+00:00",
                "revision_log": null,
                "status": true,
                "title": "Come Together",
                "created": "2020-11-24T20:58:56+00:00",
                "changed": "2020-11-24T20:58:56+00:00",
                "promote": true,
                "sticky": false,
                "default_langcode": true,
                "revision_translation_affected": true,
                "path": {
                    "alias": null,
                    "pid": null,
                    "langcode": "en"
                }
            },
            "relationships": {
                "node_type": {
                    "data": {
                        "type": "node_type--node_type",
                        "id": "d773d9e2-9c75-4547-98af-47cc41f5b28e"
                    },
                    "links": {
                        "related": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/922b838c-b63f-42ef-acbb-4e103cf640ac/node_type?resourceVersion=id%3A2"
                        },
                        "self": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/922b838c-b63f-42ef-acbb-4e103cf640ac/relationships/node_type?resourceVersion=id%3A2"
                        }
                    }
                },
                "revision_uid": {
                    "data": {
                        "type": "user--user",
                        "id": "441881cb-202d-4804-9832-9f42e32e48c0"
                    },
                    "links": {
                        "related": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/922b838c-b63f-42ef-acbb-4e103cf640ac/revision_uid?resourceVersion=id%3A2"
                        },
                        "self": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/922b838c-b63f-42ef-acbb-4e103cf640ac/relationships/revision_uid?resourceVersion=id%3A2"
                        }
                    }
                },
                "uid": {
                    "data": {
                        "type": "user--user",
                        "id": "441881cb-202d-4804-9832-9f42e32e48c0"
                    },
                    "links": {
                        "related": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/922b838c-b63f-42ef-acbb-4e103cf640ac/uid?resourceVersion=id%3A2"
                        },
                        "self": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/922b838c-b63f-42ef-acbb-4e103cf640ac/relationships/uid?resourceVersion=id%3A2"
                        }
                    }
                }
            }
        },
        {
            "type": "node--track",
            "id": "8f15d5d4-1163-4f7b-be98-1b27cf054546",
            "links": {
                "self": {
                    "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/8f15d5d4-1163-4f7b-be98-1b27cf054546?resourceVersion=id%3A3"
                }
            },
            "attributes": {
                "drupal_internal__nid": 3,
                "drupal_internal__vid": 3,
                "langcode": "en",
                "revision_timestamp": "2020-11-24T20:59:01+00:00",
                "revision_log": null,
                "status": true,
                "title": "Something",
                "created": "2020-11-24T20:59:01+00:00",
                "changed": "2020-11-24T20:59:01+00:00",
                "promote": true,
                "sticky": false,
                "default_langcode": true,
                "revision_translation_affected": true,
                "path": {
                    "alias": null,
                    "pid": null,
                    "langcode": "en"
                }
            },
            "relationships": {
                "node_type": {
                    "data": {
                        "type": "node_type--node_type",
                        "id": "d773d9e2-9c75-4547-98af-47cc41f5b28e"
                    },
                    "links": {
                        "related": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/8f15d5d4-1163-4f7b-be98-1b27cf054546/node_type?resourceVersion=id%3A3"
                        },
                        "self": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/8f15d5d4-1163-4f7b-be98-1b27cf054546/relationships/node_type?resourceVersion=id%3A3"
                        }
                    }
                },
                "revision_uid": {
                    "data": {
                        "type": "user--user",
                        "id": "441881cb-202d-4804-9832-9f42e32e48c0"
                    },
                    "links": {
                        "related": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/8f15d5d4-1163-4f7b-be98-1b27cf054546/revision_uid?resourceVersion=id%3A3"
                        },
                        "self": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/8f15d5d4-1163-4f7b-be98-1b27cf054546/relationships/revision_uid?resourceVersion=id%3A3"
                        }
                    }
                },
                "uid": {
                    "data": {
                        "type": "user--user",
                        "id": "441881cb-202d-4804-9832-9f42e32e48c0"
                    },
                    "links": {
                        "related": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/8f15d5d4-1163-4f7b-be98-1b27cf054546/uid?resourceVersion=id%3A3"
                        },
                        "self": {
                            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track/8f15d5d4-1163-4f7b-be98-1b27cf054546/relationships/uid?resourceVersion=id%3A3"
                        }
                    }
                }
            }
        },
        ..
        .
    ],
    "links": {
        "self": {
            "href": "https://dev-music-library-demo.pantheonsite.io/jsonapi/node/track"
        }
    }
}

Rich Text and Embeds

Each system handles rich text and embeds in different ways. First, let’s look at how Contentful returns content with embedded assets.

For this example, we’ll pull our Artist content titled “The Beatles.” This is how the About field is represented:

"about": {
            "data": {},
            "content": [
                {
                    "data": {},
                    "content": [
                        {
                            "data": {},
                            "marks": [],
                            "value": "The Beatles were an English rock band formed in Liverpool in 1960. The group, whose best-known line-up comprised John Lennon, Paul McCartney, George Harrison and Ringo Starr, are regarded as the most influential band of all time.",
                            "nodeType": "text"
                        }
                    ],
                    "nodeType": "paragraph"
                },
                {
                    "data": {},
                    "content": [
                        {
                            "data": {},
                            "marks": [],
                            "value": "They were integral to the development of 1960s counterculture and popular music's recognition as an art form.Rooted in skiffle, beat and 1950s rock and roll, their sound incorporated elements of classical music and traditional pop in innovative ways; the band later explored music styles ranging from ballads and Indian music to psychedelia and hard rock. ",
                            "nodeType": "text"
                        }
                    ],
                    "nodeType": "paragraph"
                },
                {
                    "data": {
                        "target": {
                            "sys": {
                                "id": "6NwAnNO3L14TjyfCpvrf0l",
                                "type": "Link",
                                "linkType": "Asset"
                            }
                        }
                    },
                    "content": [],
                    "nodeType": "embedded-asset-block"
                },
                {
                    "data": {},
                    "content": [
                        {
                            "data": {},
                            "marks": [],
                            "value": "As pioneers in recording, songwriting and artistic presentation, the Beatles revolutionised many aspects of the music industry and were often publicised as leaders of the era's youth and sociocultural movements.",
                            "nodeType": "text"
                        }
                    ],
                    "nodeType": "paragraph"
                },
                {
                    "data": {
                        "target": {
                            "sys": {
                                "id": "XLrFYAYIhAMh7thYq2gxs",
                                "type": "Link",
                                "linkType": "Entry"
                            }
                        }
                    },
                    "content": [],
                    "nodeType": "embedded-entry-block"
                },
                {
                    "data": {},
                    "content": [
                        {
                            "data": {},
                            "marks": [],
                            "value": "Nationwide interest in the Beatles had been piqued with the success of their second UK single and ",
                            "nodeType": "text"
                        },
                        {
                            "data": {
                                "uri": "https://en.wikipedia.org/wiki/Parlophone"
                            },
                            "content": [
                                {
                                    "data": {},
                                    "marks": [],
                                    "value": "Parlophone",
                                    "nodeType": "text"
                                }
                            ],
                            "nodeType": "hyperlink"
                        },
                        {
                            "data": {},
                            "marks": [],
                            "value": ", hoping to take advantage of this, promptly decided to follow it up with an album.",
                            "nodeType": "text"
                        }
                    ],
                    "nodeType": "paragraph"
                },
                {
                    "data": {},
                    "content": [
                        {
                            "data": {},
                            "marks": [],
                            "value": "",
                            "nodeType": "text"
                        }
                    ],
                    "nodeType": "paragraph"
                },
                {
                    "data": {},
                    "content": [
                        {
                            "data": {},
                            "marks": [],
                            "value": "",
                            "nodeType": "text"
                        }
                    ],
                    "nodeType": "paragraph"
                }
            ],
            "nodeType": "document"
        },

It contains no HTML markup. Each paragraph is its own “node” with a nodeType of “paragraph,” each with its own content array of “nodes.” Even links are represented as a different “node.”

Embedded content like images is represented as “embedded-asset-block” or “embedded-entry-block,” with all the data you need to get the information for those items.

If the query is built right, you can also include all of the data for embedded entities in the same API call.

This means you need to build up a page yourself on the front-end. This is like a LEGO brick set that comes with clear instructions. It’s very flexible and makes no assumptions about where this data is going to be rendered.

To compare, here is how Drupal handles a call for the same content.

"field_about": {
        "value": "

The Beatles were an English rock band formed in Liverpool in 1960. The group, whose best-known line-up comprised John Lennon, Paul McCartney, George Harrison and Ringo Starr, are regarded as the most influential band of all time.

\r\n\r\n

They were integral to the development of 1960s counterculture and popular music's recognition as an art form.Rooted in skiffle, beat and 1950s rock and roll, their sound incorporated elements of classical music and traditional pop in innovative ways; the band later explored music styles ranging from ballads and Indian music to psychedelia and hard rock.

\r\n\r\n\r\n\r\n

As pioneers in recording, songwriting and artistic presentation, the Beatles revolutionised many aspects of the music industry and were often publicised as leaders of the era's youth and sociocultural movements.

\r\n\r\n\r\n\r\n

 

\r\n\r\n

Nationwide interest in the Beatles had been piqued with the success of their second UK single and Parlophone, hoping to take advantage of this, promptly decided to follow it up with an album.

\r\n", "format": "basic_html", "processed": "

The Beatles were an English rock band formed in Liverpool in 1960. The group, whose best-known line-up comprised John Lennon, Paul McCartney, George Harrison and Ringo Starr, are regarded as the most influential band of all time.

\n\n

They were integral to the development of 1960s counterculture and popular music's recognition as an art form.Rooted in skiffle, beat and 1950s rock and roll, their sound incorporated elements of classical music and traditional pop in innovative ways; the band later explored music styles ranging from ballads and Indian music to psychedelia and hard rock.

..." },

This is a different approach. Drupal includes both the unfiltered markup and the processed markup for the field, based on the selected format. For simple content, you can just take what is returned in the “processed” key and render it. If you set things up on the back-end properly, this even works with embeds.

For some sites, that’s all you need.

This is the isolated embed code for a media asset and a content entity:

If you want to handle rendering in a more ad-hoc manner, with more flexibility, you will need some way to save embedded entities into an entity reference field on the node. This will let you include their data in the same API request. 

It requires some additional processing on the back-end, as you need to parse the rich text field and grab the entities embedded there. We did something similar on Edutopia with great success.

Conclusion

We could compare a lot more, like previews and image derivatives, but this gives you a good introduction to the differences.

Bottom line: anything Contentful does, Drupal can do as well. You can treat Drupal as a hub for your content, and it will perform admirably. Most gaps in Drupal Core have been filled with stable, secure, and reliable modules.

Contentful is a true API-first platform. It was designed with front-end consumers in mind, and it is very robust in that regard.

Drupal’s focus has been on managing large amounts of content and the editorial workflows that can come with that, as well as modeling diverse types of content. Its API capabilities are good and stable, but they have not been its sole focus. As a result, sometimes there are additional hoops you need to jump through to get your desired result.

Back-end customizations can be done for both Contentful and Drupal. For Contentful, you will want deep React experience. With Drupal, deep PHP experience. 

What does your team look like? If you are hiring an agency to help, what is their expertise? These should be considered while weighing the decision.

Since Contentful is a SaaS product, it has a very polished feature set. But this comes with limited extensibility. Your business will need to adapt to Contentful’s capabilities. Smaller companies will have no problem with this, but larger companies, or companies that are growing fast, might reach the bars of the cage sooner than they thought, finding themselves unable to flex or maneuver.

Drupal, by contrast, cannot be as polished since it doesn’t require you to go down a limited number of predetermined paths. As a result, Drupal places no arbitrary roadblocks to implementing what you need.

If you have a large editorial team with complicated workflow requirements, Drupal is ready to change for your needs. To even start with custom roles on Contentful, you will need the Enterprise tier.

In fact, for most companies with a large web presence, if you go with Contentful, you will need to go with their Enterprise tier. There are too many limitations with the Team tier. This means long-term contracts and big licensing fees. You get a lot in return, like uptime and support SLAs, but you need to take that into consideration.

What are the key advantages of Drupal compared to Contentful?

  • Unlimited users, roles, and permissions with unlimited workflow possibilities.
  • Full translatable content with unlimited locales, including built-in translations for the editorial interface.
  • Large contrib module ecosystem, providing more ways to customize the editorial experience.
  • Granular customizations of API responses.
  • Mature content modeling with unlimited content types.
  • Open-source with no licensing fees and no long-term contracts.

Do you have a decoupled project you are considering? We have helped solve some of the hardest decoupled problems with Drupal, and we would love to help you. Our experience is concrete and practical, not theoretical.

Contact us today.

Nov 10 2020
Nov 10

You Might Also Like

The success of a CMS project ultimately depends upon the content it contains. No matter how “on-time” or “under-budget” a project might be, editors have to be able to create and manage content, and they need to be able to do it without feeling the need to pull their own hair out.

If editors on your team do not like the editorial experience, disillusionment will begin to set in, and that disillusionment can cascade throughout your organization. Remember, your editors are likely the most prolific users of your website. If they don’t like it, your CMS implementation is headed for the scrapheap.

How do you balance ease-of-use with the constraints of your design system? Are there common things that can be done that ensure editors have a good experience? And how do we define “good?”

What is “good?”

For this article, we’ll use the following standard: A good editorial experience is one that allows an editor to add content in accordance with the organization’s goals with minimal frustration. If there are strict standards and safeguards in place, an editor still feels empowered and does not feel the desire to circumvent these safeguards.

We are not shooting for a perfect editorial experience. That will never exist. This is still software we are talking about. It has to conform to a lot of requirements, and many of those requirements will conflict. But we want to be careful to ensure that we don’t make the perfect the enemy of the good, and the standard above allows for some compromises and tradeoffs.

You will also notice that this standard means that what is “good” can differ from organization to organization. Content goals vary, the preferences of editorial teams vary, and so we need to allow for some subjectivity.

But there are still some baseline commonalities we can recognize.

We want to be careful to ensure that we don’t make the perfect the enemy of the good.

Common best practices

What are some best practices that apply to any CMS and organization? These are good anchors to start with because, if you have these, it’s harder to get distracted by shiny new tools and approaches.

1. Consistency

Jumping from editing one content type to another should carry some familiarity. As much as possible should be the same from form to form, down to colors and font sizes. This gives editors less they have to think about, which results in less confusion.

Different fields and options might exist, but give editors some anchor points, so they don’t get lost. For example, have common fields, like Title and Author, appear in the same place on all forms that have them.

Do not have multiple ways to include images or videos. Do not have one text field that allows direct embedding of an img tag but another that only allows a special embed code. This is a recipe for frustration. Choose one way to do it, and stick with it, and if it needs to change, apply the change consistently.

2. Clear, relevant labeling

Fields should be labeled, and additional helper text should provide relevant context. This seems obvious, but sometimes it is so obvious that you can forget to pay attention to it. Often this text is written and placed by developers, and so they bring their own bias and context, and what they put in is, at best, unhelpful and sometimes downright confusing.

Helper text should make sense to editors and use the language they are familiar with. It should explain things in a way so they can predict the results of their actions.

Bad helper text: “This is an image field.”

Good helper text: “An image that will be displayed at the top of the article and be shown when the article is in a list. The minimum size is 1000x600.”

Bad helper text: “The categories this article belongs to.”

Good helper text: “Add links to one or more category pages. If you input 'apples, oranges,’ links to 'mysite/apples' and 'mysite/oranges' will automatically be displayed on the article, and this article will be included in the lists on those pages.

Keep things contextual, not just factual. Editors usually don’t care about technical details, but they do care about the hierarchy of the page and the effects on the site that they can see.

This is a place where usability tests can really help. Run them to find places where people are getting confused and craft text that addresses their questions and uncertainty. Make an intentional effort.

3. Make the right things easy and the wrong things hard

Your experience should be designed to encourage your editors to do the right things.

One common example: should all images embedded within content have “alt” text? (The answer to that is yes). Make “alt” text required for every image so the content cannot be saved unless it is filled in. For background images, they should have empty alt text so screen readers will skip over them, so just don’t show an alt text field for those and let your CMS handle putting in the empty attribute.

Should each update to content create a new revision so changes can be rolled back? If so, that should be easy to do. Make it hard for someone to mess this up: don’t even show them the option.

Don’t make onerous formatting requirements that editors have to ensure themselves. Make proper formatting easy.

Have you ever been frustrated by an online form that requires you to enter a phone number with exact spacing and parentheses and offers no help? It's like trying to put a puzzle together, but all the pieces are flipped to the side with no picture, and that’s an extra cognitive load your editors don’t need.

4. Clear, obvious error handling

If an editor does something wrong, don’t be coy. Don’t leave them guessing. State the error clearly and be specific, making the message hard to miss. Ideally, the error will show up next to the problem in question, though this isn’t always possible to do. Clarity is the most important.

Bad error message: “An error has occurred.”

Better error message: “The ‘summary’ field allows a maximum of 160 characters.”

Error messages should make it obvious that something went wrong, and some colors communicate “wrong” more than others. Therefore, don’t highlight errors in green. Also, take into consideration editors who might be color blind or have other visual impairments, so do not rely on color alone to signify an error.

5. Simplify to necessity

Plan and design for the 80%. Do not have lots of fields and options that most editors will never use. Do your best to slim down the experience to only what is necessary. Do not, in other words, present your editors with a form that includes everything, even the kitchen sink.

What about the other 20%?

Once you have figured out what that 20% actually is, a process driven by your business goals and not by what people think they want, accommodate the need.

For example, only a small number of your articles might have a Featured Video, so most editors will not use it. That field should not clutter their experience. But video is still important, so certain editors should be able to find it and use it with no trouble.

This can be accomplished via permission management. If only some editors need the field, you can hide the field from others by denying them access. 

If all editors need access, just sporadically, the Featured Video field could be moved under a tab labeled “Advanced” or to a sidebar labeled “Add Video.” The fields are there, but they do not distract from the main editorial path.

Long, confusing forms sometimes result from a single content type being responsible for lots of different contexts and page designs. An “article” might be used for a blog post, a news release, a video post with a transcript, and a podcast. This requires lots of fields to take into account the different uses. 

But this heightens the risk of confusion and burnout.

Sometimes, simplifying will mean revisiting your content model and having distinct content types for each audience and/or presentation. 

Having sensible defaults also helps simplify things. Default to what the 80% needs, but make it easy for the 20% to change that default.

6. Easy wayfinding

Good navigation and architecture aren’t helpful only for your site visitors. Your editors would also appreciate not feeling lost when they need to edit a specific page or content block.

Pay attention to the organization on the administration side. Are your editors forced to use your normal site search, the one for visitors, to find the content they need? Maybe that’s fine. If it isn’t, though, have you provided a good alternative?

Some of this depends on how big your editorial team is and how they work. If a team is responsible for a few categories, make it easy to filter by their categories. If you have a system of revision approval, make sure the process is clear and that the next steps are easy to figure out.

Inline editing can be helpful here, but it can also be overrated and difficult to integrate with certain workflows. As long as an editor has a clear path to get where they need to go, that is often enough.

7. Avoid busywork

Don’t enforce things “just because.” Don’t require editors to fill out fields that are not really required for any business logic.

For example, some systems have a revision log field that is required whenever content is updated. This can be helpful for large teams, but sometimes, the only person who ever reads those revision logs is the ghost who lives in the server. AKA “no one.” 

Don’t make your editors fill out stuff that nobody cares about. There might be legal requirements for you to store information, and in that case, someone obviously needs to care about it. The question then becomes: how do I make the process better?

Likewise, do not make every piece of content go through a five-step approval process if only one person needs to give approval. Do what is necessary to ensure standards are met, but having faith and trust in your team is better than arbitrary safeguards.

Drupal-specific tools to help

Drupal has a lot of functionality, out of the box, that will help you deliver a good editorial experience, like places for form element helper text, requiring alt text on images, good form validation, and the ability to set default values. 

Drupal core also gives you the ability to have different “form displays” for each content type, though taking advantage of them requires a bit more work.

Text formats and WYSIWYG

Drupal comes with a robust text format system, and editors can have access to different formats based on their permission level. Take advantage of these. Do not leave extra buttons on the WYSIWYG editor that no one uses. Keep it simple.

Contextual links

Drupal includes drop-down links for privileged users at various places on a site, allowing editors to easily jump to the edit form of a block or content type. Additional links can be defined with custom modules.

If you are creating listings with Views, Drupal provides a way to add contextual links to each result that is shown. This can be an easy win.

Shortcuts

Drupal comes with a shortcut menu that each editor can easily access. You can set up permissions in a way for editors to choose their own shortcut set, giving them some say in their own experience. Set up some sensible defaults for the most common tasks, and let them tweak. 

This is simple in concept but can go a long way in improving the overall experience.

Inline Form Errors

This module is included in Core but is disabled by default. When enabled, error messages are placed next to the relevant form elements themselves instead of just as a summary at the top of the form.

Contrib extras to help you craft a good editorial experience

There are other tools and groups of modules you should pay attention to when building an editorial experience in Drupal. Using them does not guarantee a good experience, but they can make it easier to achieve one.

  • Field Group - Perfect for simplifying your forms and hiding less-used fields. A great tool for catering toward the 80%. If you end up grouping fields according to a specific pattern(field type, whether a field is required, frequency of use,) stay consistent from content type to content type.
  • Field Permissions - Another way to limit and simplify your forms, but with more explicitness. Useful for larger teams with a hierarchy of editors where access to some fields need to be enforced beyond just moving them around visually.
  • Entity Browser - A widget for entity reference fields, this allows more user-friendly selection beyond simple autocomplete. If set up correctly, it also allows inline creation of other entities before they are referenced. This can drastically improve the usability for editors. However, it depends on good practices and discipline for field naming and descriptions, so you cannot ignore the basics.
  • Embed - You can also set up easy embedding for custom elements and structured data, tying them to a button on the WYSIWYG.
  • Entity Embed - Integrates with Embed to trigger Entity Browsers to enable embedding in text fields.  It’s easy to go overboard with this module and cause more confusion, so be intentional about what you use it for.
  • Inline Entity Form - Another widget for entity reference fields. Good for creating content to reference. If you don’t need to re-use content and don’t need to search for content to reference, this can work better than Entity Browser in some situations.
  • Allowed Formats - Drupal core allows you to limit text formats by user role, but Allowed Formats will enable you to do it per field. It is very common for a text field to allow only links, for example, enabling you to have the appropriate format selected and all others hidden. This is a great way to make the wrong things harder.
  • Entityqueue - Sometimes, editors need to be able to explicitly define the order of content on a page and not depend upon things like a published date or other metadata. This makes it easy for them to reference content and order it how they wish.
  • Automatic Entity Label - Used for content that is only referenced by other content, so editors do not have to worry about creating labels. This can help avoid some busywork.
  • Override Node Options - Limit access to default fields on nodes. This fills in some gaps from Field Permissions.
  • Chosen and Select2 - If you have long select lists, either of these can make them more usable.
  • Linkit - If your editors link to lots of internal content and files, this module makes it easier to perform those tasks.
  • Require on Publish - Sometimes there are fields that editors do not want to fill out until content is actually published, and they just want to save their work or view a preview. This has provided a huge boost in usability for some editorial teams.

When editors are happy…

There is no such thing as a perfect editorial experience, but you can provide a good one that will keep your editors happy and help them avoid frustration. Don’t ignore the most prolific users of your website.

If your editors are happy, it is much more likely that your business objectives will be met, there will be less turnover and burnout, and your CMS has a better chance of sticking around for a while.

At Lullabot, we have seen the good, the bad, and the ugly of CMS experiences. Part of our work in design and strategy is to figure out how to empower your editors and not leave them behind. And we would love to help you. Reach out if you have any questions

Oct 21 2020
Oct 21

You Might Also Like

The Drupal 8 to Drupal 9 upgrade path represents a big change for the Drupal world. The big change is that…your organization’s website won’t require a big change. The first iteration of Drupal 9 is just Drupal 8 with all of the deprecated code removed, mimicking Symfony’s model of major release upgrades.

This is good news. Keeping your platform up-to-date with the next version is no longer an “all hands on deck” situation.

As with all changes, however, this new model comes with its own challenges and problems. You will need to shift your own thinking and habits. When it comes to your Drupal website, your organization will need to begin running a marathon that goes on for years. Your relationship with outside vendors will take on a new cadence.

In this brave new world where upgrading to the next major Drupal release isn’t a big re-platforming effort, what does web development strategy look like?

Establish a cadence for web development work

One good thing about major re-platforming efforts is that they have to be planned for in advance. Budget and time have to be allocated. It acts as a huge celestial star, with everything else gradually falling into orbit around the big initiative. It draws out intention, direction, and sometimes enthusiasm, and none of these are bad things to have. 

Having this large, common goal that everyone sees with clarity can make a lot of this stuff come more easily, but now, you need to figure out how to create and harness these things while not depending on the existence of a monolithic target that dominates the landscape. And you need to maintain what you have at a sensible pace.

Planning out the release cycle

 Like Drupal 8, Drupal 9 requires frequent updates. To get the latest security updates, you need to stay on the latest minor point release (9.1, 9.2, etc.). With this, you also have the possibility of getting new features that have been included, and you should be aware of them. Our article on Drupal 8 release planning is still relevant for Drupal 9. In summary:

  1.  Build a schedule of releases and support windows for your software. Not only for Drupal 9 but also for any contributed modules and other software that is part of your hosting stack.
  2.  Schedule updates ahead of time, and do not let the desire for new features cannibalize these dates. These should be scheduled from the top by project managers. This might mean a sprint every month or so 100% dedicated to updates. These should be just as visible as other initiatives that are being developed and be treated as equally important.
  3. Promote any new features that were rolled out by these updates.

Planning new initiatives and features

Ideally, with a more iterative approach to development, stakeholders stay more involved and informed, and therefore better discussions can be had around the website. With the old Drupal upgrade model, there was a risk of the dreaded stakeholder swoop: someone swoops in, lists a bunch of requirements without regard to overall goals and priorities, and swoops back out. Sometimes they aren’t seen again until close to launch.

That risk still exists but is mitigated by the extra number of touchpoints required from a more long-term, iterative approach. There are more starts and mini-launches. If a typical swooping stakeholder wants to get something done, they will have to do a lot more swooping, which might start to look more like informed involvement.

Regardless, you need to be more intentional with planning out and prioritizing new features. You can’t let every neat idea, frustration, or new design collect in a bucket over the course of two years, only to implement them on the new platform. With iterative development, your organization will need to communicate more, not less.

Set up regular touchpoints with stakeholders and domain experts. This will look different for every organization. The Marketing department might be the main driver. In that case, you’ll need to regularly meet with the person who has the authority to make requests and set priorities, in addition to domain experts that can answer questions and provide deeper knowledge. In smaller organizations, this could all be invested in one person.

If your website represents the needs of many different silos, like a company selling multiple products, then you will need regular meetings for each different product team. The same standards apply. You need someone with authority and domain knowledge.

These meetings should match up with your project management philosophy. For example, are you running sprints via agile? Invite these folks to sprint planning. Requirements with large uncertainties can trigger the creation of a targeted discovery phase with stakeholders, which becomes part of a sprint, just like all of the other tickets.

Regular usability tests are another way to find potential improvements. These don’t have to take a lot of time and money. The book Don’t Make Me Think outlines a simple framework that anyone can implement, and running them once per month is usually enough to fill any gaps in your pipeline.

Re-factoring and technical debt

Codebases tend to gather junk over time. This comes in the form of disorganized code, “temporary” fixes that have become permanent when no one was paying attention, things that work but could use performance tuning, and modules included in the codebase that aren’t used anymore.

Previous upgrade cycles allowed messes to be stacked up into a closet somewhere. When the migration or re-platforming came along, everything from that closet could be safely dragged out and lit on fire. Easy clean-up.

With an iterative model, you can’t afford to keep pushing things off. Eventually, that closet will need to be so big that it takes up the entire house.

Start making an inventory of things that need to be cleaned up, and start adding these as tasks for your team. Maybe your goal is to complete two technical debt tickets per month. Maybe you start smelling something really foul and need an entire sprint dedicated to a refactor. Maybe a new feature will be easier to implement if some other code is reorganized, so you add that task as a pre-requisite. 

However you do it, do it with intention and planning. That closet is not going to clean itself.

With an iterative model, you can’t afford to keep pushing things off.

Allocating development resources

You have planned out the release cycle. You have a list of new feature requests that is constantly growing thanks to your increased communication with stakeholders. And you have identified good targets for refactoring. 

Now what?

Prioritize and allocate. This, of course, depends on your team's size and the number of stakeholders involved in the work. Your project managers have their work cut out for them because they also have to worry about allocating themselves properly within the changing tides of shifting priorities.

You might give each stakeholder a team they work with exclusively. This helps people grow comfortable working together and builds rapport. You are less likely to need project kickoffs each time something starts. 

You might also rotate developers and teams so everyone has experience doing a bit of everything. That way, there is some overlap in case of emergencies or turnover. It also keeps things fresh and can aid in preventing burnout. Let developers speak up and tell you what they’re thinking, and, if possible, indulge their preferences.

It can be helpful to have the same person in charge of the release schedule day after day, month after month. But does someone actually want that job day-to-day? Maybe they do. But you should be sure.

For smaller teams, you may have to split things up by month or quarter. Maybe November and December are the months everyone focuses on technical debt. Maybe the first quarter of the year is reserved for new design initiatives and higher priority feature rollouts.

But do not let security and software updates get lost in the shuffle. Do not get lost in the weeds of zealous re-factoring. Do not ignore the needs of your stakeholders. This can feel like a juggling act, but it is one your organization must master to keep your website secure, relevant, and successful.

Celebrate

There is no more “big reveal” and launch of a new website. The highs and lows, the victories and stress, are hopefully flattened out to more manageable peaks and valleys. That doesn’t mean you can’t celebrate the completion of smaller initiatives, however. You absolutely should. Announce them, treat them as huge milestones, make your hand sore from giving so many high fives and pats on the back.

This can be done in many ways.

  • Public recognition in meetings and internal newsletters.
  • Demos and learning days where people responsible for the work show off what they have done and learned.
  • Small parties that happen immediately after lunch.

Whatever fits within your culture, do it.

Since each initiative and feature stands more on its own, it doesn’t get drowned out in the excitement of a “big reveal” where the gloss of so many new features can blind people from seeing certain parts of the work that have been done.

Iterative releases allow for more focus. And they give more opportunities for kudos. Take advantage of them.

Revisiting site architecture and content

Historically, many organizations have used major Drupal version migrations as a cadence to review information architecture. In part, this has been because content migrations across major versions haven't always been 1:1 migrations, so organizations have had to undertake information architecture (IA) work to decide what to migrate and where it should go. 

The other aspect of this is that in more complex migrations, it might have been faster to remove old content and deprecated content types than to spend the time migrating them, especially in the event of a custom migration.

The upside of migrating from Drupal 8 to Drupal 9 and beyond is that there is no content migration. The downside is that organizations now need another cadence for undertaking information architecture and strategy projects. This is similar to creating a new pattern of web development work, and a lot of the tips for development also apply here.

In fact, architecture and strategy should drive most new development work. Get into the habit of doing periodic IA and content audits. Every year or every six months. Whatever makes sense for your organization. It’s part of having a well-kept house. 

Some example questions you could start asking:

  • Is historic content still meeting your needs? Can it be updated, moved to another content type, or archived?
  • Does the site contain one-time-use fields that should be deprecated?
  • Do content types need to be trimmed?
  • Have the site's navigation needs changed?
  • Does our taxonomy structure still meet our needs and goals?
  • Have we added new departments or consolidated older ones? Are they represented properly?
  • Has our audience shifted? Have we started targeting new audiences?
  • How has our business changed? Have new competitors required us to think of different approaches and goals?

Sometimes your IA might require a major shift, and that shift needs to happen to a website that needs to remain up and running. For example, consolidating two content types into one new content type.

The good news is that the robust, well-tested migration tools that would have aided you during a full upgrade are there to help you accomplish a smaller shift. Drupal migrate tools are great at Importing content and pouring that content into different structures. Take advantage of them, even if it might feel like overkill at first.

Architecture and strategy should drive most new development work.

Bringing in outside help

Large upgrades and migration efforts demanded expertise and more developer hours, but without this traditional demand, is there still room to hire outside help?

Yes, there is. It can make a lot of sense, depending on your situation. In many circumstances, establishing a longer-term relationship with a vendor can yield even more gains, as the external team isn’t just around for six months to a year, then off to the next thing. Trust has time to grow. Communication settles into familiar rhythms. Everyone involved becomes more comfortable with each other.

Long-term engagements were still possible before the Drupal 9 paradigm, of course. At Lullabot, we have worked with some of our clients for 5+ years, which has enabled us to contribute in unique ways.  But without the inevitable, looming migration in the distance, it allows for additional possibilities, and we are excited about the potential.

There are many ways outside expertise can be utilized beyond a big project crunch. Keep in mind the lines between the following categories are fuzzy, but they are good places to start when trying to determine if you want to hire an external vendor.

Support and maintenance

If you want your own team to focus on new features or work you consider higher-value, using external help for support and maintenance of your existing infrastructure can provide a level of consistency that allows you to forge ahead.

Put a specialized team in charge of managing your release cycle. They manage the software updates and work within your schedule. 

A skilled support team can also help manage bug fixes. This frees up your developers’ time, so they aren’t bouncing around between tasks, losing a little bit of productivity each time. Help them avoid the concentration whiplash.

How do you know you might want help with support?

  • Assigning responsibility for the release cycle is like a game of hot potato. No developer really wants it.
  • The backlog of “urgent” bugs is growing month-over-month instead of shrinking. Complaints from stakeholders begin to grow.
  • Your software is continually months out of date, and it requires everyone’s attention to rectify the situation.

Fill gaps of expertise

Even if you have a large, diverse development team, you probably have some experience gaps. Technology is complicated. It’s hard for a team to stay up to date with everything that’s going on all of the time, and it can help to bring in some specialists.

Security audits. Accessibility audits. Performance audits. These are good opportunities for someone to come in, give you some actionable items, and ride off into the sunset. Each round of these helps educate your staff, as well. Depending on the scale of your website, it might make sense to augment your team with this type of experience for long-term engagement instead of periodic audits.

DevOps and continuous integration is also something that can benefit from a dedicated resource. A good expert in this area can help make your entire team more productive. They can set up and maintain the automatic deployment and testing of code, manage local development setups, and help enforce best practices.

Content strategy and design are areas that can benefit from outside perspectives. Good talent in these areas can help make your internal projects more successful by forcing you to clarify priorities.

Increase development velocity

Sometimes, you just don’t have the resources required to meet your goals. Too many initiatives with too many people demanding their pound of flesh. These requests and requirements could all be funneled through the Marketing department, or maybe your company has multiple departments that each own a section of the website.

Either way, you need more help, and you need that help to hit the ground running. An expert team can be integrated in several ways.

  • They can augment the current team with no change in structure. With this model, they become additional team members for you to utilize, whether they are project managers, content strategists, designers, or developers. The aim is to increase the general velocity of your development work.
  • They can come in with more focused intent as a differentiated team. They are assigned to a stakeholder or a specific initiative, so important work can get pushed forward without interrupting your normal development workflow. Close collaboration can still happen, but the external team has different priorities they will focus on.
  • A mix of both paradigms. There are no hard and fast lines to draw, and being flexible has its advantages. For example, after a team has completed a specific initiative, they move on to another one, or the team is split up and dispersed throughout other internal teams so domain knowledge can be spread. Or maybe they move to a support role.

Brave new world

Despite not having a big re-platforming effort on the horizon, web development in a Drupal 9 world still requires planning, thought, and intention. Release cycles need to be managed. New work needs to be planned and developed. Stakeholders need to be kept happy.

Drupal 9 makes it easier to take advantage of new features while keeping your site secure, successful, and relevant, but you can’t push things off anymore. No more waiting for the big migration to get rid of technical debt or re-work your information architecture. No more sweeping things under the rug until spring cleaning.

New habits need to be formed. New cadences need to be implemented. Exciting times are ahead as we juggle with this new reality.

Sep 02 2020
Sep 02

You Might Also Like

With the announcement of an extension on official community support for Drupal 7, now through November of 2022, many organizations were able to let out a sigh of relief. Their investments in Drupal 7 will continue to serve their needs. 

In addition, Drupal 7’s Extended Support(D7ES) program has announced its vetted vendors for paid support of Drupal 7 through November of 2025. Drupal 7 is here to stay for a long time, and this is good news, especially for organizations with limited time, limited budget, and limited support staff. If you are one of those organizations, you can feel safe and secure. Settle in for the long haul. Continue to improve your existing site, knowing you have plenty of time to see the ROI you need.

But eventually, like all good things, Drupal 7 will come to an end. The destination is now further down the road, and you can enjoy the journey at a more leisurely pace than expected, but eventually, you will arrive at the end of the path. You will need to transition away from Drupal 7.

You must eventually let go and say goodbye.

Since this sunset period is now longer, it is a good idea to take advantage of it. Without the threat of impending deadlines, you can use this extra time to start preparing your website for its inevitable evolution and do it in a calm, controlled, and orderly fashion. Some effort now can reduce risk and pay dividends later.

What are some things you can start doing to prepare your Drupal 7 site for migration?

We’ll cover the following topics:

Begin to Shift Your Coding and Site Building Culture

There is a vast difference between the architecture of Drupal 7 and the architecture of Drupal 8+ (currently Drupal 8 and Drupal 9), and these differences will only grow with subsequent versions of Drupal. This is reflected in how custom code is written. 

For example, object-oriented code and paradigms in PHP are here to stay, and your team should begin to adjust to this new reality, if they haven’t already. 

Because of how Drupal 7 works, it resists a lot of OOP best-practices. But there are still things you can do to help your efforts down the road. These apply for both new features and refactoring of old code.

Move Business Logic to Classes

Instead of having long walls of code crammed into hooks or preprocess functions, start to encapsulate your business logic in well-named and organized classes. This helps improve readability and maintainability. It will also be less of a lift to move this logic to a newer version of Drupal.

Form alter hooks are a common way to customize Drupal. You can’t escape hooks altogether, but you can improve their clarity and make them less intimidating.

Instead of something like this:

function example_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'example_node') {
    $form['example_field'] = [
      '#type' => 'textfield',
      '#title' => t('Example field'),
      '#weight' => -10,
      '#maxlength' => 60,
    ];
  
    $form['submit'] = 'example_submit_handler';
  }

  if ($form_id == 'example_user') {
    // different stuff is added or hidden
  }

}

You can start using something like this:

function example_form_alter(&$form, &$form_state, $form_id) {
  $exampleFormManager = new ExampleFormManager();
  $exampleFormManager->alterForm($form, $form_state);
}

The ExampleFormManager class should then have all the methods necessary to determine when and how to change the form. If everything is well-named and documented, this will make it easier to port over to Drupal 8+. 

Write these classes for your future selves. In a year or two, you don’t want to be looking at this code, scratching your head, silently cursing the person who coded it.

Another opportunity to wrap business logic in classes is with entity wrappers. Let’s take the example of related articles for a node. In a theme preprocess function, you might grab a node’s taxonomy term, pass that to a function located in some other module, load the related nodes based on some criteria, and then format them back in the preprocess function.

Instead of this, you could create an Article entity wrapper:

class Article {
  private node;

  public function getRelatedArticles() {
    $related_nids = $this->getRelatedArticleNids();
    return $this->getRelatedArticlesRenderArray($related_nids);   
  }

  private function getRelatedArticleNids()  {
    // run the queries or pass to other internal function
  }

  private function getRelatedArticlesRenderArray(array $related_nids) {
    // construct a render array
  }
}

When the time comes to eventually migrate, you won’t be combing through a multitude of module and theme folders to figure out how in the world your site populates related articles. It will be there, packed up, and ready to move.

This process not only helps your code be more organized and portable, but it also helps your team start stretching beyond procedural modes of thinking, if they haven’t already. Shifting to Drupal 8+ won’t be as big of a shock.

Gravitate Toward Solutions that Rely on Structured Content 

At its most basic, this means avoiding Blocks and Panels.

Blocks underwent a fundamental change in how they were implemented for Drupal 8 and attempting to migrate them can introduce extra complexity. It is often easier to recreate them by hand or with a custom script.

If you have only a handful of blocks, this should not be a problem. But don’t let them get out of hand. Lean more on content entities to solve problems, as the migration landscape for them is documented, tried, and tested.

The easiest way for Block usage to get out of hand is with Panels, where almost anything can go. Their very nature tends toward the wild and unstructured. Panels can create additional risk when approaching a migration, and Panels that have not had strong content governance can end up being a garden made up of nothing but weeds. Better to just pull everything up, lay new soil, and start over.

This might be fine. As long as your eyes are open and you expect this to be the case, the risk can be planned for and mitigated.

Instead of a Panel, think about using an Entity with set Entity Reference fields, which then map to pre-defined templates. This type of thinking might require another paradigm shift, however, and for that, you might want some help.

Engage a Content Strategist

Preparing your Drupal 7 site for the future, no matter how far away that future might be, requires some thinking about how you envision that future. 

  • What goals are you trying to achieve? 
  • What message are you trying to broadcast? 
  • What tools make for happy editors? 
  • How does your content and CMS best serve these needs?

A content strategist can help you answer these questions and more. 

This expertise can come in many forms. You could hire one. You could contract with an agency for limited engagements. You could nurture the curiosity of someone on your team, so they grow to have the skills required.

What can a good content strategist help you do?

Audit Your Content

The more content you have, the more varied the content types, the more complex an eventual migration will be. You don’t want to spend time and brainpower migrating old content that isn't valuable.

A content audit can help you determine which content is stale and which content needs to be either archived or updated. It can also help surface duplication.

One of the most important benefits of a content audit, however, is finding content with problematic structure, or content that lacks proper structure altogether. Is everything being crammed into the body field? As a result, is the final look of a page different based on the editor who built it? Even pages of the same content type?

What are some things that raise red flags when seen in the body field?

  • Metadata about the content itself, like author information or reading time.
  • Iframes from various sources, with inconsistent sizes.
  • Different methods of image embedding from one article to the next.
  • Related links, some of which are outdated.
  • Presentational HTML markup and CSS.

The SQueaLer Drush tool can be helpful for this.

Each of these will require different special cases when migrating, making the process more complex. Cleaning them up now will save time and money later while making your site more maintainable in the present.

Create a Plan for Content Governance

Auditing and cleaning up your content is great, but if you don’t change your old habits, weeds will keep popping up. Re-assess who is allowed to create content and what they are allowed to do within that purview.

Has your audit determined three different ways images are being embedded? Work toward settling on a single way, with input from your editors. Enforce it as best you can.

Have you spent some time identifying problematic content that doesn’t fit with your strategy? Work toward processes that help prevent the creation of more problematic content.

How much time should you spend per month cleaning up or archiving old content? Will it be one person’s job or a shared responsibility? Who makes the final decision on what content needs to be updated? The answers to these questions will be different for each organization.

If your editors keep cramming things that don’t belong in the body field, you should see it as a sign, one covered with blinking red lights and loud alarms, telling you that the system is not meeting their needs. So, find out those needs. 

A good content strategist can help facilitate these conversations, help you find ways to temporarily fill these gaps while you are still on Drupal 7, and help you determine what your future should eventually look like. Address these potential problems as soon as you are able. Start thinking about them early. 

If you don’t, they will continue to haunt your future site, even if you end up leaving Drupal. These specters are platform-neutral.

Take Time to Model Your Content

Many websites grow in an ad-hoc manner, with features pasted on whenever a stakeholder has a flight of fancy. Even if the site launched after a careful period of requirements gathering and needs analysis, its evolution afterward can descend into chaos. 

New content types are added for that big seasonal push, and then never get used again. Editors need to make a landing page look just right, and inject things in the body field as a quick fix. Questions and new requirements are always based on whether the site can do something, rather than whether the site should do something. “No” becomes the forgotten vocabulary word.

Now is a good opportunity to take stock. This is related to our “Gravitate Toward Solutions that Rely on Structured Content” recommendation above.

Your content audit has surfaced issues you need to fix at the structural level. Your content governance plan needs some guard rails to help with enforcement. Your Drupal 7 site needs to align better with the goals and message of your organization.

This can mean new content types, but it can also mean a modification of existing content types. 

Some common examples of structure changes:

  • Moving related article links out of the body field and into their own Entity Reference field.
  • Additional (or fewer) taxonomy fields.
  • Summary and Lede fields.
  • An “Authors” Entity Reference field, separate from the default author field.

For media management, think about using the Media module to help ensure proper metadata surrounding media, and to help enforce a single solution for including media in content. There is also a migration path waiting for you when you are ready.

Properly modeling your content, and beginning to implement that model, will net many benefits. It will be easier to change the presentation of your site consistently. Opportunities for content re-use will become clearer. Your next content audit will be less thorny. 

While you may give up some flexibility in the day-to-day creation of content, it pays off with more holistic flexibility. For example, if you desire to go down a decoupled route, with your content served via an API, structured content gives you that option.

But equally important, modeled and structured content will make your migration much, much easier. Well-structured content is always easier to migrate than unstructured content. 

And if your content strategist has helped you answer the proper questions, a lot of the big questions surrounding migration will be answered as well. This means a chunk of the hard work required will already have been done.

Keep Everything Secure and Up to Date

Your Drupal 7 site should be kept up to date. That means Drupal core and all the modules you use, but it also means your hosting environment. Don’t remain stuck on past versions of PHP. The latest versions of Drupal 7 support the latest versions of PHP 7, which has a nice symmetry to it.

All of this will not only keep your current site secure and performant, but it will also make a future migration easier. The latest versions of contrib modules are usually closer to their Drupal 8+ counterparts in terms of organization and how they store data. They also can take advantage of PHP 7 improvements and syntax.

This ties into our first recommendation of shifting your coding culture. Staying up to date with PHP will allow your team to start using methods and styles that do not exist for PHP 5. Being familiar with PHP 7 will ease the eventual transition.

Conclusion

Drupal 7 has been given a new lease on life, and if you are currently dependent on Drupal 7, you can breathe a little easier. Your CMS will be supported for another year, and even longer if you reach out to a qualified D7ES vendor.

Use this time wisely. Prepare for the future. Now that you know it will be around for a while, you can feel safe making smart investments in the platform and in your team. Make your Drupal 7 site work better for you in the present, while at the same time making your eventual migration go smoother.

You and your team can be seen as agents of foresight, clarity, and poise, recognized for preparing the organization to make the leap.

If you would like to start the conversation around some of these items, Lullabot’s support and maintenance team is ready to help. Through developer mentorship and close collaboration, we can help you squeeze every last drop out of your Drupal 7 investment.

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web