Mar 10 2019
Mar 10

Search is a key feature in web experience, and for a lot of people, it's the go-to method to find content. We use search countless times a day on our smartphones in various contexts. And yet, when we're building out websites, search is often an afterthought that we don't spend much time on. Search gets added to the laundry list of site features, like meta tags and social media links.

Drupal Core Search

Drupal is fantastic at managing content. It gives you loads of flexibility when it comes to building out your information architecture and categorizing content. But we often don't set aside a lot of time to build out a customized search UI to find that content. At the end of a project, you might just turn on the core search module and call it done. And then we find out that people use Google to search our website.

Drupal's core search functionality hasn't changed much in the last 10 years, and is lacking features that users expect. It can be slow, and it doesn't correct for misspellings or allow you to prioritize results. Search should make your content easy to find, and make your site more engaging for users. Over the years, we've worked on lots of websites that integrate with Solr, to provide an enterprise-level search engine on top of Drupal. But setting up Solr takes time, and can be tricky if you don't have a lot of time to set it up, or the know-how to configure your server.

Why Cludo?

We recently decided to add search to evolvingweb.ca, and decided to try out Cludo. It's a "search as a service" tool that allows you to add on a search interface to an existing site. Kind of like you'd add Disqus, or Google Analytics. It was pretty easy for our developers to set up Cludo. Besides some challenges setting up search of the French language side of our site, particularly searches with UTF8 characters, the setup was straight-forward and only took a few hours to add.

The immediate advantage is that you don't have a lot of setup time for a search that just works how users expect. But after it was all set up, I realized that there are a lot of extra features that you get that we wouldn't normally take the time to configure for a basic search:

  • Autocomplete - start typing the title of a node and it'll autocomplete
  • Customize the index - you can pick and choose what's searchable and what's not
  • Analytics - you can see who searches for what, giving non-technical users visibility on how users search for content
  • Boosting - you get nice defaults for results ordering, but you can also customize the criteria to prioritize certain types of pages or certain criteria
  • Machine learning - an add-on feature that does the boosting and changes the autocomplete ordering for you based on user behaviour
  • Easy-to-use interface - non-technical users can update all the settings through Cludo's UI

Cludo analytics interface

Before you ask, yes there's a module for that! The Cludo module was released a couple weeks ago. It's still in development, but you can try it out. You just have to add your Cludo account number and key, and it provides a search form block that you can place on the page.

Here are some examples of websites using Drupal:

Open Source vs. Paid Third-Party Service

So what's the catch? Cludo isn't a free service, it comes with a $200/month price tag for most websites. And it will cost more than that if your site has more than 20,000 pages or you want bells and whistles like document search, machine learning or searching private content. There are discounts for non-profits and educational organizations.

There's a trend towards using third-party services for everything from marketing automation tools to comments and now search. I know a lot of Drupal developers prefer to use open source tools as much as possible. I think the great thing about third-party tools is that it gives us another option. We can offer our clients a way to get a search interface up-and-running quickly, without a lot of up-front development time. It gives the end-user something that's easier to configure.

On the other hand, for a large website with a lot of content, we might want more control over the functionality and costs. And for an intranet, we might want more control over where the data is stored. If we have a lot of site installs, Cludo could start to become very pricey. In these cases, using Search API would be a better option. But for lots of use cases, when that "instant" quality is the priority, Cludo is a great option, to make sure your content is discoverable and that your users can find it.

Jan 29 2019
Jan 29

We at Evolving Web are really excited to see the progress being made on improving the Drupal admin UI. As a designer, I’m curious about the process that drives such a huge project. I talked to the designer in charge of the refreshed interface, Cristina Chumillas, and got super interesting insights into what’s behind the new design.

Claro – fresh and clear

So far, Cristina and the team developed a new theme which is called “Claro”. The main UX problems in the existing admin UI have not been addressed yet. However, the visual refresh is already a great improvement! In Spanish, “Claro” means “clear” and this seems to be the main motivation.

The old admin interface (left) and the new UI design (right).The old admin interface (left) and the new UI design (right).

I especially like the new colour palette that is a literal refresh with grey tones that are slightly bluish and a primary blue that is very lively. Compared to the old warm colour scheme, this simple step results in a much more modern look. The contrast has been increased a bit, which has several positive effects. It helps create a clear hierarchy and, of course, it helps make the interface more accessible. 

Interaction Design Challenges

I asked Cristina about the biggest challenge in the redesign. She said that complying with the latest accessibility standards was a tough one. 

“We are not designing for a private company, we are designing for Drupal and this means for anyone. The design has to be accessible for anyone.”

One example Cristina gave me was the form field designs. The initial form fields were similar to those in the Material Design system, with the label inside the input field. Once you select the field, the label floats to the top. It is an elegant technique that has become popular over the last few years. However, Cristina remarked that this kind of animated form design caused a problem with accessibility.

“We decided not to implement something that is super fancy.”

I appreciate the fact that the team behind the new Drupal design puts the user front and centre. The purpose of the redesign is not to create something original for the sake of being extraordinary. On the contrary, the goal is a clear design that prefers well-known design patterns over personality. This doesn’t mean that they kept the old form UI, which was mainly the browser default. The new form design is simple, but clear and therefore very usable.
 

Comparing Form FieldsForm field examples of the old UI (left) and of the new design system (right).

Hierarchy & Proportions

The new UI system is extensive. It includes different states of interactive elements which results in a very consistent design from page to page. Sometimes, these little details make a huge difference. Let’s compare the old and the new second-level of the toolbar. The size ratio between the font size and the icon is not very balanced in the current UI. The chevron buttons have the heaviest visual weight which makes it difficult for the active page to stand out. 
 

Comparing toolbarOld second level toolbar (left) and new toolbar (right)

The new design uses the primary blue for highlighting active states. The chevrons are simple and don’t draw too much attention. The third-level of the menu is visually separated by a light blue background which also communicates depth.

Typography – Fluid and Flexible

I asked Cristina what she enjoyed most during this project. She didn’t have to think long:

“Typography! – Something that I’m really looking forward to implementing is Fluid Typography.”

Fluid Typography is a CSS trick which adjusts the font size and line height based on screen size. Instead of jumping from one size to the next bigger size at a breakpoint, the changes are fluid. This creates a really smooth responsive web experience.

Animation of fluid text sizesImage credits: css-tricks.com/snippets/css/fluid-typography

Cristina and her team decided to use system fonts instead of a brand typeface in the new UI. She told me that it’s not about branding when you create a functional user interface. They didn’t want the typeface to take too much attention. Cristina pointed out that it is the functionality and usability of software like Drupal that counts. A smooth user experience with the application itself is more important than the branding. Besides, other elements such as the colour palette help with the recognition of the brand.

“Using system fonts feels more natural, more like working with your system and for the user it is not really important that it is Drupal or something else. It is just a tool.”

3 examples of headings and paragraphsSystem font examples (Apple, Windows Vista and KDE)

Another reason for the use of system fonts, Cristina told me, is that sometimes the font is changed to the system font anyway, for instance in other languages that are not included in the character set. Depending on the language, the range of word length is huge as well. When designing an interface like Drupal, you have to keep it flexible anyway.

“There are some languages that are short, and then there is German…” 

As a last question, I asked Cristina, if she had one ultimate tip for other designers to improve their UI design. Her advice was: “Keep in mind that when we are dealing with content management UI, it is not about advertising, not about branding. UI should not be invisible, but it should serve a purpose.” 
“It should serve the user needs?” I suggested.
“Exactly! The [admin] UI should be useful for creating content – in our case, because that’s what Drupal is for – instead of being super fancy.”
 

About Cristina and the team

Cristina Chumillas is a very experienced designer with a background in graphic design and frontend development. She has been active in the Drupal community for many years and works as Creative Director and partner at Ymbra, a Drupal web agency based in Barcelona. The other designers contributing to the Claro theme are Sascha Eggenberger, Archita Arora as well as Dennis Cohn.

Next steps

Following the work on these visual improvements, the team will continue with this user-centered approach and address functionality issues. Suzanne and I helped figure out usability problems in different CMS’s in a comparative study in November and are currently working on a follow-up study to gather more data about how editors create more complex content. Cristina told me that our findings will help guide the the user experience of the Drupal admin interface. We can’t wait to see the results of the next steps!

Jan 24 2019
Jan 24

We at Evolving Web are really excited to see the progress being made on improving the Drupal admin UI. As a designer, I’m curious about the process that drives such a huge project. I talked to the designer in charge of the refreshed interface, Cristina Chumillas, and got super interesting insights into what’s behind the new design.
 

Claro – fresh and clear

So far, Cristina and the team developed a new theme which is called “Claro”. The main UX problems in the existing admin UI have not been addressed yet. However, the visual refresh is already a great improvement! In Spanish, “Claro” means “clear” and this seems to be the main motivation.

The old admin interface (left) and the new UI design (right).The old admin interface (left) and the new UI design (right).

I especially like the new colour palette that is a literal refresh with grey tones that are slightly bluish and a primary blue that is very lively. Compared to the old warm colour scheme, this simple step results in a much more modern look. The contrast has been increased a bit, which has several positive effects. It helps create a clear hierarchy and, of course, it helps make the interface more accessible. 

Interaction Design Challenges

I asked Cristina about the biggest challenge in the redesign. She said that complying with the latest accessibility standards was a tough one. 

“We are not designing for a private company, we are designing for Drupal and this means for anyone. The design has to be accessible for anyone.”

One example Cristina gave me was the form field designs. The initial form fields were similar to those in the Material Design system, with the label inside the input field. Once you select the field, the label floats to the top. It is an elegant technique that has become popular over the last few years. However, Cristina remarked that this kind of animated form design caused a problem with accessibility.

“We decided not to implement something that is super fancy.”

I appreciate the fact that the team behind the new Drupal design puts the user front and centre. The purpose of the redesign is not to create something original for the sake of being extraordinary. On the contrary, the goal is a clear design that prefers well-known design patterns over personality. This doesn’t mean that they kept the old form UI, which was mainly the browser default. The new form design is simple, but clear and therefore very usable.
 

Comparing Form FieldsForm field examples of the old UI (left) and of the new design system (right).

 

Hierarchy & Proportions

The new UI system is extensive. It includes different states of interactive elements which results in a very consistent design from page to page. Sometimes, these little details make a huge difference. Let’s compare the old and the new second-level of the toolbar. The size ratio between the font size and the icon is not very balanced in the current UI. The chevron buttons have the heaviest visual weight which makes it difficult for the active page to stand out. 
 

Comparing toolbarOld second level toolbar (left) and new toolbar (right)

The new design uses the primary blue for highlighting active states. The chevrons are simple and don’t draw too much attention. The third-level of the menu is visually separated by a light blue background which also communicates depth.
 

Typography – Fluid and Flexible

I asked Cristina what she enjoyed most during this project. She didn’t have to think long:

“Typography! – Something that I’m really looking forward to implementing is Fluid Typography.”

Fluid Typography is a CSS trick which adjusts the font size and line height based on screen size. Instead of jumping from one size to the next bigger size at a breakpoint, the changes are fluid. This creates a really smooth responsive web experience.

Animation of fluid text sizesImage credits: css-tricks.com/snippets/css/fluid-typography

Cristina and her team decided to use system fonts instead of a brand typeface in the new UI. She told me that it’s not about branding when you create a functional user interface. They didn’t want the typeface to take too much attention. Cristina pointed out that it is the functionality and usability of software like Drupal that counts. A smooth user experience with the application itself is more important than the branding. Besides, other elements such as the colour palette help with the recognition of the brand.

“Using system fonts feels more natural, more like working with your system and for the user it is not really important that it is Drupal or something else. It is just a tool.”

3 examples of headings and paragraphsSystem font examples (Apple, Windows Vista and KDE)

Another reason for the use of system fonts, Cristina told me, is that sometimes the font is changed to the system font anyway, for instance in other languages that are not included in the character set. Depending on the language, the range of word length is huge as well. When designing an interface like Drupal, you have to keep it flexible anyway.

“There are some languages that are short, and then there is German…” 

As a last question, I asked Cristina, if she had one ultimate tip for other designers to improve their UI design. Her advice was: “Keep in mind that when we are dealing with content management UI, it is not about advertising, not about branding. UI should not be invisible, but it should serve a purpose.” 
“It should serve the user needs?” I suggested.
“Exactly! The [admin] UI should be useful for creating content – in our case, because that’s what Drupal is for – instead of being super fancy.”
 

About Cristina and the team

Cristina Chumillas is a very experienced designer with a background in graphic design and frontend development. She has been active in the Drupal community for many years and works as Creative Director and partner at Ymbra, a Drupal web agency based in Barcelona. The other designers contributing to the Claro theme are Sascha Eggenberger, Archita Arora as well as Dennis Cohn.

Next steps

Following the work on these visual improvements, the team will continue with this user-centered approach and address functionality issues. Suzanne and I helped figure out usability problems in different CMS’s in a comparative study in November and are currently working on a follow-up study to gather more data about how editors create more complex content. Cristina told me that our findings will help guide the the user experience of the Drupal admin interface. We can’t wait to see the results of the next steps!

Dec 19 2018
Dec 19

I’ve recently been researching, writing, and talking about the content editor experience in Drupal 8. However, in the back of my mind I’ve been reflecting on the site builder experience. Every developer and site builder who learns Drupal is going to use the admin UI to get their site up-and-running. What are some things site builders often struggle with in the admin UI when learning Drupal?

Blocks

For most Drupal site builders, the Block layout page is key to learning how Drupal works. However, there is more to Blocks than just the Block layout page. You can also create different types of blocks with different fields in Drupal 8.

Site builders new to Drupal don’t usually stumble across the Block Types page on their own. In fact, I think a lot of site builders don’t know about block types at all. Probably because "Block Types" is not listed in the in the 2nd level of the administration menu under “Structure”, but instead buried in the third level of the menu. There's already work underway to make this change.

Similarly, site builders might never find the “Custom block library” page for creating block content. Depending on how blocks are being used on a particular site, this page might be more logically nested under “Content”. If you like this idea, there's an issue on Drupal.org to make this update and a discussion about how best to integrate it into Drupal 8 (or 9).

Many users never find the “Demonstrate block regions” link, a really key page for anyone learning how Drupal works and what regions are. Most Drupal site builders who see this page for the first time are delighted, so making this link more prominent might be an easy way to improve the experience for site builders.

Appearance

Typically, a Drupal site has two themes: the default/front-end theme and the admin/back-end theme. The appearance page doesn’t make this clear. Some site builders learning Drupal end up enabling an admin theme on the front-end or a front-end theme for the admin UI. I think the term "default theme" is confusing for new users. And making a consistent UI for setting a theme as the default theme or the admin theme would be a nice improvement. If you like this idea, you can jump into the conversation about updating the appearance page.

Install vs. Download

The difference between installing and downloading a module is not laid out clearly. If someone is trying Drupal for the first time, they’ll likely use the UI to try and install modules, rather than do it through the command line. In the UI, they see the link to “Install New Module”. Once this is done, it seems like the module should be installed. Even though they have the links available to “Enable newly installed modules”, they might not read these options carefully. I think re-labelling the initial link to "Download New Module" might help here.

Most users are also confused about how to uninstall a module. They don’t know why they can’t uncheck a checkbox on the "Extend" page. Providing a more visible link to the uninstall page from installed modules might help with this.

Configuration Management

The UI for configuration management is pretty hidden in Drupal 8. In practice, configuration management is something we typically do via the command line, this is how most seasoned Drupalers would import/export configuration. However, for someone learning how Drupal 8 works, they’re going to be learning initially from the UI. And at the moment, site builders are virtually unaware of Configuration Management and how it affects their work.

Having some kind of simple reminder in the UI to show site builders the status of their configuration could go a long way to them understanding the configuration management workflow and that they should be using it.

The Admin Toolbar

Everyone loves the admin toolbar module. Once it’s installed, site builders are happy and ask “Why isn’t this part of Drupal core?”

But, for a certain set of people, it’s not clear that the top-level of this navigation is clickable. The top-level pages for “Configuration” and “Structure” are index pages that we don’t normally visit. But the “Content” page provides the content listing, and the “Extend” page shows use all our modules. These are obviously key pages. Imagine trying to learn Drupal if you don’t realize you can click on these pages for the first week. But users who are used to not being able to click top-level elements might simply miss these pages. Does anyone know a good way to signal that these are clickable?

What's Next?

I would love to hear how you think we should improve the admin UI for site builders and if you have any thoughts on my suggestions. 

One thing that I'm very excited about that's already happening is a new design to modernize the look and feel of the Admin UI in Drupal. This will go a long way to making Drupal seem more comfortable and easy to use for everyone, content editors and site builders alike. You can see the new designs here.

Dec 10 2018
Dec 10

Over the last few months, I've been involved in a UX study to shed some light on what would make a good content editor experience in Drupal. I helped run a survey asking content editors for their feedback about the Drupal admin UI and got some interesting results. Then, we started looking around for examples of good content editor UX, which led to a comparative usability test of other CMS's, generating some ideas about patterns to follow and avoid.

I have a job where I get to train lots of people how to use Drupal: developers, site builders, and sometimes content editors. So I've gathered a lot of anecdotes of people's first impressions of editing content with Drupal.

As you've probably heard, there is work being done on a brand new Admin UI for Drupal, but this might take a while to build. So what are some things about content editor UX that we might be able to improve on before that?

Autosave

When you ask content editors what we should change about the admin UI, this one always come up. All content authors have anxiety about losing their content. And when we ran our user testing with other CMS’s, autosave clearly reassured and delighted editors. For example, Contentful has a nice autosave message that helps users know that their content is saved.

"Last saved" screenshot

There is an open issue for adding autosave to Drupal. It would be great to get momentum behind implementing this!

A Content Editor Role

One of the challenges of using Drupal is that there are so many options. For site builders and developers, a UI that provides a lot of options is great because you can see that the platform is flexible. For content editors, seeing a lot of options that don’t relate to content editing is intimidating. From our usability testing, we can see that content editors love using a UI that is more streamlined, less complicated, and clearly designed for them.

Creating a content editor role as part of the Standard install profile might be a nice way to encourage the practice of limiting what content editors have access to by providing a set of default permissions to start with.

What should the content editor role look like? Of course, content editors need to be able to create and edit content. And they will need access to the content overview page. Should they have access to the Administer Content permission? What about working with files, taxonomy terms, revisions, and menus? Based on our content editor survey, it seems like giving all these permissions would align the role with a content editor’s typical tasks. But I think a more limited set of permissions would work as well, as long as it's clear that the permissions are a starting point that can be expanded on by an administrator.

Show Me the Content!

On a standard Drupal install, when you log into Drupal you're redirected to your profile page. I think for most content editors, this doesn’t make sense. Your home base is probably the content overview page. Maybe we should redirect content editors to the content overview page when they log in.

Move the Save Button

Currently, the Save button, along with the preview buttons and the interface to publish and moderate content is at the bottom of the node edit page. From our usability testing, it seems like content editors expect the Save button to be in the top right-hand corner. For long-form content, this would make those links more readily available and I think this would be a usability improvement for new content editors.

Current Drupal add content page screenshot

The key to success with all the save, preview, and content moderation options seems to be to put them all together. In the comparative usability testing, this feedback rang loud and clear.

One thing I like about moving the Save button top right-hand corner is that it puts those buttons in proximity to the “Revisions” section of the edit page, which is closely related to the task of saving or changing the status of a node.

That being said, I think it could really confuse existing Drupal editors if we just start moving buttons around. And I assume that there could be accessibility implications that we should take into account. So I leave this one as an open question. What do you think?

Modernizing the UI

One of the big pieces of feedback we got from the content editors survey was that the Drupal UI looks dated. Well, the idea of modernizing the UI already has a ton of momentum behind it. I’m super excited about the work Christina Chumillas and others have done to create new, improved designs for the existing Admin UI of Drupal 8. This is not an overhaul of the UX, but a new, modern style guide applied to the existing one. It's a big improvement that I think will bolster first impressions of Drupal. And it's something that is planned to be implemented in the near future.

What’s Next?

If you’re a UX person who wants to contribute to Drupal, there are ways to get involved! See the #ux and #admin-ui channels on Drupal Slack. If you have ideas for other content editor UX improvements, or know of existing UX issues in the queue that need some attention, I'd love to hear about them here. Or continue the conversation in those channels.

Nov 26 2018
Nov 26

There is exciting work being done in the Drupal community to improve the Admin UI, including the JavaScript Modernization Initiative and an overhaul of the look and feel of the Seven theme. Meanwhile, I've been working with a group in the Drupal community to research what user experience improvements we should be making for content editors.

So far, we have conducted a survey to get feedback from content editors, performed a card sort to see how content editors group their tasks, and recently, conducted a comparative usability study that looks at the authoring experience provided by other content management systems.

We chose four content management systems that offer different experiences: Craft CMS, Contentful, SquareSpace, and WordPress with Gutenberg. In this article, I’ll walk through the different aspects that we tested: first impressions, the editing experience, the publishing workflow, and what we can learn.

The setup

Going through the process of setting up several other content management systems was an eye-opening experience. I highly recommend it for anyone involved in building Drupal websites for a living. The setup process gave me lots of food for thought about the onboarding experience for new users, what configuration comes out of the box, and the language and positioning of Drupal in the CMS landscape.

We recruited volunteers with Drupal content editing experience (from 1 month to 9 years of experience!)

My colleague Annika Oeser and I conducted the studies using a script that we had put together. We asked participants for their first impressions of each platform, then asked them to do a few simple tasks: creating an article from content in a Google Doc, editing and previewing it, and then deleting the content. Then, we asked what they thought of the platform.

First Impressions

First impressions are important. Each platform that we selected had some type of content editor dashboard that we presented to users. While some platforms have more of a learning curve than others, it’s obvious that platforms with a more inviting dashboard will encourage new editors to like the tool and want to use it more.

Contentful

Right away, participants found Contentful intimidating. One even said it looked “scary”. The dashboard’s messaging is not aimed at content editors (although in the setup process, it asks if you're a content editor or developer), and the terminology is just obscure enough to be intimidating. As one participant pointed out that “None of this says build an article”. That being said, the interface didn’t prevent authors from performing their task, it just made them more apprehensive.

Contentful dashboard

On the content overview page, there are filters to narrow down the list of content. Because of the colorful button-like design of the filter, some participants mistook this for the link to add content.

Contentful Content Overview

Craft CMS

Overall, participants liked the fact that Craft CMS has a form to create content directly from the dashboard. Putting content creation forms on the dashboard makes it clear that this is a platform designed for content editors. That being said, everyone complained that the form was too narrow, and made the experience of filling in the form not great. Participants all liked it better once they were on a dedicated content creation page.

Some participants mentioned a solution, removing the “Craft News” block form the default dashboard to free up space, which is possible by configuring the dashboard if you know how to do this. I also think that having a button to expand the form or jump to the content entry page would be incredibly helpful.

Craft CMS dashboard

Squarespace

The Squarespace dashboard gives content editors the impression that it would not be ideal for larger, more complex websites. Everyone mentioned that the UI seemed “simple” or “for a blog”. I found this an interesting observation. The editors in our study were all familiar enough with their requirements for a CMS (a large amount of content, taxonomy, content hierarchy) that they felt that the simplicity of Squarespace might be too good to be true, and that they would be alright with a more complex UI if it meant a more featureful one.

Squarespace dashboard

WordPress

Participants described WordPress’s dashboard as “clean”. They see right away that it's an interface designed for them. Although there are more advanced features presented (e.g. Appearance, Plugins, Tools, Settings) the UI for creating and editing content are prioritized. Granted, some of our participants had WordPress experience, giving this particular UI the bias of familiarity. One mentioned that "They don't change the interface often, which is good."

WordPress dashboard

Content Editing Experience

To assess the content editor experience, we asked participants to create an article and then add some standard elements to it (an image, a link, bold text, a quote). When building the study, we selected four CMSs with very different editing experiences:

Contentful

Contentful provides a content structure similar to Drupal, with content types broken down into fields. It has some very particular terminology which will be unfamiliar to most people. Instead of a WYSIWYG editor, it provides a markdown editor with a tab for previewing the content.

Contentful UI for creating a news item

It’s amazing how important labels are. Participants were confused by labels like “Slug” and the subtle difference between the purpose of the “Description” and “Body” fields. Another thing, most content editors don’t know markdown. So as much as developers might love having the markdown editor tab and a tab for previewing the content, this experience seemed like a big hurdle to content editors. A minor experience gap that we noticed was in the way the link button in the editor pre-fills “https” at the beginning of the link. Since most editors copy and paste a URL instead of write it out by hand, this led to mistakes and frustration.

Craft CMS 

Craft CMS has a WYSIWYG editor for editing long text, but instead of a large main content textarea, it provides a UI for creating sections, such as headings, text, images (this works similar to Drupal’s Paragraphs module).

Craft CMS UI for adding an entry

All the participants easily understood the UI for adding sections to create the Article Body. It was somewhat confusing to have two ways to add some elements, for example an image or a quote can be added through a Text section, or by creating a new Image or Quote section. If anything, this maybe shows content editors’ eagerness to add content "the right way" and their willingness to work within a content structure rather than having one large WYSIWYG editor.

Squarespace

Squarespace provides a much more visual editor. The editing interface appears in an overlay. Users paste everything into one text area. There is also the notion of adding new elements (images, quotes, etc.) to this text area using a + button.

Squarespace UI for creating a post

There were a couple ways to add images in Squarespace. Adding a “Thumbnail” image in the metadata of the post, which is used in the teaser version of the post. Or, using the + button to add an image element, which can then be dragged/dropped above or below other elements, such as text, buttons, etc.

None of the participants found the + button without help. I had always assumed that this UI was easy-to-use, but for a content editor not expecting to use a page building experience to add images to content, it was clearly not obvious. As one participant said "I would never have found that, it's so not clear."

Another sticking point was that the thumbnail image field in the "Options" tab doesn’t adequately explain to users that the image won’t be displayed on the full post page, only in teasers. This is something I see a lot on Drupal sites, that have images that are used in content listings, but without a proper help text to explain this to editors.

WordPress

WordPress’s new Gutenberg editing UI provides a similar experience to Squarespace, in that the editor is visual and invites users to create components, such as headings, text, columns, or media.

WordPress Gutenberg UI for adding components

One participant described the interface as having an “instant preview” quality. It seemed like they thought that the way the article they were creating looked here would be how it would look as published content. "I like this a lot". "The paragraphs are clearly divided with white space". One called the different components that were created "blocks".

"The great thing here is that I can see everything". Almost all the participants brought up the fact that they assumed they could edit the HTML. "I assume I can go to the source code if I need to".

WordPress with Gutenberg editing experience

Publication Workflow

We asked authors to preview, edit, and then delete the content they had created. We knew from user surveys that content editors want autosave, but from watching them go through these steps for each CMS, we realized the anxiety that the publication workflow can cause. Content editors really want to be reassured about the state of their content.

Contentful

Contentful is designed as a backend for a decoupled website. So the preview provided is not an actual preview, but a read-only version of the fields of content you’ve created. Unsurprisingly, content editors found this confusing. In terms of workflow, users found it difficult to delete the content, because the current state of content and the fact that it needed to be unpublished before it was deleted was not clear. It seemed like the status of the content was unclear, and users ended up back on the content listing page to change the status.

Contentful workflow buttons

Craft CMS

Craft CMS has a “Live Preview” that provides a side-by-side editing and previewing interface. All the editors liked seeing that when they add content, it looks like a page right away. One exclaimed “I'm great at this, look how good it looks.” The one part of the workflow that was confusing for editors is when they click “Save” from the initial dashboard, and they’re not redirected to the page they’re just created. If this button was "Save and preview" and it went to the edit screen with live preview, that would be more natural.

Craft CMS side-by-side preview

SquareSpace

SquareSpace doesn’t provide a way for authors to preview content before publishing. They expected that clicking on the content in the listing would display the preview. Saving and publishing the content was intuitive for users.

Squarespace workflow buttons

WordPress

WordPress workflow buttons

Overall, the publishing workflow in WordPress seemed to be the most clear to users. Having the status of the content, and the links to preview, publish, and delete in close proximity seemed natural to all users. The only part that participants got stuck on was the phrase "move to trash". Some users suspected that this meant they had to empty the trash. One other sticking point was the preview. The WordPress Gutenberg UI looks so much like the front-end of a site that users are surprised or disappointed when they realize that the theme enabled on their site looks different and perhaps less good.

Takeaways

We learned a lot from this usability testing. Here are some of the most interesting takeaways:

  • Editors appreciate that a more complex UI is necessary for a more complex website. This doesn’t mean we don’t need to create a user-friendly admin UI, it just means that some degree of complexity is expected.

  • A content editor-friendly dashboard, with content-editor tasks prioritized and easy-to-understand terminology will help smooth the learning process.

  • Sometimes editors find it hard to distinguish between the admin UI and the front-end UI when learning a new platform.

  • Editors have anxiety about clicking save and what this will do. Having autosave and a clear workflow for previewing content will make this process smoother.

  • Editors feel like they should be able to edit the HTML. They don’t want to learn markdown. That being said, I think the goal of a great content authoring experience would be that authors don’t feel that they have to edit the HTML, because they have the right balance of flexibility and content structure.

  • Editors want to know what the state of their content is, and they want clear options to Preview, Save, and Delete. The state of the content and the links to change the state should be in close proximity.

  • Even with a small number of participants, usability testing can help inform improvements in a user interface. We learned a lot from testing with just 5 participants.

What’s Next?

Now that we’ve taken the pulse of how content editors interact with these CMSs, I think it would be helpful to look more closely at the experience of creating more complex content. I would like to do a follow-up study looking at authoring of structured content, something Drupal is highly valued for and excels at, and more flexible, landing-page-style content, something that Paragraphs has been widely used to for over the last couple years. I think it’s essential that Drupal provides a great interface for both these use cases (whether in core or contrib). Testing how editors edit both styles of more complex content will help us understand how to do this better.

How Can I Get Involved?

The Drupal Admin Experience group that includes Cristina ChumillasAntonella Severo, Jessica Becker, and myself. If you want to get involved, join the #admin-ui channel on the Drupal Slack.

A huge thanks to my colleague Annika for planning and running the usability testing with me and to McGill University for providing the venue for the testing.

Sep 28 2018
Sep 28

Drupal 8.6 was released a couple weeks ago and it’s probably the most exciting release since Drupal 8.0. As you might know, new features are added with each minor release of Drupal 8 (e.g. between 8.5 and 8.6). At first, I thought that this would just change how we test and update our sites. But it’s amazing to see how many new, valuable features are being added in minor versions. These are the features that allow Drupal to constantly evolve and innovate, and keep everyone excited about using Drupal.

Also, minor releases that add features are a great reason to keep your Drupal site up-to-date with the latest minor version!

I tried out Drupal 8.6 the other day and here are some of the highlights. Note that some of these features (Media management, Workspaces) are provided by experimental modules. They are not ready to use in production yet, but are ready to be tested out in development and sandbox environments:

Media

As a Drupal site builder, the media features are a huge step forward. I watch a lot of content editors use Drupal and it’s clear that having media editing work smoothly greatly improves the content editing experience. From the Admin UX research I’ve worked on, better media management is one of the number one things that content editors want.

So, what does media in core provide? You can now add media (images, video, audio, etc) through the WYSIWYG editor and via a new media field. You can re-use media that’s already been added to the site, or upload new items. You can also manage the media via an overview page and add new media items directly without creating content.

Screenshot Drupal media library

Quickstart

Drupal 8.6 comes with a Quickstart command that lets you install Drupal on your machine with a limited number of requirements. This makes it really easy to test out Drupal without installing other software, configuring a VM, or finding a vendor that provides cloud hosting.

I think it’s great to have a feature like this out-of-the-box so that we can have a better experience for newcomers to Drupal. In fact, there’s already updated documentation on Drupal.org about how to install a quick version of Drupal.

Thanks to Matt Grasmick for putting this together!

Out-of-the-box Demo

At DrupalCon Nashville, I tested out the new Umami install profile, which provides a demo of Drupal out-of-the-box. When you install Drupal, you’ll now see the Umami as an option on the install profile step. Umami comes with content, content types, views, and a theme for a recipe website. I think this profile, along with the Quickstart feature will allow developers and site builders new to Drupal to easily test out and demo its features.

Screenshot of Umami. Vegetarian pasta bake

Migrate!

Migrate has been around since the first minor release of Drupal 8, it’s the module that allows you to pull content into Drupal 8 from previous versions of Drupal or external sources. Migrate is now a stable module, which means that it will be easier for developers to create custom migrations without worrying about changes to the underlying code. This will also make it easier to write documentation and blog posts about how to do things with Migrate.

There are some features around migrating multilingual content which have been set aside in a separate module (Migrate Drupal Multilingual). This module is an experimental module, as there is still some outstanding work to be done in this area.

Workspaces

You are probably wondering: what is « workspaces »? This is a new, experimental module that allows a site administrator to create a new, parallel version of the site content - e.g. a Staging workspace - that can be deployed to the live site in one go. In Drupal 8.5, content moderation was introduced to Drupal, providing a workflow for content to be drafted, reviewed, and approved by different types of users. Workspaces takes this to the next level, allowing entire sections of content to be staged before publishing.

More Under the Hood

Besides new modules, there have been other improvements made to Drupal under the hood. There have been updates to the experimental Layout Builder module. It is now possible to create blocks via the layout builder interface, which will not show up in the global list of blocks. The process of porting tests from Simpletest to PHPUnit is almost done. Nightwatch.js was added to allow for automated javascript testing.

What’s next?

There are lots of new features planned for Drupal 8.7 including support for JSON API in core, potentially a refresh of the default Drupal admin theme (Seven) and work on features like automatic upgrades. Looking forward to seeing what’s next with Drupal in that release, which will come out early next year. Watch the latest DriesNote here, from Drupal Europe for an overview of the Drupal roadmap and new development in the works.

You can get more information from the blog post on drupal.org and the Drupal 8.6 press release.

Let us know in the comments what’s your favourite part of Drupal 8.6!

Sep 21 2018
Sep 21

I spent last week hanging out with over 1000 Drupalers at Drupal Europe, the biggest Drupal event of the year in Europe. It was held in Darmstadt, Germany and brought Drupal users of all sorts from all over the world. Most attendees were from Europe, but many travelled from Asia, North America, and as far away as Australia to attend.

What Was Special About Drupal Europe?

Drupal Europe was basically a community-organized DrupalCon. It was a large event that had most of the features that you would associate with a DrupalCon from the professional venue to the DriesNote to the hundreds of valuable sessions to Trivia Night and the large contribution sprint on Friday.

Watching the 12 core organizers and countless other volunteers step up and organize this event was an inspiration. The volunteers are community members and they brought so many great ideas to the event that made the event excellent. Here are some of the things that I loved about the conference:

BoFs (small break-out sessions that are conversations between attendees rather than speaker-led) were incorporated into the main calendar of events making them highly visible. This made it easy to see which ones were going on. This meant that BoFs were popular and all that I attended seemed highly productive.

There were also lots of opportunities to contribute throughout the conference, and reduced-price contributor tickets were available for people who just wanted to work on the project and not attend sessions.

Diversity tickets were available. I haven’t seen the data, but it seemed like a more geographically and gender diverse conference than other Drupal events I’ve attended in Europe. 

The Splash Awards that kicked off the Tuesday of the event and highlighted great Drupal work being done. I think this is a great way to integrate more success stories and customers into the community.

The overall conference venue from the way the space and sponsor booths were laid out to the food were all very conducive to networking opportunities. There were lots of different spaces to chat, hang out, talk to sponsors, drink coffee, and contribute. The signage kept everything on track and allowed real-time updates to the schedule as needed (thanks Gabor Hojtsy!)

Updates from the Dries Note

If you didn’t attend the event, I recommend watching the DriesNote to get an update on what’s happening with the Drupal project and the community as a whole. Dries talked about the roadmap for Drupal. He touched on recent work on improving the evaluator experience, the work being done on the admin UI, and updates to drupal.org.
 

Image from the DriesNote slidedeck

Drupal User Experience Study

I spent some of the week co-ordinating efforts around the Drupal UX Study that I’ve been working on. I got to meet with Cristina Chumulls and new contributors. We worked on the wireframes for the new Admin UI. The work we’re doing was promoted at the DriesNote, so watch from here to find out more.

If you want to get involved in helping us do user testing to improve the Drupal Admin UI, find us on the Admin UI channel on the Drupal Slack.

Image of the Contribute sign from the Friday

Working Together to Market Drupal!

I also spent a lot of my week talking to folks from different parts of the community about how we can work together to better promote Drupal. This resulted in three separate community efforts: creating a starter kit to help local associations promote Drupal, hiring a marketing manager to create materials for local communities, and a marketing pitch deck for the Drupal project as a whole.
Get in touch with me on the #marketing channel on the Drupal Slack if you want to get involved in these efforts and I’ll connect you to the right person! (my username is pixelite).

Image of the marketing Drupal BOF

Where’s All the Drupal Talent?

Many Drupal agencies face challenges recruiting new talent. When we talk about marketing Drupal, the need to bring new people into the community always comes up. At Drupal Europe, I participated in a panel about how to recruit Drupal talent organized by Josef Dabernig. I talked about our efforts to Axcelerant. I also learned a lot about how other Drupal teams are organized and innovative programs for on-boarding junior developers.

Drupal Association

This was the first big Drupal event that I attended as a member of the board of the Drupal Association. I attended a board retreat the two days before Drupal Europe and got up-to-speed on what the Board is working on. I took advantage of the conference to connect with people in the community who are interested in the Promote Drupal initiative and other efforts of the association. I also sat on a panel about the past, present, and future of the Drupal Association and collected the feedback from audience members who were asking questions about the role of the association going forward.

I’m excited to get started on the board and I’ll post more updates as my involvement advances.

Image of meeting

Watch more here!

#DrupalThanks
Again, huge thanks to the volunteer organizers of the event! 

Drupal Thanks

Aug 21 2018
Aug 21

The administrative interface for Drupal is notoriously intimidating for content editors who are new to the platform. I do a lot of training for Drupal content editors and administrators and have witnessed this first-hand. I've written and spoken in the past about how site builders can improve the user experience for content editors by making configuration changes. However, there are lots of improvements that could be made to Drupal out-of-the-box.

I’m working with the Admin UX User Study group in the Drupal community. We're doing user research to help inform improvements to the Drupal admin UI. Our goal is to make Drupal an amazing platform for site administrators. Our first priority is the user experience of content editors.

We started by conducting a survey to look at how content editors use Drupal now and the challenges and pain points they face. So far, we've had 260 submissions to the content editor survey and have some interesting results to share!

What’s rewarding about using Drupal?

We asked content editors about the rewarding aspects of using Drupal. Almost every response included the adjectives flexible and customizable. Editors like that Drupal allows them to have control over their content.

What’s challenging about using Drupal?

While our respondents tended to agree about why they like Drupal, they had many different answers when we asked them about the challenges they face.

Many respondents voiced the paradox that the flexibility of Drupal and the customization that it allows also makes the interface complex and a challenge to use. Content editors specifically mentioned that the UI provided by paragraphs and panels adds a lot of complexity.

Content editors talked about the challenges of finding documentation, working with media, understanding jargon and technical terminology, and finding what content to edit. A couple respondents mentioned that adding content translation to the mix further complicates the content editing interface.

What can we improve about the content editorial experience?

Good news! The things that content editors want to improve about Drupal are mostly areas where the community is already working. The most common improvement suggested was providing a more modern UI, which is exactly what the Drupal Admin UI Initiative is focusing on.

Not surprisingly, it seems that content editors want a better experience on the content overview page, the content editing page, and the tools available on those pages, like media management, page-building tools (e.g. paragraphs and panels), and WYSIWYG.

Here are the highlights of what content editors suggested:

  • A more modern UI. Several content editors mentioned WordPress with Gutenberg and SquareSpace as examples of a more modern UI to emulate.
  • Simplifying the complexity of the content editing UI. This is particularly challenging when the editing experience is actually a page building experience, like when sites have paragraphs, panels, or the layout builder module enabled.
  • Better media management. Content editors mentioned file versioning, asset libraries, and cited WordPress as an example of a good media management experience.
  • Improvements to the WYSIWYG editor. Several content editors mentioned specific improvements they would want to see, including auto-save.
  • More role-based configuration for content editors. Some content editors mentioned adding a special menu for content editors.

As a site builder, it’s interesting to note that a lot of pain points that respondents mentioned in the survey could be fixed with configuration changes. For example, reducing the permissions for content editors, giving them access to an admin menu with a limited set of options, and customizing some of the default widget settings. This means that maybe by configuring a role for content editors out-of-the-box, and tweaking some of Drupal's default configuration, we might be able to easily improve the content editing experience.

Another interesting note: no one mentioned a complete overhaul of the information architecture. Re-organizing all the items in the admin menu doesn't seem to be a top priority.

Tell me your story!

We also asked content editors what type of tasks they do on their sites. We gathered a lot of stories. Many self-ascribed content editors do site building and advanced admin tasks as well. A good reminder that the classic Drupal personas that we might have in mind, like site builder, content editor, and developer are probably too rigid. A lot of content editors do have full access to all the complexity of the Drupal admin UI.

What’s next?

We are an ambitious bunch with lots of ideas about what to do next! Our next steps are to do some initial user testing, and an online card sorting exercise.

We're planning to start the user testing with a smaller group of content editors. Our testing will include:

  • Testing the new admin UI wireframes that are being developed by the admin UI initiative
  • Doing a comparative study of the content overview, content edit pages and media management tools in other CMS’s to gather data about what aspects users like and what we can apply to Drupal
  • Later, a comparative study looking at page building tools

We’ll also do an online card sort exercise to gather information about how content editors would classify the stories that we gathered in the survey. This will help us generate suggestions for how to organize the information architecture of the admin UI in a more content editor-centric way.

I want a better admin UI now!

The team working on the Admin UX User Study includes Sarah Lowe, Michelle Jackson, Cristina Chumillas, Antonella Severo, and Roy Scholten. We need help recruiting content editors, planning and conducting user testing, and processing results from the tests, so please reach out to us on the #admin-ui channel on the Drupal slack if you want to help out. 

We’re excited about how the community will use the results of the user testing! Let us know if you have ideas for what we should be testing now and in the future.

Jul 30 2018
Jul 30

Choosing a content management system is like choosing a set of building materials: it has ramifications for what you'll be able to create, how much it will cost and how well it will turn out. Like many other web development companies, mine started off building WordPress sites. However, we soon found that WordPress couldn't always deliver the custom functionality our clients needed. We also built out some applications with Ruby on Rails but ran into the opposite problem: it was definitely flexible enough, but it was too expensive for many of our clients because it required a great deal of custom development. Finally, we tried Drupal, which proved to give us the best of both worlds: it provided a lot of functionality, but also allowed to us to fulfill our customers' specific needs.

Here are five of the reasons why I continue to recommend Drupal:

1.Flexibility and Modularity

As I've mentioned, Drupal allows you to craft exactly the website solution you need. It doesn't assume a particular use case out-of-the-box. Its flexibility comes from its modularity. There are thousands of modules available on Drupal.org, covering everything from event registrations to embedded videos to analytics. When necessary, you can also create your own custom modules.In general, Drupal modules are designed to do one thing or add one new feature to your site. Sometimes you need to add multiple modules that work together to get the functionality you want. This means they can be combined in flexible ways. You can think of them like a LEGO set: whereas other content-management systems might offer you a pre-assembled house or car or boat, Drupal provides the blocks to let you build whatever suits you best.

2.Active Community

It's supported by an active community. Drupal is more than just software: it's also the focal point of an open-source community of more than a million people. Developers, designers, trainers, translators, strategists and others all contribute to improving its core, developing new modules, sharing best practices, organizing events and supporting each other with troubleshooting advice, constructive feedback and tutorials.

Drupal's community is one of the reasons why it's trusted by the United Nationss,NASA, UNESCO and hundreds of other governmental bodies around the world. Security threats do arise---and this is inevitable no matter what system you're using---but with tens of thousands of people constantly reviewing the code, they are quickly reported to Drupal's dedicated security team and efficiently addressed.

3.Multilingual Features

It's thoroughly multilingual. Right from the get-go, Drupal lets you choose from 100 installation languages. Each member of your team can then choose their own preferred language for the administrative interface, which will help them feel comfortable and do their best work.

When it comes to user-facing elements, Drupal gives you the power to fine-tune your language strategy. For instance, do you need tailored information or page layouts for particular languages? What would you like to display if there's no translation available for a given page? Should user searches bring up content from all languages or just the selected one? The choice is yours.

Finally, the Drupal community itself is multilingual, which means you'll likely be able to ask questions and find resources in your chosen tongue. (Good news for Canadians: French is highly supported.)

4.API-First Architecture

It's a platform that can be used as a backend for front-end applications. The latest version of Drupal was created with today's mediascape in mind. It recognizes that people consume content not only on websites but also using mobile apps, email newsletters, social media, wearables and so on.

Drupal is an "API-first" system, meaning that it can help you easily create and manage your content in one central location, then display various front-end versions of it, each one adapted to a particular channel. There are plans to add JSON API support to Drupal 8.7, which will provide even better API support out- of-the-box.

5.Accessibility

It's accessible by default. Drupal is set up to build websites that can be used, edited and administered by people with visual, auditory, cognitive or mobility disabilities. In fact, internationally recognized accessibility standards---the World Wide Web Consortium's Web Content Accessibility Guidelines (WCAG 2.0) and Authoring Tool Accessibility Guidelines (ATAG 2.0)---are built right into Drupal's core code. Some organizations, especially government agencies, are required to meet these standards, and the rest still have every reason to improve their site's usability and reach in this way. As a nice bonus, accessible sites rank higher in search engines.

To discuss how Evolving Web could use Drupal to meet the needs of your web project, contact us. To try out Drupal for yourself, sign up for one of our training sessions.

Jul 13 2018
Jul 13

One of the reasons why I’ve chosen to run for a position on the Drupal Association Board of Directors is because I’ve noticed that small-to-medium-sized agencies would like to contribute more to Drupal’s strategic direction. These businesses have played a huge role in building Drupal’s code, community and success over the years, and I believe they’re also a key component of its long-term sustainability. Companies with 25 or fewer people registered on Drupal.org make up the majority of those listed in Drupal’s Marketplace. It’s not a comprehensive survey, but it suggests that smaller agencies are the backbone of the community.

company numbers according to employees with accounts on drupal.org

I’m an owner and co-founder of an 11-year-old agency that employs just over a dozen team members. We have a diverse client stable that includes non-profits, government departments, universities and businesses of varying sizes. Their project budgets range from $5,000 to $500,000, so it’s important to us—and many others like us—that Drupal continues being able to offer powerful and complex functionality for a wide price range.

I’ve heard the conversations about how Drupal 8 has made it more challenging to work with a smaller team and more expensive to build sites and applications. I’ve seen its relatively sluggish adoption statistics. I’ve watched with interest as Backdrop works on advancing a Drupal fork that doesn’t leave the needs of the smaller agencies behind. I sense that we’re at a watershed moment when these businesses need a strong voice at the table.

Small shops have unique strengths to offer clients: they’re often flexible, speedy, local and personal, with strong customer support. One way the Drupal Association could give a boost to these agencies would be by developing more guidelines and models for Drupal Business Summits. Aimed at helping prospective end-users decide whether Drupal could help meet their needs, these events have the potential to drive Drupal’s growth in new regions. Smaller agencies, often located in places with under-tapped markets, are perfectly positioned to lead the charge.

Getting elected to the Drupal Association Board of Directors would give me the opportunity to share my experience and expertise as a small-business owner. I invite you to make your own voice heard as well, by voting in this important election. (Voting ends today: July 13, 2018).

Jul 12 2018
Jul 12

As you probably know, voting is currently open for the Drupal Association’s Board of Directors. The Board of Directors plays an important role in developing the Association’s strategic direction, and voting for the Board of Directors is an opportunity for members of the Drupal community to participate in shaping the Association’s future.

One of the reasons I’m running for this position is because I want to help grow the Drupal community into new areas, and to ensure that the Association’s strategic vision is representative of the needs of Drupal’s diverse community.

Although Evolving Web is a relatively small Drupal company, we have an incredibly diverse team, with our 15 employees coming from 11 different countries. Managing such an international team has broadened my perspective and made me think about the the Drupal experience in communities around the world.

Where Evolving Web employees come from

There are several areas where I want to make sure that Drupal better serves the needs of its growing communities:

Toolkit for Drupal Event Organizers

Anyone who’s been to DrupalCon or a DrupalCamp knows that it’s an amazing opportunity to make connections with other developers and designers, to ask questions, share knowledge, and build a sense of community.

There are plenty of opportunities I see to create a toolkit that would allow for more and larger community-organized events. Already, the Association has standardized the branding for future DrupalCons, and provided a DrupalCon license that will be available so that the community can organize DrupalCons in Europe.

I think that it would be great to provide a more open version of this license, that would be a template anyone can use to organize DrupalCamps. For regions where the Drupal community is still small, and there are only so many people able to volunteer their time and effort, having an easily-adaptable format, planning procedures and best practices could make organizing a DrupalCamp a much less daunting prospect.

Similarly, this year we’re organizing the first ever Drupal Business Summit in Montreal. This is another type of event which could be replicated in other cities and regions, and could be a great tool for growing Drupal adoption along with community.

Promote Drupal Global Training Days

Drupal Global Training Days (GTD) is an exciting community initiative that I’m proud to be a part of. The idea behind Global Training Days is to introduce new and beginner users to Drupal. It’s a great way to introduce Drupal to regions where there are not yet large or active Drupal communities. It also provides a welcoming environment that can be less intimidating for non-developers or people just starting to explore Drupal.

Global Training Days are a great opportunity to expand any Drupal community, whether new or established, and can be used at the community level to promote Drupal. I think having more shared marketing tools to promote these trainings would be a powerful tool for growing the community.

Suzanne and students

Understand New Users’ Needs

As a trainer, I’ve had the exciting opportunity to introduce people from all over the world to Drupal and to see them on their journey toward using Drupal and becoming involved in the community. Over the past seven years, I’ve trained over 1,200 people from at least 17 different countries; across Canada and the US, at DrupalCon Munich, and at DrupalCon Asia in Mumbai.

Through these trainings, and my interaction with trainees, I’ve developed an understanding of how newcomers perceive Drupal, as well as an appreciation for the diversity of needs and priorities of Drupal users around the world. There’s an Admin UI initiative underway to improve the experience of content editors, which I think will go a long way to making Drupal feel more intuitive for new users.

Jul 12 2018
Jul 12

It’s time to vote in the Drupal Association Board election! If you have an account on drupal.org, and have logged in in the last year, you can vote here

Our co-founder Suzanne Dergacheva is running for a member-at-large position on the board. Here are three things Suzanne wants to prioritize:

1. Increasing Drupal adoption: Suzanne has trained thousands of new people in Drupal, so she understands how important good communication is to increase adoption. She wants to help the association seize opportunities for Drupal growth through more targeted and consistent communication and marketing tools.

2. Enabling Drupal shops to grow their businesses: Suzanne is organizing the first Drupal Business Summit in Montreal this year, and believes this could be a replicable model in other regions to help Drupal shops promote the value of Drupal to businesses.

3. Growing the Drupal community: Suzanne manages a diverse team, comprised of employees from 11 different countries. Through her work as a trainer, she has introduced Drupal to people throughout North America and Europe, and at Drupalcon Asia in Mumbai. She’s passionate about making Drupal accessible to more people, and believes that the association can facilitate initiatives to communicate the value that Drupal places on user experience and accessibility.

In addition to her ambitious vision for the Drupal Association, Suzanne brings impressive qualifications:

  1. She served 5 years on the board the McGill Young Alumni, two as president. She was treasurer of the Montreal Drupal Association for five years. 
  2. Her talks “Building Landing Pages and Layouts for Drupal 8 ” and “Creating a Great User Experience for Content Editors”, were among the most attended and best reviewed at #Drupalcon. She keynoted DrupalCamp Montreal 2018, talking about the Drupal experience.
  3. She co-founded a successful Drupal agency which is 11 years old. She lead developers, designers, project managers, and marketers on Drupal projects big and small.
  4. She has volunteered her time to various Drupal community initiatives over the last 10 years

[embedded content]

So go vote now! And better still, share this post with your friends and colleagues in the Drupal Community.

Vote on Drupal.org

Related Posts

How We Can All Improve the Drupal Experience

The best part of my job is teaching Drupal. As a Drupal trainer, I get to meet a lot of Drupalers with really different backgrounds. Some are brand-new to Drupal, some have lots of experience. Listening to them tell of their Drupal journeys, both the highlights and the low points, has given me insights into the different ways people encounter Drupal and some of the most common reasons why they love it, use it and get involved in the community (or not).

Read More about How We Can All Improve the Drupal Experience »

Jul 12 2018
Jul 12

It’s time to vote in the Drupal Association Board election! If you have an account on drupal.org, and have logged in over the last year, you can vote here

Our co-founder Suzanne Dergacheva is running for a member-at-large position on the board. Here are three things Suzanne wants to prioritize:

1. Increasing Drupal adoption: Suzanne has trained thousands of new people in Drupal, so she understands how important good communication is to increase adoption. She wants to help the association seize opportunities for Drupal growth through more targeted and consistent communication and marketing tools.

2. Enabling Drupal shops to grow their businesses: Suzanne is organizing the first Drupal Business Summit in Montreal this year, and believes this could be a replicable model in other regions to help Drupal shops promote the value of Drupal to businesses.

3. Growing the Drupal community: Suzanne manages a diverse team, comprised of employees from 11 different countries. Through her work as a trainer, she has introduced Drupal to people throughout North America and Europe, and at Drupalcon Asia in Mumbai. She’s passionate about making Drupal accessible to more people, and believes that the association can facilitate initiatives to communicate the value that Drupal places on user experience and accessibility.

In addition to her ambitious vision for the Drupal Association, Suzanne brings impressive qualifications:

  1. She served five years on the board the McGill Young Alumni, two as president. She was treasurer of the Montreal Drupal Association for five years. 
  2. Her talks “Building Landing Pages and Layouts for Drupal 8 ” and “Creating a Great User Experience for Content Editors”, were among the most attended and best reviewed at #Drupalcon. She keynoted DrupalCamp Montreal 2018, talking about the Drupal experience.
  3. She co-founded a successful Drupal agency which is 11 years old. She lead developers, designers, project managers, and marketers on Drupal projects big and small.
  4. She has volunteered her time to various Drupal community initiatives over the last 10 years

[embedded content]

So go vote now! And better still, share this post with your friends and colleagues in the Drupal Community.

Vote on Drupal.org

Related Posts

How We Can All Improve the Drupal Experience

The best part of my job is teaching Drupal. As a Drupal trainer, I get to meet a lot of Drupalers with really different backgrounds. Some are brand-new to Drupal, some have lots of experience. Listening to them tell of their Drupal journeys, both the highlights and the low points, has given me insights into the different ways people encounter Drupal and some of the most common reasons why they love it, use it and get involved in the community (or not).

Read More about How We Can All Improve the Drupal Experience »

Jul 12 2018
Jul 12

Drupal is an open source Content Management System (CMS) which is free to download and use; it allows you to create and manage websites, intranets, and web applications without writing any code.

Why Use Drupal?

Most websites share a common set of features. They typically have navigation menus and lists of content, pages of content with nice URLs, a header with a logo, a footer with contact info, etc. At the same time, there are a lot of differences between websites. They often have a unique content structure, a customized look and feel, and customized features.

Drupal works well for websites that need those shared features. Drupal provides lots of functionality out-of-the-box that most websites need, for example:

  • Content management
  • Taxonomy for organizing content
  • Flexible navigation system
  • Comments
  • Search
  • Content listings
  • Contact forms
  • WYSIWYG Editor
  • Nice content authoring experience
  • Multilingual content & user interface
  • User management
  • Accessibility
  • Responsive design

At the same time, Drupal is really flexible, so you can customize the aspects of your website that are unique and add custom features.

[embedded content]

By using Drupal, you can create: 

  • Corporate websites : contents types of services, workflow for publishing, corporate branding, etc.
  • Intranets: private content, custom workflow for internal processes, listings of internal contents such as internal news and meeting notes. 
  • Online directories: search tools, embedded listing, etc. 
  • Interactive websites: user accounts, multi-step form, custom javascript, decoupled front-ends, etc. 
  • Marketing portals: landing pages for SEO, mix of content and marketing material, campaign landing pages, etc.

Here is some handy Drupal terminology:

  • Node - Piece of content
  • Content type - A template for content
  • Vocabulary - A way of categorizing your content
  • View - Content listing
  • Module - Functionality that you can add to a Drupal website 
  • Theme - Defines the layout, look and feel
  • Block - Displays content, a list, menu, form, etc. on the page (often in the sidebar, header, footer)
  • Permission - A task that a user can do
  • Role - A type of user

What is Drupal? An Introduction to Drupal8

Fun facts!

Drupal was created by Dries Buytaert in 2001

The word Drupal comes from “druppel”, which means drop in Dutch

Drupal Community is originally used for university discussions but there are now thousands of organizations using Drupal, including companies, non-profits, governments, universities to power their web presence.

As of January 2018, the Drupal community reached over 1.3 million users, including developers, designers, content writers, sponsors etc. According to statistics, there are more than 100,000 members that are actively contributing to the community. This results in tens of thousands of free modules that allow to further personalize Drupal functionality, thousands of free themes that help customize the appearance of Drupal and more than one thousand distributions that allow users to easily and efficiently set up Drupal websites.

If you would like to learn more about Drupal, we offer a large variety of trainings from beginner to advanced levels, with our team-lead, Suzanne Dergacheva. Check out Evolving Web’s “Training” section. 
 

Jul 10 2018
Jul 10

The best part of my job is teaching Drupal. As a Drupal trainer, I get to meet a lot of Drupalers with really different backgrounds. Some are brand-new to Drupal, some have lots of experience. Listening to them tell of their Drupal journeys, both the highlights and the low points, has given me insights into the different ways people encounter Drupal and some of the most common reasons why they love it, use it and get involved in the community (or not).

Drupal Thanks at DrupalCon Asia 2016

I've recently been thinking about the Drupal community from a user experience point of view. I regularly host UI meetups for developers and designers, and I'm also volunteering on Drupal's Admin UI initiative, which is creating an accessible administrative interface based on user data and feedback. Both have taught me to empathize with others and understand why they might be feeling excited, warm and fuzzy, anxious, frustrated or curious about Drupal at any given point. It's also given me ideas about what we can all can do to improve the Drupal experience, including:

1. Participate in the community

If you think back to your own best experience with Drupal, there's a decent chance that it was a DrupalCon, DrupalCamp or another time when you had the chance to learn from other Drupalers or share your knowledge with them. It feels inspiring to mentor newcomers, help people solve problems on Drupal Slack or get advice from someone who seems to care. Let's keep it up and look for opportunities to take it further!

2. Recognize the challenges that you and others are facing

There's no point in pretending that using Drupal is always smooth sailing. Hiding the challenging parts of our experiences only makes others feel like they're alone or that they've missed something everybody else has understood. Asking new users around the world to tell me about their pain points has shown me, as just one small example, that Drupal terminology can often be intimidating. We all have our issues, and talking about them is the first step toward finding solutions for them.

Drupal Training at Drupal North in Ottawa

3. Get involved with existing initiatives

Community members are on the job when it comes to refining certain aspects of the Drupal experience. The Promote Drupal Initiative has already enhanced Drupal.org's landing page with the persona-specific information its audience was looking for. Their next step will be devising ways to make it easier for new users to find their way into community engagement. And they're not the only ongoing project that could benefit from your time, expertise or financial support: the Out of the Box Experience Initiative, for example, is helping Drupal to make a better and more helpful first impression when it's installed by a prospective user.

4. Imagine new ways of solving problems

The beauty of being part of an open source community is that if you see a problem, you have the power to address it. If you have an idea for helping others have a better Drupal journey, why not try it out? Great user experiences encourage user-base growth and vice versa: a virtuous cycle that I'm committed to supporting.

Inspired by these ideas, I recently decided to run for a position on the Drupal Association's Board of Directors as a "director at large"---a community representative, in other words---because I would love to put my time, energy and knowledge towards growing the community and promoting Drupal to new groups and markets.  If you have an active profile on Drupal.org then you can vote in this election here any time before Friday, July 13.

For a video version of this post, here's a recording of my session on the topic at DrupalCamp Montreal:

[embedded content]
Jul 09 2018
Jul 09

Gatsby is a really fast React-based static site generator. You can use it to create a static site, with content pulled from Drupal and other content management systems. 

Why Use Gatsby?

Unlike dynamic sites which render pages on-demand, static site generators pre-generate all the pages of the website. This means no more live database querying and no more running through a template engine. Performance goes up and the maintenance cost goes down.

Static site generators have been evolving over the last few years. Tools like Jekyll, Gatsby, Hexo, Hugo become more and more popular. They have been chosen by developers who want a simple website/blog solution. They need very minimal server setup and have a low maintenance cost. However, static site generators usually require writing content in Markdown, which is not a great authoring experience for most content editors.

On the other hand, content management systems such as Drupal and Wordpress can provide a very powerful back-end. Having a WYSIWYG editor and content types help editors to manage content more easily and systematically. However, maintaining a CMS requires hosting a web server and database, and opens you up to security vulnerabilities and performance issues.

Gatsby stands in between the simplicity and robustness of static site, and the versatile back-end of a content management system. Using Gatsby means that you can host the CMS in-house and publish content generated by Gatsby as a static website. The first thing you’ll notice about Gatsby is how amazingly fast it is.
 

A diagram showing how content gets published with Gatsby

How to Integrate Drupal and Gatsby

In this tutorial, we are going to put together a demo that pulls Drupal content into a Gatsby site. We’ll borrow content of this awesome blog post to create a list of coffee types in Drupal, then transfer the list content to Gatsby.

This goal can be achieved with 4 steps:

  1. Build a Drupal server
  2. Build a Gatsby site
  3. Fetch content from the Drupal server
  4. Publish the Gatsby site

1. Build a Drupal server

Let’s say we already have a Drupal 8 site installed. We’ll need to:

  • Create a content type name Coffee with three fields: Title, Body and Image
    Content type Coffee
  • Turn Drupal into an API server by installing 2 modules jsonapi and jsonapi_extras.
  • Give Anonymous user permission to Access the JSON API resource list
    JSONAPI permission
  • Verify that the API server is working well by going to http://[your-site]/jsonapi as an Anonymous user. The page should show up with all information of your API server
    JSONAPI endpoint

Tips

  • If you use Chrome, use JSON Viewer Chrome extension to view JSON data in a better format
  • If you don’t set permission for Anonymous user to Access JSON API resource list, you’ll get error 406 - Not acceptable when trying to connect to Drupal from Gatsby
  • If you don’t have jsonapi_extras installed, you’ll get error 405 - Method Not Allowed when query data from Gatsby

2. Build a Gatsby Site

First, make sure you have node and npm installed on your computer. Verify it by typing node -v and npm -v into Terminal

node -v
v10.1.0
npm -v
5.6.0

Install Gatsby’s command line tool

npm install --global gatsby-cli

Create a new Gatsby site and run it, I’ll call my Gatsby site coffees.gatsby

gatsby new coffees.gatsby
cd coffees.gatsby
gatsby develop // start hot-reloading development environment

By default, the new Gatsby site is accessible at localhost:8000

Gatsby default page

3. Fetch Content from the Drupal Server

At this step, we’ll be creating a new simple page /coffees that displays all the coffee types from the Drupal site.

Create the /coffees page

Create a new page in Gatsby is as simple as creating a new JS file. All Gatsby pages should be stored in /src/pages. In this case, we’ll create the file coffees.js in /src/pages and add the following code in coffees.js:

import React from "react"
const CoffeesPage = () => (
  <div>
    <h1>Different types of coffee</h1>
  </div>
)
export default CoffeesPage

This simple code does one thing: create a new page at /coffees. The content of this page is a heading h1 with the text “Different types of coffee”

Page “Different types of coffee”

Query Drupal content using GraphQL

In order to pull data from Drupal 8 site, we’ll need to install the gatsby-source-drupal plugin

// in your coffees.gatsby folder
npm install --save gatsby-source-drupal

Configure the gatsby-source-drupal plugin

// In gatsby-config.js
plugins: [
  ...
  {
    resolve: 'gatsby-source-drupal',
    options: {
      baseUrl: 'http://dcmtl2018-demo.server/',
      apiBase: 'jsonapi', // endpoint of Drupal server
    },
  }
],

After adding the plugin configuration, the site should still be functioning. If Gatsby throws a 406 error, check the permission on the Drupal site; if Gatsby throws a 405 error, make sure module jsonapi_extras is enabled.

Build GraphQL to query all coffee nodes from Drupal

Gatsby comes with an in-browser tool for writing, validating and testing GraphQL queries named GraphiQL, and it can be found at localhost:[port]/___graphql, in our case it’s localhost:8000/___graphql

Let’s try querying all the Coffee nodes in this tutorial

GraphiQL interface

After building the query successfully, let’s go back to the coffees.js file to execute the query.

export const query = graphql`
  query allNodeCoffee {
    allNodeCoffee {
      edges {
        node {
          id
          title
          body {
            value
            format
            processed
            summary
          }
        }
      }
    }
  }
`

Then, update the const CoffeesPage to display the title and body content:

const CoffeesPage = ({data}) => (
  <div>
    <h1>Different types of coffee</h1>
    { data.allNodeCoffee.edges.map(({ node }) => (
      <div>
        <h3>{ node.title }</h3>
        <div dangerouslySetInnerHTML={{ __html: node.body.value }} />
      </div>
    ))}
  </div>
)

Thanks to hot-reloading, we can see the sweet fruit of the work right after saving the file

Render content

So far, we have done:

  • Create an API server with Drupal and jsonapi, jsonapi_extras
  • Create a Gatsby site with page coffees.js that “reads” content from Drupal server

Let’s move the the last step of the tutorial: publish Gatsby site.

4. Publish the Gatsby Site

Gatsby names itself as a static static site generator, meaning its main purpose is to generate a bunch of static HTML, JS, CSS and images files. This action can be done by only one command:

gatsby build

Once finished, checkout /public folder to see result of your hard work along this long tutorial. Deploying your site is now simply copy/push contents in /public to server.

[embedded content]

Conclusion

In this tutorial, we got to know how to:

  • Create a new Gatsby site
  • Install new plugin in Gatsby
  • Use GraphiQL to write, validate and test GraphQL query

I personally find that Gatsby is a good solution for setting up a simple blog. It’s easy to install, very fast, and requires zero server maintenance. In a future blog post, I’ll talk about how to integrate more complex data from Drupal into Gatsby.

Jul 05 2018
Jul 05

Evolving Web is proud to announce that it's giving out a scholarship for our 5 Day Drupal 8 Training in Toronto in October. Everyone is welcome to apply. We encourage students, freelancers, and those looking to switch careers to attend, as well as anyone wanting to learn Drupal for a project for the social good.

If you're not in Toronto, we'll be offering scholarships in the future for trainings in other cities and online. Subscribe to our newsletter for updates.

Why do you need this training?

Many businesses, higher education institutions, governments, NGOs, and communities around the world use Drupal to power their websites. Drupal is one of the most sought-after CMS technologies and there is generally a shortage of Drupal talent.

Learning Drupal can be challenging and while there are many resources online, it's useful to have a hands-on course to guide you through the process.

What will you learn in this program?

During the course, you'll learn how to build websites with Drupal from top to bottom. The class is divided into three parts:

Who should apply?

Scholarships will be given to those who demonstrate an eagerness to learn, a vision for how they will implement their Drupal skills, and a need for financial support.

It's important that applicants clearly indicate why they want to learn Drupal and what projects they're planning to use Drupal for.

Some experience with HTML, CSS, and programming is required to take the course. Please contact us if you have questions about the course requirements.

Course Details

  • Dates: October 1, 2018 - October 5, 2018 - 5 full days of intensive learning
  • Location: Toronto (Centre for Social Innovation)
  • Cost: $1,850
  • We’re giving away 1 scholarship for the full class as well as 3 scholarships for 50% discounts  — apply today!
  • Deadline for applications: August 17, 2018
Jul 04 2018
Jul 04

When you're building a site, it's standard to set up "pretty URLs". For example, we'd rather see /catalog/accessories than /taxonomy/term/18 and we'd rather see /about-us than /node/19. With Drupal, we use the Pathauto module to configure these types of standard content paths. But in some cases, there's no option to create a nice URL pattern, so we end up seeing those URLs.

This happens with Views that are filtered by a taxonomy term in the URL. The result is that you end up seeing taxonomy term IDs in the URL (e.g. catalog/19/search) rather than a pretty URL (e.g. catalog/accessories/search).

In this tutorial, I'll walk you through how to create a field that is used to make generate URLs for Views pages that take taxonomy terms as contextual arguments. Using this approach, a site editor will be able to configure what the URL path will look like.

Assumptions

It has been assumed that you know:

  • The basic concepts of Drupal 8.
  • How to configure fields.
  • How to configure a view with a contextual filter.
  • How to create a custom module in Drupal 8.
  • How to create a custom plugin in Drupal 8.

The solution

We're going to use the core taxonomy argument plugin (Drupal\taxonomy\Plugin\views\argument\Taxonomy) to help us fix this problem. The plugin takes a term ID from the URL and passes it to Views. We'll override the plugin so that it takes a string from the URL (slug), and then looks up the associated term ID. All the rest of the functionality we'll leave as is.

Step 1: Content and field configuration

To make the example work, we need the following configuration to be in place (most of this you get out-of-the-box with Drupal, you'll just need to add the Slug field):

  • A taxonomy vocabulary named tags.
  • Tags should have the following field:
    • Field name: Slug
    • Machine name: field_slug
    • Type: Text (Plain)
    • Size: 32 characters
  • A content type named article.
  • Article should have the following field:
    • Field name: Tags
    • Machine name: field_tags
    • Type: Entity reference (to taxonomy terms from Tags)
    • Number of values: At least one

Configuring field slug on taxonomy termConfiguring field slug on taxonomy term

Step 2: Create a custom module

Create a custom module called custom_views_argument. Declare a dependency on the views module in the .info.yml file.

Step 3: Implement hook_views_data_alter()

Reference: custom_views_argument.module

The hook_views_data_alter() hook tells Views about the various database tables, fields and the relevant plugins associated to them. We implement this hook to tell Drupal to include our custom argument plugin which we will create in the next step.

Step 4: Create a custom views argument plugin

Reference: CustomTaxonomySlug.php

Next we implement the CustomTaxonomySlug class with a proper annotation @ViewsArgument("custom_taxonomy_slug"). This tells the Views module that the class is a special class which implements a custom Views argument plugin. We extend the Drupal\taxonomy\Plugin\views\argument\Taxonomy class and override one important method CustomTaxonomySlug::setArgument().

public function setArgument($arg) {
  // If we are not dealing with the exception argument, example "all".
  if ($this->isException($arg)) {
    return parent::setArgument($arg);
  }
  // Convert slug to taxonomy term ID.
  $tid = is_numeric($arg)
    ? $arg : $this->convertSlugToTid($arg);
  $this->argument = (int) $tid;
  return $this->validateArgument($tid);
}

All we do here is catch the argument from the URL and if it is a slug, we use a convertSlugToTid() method to retrieve the underlying taxonomy term ID. That is it! The rest of the things are handled by the taxonomy plugin.

Step 5: Create Demo Content

Now that everything is in place, we'll put our solution to the test. Start by creating some demo content. Create 2-3 articles and assign them some tags. The tags are created, however, they don't have a slug.

Once done, go to the Admin > Structure > Taxonomy > Tags page and edit the tags and give them nice URL slugs containing only English alphabet letters, numbers and dashes. For real projects, you might need to use a custom or contrib module to automatically generate slugs (see the machine_name module).

Step 6: Configure a View

Now we're all set! The last step is to create and configure a View which will put everything together.

  • Create a View of Content. You can name it Blog.
  • Create a page display and set it's URL to /blog/%.
  • Add a relationship to taxonomy terms referenced from field_tags.
    • We do this to be able to use the Slug field in a filter. 

Configure a relationship with taxonomy termsConfigure a relationship with taxonomy terms

  • Now, define a contextual filter for the Slug using the custom argument plugin which we created.
    • Click on the Add button for Contextual filters
    • Choose the Slug filter which we created. It should have the name we had defined in our plugin, i.e. Custom: Has taxonomy term with slug.
    • Optionally, specify a validation criteria for Taxonomy Term and specify the Tags vocabulary.

Configuring the custom views argument pluginConfiguring the custom views argument plugin for contextual filters

  • Save the view for the new configuration to take effect.

And we're done! If you visit the /blog/SLUG, you should see all the articles which have the taxonomy term associated to SLUG. Here, SLUG refers to the value you put in the Slug field for the tag. E.g. if you have a tag named Accessories and you wrote accessories in the Slug field, you should go the the URL /blog/accessories.

Next steps

If you're looking for hands-on training about how to develop Drupal modules, we offer professional Drupal training online and in-person. See the full Drupal 8 Module Development training curriculum for details.

Jun 22 2018
Jun 22

Before the Camp:

My name is Ami Koga. A couple weeks ago, I started my summer internship at Evolving Web. I had no idea about Drupal before starting at Evolving Web. I did a bit of research on it beforehand; and the internet gave me some basic information such as 

This was all very abstract to me until I attended DrupalCamp Montreal. Now that I have experienced the DrupalCamp vibes, attended presentations and training, and gotten involved in the Drupal community by volunteering at the camp, I have a much better understanding of what Drupal is.

Training Day:

The first day of DrupalCamp, I went to a Drupal training called “What is Drupal? An Introduction to Drupal 8”, presented by our team lead Suzanne Dergacheva. It was an Introductory Drupal course and the training was available both in English and French. It was my very first time trying out Drupal; and, I was able to understand why the internet claims that “Drupal is easy to use” over and over again. We started with installing Drupal (of course, it was free!!), then, we played around with it by adding content, inserting pictures, changing fields, etc. I created the following basic website within 2 mins without knowing any coding knowledge. Very simple, fast and easy.

drupal-website

Camp Day:

On the second day, I attended the camp as a volunteer, as well as a team member of Evolving Web. During the registration, I noticed a large variety of people came to sign in; all ages, all genders, from different cities, but all gathered for the same common interest: Drupal.

Moreover, the people who stopped by at our company’s booth were very passionate and motivated to learn more about Drupal, and chat with us about their future projects. “Wow, Drupal is actually used by many people from different fields”, was my first impression at the DrupalCamp. Beginners, developers and agencies are all part of the community and all seemed happy to discuss problems and ideas related to Drupal.

Presentations:

Overall, the presentations were the main and most fun part of the DrupalCamp. My Evolving Web colleagues presented 12 sessions, so I got to learn a lot from them! Here are some of the presentations I saw :

  1. Our Co-founder and front-end lead, Suzanne Dergacheva was the Keynote speaker. She gave a presentation titled, “It’s All About the Experience: What I’ve Learnt from Talking to Thousands of People About Drupal.” The essence of the presentation was that we can learn a lot by looking at the Drupal experience from different perspectives and thinking about the personas of people who interact with Drupal. This gave me some insight into the Drupal community and who makes up that community.
    [embedded content]
  2. Our Co-Founder and Technical Lead, Alex Dergachev presented, “Migrating 10000 Classic Books to Drupal 8.” He discussed the technical and business motivations for the project, and provided a technical overview of the Drupal migration.
    [embedded content]
  3. Our UI/UX Designer, Annika Oeser gave us 10 tips on designing a website, so that we can make our own website projects. Annika's talk gave me insight into the web design process and how designers and developers interact.
    [embedded content]
  4. Our Senior Drupal Developer, Jigar Mehta and Marketing & Content Manager, Meyzi Mazalto gave a presentation on Accessibility. Making a website more accessible can also improve the SEO value and usability of your site.
    [embedded content]

In summary, the 3 day long DrupalCamp gave me interesting insight about the Drupal Community. It was highly beneficial to my development as an intern at Evolving Web and I was glad that I took the opportunity to get involved in this community as it opened up a “window” for me into web development and design.

Jun 14 2018
Jun 14

Drupal's field system is awesome and it is one of the reasons why I started using Drupal in the first place. However, there are some small limitations in it which surface from time to time. Say, you have a Text (Plain) field named field_one_liner which is 64 characters long. You created around 30 nodes and then you realized that the field size should have been 255. Now, if you try to do this from Drupal's field management UI, you will get a message saying:

There is data for this field in the database. The field settings can no longer be changed.

So, the only way you can resize it is after deleting the existing field! This doesn't make much sense because it's indeed possible to increase a field's size using SQL without saying goodbye to the data.

In this tutorial, we'll see how to increase the size of an existing Text (Plain) field in Drupal 8 without losing data using a hook_update_N().

Assumptions

  • You have intermediate / advanced knowledge of Drupal.
  • You know how to develop modules for Drupal.
  • You have basic knowledge of SQL.

Prerequisites

If you're going to try out the code provided in this example, make sure you have the following field on any node type:

  • Name: One-liner
  • Machine name: field_one_liner
  • Type: Text (Plain)
  • Length: 64

After you configure the field, create some nodes with some data on the One-liner field.

Note: Reducing the length of a field might result in data loss / truncation.

Implementing hook_update_N()

Reference: Custom Field Resize module on GitHub

hook_update_N() lets you run commands to update the database schema. You can create, update and delete database tables and columns using this hook after your module has been installed. To implement this hook, you need to have a custom module. For this example, I've implemented this hook in a custom module which I've named <a>custom_field_resize</a>. I usually name all my custom modules custom_ to namespace them. In the custom module, we implement the hook in a MODULE.install file, where MODULE is the machine-name of your module.

/**
 * Increase the length of "field_one_liner" to 255 characters.
 */
function custom_field_resize_update_8001() {}

To change the field size, there are four things we will do inside this hook.

Resize the Columns

We'll run a set of queries to update the relevant database columns.

$database = \Drupal::database();
$database->query("ALTER TABLE node__field_one_liner MODIFY field_one_liner_value VARCHAR(255)");
$database->query("ALTER TABLE node_revision__field_one_liner MODIFY field_one_liner_value VARCHAR(255)");

If revisions are disabled then the node_revision__field_one_liner table won't exist. So, you can remove the second query if your entity doesn't allow revisions.

Update Storage Schema

Resizing the columns with a query is not sufficient. Drupal maintains a record of what database schema is currently installed. If we don't do this then Drupal will think that the database schema needs to be updated because the column lengths in the database will not match the configuration storage.

$storage_key = 'node.field_schema_data.field_one_liner';
$storage_schema = \Drupal::keyValue('entity.storage_schema.sql');
$field_schema = $storage_schema->get($storage_key);
$field_schema['node__field_one_liner']['fields']['field_one_liner_value']['length'] = 255;
$field_schema['node_revision__field_one_liner']['fields']['field_one_liner_value']['length'] = 255;
$storage_schema->set($storage_key, $field_schema);

The above code will update the key_value table to store the updated length of the field_one_liner in its configuration.

Update Field Configuration

We took care of the database schema data. However, there are other places where Drupal stores the configuration. Now, we will need to tell the Drupal config management system that the field length is 255.

// Update field configuration.
$config = \Drupal::configFactory()
  ->getEditable('field.storage.node.field_one_liner');
$config->set('settings.max_length', 255);
$config->save(TRUE);

Finally, Drupal also stores info about the actively installed configuration and schema. To refresh this, we will need to re-save the field storage configuration to make Drupal detect all our changes.

// Update field storage configuration.
FieldStorageConfig::loadByName($entity_type, $field_name)->save();

After this, running drush updb or running update.php from the admin interface should detect your hook_update_N() and it should update your field size. If you're committing your configuration to git, you'll need to run drush config-export after running the database updates to update the config in the filesystem and then commit it.

Conclusion

Though we've talked about resizing a Text (Plain) or varchar field in this tutorial, we can resize any field type which can be safely resized using SQL. In certain rare scenarios, it might be necessary to create a temporary table with the new data-structure, copy the existing data into that table with queries and once all the data has been copied successfully, replace the existing table with the temporary table. For example, if you want to convert a Text (Plain) field to a Text (Long) field or some other type.

Maybe someday we'll have a resizing feature in Drupal where Drupal will intelligently allow us to increase a field's size from it's field UI and only deny reduction of field size where there is a possibility of data loss. But, in the meanwhile, we can use this handy trick to resize our fields. Thanks for reading! Please leave your comments / questions in the comments below and I'll get back to them as soon as I have time.

May 01 2018
May 01

By now, we all know the importance of building responsive websites that dynamically adjust to any screen size. According to Statista, 52 percent of all global web pages served in 2018 were viewed on smartphones. And now that Google’s index is mobile first, it’s essential for websites to be designed (or redesigned) mobile first — with a smartphone screen size as the starting point, and resizing up from there.

Building a site to be fully responsive starts with organizing your content so it can be browsed and read on even the smallest smartphone. Whether you’re creating content for a new site, or restructuring a legacy site, begin with a responsive content strategy that defines how you will optimize and structure content for mobile users.

Here are the key components of responsive (and mobile first) content strategy:

1. Be mobile first

When you begin planning content, start with the smallest screen size and work your way up. This will allow you to tackle the most challenging task first, and it will help you make the most of the smallest interface. This process is also very effective for eliminating unnecessary content elements that you may be tempted to include if you’re designing desktop first. An effective and efficient mobile-first design will more easily translate to a clean desktop design (rather than trying to scale down your desktop design).

2. Structure your content first, design later

Begin by stripping all the design elements from your text content. Develop and structure your content, add it to your Drupal 8 CMS and then apply styling and design.

3. Optimize and structure your content for mobile

Responsive content needs to be modular so it will easily break into mobile-friendly pieces. And it needs to be skimmable, so mobile readers can easily consume it.

Create less content (if that’s an option) and keep it short. Organize website copy into small, granular paragraphs or chunks, no longer than three paragraphs. Add subtitles that define each piece, so mobile users can easily browse and scan content.

Working in your Drupal CMS, define separate fields for different pieces of content. The more fields you create for your content, the more flexibility you will have. In other words, you’ll have a field for a title, subtitle, pull-quote, body text, instructions, etc. Each field can be uniquely styled according to its content type. Then prioritize fields based on their importance so they stack in a logical way on a user’s screen — the most important content up top, less useful content can be condensed, stacked below, or even hidden.

4. Simplify navigation

Nobody wants to browse a mega menu that consumes their entire smartphone screen. The ubiquity of mobile means menus need to be reduced and simplified. Put a lot of thought into how you will make your most important content accessible via your menu. How many menu items can you remove or de-prioritize? Flatten your navigation — stop nesting menus inside menus inside menus and instead create fewer layers and way less navigation points. If you’ve decided to take links out of the menu, you can add them elsewhere as links or call to action.

5. Be strategic with your calls to action

Take the time to prioritize your calls to action. On mobile, it’s even more important to define your most important CTAs — the ones that directly impact your business objectives. List your objectives in order of importance, and align a call to action with each one. Then choose objective that’s most critical to your bottom line. This is the only CTA that should live above the fold on your mobile screen.

6. Optimize media

Make sure your sound, video and image files are optimized for devices large and small. Always use image thumbnails so users don’t have to load a video player. And never, never use autoplay on your video and audio content.

For images, start with image sizes and proportions that can be adapted. And don’t resize or add image treatments before adding images to your CMS — let Drupal do the heavy lifting (just like you did with your text content). Images should not be larger than you need them to be (even on large screens). Rely on Drupal 8’s Responsive Image module to resize images to the screen-appropriate size.

7. Begin the long, hard task of cleaning up legacy content

Of course, there’s always the large, old-school website that needs to have its content converted to mobile first. In addition to all the content tips we’ve outlined above, you want to dive into that static HTML and clean it up. Remove fixed-width tables, inline media and floats with content (ouch). And on the content level, start to structure long content into browsable chunks that can be organized into content fields.

Mobile first: it’s universal

Many of us been applying similar content guidelines and strategies for quite some time; but the need for a mobile-first approach was not universal. It was dependent on the project, technology used, the target user, etc. In today’s digital ecosystem, mobile-first has become a given. Now it’s time to explore the creative potential for creating sharp, sparse, targeted content that fits in the palm of a user’s hand.

Apr 26 2018
Apr 26

The 10th annual DrupalCamp Montreal will be held Thursday, June 14th to Sunday, June 16th at the John Molson School of Business.

While it will be my first DrupalCamp, I am very excited to be part of the organizing committee. I am helping promote the event through social media channels and the local community. I am not a web developer but I think whether you are a Drupal developer or not, I’m sure you’ll have a lot to learn from this event.

5 reasons you should attend:

  • Meet people in the web community

  • Learn about Drupal and other web technologies

  • Learn about web strategy and design

  • Find collaborators for your next project

  • Share your knowledge and your experience with other tech lovers

Who should consider attending:

  • Site builders, developers and site admins who are new to Drupal

  • Drupal experts

  • Project managers, decision makers, content writers

  • Web marketers and designers

We Want You to Speak at DrupalCamp Montreal!

This year, we’re thinking outside the box and encouraging speakers to present on topics beyond the sphere of Drupal. So if you have content strategy techniques to show, a new JavaScript framework you want to talk about, or a CSS technique that you’re excited to use, this is your opportunity to share your ideas with the community and get experience presenting.

Any topic related to web development or Drupal is welcome. The four main tracks of the camp: site building, development, strategy & business and front-end. Sessions can be given in either French or English.

We’re also accepting session proposals until 11th of May, so if you have a great idea or know someone who does, let us know!

Learn Drupal!

The training day on June 14th includes two “What is Drupal?” training sessions (delivered by our very own Suzanne Dergacheva) where you can learn the basics of Drupal:

  • French from 9am to 12pm

  • English from 1pm at 4pm

You can see the details of training here.

Friday 15th of June and Saturday 16th of June will include sessions about Drupal, web technology, strategy, and design.

Registration is now open for the DrupalCamp Montreal 2018. You can sign up for both training or sessions.

Volunteer!

There is another way to join in the camp! If you are passionate about Drupal and web technology and you want to help make the DrupalCamp a success, you can consider volunteering at the event. To become a volunteer, you can fill out the form here.

Celebrate 10 Years of DrupalCamp Montreal

We are becoming a big community! Evolving Web was one of the web agencies that helped organize the first DrupalCamp in 2008 and approximately 50 people attended . This year, we are very proud to be sponsoring the event at the “Diamond” level and we are expecting around 200 - 250 attendees.

See you at the camp!

Apr 25 2018
Apr 25

Using Auth0 to create a centralized login page for Drupal sites

Drupal’s basic user authentication system is ideal for small and isolated apps. But when users are signing into multiple interactive sites and apps, it makes sense to offer a centralized authentication system to save users from remembering multiple passwords.

These days, social sites have become de facto identity providers. Users expect websites to provide social login and single sign on functionality. In these scenarios, the built-in Drupal authentication system is very limited.

Introducing Auth0: authentication and authorization as a service

There are several ways of enabling single sign-on and social logins on Drupal websites. In this article, we’ll introduce Auth0 and explain how to use it to create a cool, centralized login page like the one shown below.

Auth0 Login Page

Auth0 provides authentication and authorization as a service. It includes various methods to authenticate, such as username/password, social accounts, SAML and OTP. It can also connect on-premise identity databases. The authentication mechanism is device-agnostic, so it works consistently across various devices.

Auth0 implements OAuth 2.0 — an open standard for authentication that can be used between applications and websites. It also implements other standards that can be used for authentication, including SAML and OpenID Connect.

Here are some of the ways you can integrate Auth0 with Drupal

  • As a single sign-on across multiple Drupal apps, where Auth0 acts as a central store for credentials

  • To allow users to log into Drupal using existing credentials from systems such as LDAP, Google Suite, or Office 365

  • To integrate social logins such as Google and Facebook

How to implement Auth0

In the steps below, you’ll learn how to set up Auth0 on a Drupal site for a typical use case. It will enable users to log into your Drupal site using their social media accounts. They'll also be able to create an account if they don't already have one.

There are two Auth0 modules you can choose from:

  • Auth0 module on GitHub: is the official module. It has more features but doesn't follow all of Drupal coding standards.

  • Auth0 module on Drupal.org is a fork of the official module on drupal.org. It follows coding standards, but lacks some functionality, as many changes have not been merged from the aforementioned GitHub repository.

When we integrated Auth0 on a client’s site a few months ago, we spent a good amount of time analyzing these two modules.

Only some basic features were required, all of which were available in the Drupal.org module. We therefore opted for cleaner code over the additional features.

In fact, both modules contained errors that we needed to fix. The generic patches that resulted from this process were submitted to both repositories. These patches were recently merged; there is some collaboration underway to sync changes between the two repositories. In the future, this will save users the extra step of choosing a module.

Create an Auth0 Application

Here is the basic configuration to get started with Auth0 for Drupal.

Note that it’s very important that the callback you use in this configuration is HTTPS. You should always use HTTPS in production (or even during development if sensitive user accounts are being used).

  1. Create an Auth0 account and log into the Auth0 Dashboard.

  2. Create a new application and select Type as "Regular Web Applications".

  3. In the Settings tab, do the following:

    1. Add https://example.com/auth0/callback to the Allowed callback URLs section. Make sure you replace example.com with the domain name of your site. You can also add local URLs.

    2. Add https://example.com/user/logout to the allowed logout URLs section.

    3. Add https://example.com to the Allowed Origins (CORS) section to allow the origins that will be able to make requests.

Auth0 Client configuration

  1. Proceed to the next step and select PHP for "What technology are you using for your web app?"

  2. Go to Connections > Social and enable the social logins that you want to use (these links are located in left sidebar of the Auth0 Dashboard)

You are now done with the basic setup! Users can now create accounts, or log in using their credentials from the providers that you enabled in the previous step.

Optional Configuration

Additionally, Auth0 provides many features for building advanced authentication mechanisms, and it can determine how data is stored and passed to applications.

For example, Auth0 enables you to:

  • Use add-ons to generate access tokens for systems such as Salesforce, Azure Service Bus and SAP.

  • Configure social connections for authentication.

  • Implement username and password authentication to have an Auth0 DB or your own DB connected to store authentication information.

  • Use passwordless authentication to send a login link to email or OTPs to mobile.

  • Use multi-factor authentication.

  • Customize data shared with apps, but using simple JavaScript based rules.

Configure Auth0 in Drupal

Next, you'll need to configure Drupal to connect to the Auth0 Client we created:

Drupal Auth0 Basic Configuration

  1. Go to the Auth0 configuration page (admin/config/auth0) in your Drupal site’s admin area.

  2. Add the Auth0 Credentials Client ID, Domain and Client Secret. This information is in the Auth0 dashboard.

  3. Make sure you select RS256 as the "JWT signature algorithm". This is the default algorithm configured in the Auth0 Client.

Advanced Setup

Depending on how you want users to log in, you can use the Auth0 hosted login page or embed a widget in the Drupal login page/block:

  • Select Redirect login for SSO to use an Auth0 hosted login page. We recommend this option because it’s more secure. It is ideal if you have multiple web applications using the same authentication information — users will be logged in automatically without having to provide their credentials each time. If you want more control over how the widget looks using the hosted login approach, you can customize the look in the "Hosted Pages" section in the Auth0 Dashboard.

Similarly you can select other options, such as: allowing users to signup via Auth0, or requiring users to verify their email addresses before they can log in.

Drupal Auth0 Advanced Configuration

Next Steps

Now that you have done the basic Auth0 setup, it’s time to learn more about what Auth0 can bring to your Drupal site and explore how you can extend Auth0 functionality:

We’d love to hear about new ways you’ve found to implement Auth0 to streamline authentication. Leave us a comment to share your questions, experiences and use cases.

Apr 04 2018
Apr 04

Structuring Your Drupal Website

Drupal has always been a strong content management platform. The number one reason we use Drupal is because it so easily adapts to our clients’ content models. It enables us to easily map and structure many different types of complex content.

Let’s look at how we go about structuring that content in Drupal, and how we use terminology to define, group and link different types of content.

Content Entities

In Drupal 8, every piece of content is an entity. To structure a site, you want to define different types of entities that will store different types of content.

Let’s take a publishing website as an example. We’re going to create entities for: books, authors, editions, interviews, reviews, book collections, book categories, and so on. You can start by drawing a map of all these nouns. I like mapping out content on a whiteboard because it’s easy to erase and change your mind and it’s bigger than a piece of paper.

Content mapping on a white board

Relationships

Once you’ve mapped all the different types of content that will exist on your site, identify the connections between them. Simply draw arrows arrows between the content types that are related to one another.

For example:

  • A book has an author (or multiple authors): draw an arrow from book to author

  • A book can have editions: draw an arrow from book to edition

  • A book can have reviews, interviews: connect these

  • A book collection has books: group books by collection

  • A book has categories: associate books with topics and categories

Entity Terminology: Bundles, Nodes, Taxonomy, Paragraphs, Blocks

Nodes, taxonomy terms, custom blocks, and paragraphs are all different types of entities. Each entity type has unique properties that make it better suited for different use cases and content types.

Here’s a breakdown of the most important Drupal terminology you need to know to structure your content:

  • Node: A page of content is a node, accessible via its own URL
  • Taxonomy terms: Used to categorize other content, taxonomy terms live in a hierarchy. They can be used to filter content and create unique landing pages.
  • Paragraphs: Content that lives within other content and doesn’t need a dedicated URL is a paragraph.
  • Custom Block: Any content that will be reused throughout the site becomes a custom block. You can also embed a block in a node.
  • Bundle: An entity sub-type is a bundle. Usually, bundles can have unique fields and settings.
  • Field: A field is a component of the content, i.e. an ISBN, author’s name, or book title

Applying this Model to our Example Project

Here’s how we would decide which entity type to use for each content type:

  • Books and authors become nodes

  • Book categories become taxonomy terms

  • Interviews, reviews and editions could be paragraphs

  • Books and authors would be node bundles (aka content types)

  • A book category is a taxonomy bundle (aka vocabulary)

  • A book collection is a block bundle (block type)

  • Reviews and interviews are paragraph bundles (aka paragraph types)

  • A book collection that needs to be displayed on several pages becomes a block

Focusing on Each Entity to Create Fields

Once you’re looking at a book, you can start to think about what defines a book.

Ask yourself:

  • What information should it have?

  • Which information needs to be displayed?

  • How will we filter and order this content?

  • Will there be a single value for the field or multiple values?

List the various components of the content: title, author, ISBN, covers, genres, editions, reviews, interviews. Each of these will be a field.

Fields in Drupal can be single value (for example, each book has a single ISBN number) or multi-value (a book can have multiple reviews or authors). There are many other fields types that can store the content in a certain way that will affect how it can be displayed or used later (text, date, number, email, link, etc). A field that links one entity to another is a ‘reference’ field.

Information Architecture

So far we’ve talked about structuring your content using entities and bundles. But how do users actually access your content? When you’re building out your site map, you’ll probably picture top-level pages. These may link to dynamic lists of content, or they may have sub-pages that are added beneath them.

Linking to Content

In Drupal, we have three main ways to link to content: menus, views, and fields. In general, this is how we use them:

Menus are for static content: Menus are a static hierarchy of content. If you’re creating permanent content on the site that will be relevant for a long time, you’ll probably link to it through a menu.

Views are for dynamic content: Content that is ‘dynamic’ that will be added to frequently and is too abundant to add to a menu will probably be listed and linked to via views (the Drupal term for ‘list of content’).

Entity reference fields or link fields: You can also explicitly add a link from one content item to another using an entity reference field or a link field. For example, if you have a book and you want to have it link to three other hand-selected ‘related books’, you could create a ‘Content’ reference field for this.

You can go through your site map and figure out which pages are static (linked to by the menu) and dynamic content (linked via views). Landing pages tend to be connection pages. For example, a landing page might live in the menu, list a bunch of dynamic pages and also include explicit links to other pages via ‘calls to action’.  

Applying Menus and Views to Our Example

Using our example, you may have a static page for ‘About Us’, ‘Contact Information’, or ‘History of Publishing’. These would be created as pages and linked to via the menu.

You may also have a page that lists all the books and another that lists all the authors. Because your lists of books and authors are likely to change often, these lists should be created using views. When you add a new book or a new author, it automatically appears in the list.

Taxonomies make creating lists more interesting because we can create lists of content that are filtered by a particular taxonomy term. For example, if ‘prize winning’ is a book category, a taxonomy allows us to create a list of all the books that are ‘prize-winning’.

Finally, you might have a landing page for an upcoming book tour that includes details about the tour, a link to the book being promoted, and also links to other books by the author.

Conclusion

There are many more things to know to build a site with Drupal. But when you’re planning out your content, you simply need to be able to draw out the structure and communicate this with your team. Knowing the basic Drupal concepts will help you communicate clearly and think about the site’s architecture at a high level.

To read about a real-life project in which we built out book content in Drupal 8, read about our project for Princeton University Press.

Mar 19 2018
Mar 19

One of the most interesting features added in Drupal 8.5 is the new layout builder module. The layout builder lets you change the way your content is presented. You can add sections to display content using different layouts, and build out according to your design requirements. The exciting part is that you can combine these sections together to create truly customized pages. The user interface, though still a work-in-progress, is similar to page builders in systems like Square Space, WordPress, and Wix. Combine this UI with Drupal's content management features, and the layout builder is a really powerful site building tool.

The layout builder can be used in two ways. You can use it to create a layout for each content type on your site and you can also use it to create a layout for each individual piece of content. This second use case makes the layout builder a landing-page-building tool that content editors and marketers can use to create flexible pages within a Drupal site.

One might think of this module as a Drupal core version of the Display Suite or Panels modules.

The layout builder module is currently experimental, meaning that its API might change and it's not recommended to use it in production sites yet. That's because there's a risk that your layouts will stop working when you do an update because of changes to the module.

Configuring the Layout Builder Module for Content Types

Let's say that we want to display an article in two columns. One column for the image and another for our text fields:

Screenshot of a two column layout created with the layout builderA two-column layout created with the layout builder.

To be able to use the layout builder, enable the module named Layout Builder from the Extend page (admin/modules) in the admin section.

Layout builder module on the 'Extend' page

Having enabled the module, the next step is to configure the display of our article content type. For this example, we will modify the Default display of the Article content type. Simply go to Admin > Structure > Content types > Article > Manage Display (admin/structure/types/manage/article/display) and click on the Manage Layout button.

Manage layout for the article default display

Clicking on Manage Layout should take you to a page where you can modify the layout for articles. The layout is made up of sections and each section can display blocks and fields.

  • Sections: Each section can contain content arranged in a certain layout. Example: 2 columns, 3 columns, etc.
  • Inside each section, you can display:
    • Fields from the content being displayed. Example: title, body, tags, etc.
    • Blocks which appear on the Structure > Block Layout page. Example: Page title, tabs, blocks from the custom block library, etc.

For this example, we configure a 2-column layout with the image in the left column and some other fields like author name, body and tags in the right column.

Configure sections and blocks for the contentChoose the layout and arrange your blocks​​​​.

Once you are done configuring, click on the Save Layout link towards the top of the page. That's it! Now, when you visit the article view page, you should be able to see your layout in action.

Configuring the Layout Builder Module for Specific Nodes

On the Manage Display tab, you can also select a checkbox to 'Allow each content item to have a customized layout'. This means that each piece of content has its own 'Layout' tab where you can add sections and change the layout and content for each individual article.

The layout mechanism works the same way, and you can place sections on the page and pick the layout and content for each one.

Video Tutorial

Confused? Check out this video created by my colleague Suzanne Dergacheva explaining how the layout builder works. For more in-depth training on creating landing pages with Drupal using this and other techniques, see our Landing Page Architecture and Theming course. We're offering this course at DrupalCon Nashville in April.

[embedded content]

Mar 06 2018
Mar 06

After many years of development, Bootstrap had an official 4.0 release on January 18th, 2018. Bootstrap has been a popular front-end framework for several years and the release of the new version is really exciting!

Because of its popularity, there have always been lots of new front-end developers looking to learn Bootstrap and with the recent release of Bootstrap 4, I’ve been writing a Bootstrap & SASS course for Evolving Web. If you’re interested in learning Bootstrap 4 and SASS, you can find out about the course over here.

This post outlines a few of the differences between Bootstrap 3 and Bootstrap 4.

SASS

When Bootstrap 3 was first released in 2013, the only CSS pre-compiler option was to use LESS. A few years later, a SASS version was released.

From the get-go, Bootstrap is SASS only. This may sound like bad news, but the CSS community has rallied around SASS over LESS for the last few years. By creating a single SASS-based codebase, this means developers can focus on only one branch of the framework.

The Bootstrap documentation has information on many build tools that you can use to compile the SASS files.

Flexbox

In Bootstrap 3, the layout and grid system was based on the CSS float property. This worked well for most people. Bootstrap 4 is now based on Flexbox. If you're not familiar with Flexbox, check out this guide from CSS tricks.

Basing the layout and grid system on Flexbox allows for some handy options when creating your layouts.

One quick example: Have you ever had a grid of “cards” of varying content length that you wanted to all be the same height? Before, you would have to use some JavaScript to detect the height of the tallest one, then apply that height with inline CSS to get them to match. 

With Flexbox? You can do this with a purely CSS solution. Just one example where Flexbox makes layout much easier. 

Grid System

If you’ve used Bootstrap 3, you’re likely familiar with the list of breakpoint prefixes:

  • xs (extra small)
  • sm (small)
  • md (medium)
  • lg (large)

If you wanted to create different column layouts for each screen size, you would use these prefixes in your CSS classes, such as: ‘col-sm-6 col-md-9’.

The default breakpoints for these media queries were a little bit limiting too (though you could override them if you prefer). Here’s how they stacked up:

  • col-xs-* : (phones, less than 768px)
  • col-sm-* : (tablets, 768px and up)
  • col-md-* : (desktops, 992px and up)
  • col-lg-* : (large desktops, 1200px and up)

In Bootstrap 4, these media queries, breakpoints, and prefixes have changed. Here’s the list with their media queries:

  • col-* : (extra small, less than 576px)
  • col-sm-* : (small, 575px and up)
  • col-md-* : (medium, 768px and up)
  • col-lg-* : (large, 992px and up)
  • col-xl-* :  (extra large, 1140px and up)

In Bootstrap 4’s defaults, we’ve been given another breakpoint, “extra large”.

The other thing to note is that we no longer write a prefix for “extra small”. We simply write ‘col-*’ and it’s implied that it’s extra small.

One frustrating thing I found about Bootstrap 3 was layout options for smartphones, especially ones with larger screens. It always felt a little bit underbaked. But now with two breakpoints underneath the “tablet” breakpoint, this makes layout on those devices much easier.

One more thing to note with Bootstrap 4’s grid system is that, with Flexbox, if you don’t use a column prefix on your div elements, Flexbox is smart enough to figure out the width of each one. Or, if you have a 3-column layout, and only give a column prefix to one of those columns, the other two columns will have expand to fill the remaining space in the rest of the row.

Utility Classes

While using Bootstrap 3, I often found I had to write a separate file for little ‘helper’ CSS classes. Sometimes, I just want to add a little bit of margin or padding on a single element, so I had to create a specific CSS class so that I could apply it to my element.

Luckily, in Bootstrap 4, there’s a full set of default utilities that allow you to apply things like colors, positioning, border styles, alignment, and visibility of elements.

Want to add a border to an element, but only on the top? There’s a utility class for that. Want to add some some padding on just the right-hand side of an image? Yep, utility class for that. Want to float an element to the right, but only on medium-sized screens? You got it.

Browser Support

Bootstrap 3 supported all major mobile browsers and Internet Explorer 8+, though some CSS3 and HTML5 properties weren’t fully supported.

Bootstrap 4 also supports all major mobile browsers, however official support for Internet Explorer 8 and 9 has been removed. The framework only officially supports Internet Explorer 10 and up.

Documentation

This may seem strange to say, but one thing I love about Bootstrap 4 reading the documentation.

When visiting a section in Bootstrap 3’s documentation, you were presented with a very long page detailing everything within that section. Mentally, I found this taxing.

In Bootstrap 4, each section has sub-sections with their own page. This may seem like a small thing, but I found I was much more focused on the thing that I was trying to accomplish while reading the documentation. The Bootstrap framework comes with a lot of bells and whistles and, in Bootstrap 3, I constantly found myself reading something, scrolling down a bit too far, and then getting distracted by another component.

Bootstrap 4’s documentation structure also makes more sense to me and seem much more human-centric. The sections now are:

  • Getting Started
  • Layout
  • Content
  • Components
  • Utilities
  • Extend

The ‘Content’ section is essentially for how basic typography, images, and tables are displayed in the browser, while 'Components' focus on functional elements like buttons, navigation, forms, etc. 

And if you ever get confused, the documentation also has an auto-complete search box that quickly gets you to the sub-section you're looking for.

Using Bootstrap 4 with Drupal

Now that Bootstrap 4 is out and ready to use, there are many Drupal front-end developers eager to start using it. For the moment, the Bootstrap theme doesn't have a release that uses Bootstrap 4, but you can use it yourself by downloading the SASS files and compiling them along with your own styles in your theme.

Creating a theme from scratch like this has downsides (you have to figure out where to put classes, and do the work of deciding which parts of Bootstrap to use) but it also gives you more flexibility in how you adopt the framework. If you have experience creating Drupal themes and want to take advantage of Bootstrap 4's features, this is a great approach. 

Conclusion

The changes between Bootstrap 3 and Bootstrap 4 are significant, but there are lots of improvements to take advantage of. It won't be hard for Bootstrap users to adapt to the new version of the framework, and it will be easier to pick up for those learning Bootstrap for the first time. But it will take time to upgrade from Bootstrap 3 to Bootstrap 4 on your existing projects.

Feb 26 2018
Feb 26

While working on a project with Acquia Dev Desktop (ADD), we needed to run a specific version of PHP which is not included with ADD by default. We started hacking ADD and came up with our own solution. For those in a hurry, you can go directly to the solution.

The Problem

While working for one of our clients, we had to work with some tools which were a part of their workflow. Their websites were hosted on Acquia Cloud so they were using Acquia Dev Desktop (ADD) - Acquia's development stack and cloud client. This tool allows developers to "run and develop Drupal sites locally and to optionally sync them with Acquia Cloud".

At the time of writing this post ADD is was version 2.1 and it supported only up to PHP 7.0.14. At first, we thought it was good enough. But soon we discovered that the cloud servers were running more cutting-edge versions such as PHP 7.1.8. 

The first issue came when we had to update our Composer packages. Running composer from different environments running different versions of PHP may result in each environment downloading a different version of the same package. A workaround is to always have the same environment run the composer update. However, we needed to ensure that the environment with the oldest version of PHP was able to run all the updated libraries. For example, the latest doctrine/common libraries require PHP ~7.1, so using ADD 2 with PHP 7.0.14 we couldn't run it.

Another issue arose when we decided to update to Drupal 8.4.x. According to an issue on drupal.org, Drupal 8.4.x requires Drush 8.1.12+, but ADD 2 ships with Drush 8.1.10.

Facing such issues, we asked Google, "how to add a version of PHP to Acquia Dev Desktop?" No good results came up so we decided to start hacking ADD and ultimately found a solution.

Adding a specific version of PHP to Acquia Dev Desktop

Our solution worked on a Mac, but we believe it should work somewhat similarly on Windows.

Step 1: Install the required version of PHP

Install the desired PHP version with Brew, in our situation it was PHP 7.1.8_20:

$ brew install homebrew/php/php71

Step 2: Copy PHP files into Acquia Dev Desktop

Stop ADD if it's running and copy the PHP files into the Acquia Dev Desktop directories:

$ cp -r /usr/local/Cellar/php71/7.1.8_20/ /Applications/DevDesktop​/php7_1
$ cp /usr/local/etc/php/7.1/php.ini /Applications/DevDesktop​​/php7_1/bin/php.ini

Note: We tried to create a symlink to prevent file duplication but it didn't work, so we ended simply copying the files into ADD, respecting its directories nomenclature and structure.

Step 3: Make Acquia Dev Desktop detect the new version of PHP

Edit /Applications/DevDesktop/Acquia Dev Desktop.app/Contents/MacOS/static.ini and after the last contiguous line under [php/4] add the following lines:

[php/5]
id=php7_1
executablePath=php7_1/bin/php
cgiExecutablePath=php7_1/bin/php-cgi
configPath=/Applications/DevDesktop/php7_1/bin/php.ini

Note: If you are using Finder to navigate to the file, you may have to right click on the Acquia Dev Desktop application icon to see its content.

Step 4: Configure Acquia Dev Desktop

Open the ADD Preferences and select the Config tab. Now, in the Default PHP Version, select the one we just added. Make sure you select PHP mode Fast CGI and have PHP use the php.ini we previously copied into ADD in Step 2. Back in the ADD Preferences main window, in the left panel select the site you are working on, and then in Default PHP Version select the desired version. Then, click Ok and restart Apache.

Step 5: Configure Drush to use the same PHP version

To configure ADD's Drush to use the same PHP version, edit /Applications/DevDesktop/tools/drush and replace the following:

# Before
[ -z "$PHP_ID" ] && PHP_ID=php5_5    
# After
export PHP_ID="php7_1"

Step 6: Update Acquia Dev Desktop's version of Drush

To udpate Acquia Dev Desktop's Drush, edit /Applications/DevDesktop/tools/composer.json and make the following change:

// Before
"drush/drush": "8.1.10"
// After
"drush/drush": "^8.1.12"

Note: Drupal 8.4.x requires Drush 8.1.12+.

Now, in the terminal, go to the same directory as composer.json and run this command to finish:

composer update --optimize-autoloader

Et voilà! We have just installed a custom version of PHP on Acquia Dev Desktop. Feel free to share your experiences in the comments below to help other fellow readers.

Feb 26 2018
Feb 26

While working on a project with Acquia Dev Desktop (ADD), we needed to run a specific version of PHP which is not included with ADD by default. We started hacking ADD and came up with our own solution. For those in a hurry, you can go directly to the solution.

This article would not have been possible without significant contributions from my colleague Benoit Borrel.

The Problem

While working for one of our clients, we had to work with some tools which were a part of their workflow. Their websites were hosted on Acquia Cloud so they were using Acquia Dev Desktop (ADD) - Acquia's development stack and cloud client. This tool allows developers to "run and develop Drupal sites locally and to optionally sync them with Acquia Cloud".

At the time of writing this post ADD is was version 2.1 and it supported only up to PHP 7.0.14. At first, we thought it was good enough. But soon we discovered that the cloud servers were running more cutting-edge versions such as PHP 7.1.8. 

The first issue came when we had to update our Composer packages. Running composer from different environments running different versions of PHP may result in each environment downloading a different version of the same package. A workaround is to always have the same environment run the composer update. However, we needed to ensure that the environment with the oldest version of PHP was able to run all the updated libraries. For example, the latest doctrine/common libraries require PHP ~7.1, so using ADD 2 with PHP 7.0.14 we couldn't run it.

Another issue arose when we decided to update to Drupal 8.4.x. According to an issue on drupal.org, Drupal 8.4.x requires Drush 8.1.12+, but ADD 2 ships with Drush 8.1.10.

Facing such issues, we asked Google, "how to add a version of PHP to Acquia Dev Desktop?" No good results came up so we decided to start hacking ADD and ultimately found a solution.

Adding a specific version of PHP to Acquia Dev Desktop

Our solution worked on a Mac, but we believe it should work somewhat similarly on Windows.

Step 1: Install the required version of PHP

Install the desired PHP version with Brew, in our situation it was PHP 7.1.8_20:

$ brew install homebrew/php/php71

Step 2: Copy PHP files into Acquia Dev Desktop

Stop ADD if it's running and copy the PHP files into the Acquia Dev Desktop directories:

$ cp -r /usr/local/Cellar/php71/7.1.8_20/ /Applications/DevDesktop​/php7_1
$ cp /usr/local/etc/php/7.1/php.ini /Applications/DevDesktop​​/php7_1/bin/php.ini

Note: We tried to create a symlink to prevent file duplication but it didn't work, so we ended simply copying the files into ADD, respecting its directories nomenclature and structure.

Step 3: Make Acquia Dev Desktop detect the new version of PHP

Edit /Applications/DevDesktop/Acquia Dev Desktop.app/Contents/MacOS/static.ini and after the last contiguous line under [php/4] add the following lines:

[php/5]
id=php7_1
executablePath=php7_1/bin/php
cgiExecutablePath=php7_1/bin/php-cgi
configPath=/Applications/DevDesktop/php7_1/bin/php.ini

Note: If you are using Finder to navigate to the file, you may have to right click on the Acquia Dev Desktop application icon to see its content.

Step 4: Configure Acquia Dev Desktop

Open the ADD Preferences and select the Config tab. Now, in the Default PHP Version, select the one we just added. Make sure you select PHP mode Fast CGI and have PHP use the php.ini we previously copied into ADD in Step 2. Back in the ADD Preferences main window, in the left panel select the site you are working on, and then in Default PHP Version select the desired version. Then, click Ok and restart Apache.

Step 5: Configure Drush to use the same PHP version

To configure ADD's Drush to use the same PHP version, edit /Applications/DevDesktop/tools/drush and replace the following:

# Before
[ -z "$PHP_ID" ] && PHP_ID=php5_5    
# After
export PHP_ID="php7_1"

Step 6: Update Acquia Dev Desktop's version of Drush

To udpate Acquia Dev Desktop's Drush, edit /Applications/DevDesktop/tools/composer.json and make the following change:

// Before
"drush/drush": "8.1.10"
// After
"drush/drush": "^8.1.12"

Note: Drupal 8.4.x requires Drush 8.1.12+.

Now, in the terminal, go to the same directory as composer.json and run this command to finish:

composer update --optimize-autoloader

Et voilà! We have just installed a custom version of PHP on Acquia Dev Desktop. Feel free to share your experiences in the comments below to help other fellow readers.

Jan 16 2018
Jan 16

With so many shiny new Drupal 8 modules emerging this year, we were hard pressed to pick our recommendations for 2018. It came down to asking ourselves: which modules are we excited about implementing in 2018… the ones that will make our projects better, faster, smarter brighter? Read on for our list of Drupal 8 modules we're excited about.

Configuration Split

The Drupal Configuration Split module makes Drupal 8 configuration management more customizable. This means you can set up some configurations that can be edited on the live site, without interfering with your configuration management workflow. Instead of importing and exporting the whole set of a site’s configuration, the module enables you to define sets of configuration to export to different directories that automatically merge again when they are imported.

Content Workflow

If you’ve shied away from implementing complicated workflows in the past, you’ll enjoy how the Content Workflow module makes it easy to set up a simple workflow. This core module enables you to streamline the content publication process by defining states for content (such as draft, unpublished and published) and then manage permissions around these states.

Deploy

The Deploy content staging module makes it easier to stage and preview content for a Drupal site. It’s often used to deploy content from one Drupal site to another. Redesigned for Drupal 8, the new version is based on the Multiversion and Replication modules, making it more efficient and flexible.

Drupal Commerce

The new full release of Drupal Commerce has us very excited to start building ecommerce sites in Drupal 8. Fully rebuilt for Drupal 8, the new Drupal Commerce module doesn’t presume a specific ecommerce business model, enabling developers to customize the module to suit a merchant’s needs.

JSON API

The JSON API module formats your JSON requests and responses to make them compliant with the JSON API Specification. This module is the key to setting up Drupal as a backend so you can implement the font-end with React or your front-end platform of choice.

Schema.org Metatag

Ramp up your SEO with structured data that helps Google categorize and display your pages. The Schema.org Metatag module allows you to add and validate Schema.org structured data as JASON LD, one of Google’s preferred data formats.

UI Patterns

If you’re looking for a way to implement an ‘atomic design’ in Drupal the UI Patterns project is a nice option. It consists of six modules that allow you to define and expose UI patterns as Drupal plugins. You can use them as drop-in templates for all entity types — paragraphs, views, field groups and more.

Webform

The Drupal webform module has a new release candidate for Drupal 8. A ton of work has been put into the module; it’s like a whole form-building application inside your Drupal site. Quickly integrate forms into any Drupal 8 website. enables you to build, publish and duplicate webforms. You can also manage and download submissions, and send confirmations to users.

Which Drupal 8 modules are doing it for you?

We’d love to hear about which Drupal 8 modules your team is excited about. Leave us a comment.

Jan 04 2018
Jan 04

In the last few projects I've worked on at Evolving Web, we've come across a common requirement: having a collapsible section of the site on mobile devices containing the site's logo, a menu and other Drupal blocks. The Responsive Menus module is quite popular, but it only works with menu blocks - no logo, no custom text. Since we couldn't find any contrib module to solve the problem, we wrote some custom JavaScript to integrate a JavaScript plugin called Sidr, which inspired me to write a Sidr integration module for Drupal. In this article, we will discuss how the module works and how you can get it working in your next project.

Here's a screenshot from a quick demo site I prepared. You click on the hamburger menu, and the black sidr region appears on the left. You click it again and the region slides back out.

Screenshot of a collapsible Sidr in DrupalA quick demo with a Sidr panel in Drupal with the Dark theme

Installing the Sidr module and libraries

To install the module, we must install the module files and then the Sidr libraries.

  • Download the Sidr module into the modules or modules/contrib directory in your Drupal project and install the module
  • Install the Sidr libraries
    • Download the version of Sidr recommended in the module's README file, which at the time of writing this article is Sidr 2.2.1
    • Once downloaded, copy the dist directory in the Sidr project to the libraries directory in your Drupal project and rename it to sidr
    • At this point, there should be valid JavaScript file at DRUPAL/libraries/sidr/jquery.sidr.js and the Drupal status report page should show the Sidr libraries as Installed

Sidr library statusSidr library status

  • Configure the Sidr theme from the admin/config/media/sidr page. Here's some quick info about the themes:
    • The dark (default) and the light themes are provided by Sidr.
    • Typically, for a project with a custom look and feel, you'll use the bare theme. This provides minimal CSS, allowing you to style the .sidr element and its children in your theme. Yeah!

Sidr global settingsSidr global settings

Congratulations! You now have the module installed. All that's left now is a bit of configuration.

Configure collapsible content

Depending on the project requirements, you might have one or more sidr instances. For this article, let's say you want a sliding panel on the left with the following contents:

  • Site logo (the site branding block).
  • The main menu (the main menu block).

We can achieve this using two different approaches:

With a custom region (recommended)

Create a custom region named, say, Drawer (Left) in your theme where you can place whatever blocks you want to show in your Sidr. We will then configure the Sidr plugin to use the contents of this region to populate the collapsible panel (discussed below).

Note: Make sure you hide this region using CSS because Sidr will copy the contents of the region in to a div.sidr element during its initialization.

Without a custom region

If all your blocks are already present on your page, you can use multiple jQuery selectors in the Source configuration for the Sidr trigger block (discussed below) and the Sidr plugin will copy the contents of those elements and put them in the Sidr. Sidr will not copy the elements for the jQuery selector, but all of their children. This is the reason why I prefer to use a custom region. Using the above-mentioned custom region approach, you can preserve wrapper elements which give you nice CSS selectors for theming your Sidr.

Configure a trigger button

Now that we have set up the contents for the collapsible region, we are ready to create a Sidr trigger block. This trigger block will provide a button to open and close the Sidr panel. To do this,

  • Go to the Block management admin/structure/block page.
  • Click the Place block button for the region where you want to place the trigger button (usually somewhere in the header).
  • Choose the Sidr trigger block, configure it and save it. Some of the configuration options have been discussed below.

Sidr trigger settingsSidr trigger settings

Trigger text and icon

The trigger text is the text which is displayed on the Sidr trigger button. You can also enter some custom HTML in the Advanced settings > Trigger icon field to configure an icon, say, a hamburger icon or an <i class="fa fa-bars"></i>.

Note: It is compulsory to have either a trigger text or a trigger icon. You can also have both if you want.

Source

The source is from where the Sidr panel will be populated. It can be one of the following:

  • A jQuery selector: If you provide a jQuery selector, the inner HTML of the selected elements will be copied into the relevant Sidr panel. You might be interested in the renaming option which makes Sidr rename the ID attributes of the copied elements to avoid getting repeated DOM IDs. Here are some examples:
    • Using a custom region, source should look like .region-drawer-left or .region-drawer-right or whatever you name your custom region.
    • Without a custom region, you will have to refer to various blocks like #block-site-branding, #block-main-menu, #block-copyright-notice.
  • A URL: If source is a URL, the content on the URL will be fetched via AJAX and displayed in the Sidr panel.
  • A callback: You can even provide a JavaScript function as the source, in which case, the contents returned by the callable will be used to populate the Sidr panel. If you do not like the idea of copied elements provided by the jQuery selector option above, a callback might give you more flexibility.

Most of the Advanced settings are optional and you can learn about them by reading the Sidr documentation. Once you have configured everything, all you'll be missing is some custom styling to bring your Sidr to life.

Feel free to leave comments about problems you face and any suggestions you might have. You might want to read the Sidr module's project page and issue queue for the latest updates.

Dec 18 2017
Dec 18

Usually, Drupal migrations get run at the beginning of a project to get all your content into Drupal. But sometimes, you need to create a migration that runs on a regular basis. For example, you have an external database of courses and programs maintained by a university that needs to be displayed on a Drupal site. Another example: you have a database of book data that needs to be pulled into Drupal nightly.

When working with migrations where the source files are updated every day, it can get really tedious to download the updated source files manually each time the migration runs.

In this tutorial, we'll write a source plugin based on the CSV source plugin which will allow us to automatically download CSV files from a remote server via SFTP before running migrations. This article was co-authored by my colleague David Valdez - gracias David for your contribution.

The Problem

In a project we worked on recently, we had the following situation:

  • CSV files are updated by a PowerShell script every night on the client's server.
  • These CSV files are accessible via SFTP.

Our task is to download the CSV source files over SFTP and to use them as our migration source.

Before We Start

  • This articles assumes that you can write custom modules. If you have never written a custom module, you can try reading this article on creating custom modules.
  • It is assumed that you have working knowledge of migrations in Drupal 8. If you are new to Drupal 8 migrations, I recommend you to start by reading these articles first:

The Plan

The goal is to avoid downloading the file manually every time we run our migrations. So we need a way to doing this automatically everytime we execute a migration. To achieve this, we create a custom source plugin extending the CSV plugin provided by the Migrate Source CSV module, which will download CSV files from a remote server and pass it to the CSV plugin to process them.

The Source Migrate Plugin

To start, let's create a custom module and call it migrate_example_source and implement a custom migrate source plugin by creating a PHP class inside it at /src/Plugin/migrate/source/MigrateExampleSourceRemoteCSV.php

We start implementing the class by simply extending the CSV plugin provided by the migrate_source_csv module:
namespace Drupal\migrate_source_csv\Plugin\migrate\source;

use Drupal\migrate_source_csv\Plugin\migrate\source\CSV as SourceCSV;
use phpseclib\Net\SFTP

/**
 * @MigrateSource(
 *   id = "migrate_example_source_remote_csv"
 * )
 */
class MigrateExampleSourceRemoteCSV extends SourceCSV {}

If you are building a source plugin from scratch, you will need to extend the SourcePluginBase class instead of the CSV class given in this example. Adding the annotation @MigrateSource is very important because that is what will make the migrate module detect our source plugin. In our plugin, we use the phpseclib/phpseclib libraries to make SFTP connections. Hence, we need to include the libraries in our project by running the following command in the Drupal root:

composer require phpseclib/phpseclib

Our plugin will download the source CSV file and will simply pass it to the CSV plugin to do the rest. We do the download when the plugin is being instantiated like this:

/**
 * {@inheritdoc}
 */
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
  // If SFTP connection parameters are present.
  if (!empty($configuration['sftp'])) {
    // A settings key must be specified.
    // We use the settings key to get SFTP configuration from $settings.
    if (!isset($configuration['sftp']['settings'])) {
      throw new MigrateException('Parameter "sftp/settings" not defined for Remote CSV source plugin.');
    }
    // Merge plugin settings with global settings.
    $configuration['sftp'] += Settings::get('sftp', []);
    // We simply download the remote CSV file to a temporary path and set
    // the temporary path to the parent CSV plugin.
    $configuration['path'] = $this->downloadFile($configuration['sftp']);
  }
  // Having downloaded the remote CSV, we simply pass the call to the parent plugin.
  parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
}

In the constructor we are using global SFTP credentials with Settings::get(). We need to define the credentials in settings.php like this:

$settings['sftp'] = array(
  'default' => [
    'server' => 'ftp.example.com',
    'username' => 'username',
    'password' => 'password',
    'port' => '22',
  ],
);

Once we have the credentials of the FTP server we use a downloadFile() method to download the remote CSV file. Here's an extract of the relevant code:

protected function downloadFile(array $conn_config) {
  ...
  // Prepare to download file to a temporary directory.
  $path_remote = $conn_config['path'];
  $basename = basename($path_remote);
  $path_local = file_directory_temp() . '/' . $basename;
  ...
  // Download file by SFTP and place it in temporary directory.
  $sftp = static::getSFTPConnection($conn_config);
  if (!$sftp->get($path_remote, $path_local)) {
    throw new MigrateException('Cannot download remote file ' . $basename . ' by SFTP.');
  }
  ...
  // Return path to the local of the file.
  // This will in turn be passed to the parent CSV plugin.
  return $path_local;
}

Note: The code block above has been simplified a bit. If you see the actual source plugin, there are some lines of code which make things more compatible with the migration_lookup plugin.

This method creates an SFTP connection, downloads the file to a temporary location and returns the path to the downloaded file. The temporary file path is then passed to the Migrate Source CSV and that's it! Finally, to use the plugin in our migration we just set our plugin as the source/plugin:

id: migrate_example_content
label: 'Example content'
...
source:
  plugin: migrate_example_source_remote_csv
  # Settings for our custom Remote CSV plugin.
  sftp:
    settings: sftp
    path: "/path/to/file/example_content.csv"
  # Settings for the contrib CSV plugin.
  header_row_count: 1
  keys:
    - id
...

The code for this plugin and the example module is available at migrate_example_source. Great!

Nov 08 2017
Nov 08

A few weeks ago, us at Evolving Web finished migrating the Princeton University Press website to Drupal 8. The project was over 70% migrations. In this article, we will see how Blackfire helped us optimize our migrations by changing around two lines of code.

Before we start

  • This article is mainly for PHP / Drupal 8 back-end developers.
  • It is assumed that you know about the Drupal 8 Migrate API.
  • Code performance is analyzed with a tool named Blackfire.
  • Front-end performance analysis is not in the scope of this article.

The Problem

Here are some of the project requirements related to the problem. This would help you get a better picture of what's going on:

  • A PowerShell script exports a bunch of data into CSV files on the client's server.
  • A custom migration plugin PUPCSV uses the CSV files via SFTP.
  • Using hook_cron() in Drupal 8, we check hashes for each CSV.
  • If a file's MD5 hash changes, the migration is queued for import using the Drupal 8 Queue API.
  • The CSV files usually have 2 types of changes:
    • Certain records are updated here and there.
    • Certain records are added to the end of the file.
  • When a migration is executed, migrate API goes line-by-line, doing the following things for every record:
    • Read a record from the data source.
    • Merge data related to the record from other CSV files (kind of an inner join between CSVs).
    • Compute hash of the record and compare it with the hash stored in the database.
    • If a hash is not found in the database, the record is created.
    • If a hash is found and it has changed, the record is updated.
    • If a hash is unchanged, no action is taken.

While running migrations, we figured out that it was taking too much time for migrations to go through the CSV files, simply checking for changes in row hashes. So, for big migrations with over 40,000 records, migrate was taking several minutes to reach the end of file even on a high-end server. Since we were running migrate during cron (with Queue Workers), we had to ensure that any individual migration could be processed below the 3 minute PHP maximum execution time limit available on the server.

Analyzing migrations with Blackfire

At Evolving Web, we usually analyze performance with Blackfire before any major site is launch. Usually, we run Blackfire with the Blackfire Companion which is currently available for Google Chrome and Firefox. However, since migrations are executed using drush, which is a command line tool, we had to use the Blackfire CLI Tool, like this:

$ blackfire run /opt/vendor/bin/drush.launcher migrate-import pup_subjects
Processed 0 items (0 created, 0 updated, 0 failed, 0 ignored) - done with 'pup_subjects'

Blackfire Run completed

Upon analyzing the Blackfire reports, we found some 50 unexpected SQL queries being triggered from somewhere within a PUPCSV::fetchNextRow() method. Quite surprising! PUPCSV refers to a migrate source plugin we wrote for fetching CSV files over FTP / SFTP. This plugin also tracks a hash of the CSV files and thereby allows us to skip a migration completely if the source files have not changed. If the source hash changes, the migration updates all rows and when the last row has been migrated, we store the file's hash in the database from PUPCSV::fetchNextRow(). As a matter of fact, we are preparing another article about creating custom migrate source plugin, so stay tuned.

We found one database query per row even though no record was being created or updated. Didn't seem to be very harmful until we saw the Blackfire report.

Screenshot of Blackfire report highlighting the problem

Code before Blackfire

Taking a closer look at the RemoteCSV::fetchNextRow() method, a call to MigrateSourceBase::count() was found. It was found that the count() method was taking 40% of processing time! This is because it was being called for every row in the CSV. Since the source/cache_counts parameter was not set to TRUE in the migration YAML files, the count() method was iterating over all items to get a fresh count for each call! Thus, for a migration with 40,000 records, we were going through 40,000 x 40,000 records and the PHP maximum execution time was being reached even before migrate could get to the last row! Here's a look at the code.

protected function fetchNextRow() {
  // If the migration is being imported...
  if (MigrationInterface::STATUS_IMPORTING === $this->migration->getStatus()) {
    // If we are at the last row in the CSV...
    if ($this->getIterator()->key() === $this->count()) {
      // Store source hash to remember the file as "imported".
      $this->saveCachedFileHash();
    }
  }
  return parent::fetchNextRow();
}

Code after Blackfire

We could have added the cache_counts parameter in our migration YAML files, but any change in the source configuration of the migrations would have made migrate API update all records in all migrations. This is because a row's hash is computed as something like hash($row + $source). We did not want migrate to update all records because we had certain migrations which sometimes took around 7 hours to complete. Hence, we decided to statically cache the total record count to get things back in track:

protected function fetchNextRow() {
  // If the migration is being imported...
  if (MigrationInterface::STATUS_IMPORTING === $this->migration->getStatus()) {
    // Get total source record count and cache it statically.
    static $count;
    if (is_null($count)) {
      $count = $this->doCount();
    }
    // If we are at the last row in the CSV...
    if ($this->getIterator()->key() === $count) {
      // Store source hash to remember the file as "imported".
      $this->saveCachedFileHash();
    }
  }
  return parent::fetchNextRow();
}

Problem Solved. Merci Blackfire!

After the changes, we ran Blackfire again and found things to be 52% faster for a small migration with 50 records.

Blackfire before-after comparison report

For a bigger migration with 4,359 records the migration import time reduced from 1m 47s to only 12s which means a 98% improvement. Asking why we didn't include the screenshot for the bigger migration? We did not (or rather could not) generate a report for the big migration because of two reasons:

  • While working, Blackfire stores function call and other information to memory. Running a huge migration with Blackfire might be a bit slow. Besides, our objective was to find the problem and we could do that more easily while looking at smaller figures.
  • When running a migration with thousands of rows, the migration functions are called over thousands of times! Blackfire collects data for each of these function calls, hence, the collected data sometimes becomes too heavy and Blackfire rejects the huge data payload with an error message like this:
The Blackfire API answered with a 413 HTTP error ()
Error detected during upload: The Blackfire API rejected your payload because it's too big.

Which makes a lot of sense. As a matter of fact, for the other case study given below, we used the --limit=1 parameter to profile code performance for a single row.

A quick brag about another 50% Improvement?

Apart from this jackpot, we also found room for another 50% improvement (from 7h to 3h 32m) for one of our migrations which was using the Touki FTP library. This migration was doing the following:

  • Going through around 11,000 records in a CSV file.
  • Downloading the files over FTP when required.

A Blackfire analysis of this migration revealed something strange. For every row, the following was happening behind the scenes:

  • If a file download was required, we were doing FTP::findFileByName($name).
  • To get the file, Touki was:
    • Getting a list of all files in the directory;
    • Creating File objects for every file;
    • For every file object, various permission, owner and other objects were created.
    • Passing all the files through a callback to see if it's name was $name.
    • If the name was matching, the file was returned and all other File objects were discarded.

Hence, for downloading every file, Touki FTP was creating 11,000 File objects of which it was only using one! To resolve this, we decided to use a lower-level FTP::get($source, $destination) method which helped us bypass all those 50,000 or more objects which were being created per record (approximately, 11,000 * 50,000 or more for all records). This almost halved the import time for that migration when working with all 11,000 records! Here's a screenshot of Blackfire's report for a single row.

Blackfire before-after comparison report

So the next time you think something fishy is going on with code you wrote, don't forget to use use Blackfire! And don't forget to leave your feedback, questions and even article suggestions in the comments section below.

More about Blackfire

Blackfire is a code profiling tool for PHP which gives you nice-looking reports about your code's performance. With the help of these reports, you can analyze the memory, time and other resources consumed by various functions and optimize your code where necessary. If you are new to Blackfire, you can try these links:

Apart from all this, the paid version of Blackfire lets you set up automated tests and gives you various recommendations for not only Drupal but various other PHP frameworks.

Next Steps

  • Try Blackfire for free on a sample project of your choice to see what you can find.
  • Watch video tutorials on Blackfire's YouTube channel.
  • Read the tutorial on creating custom migration source plugins written by my colleague (coming soon).
Aug 24 2017
Aug 24

When content URLs change during migrations, it is always a good idea to do something to handle the old URLs to prevent them from suddenly starting to throw 404s which are bad for SEO. In this article, we'll discuss how to migrate URL aliases provided by the path module (part of D8 core) and URL redirects provided by the redirect module.

The Problem

Say we have two CSV files (given to us by the client):

The project requirement is to:

  • Migrate the contents of article.csv as article nodes.
  • Migrate the contents of category.csv as terms of a category terms.
  • Make the articles accessible at the path blog/{{ category-slug }}/{{ article-slug }}.
  • Make blog/{{ slug }}.php redirect to article/{{ article-slug }}.

Here, the term slug refers to a unique URL-friendly and SEO-friendly string.

Before We Start

Migrate Node and Category Data

This part consists of two simple migrations:

The article data migration depends on the category data migration to associate each node to a specific category like:

# Migration processes
process:
  ...
  field_category:
    plugin: 'migration_lookup'
    source: 'category'
    migration: 'example_category_data'
    no_stub: true
  ...

So, if we execute this migration, we will have all categories created as category terms and 50 squeaky new nodes belonging to those categories. Here's how it should look if we run the migrations using drush:

$ drush migrate-import example_article_data,example_category_data
Processed 5 items (5 created, 0 updated, 0 failed, 0 ignored) - done with 'example_category_data'
Processed 50 items (50 created, 0 updated, 0 failed, 0 ignored) - done with 'example_article_data'

Additionally, we will be able to access a list of articles in each category at the URL blog/{{ category-slug }}. This is because of the path parameter we set in the category data migration. The path parameter is processed by the path module to create URL aliases during certain migrations. We can also use the path parameter while creating nodes to generate URL aliases for those nodes. However, in this example, we will generate the URL aliases in a stand-alone migration.

Generate URL Aliases with Migrations

The next task will be to make the articles available at URLs like /blog/{{ category-slug }}/{{ article-slug }}. We use the example_article_alias migration to generate these additional URL aliases. Important sections of the migration are discussed below.

Source

source:
  plugin: 'csv'
  path: 'article.csv'
  ...
  constants:
    slash: '/'
    source_prefix: '/node/'
    alias_prefix: '/blog/'
    und: 'und'

We use the article.csv file as our source data to iterate over articles. Also, we use source/constants to define certain data which we want to use in the migration, but we do not have in the CSV document.

Destination

destination:
  plugin: 'url_alias'

Since we want to create URL aliases, we need to use the destination plugin url_alias provided by the path module. Reading documentation or taking a quick look at the plugin source at Drupal\path\Plugin\migrate\destination\UrlAlias::fields(), we can figure out the fields and configuration supported by this plugin.

Process

...
temp_nid:
  plugin: 'migration_lookup'
  source: 'slug'
  migration: 'example_article_data'
...
temp_category_slug:
    # First, retrieve the ID of the taxonomy term created during the "category_data" migration.
    -
      plugin: 'migration_lookup'
      source: 'category'
      migration: 'example_category_data'
    # Use a custom callback to get the category name.
    -
      plugin: 'callback'
      callable: '_migrate_example_paths_load_taxonomy_term_name'
    # Prepare a url-friendly version for the category.
    -
      plugin: 'machine_name'

Since we need to point the URL aliases to the nodes we created during the article data migration, we use use the migration_lookup plugin (formerly migration) to read the ID of the relevant node created during the article data migration. We store the node id in temp_nid. I added the prefix temp_ to the property name because we just need it temporarily for calculating another property and not for using it directly.

Similarly, we need to prepare a slug for the category to which the node belongs. We will use this slug to generate the alias property.

source:
  plugin: 'concat'
  source:
    - 'constants/source_prefix'
    - '@temp_nid'

Next, we generate the source, which is the path to which the alias will point. We do that by simply concatenating '/nid/' and '@temp_nid' using the concat plugin.

alias:
  plugin: 'concat'
  source:
    - 'constants/alias_prefix'
    - '@temp_category_slug'
    - 'constants/slash'
    - 'slug'

And finally, we generate the entire alias by concatenating '/article/', '@temp_category_slug', a '/' and the article's '@slug'. After running this migration like drush migrate-import example_article_alias, all the nodes should be accessible at /article/{{ category-slug }}/{{ article-slug }}.

Generate URL Redirects with Migrations

For the last requirement, we need to generate redirects, which takes us to the redirect module. So, we create another migration named example_article_redirect to generate redirects from /blog/{{ slug }}.php to the relevant nodes. Now, let's discuss some important lines of this migration.

Source

constants:
  # The source path is not supposed to start with a "/".
  source_prefix: 'blog/'
  source_suffix: '.php'
  redirect_prefix: 'internal:/node/'
  uid_admin: 1
  status_code: 301

We use source/constants to define certain data which we want to use in the migration, but we do not have in the CSV document.

Destination

destination:
  plugin: 'entity:redirect'

In Drupal 8, every redirect rule is an entity. Hence, we use the entity plugin for the destination.

Process

redirect_source:
  plugin: 'concat'
  source:
    - 'constants/source_prefix'
    - 'slug'
    - 'constants/source_suffix'

First, we determine the path to be redirected. This will be the path as in the old website, example, blog/{{ slug }}.php without a / in the front.

redirect_redirect:
  plugin: 'concat'
  source:
    - 'constants/redirect_prefix'
    - '@temp_nid'

Just like we did for generating aliases, we read node IDs from the article data migration and use them to generate URIs to which the user should be redirected when they visit one of the /blog/{{ slug }}.php paths. These destination URIs should be in the form internal:/node/{{ nid }}. The redirect module will intelligently use these URIs to determine the URL alias for those paths and redirect the user to the path /article/{{ slug }} instead of sending them to /node/{{ nid }}. This way, the redirects will not break even if we change the URL alias for a particular node after running the migrations.

# We want to generate 301 permanent redirects as opposed to 302 temporary redirects.
status_code: 'constants/status_code'

We also specify a status_code and set it to 301. This will create 301 permanent redirects as opposed to 302 temporary redirects. Having done so and having run this third migration as well, we are all set!

Migration dependencies

migration_dependencies:
  required:
    - 'example_article_data'

Since the migration of aliases and the migration of redirects both require access to the ID of the node which was generated during the article data migration, we need to add the above lines to define a migration_dependency. It will ensure that the example_article_data migration is executed before the alias and the redirect migrations. So if we run all the migrations of this example, we should see them executing in the correct order like:

$ drush mi --tag=example_article
Processed 5 items (5 created, 0 updated, 0 failed, 0 ignored) - done with 'example_category_data'
Processed 50 items (50 created, 0 updated, 0 failed, 0 ignored) - done with 'example_article_data'
Processed 50 items (50 created, 0 updated, 0 failed, 0 ignored) - done with 'example_article_alias'
Processed 50 items (50 created, 0 updated, 0 failed, 0 ignored) - done with 'example_article_redirect'

Next steps

Jun 17 2017
Jun 17

Since the release of Drupal 8 with a standardized way of managing translations, many sites running Drupal 7 are making a switch to Drupal 8. In Drupal 7 there are two ways to translate content:

  1. Using the content_translation module. The D7 core way of translating content, where every translation is a separate node.
  2. Using the entity_translation module. Maintains one node with a unique nid, while translations take place at the field level.

In this article we will discuss how to migrate content translations created with the content_translation module from Drupal 7 to Drupal 8. You can find our tutorial about migrating translations that use Entity Translation here.

This article would not have been possible without the help of my colleague Dave. ¡Gracias Dave!

The problem

We have a Drupal 7 database containing article nodes, which might have translations in English, Spanish and French. Some of these nodes are language-neutral, i.e. non-translatable. Our target is to migrate the Drupal 7 nodes into a Drupal 8 website, preserving the translations.

Before we start

  • Since this is an advanced migration topic, it is assumed you already know the basics of migration. If are new to migrations in Drupal 8, I recommend that you read about migrating basic data to Drupal 8 first.
  • If you'd like to run the migrations in this example yourself, see the quick-start documentation in our drupal migration i18n example repository.
  • The source website used in this example is Drupal 7.54.
  • The destination website used in this example is Drupal 8.3.x. However, an alternative solution for earlier versions is included towards the end of the article.

The module

To write the migrations, we create a module - in our case, migrate_example_i18n. There's nothing special about the module declaration, except for the dependencies:

  • migrate_plus and migrate_tools provide various features for defining and executing migrations.
  • migrate_source_csv: Will be used for demonstrating migration of translated content from non-Drupal sources in an upcoming article.
  • migrate_drupal: This module provides tools for migrating data from older versions of Drupal. It comes with Drupal 8.x core. Since this migration uses a Drupal 7 site as a source for its data, we need the migrate_drupal module.

How do translations work?

Before jumping into writing these migrations, it is important to mention that Drupal 7 and Drupal 8 translations work very differently. Here's the difference in a nutshell:

  • Drupal 7: When we translate a node, a new node is created with a different ID. This translated node has a property named tnid, which stores the ID of the original node, linking the two nodes together. For language-neutral or untranslated content, the tnid is set to 0.
  • Drupal 8: When we translate a node, no new node is created! The translation is saved in the fields of the original node, but with a different language code.

So just like we do when migrating translated content from Drupal 6 to Drupal 8, we create two migrations:

  • The example_dog_base migration will migrate the original content of each node, untranslated.
  • The example_dog_i18n migration will migrate only translations and associate them with original content created by example_dog_base.

We group the two migrations using the example_dog migration group to keep things clean and organized. Then we can execute both migrations with drush migrate-import --group=example_dog --update.

Step 1: Base migration

We start with example_dog_base to migrate all base data or non-translations. Described below are some noteworthy parameters:

Source

source:
  plugin: d7_node
  node_type: article
  key: drupal_7_content
  constants:
    uid_root: 1
    node_article: 'article'
  • plugin: Since we want to import data from a Drupal installation, we need to set the source plugin to d7_node. The d7_node source plugin is introduced by the migrate_drupal, module and it helps us read nodes from a Drupal 7 database without having to write queries manually. Since Drupal 8.3.x, this plugin supports translations created with the content_translation module. If you are using an older version of Drupal 8, then check the alternative solution provided towards the end of this article.
  • node_type: This tells the source plugin that we are interested in just one particular Drupal 7 node type, namely article.
  • key: Our Drupal 7 data doesn't come from our main Drupal 8 database - instead it comes from a secondary database connection. We choose a key to identify each such connection and we need to tell the source which such key to use. The keys themselves are defined in the $databases variable in our settings.php or settings.local.php. See the example settings.local.php file to see how it's done.
  • constants: We define some hard-coded values under this parameter.
  • translations: Notice there is no translations parameter here. The default value (false) tells the source plugin that we're only interested in migrating non-translations, i.e. content in the base language and language-neutral content.

Destination

destination:
  plugin: 'entity:node'
  • plugin: Since we want to create node entities in Drupal 8, we specify this as entity:node. That's it.
  • translations: Again we do not define the translations parameter while migrating base data. Omitting the parameter tells the destination plugin that we are interested in creating fresh nodes for each record, not translations of existing nodes.

Process

type: constants/node_article
langcode:
  plugin: default_value
  source: language
  default_value: und
uid: constants/uid_root
title: title
body: body
field_one_liner: field_one_liner
sticky: sticky
status: status
promote: promote

This is where we map the old node properties to the new node properties. Most of the properties have been assigned as is, without alteration, however, some noteworthy properties have been discussed below:

  • nid: There is no nid parameter here, because we don't care what nid each new node has in Drupal 8. Drupal can just assign a new nid to each node in the normal way.
  • type: We specify that we want to create article nodes.
  • langcode: The langcode parameter was formerly language in Drupal 7, so we rename it here. Also, if a Drupal 7 node is language-neutral, the language property will have no value. In that case,  we default to und.

This takes care of the base data. If we run this migration with drush migrate-import example_hybrid_base --update, all Drupal 7 nodes which are in base language or are language-neutral will be migrated into Drupal 8.

Step 2: Translation migration

We are halfway through now! All that's missing is migrating translations of the nodes we migrated above. To do this, we create another migration with the ID example_dog_i18n:

source:
  plugin: d7_node
  node_type: article
  translations: true
  # ...
destination:
  plugin: 'entity:node'
  translations: true
process:
  nid:
    plugin: migration
    source: tnid
    migration: example_dog_base
  langcode: language
  # ...
migration_dependencies:
  required:
    - example_dog_base
  • source:
    • translations: We set this to true to make the source plugin read only translations.
  • destination:
    • translations: We set this to true to make the destination plugin create translations for existing nodes instead of creating fresh new nodes.
  • process:
    • nid: In this case, we do care what the Drupal 8 nid is for each node. It has to match the nid for the untranslated version of this content, so that Drupal can add a translation to the correct node. This section uses the migration (migration_lookup) process plugin to figure out the right nid. It tells Drupal to check the previously-executed example_hybrid_base migration for a D6 node that has the same tnid as this D6 node. It will then then reuse the resulting nid here.
    • langcode: We define the language in which the translation should be created.
  • migration_dependencies: Since we cannot add translations to nodes that do not yet exist, we tell Drupal that this migration depends on the base migration example_dog_base. That way, the base migration will run before this migration.

That's it! We can run our translation migration with drush migrate-import example_dog_i18n --update and the translations will be imported into Drupal 8. Alternatively, we can use the migration group we defined to run both these migrations at once - the base migration will automatically be executed first and then the i18n migration. Here's how the output should look:

$ drush migrate-import --group=example_dog --update
Processed 7 items (7 created, 0 updated, 0 failed, 0 ignored) - done with 'example_dog_base'
Processed 7 items (7 created, 0 updated, 0 failed, 0 ignored) - done with 'example_dog_i18n'

You can check if everything went alright by clicking the Translate option for any translated node in Drupal 8. If everything went correctly, you should see that the node exists in the original language and has one or more translations.

Article migrated from Drupal 7 to Drupal 8Article migrated from Drupal 7 to Drupal 8

Alternate Solution for Drupal 8.2.x and Older

The example code for this article works out of the box with Drupal 8.3 or higher. However, it will not work with earlier versions of Drupal 8. For Drupal 8.2 or older, we need to use a custom source plugin (inspired by the d6_node plugin). All we have to do is use the D7NodeContnentTranslation source plugin included in the code for this example, like source: d7_node_content_translation. This custom source plugin adds support for the translations parameter, which in turn makes the migration of content translations work correctly.

Next Steps

Jun 17 2017
Jun 17

Since the release of Drupal 8 with a standardized way of managing translations, many sites running Drupal 7 are making a switch to Drupal 8. In Drupal 7 there are two ways to translate content:

  1. Using the content_translation module. The D7 core way of translating content, where every translation is a separate node.
  2. Using the entity_translation module. Maintains one node with a unique nid, while translations take place at the field level.

In this article we will discuss how to migrate content translations created with the entity_translation module from Drupal 7 to Drupal 8. You can find our tutorial about migrating translations that use Content Translation here.

This article would not have been possible without the help of my colleague Dave. Merci Dave!

The problem

We have a Drupal 7 database containing article nodes, which might have translations in English, Spanish and French. Some of these nodes are language-neutral, i.e. non-translatable. Our target is to migrate the D7 nodes into a D8 website, preserving the translations.

Before we start

  • Since this is an advanced migration topic, it is assumed you already know the basics of migration. If you are new to migrations in Drupal 8, I recommend that you read about migrating basic data to Drupal 8 first.
  • This article assumes that you have read our previous article on how to migrate content translations from Drupal 7 to Drupal 8 or have the relevant knowledge.
  • To execute the migrations in this example, you can download the drupal migration i18n example repository from GitHub. The module should work without any trouble for a standard Drupal 8 install. See quick-start for more information.
  • To see the example migrations in action, you need:
    • A Drupal 8 site.
    • The relevant D7 database, since we are migrating data from a Drupal 6 site.
    • Drush will be required to execute migration commands.

The module

To write the migrations, we create a module - in our case, it has been named migrate_example_i18n. Just like migrating content translations from D7 to D8, we create 2 YML files to define:

  • The example_creature_base migration will migrate all base data or non-translations.
    • The source/translations parameter is omitted or set to false.
    • The destination/translations parameter is omitted or set to false.
  • The example_creature_i18n migration will migrate all translations.
    • The process/nid is configured to use the migration plugin to lookup the node in the base language.
    • The source/translations parameter is set to true.
    • The destination/translations parameter is to true.
    • The migration_dependencies parameter declares example_creature_base as a dependency.

We group the two migrations using the example_creature migration group to keep things clean and organized. Then we can execute both migrations with drush migrate-import --group=example_creature --update.

How to migrate Entity Translations?

Entity translations! Drupal 7 content translations are supported since Drupal 8.3. At the point of writing this, there is no standard method for migrating entity translations to Drupal 8. In this example, we will migrate D7 nodes translated with the entity_translation module, however, the procedure should be similar for other entity types as well. Before we start, here are some notes about what's so different about entity translations:

  • All translations have the same entity_id. So, for a translated node, the entity_translation module will result in only one entry in the node table.
  • Translation information, certain metadata and revision information for entities is stored in the entity_translation table.

So if an English node with ID 19 has translations in Spanish and French, the entity_translations table has the following records:

An extract from the entity_translation table. entity_type entity_id revision_id language source uid status translate created changed node 19 1 en   1 1 0 1485800973 1487198982 node 19 1 es en 1 1 0 1485802336 1487199003 node 19 1 fr en 1 1 0 1487185898 1487198969

The above data structure is significantly different from the content translation structure. In fact, Drupal 8 handles translations much like the entity translation module! Hence, to handle entity-translations, we must take the entity_translation table into consideration, which the core d7_node source plugin does not do at the time of writing this article. Hence, we override the d7_node source with a custom source plugin named d7_node_entity_translation.

This is where we jump into code! We override certain methods of d7_node source to add support for the entity_translation table.

class D7NodeEntityTranslation extends D7Node {
  // Determines if the node-type being translated supports entity_translation.
  protected function isEntityTranslatable() {}
  // Depending on the "source/translations" parameter, this method alters
  // the migration query to return only translations or non-translations.
  protected function handleTranslations(SelectInterface $query) {}
  // This method has been overridden to ensure that every node's fields are
  // are loaded in the correct language.
  public function prepareRow(Row $row) {}
  // This method is called by the prepareRow() method to load field values
  // for source nodes. We override this method to add support for $language.
  protected function getFieldValues($entity_type, $field, $entity_id, $revision_id = NULL, $language = NULL) {}
  // Since all source nodes have the same "nid", we need to use a
  // combination of "nid:language" to distinguish each source translation.
  public function getIds() {}
}

Here's a quick look at the changes we need to make:

  • function getIds() tells the migrate API to use one or more source properties which should be used to uniquely identify source records. When working with entity translations, all translations have the same entity_id, but they have a different language. We override this method to tell Drupal to consider both the entity_id and the language properties to uniquely identify source records. So, the source records are uniquely identified something like 19:en, 19:es, 19:fr instead of using just 19.
  • function handleTranslations() is the method which adds support for the translations parameter we use in the source plugin. The translations parameter tells Drupal whether to migrate entities in their base language or to migrate translations. We override this method to:
    • See if the node type being migrated supports entity translations.
    • If the node type supports entity translations, then we INNER JOIN entity_translation and read translation data and some entity metadata, like date of creation, date of updation, etc from that table.
  • function prepareRow() as the name suggests, prepares a row of source data before it is passed to the process plugins. At this stage, field data is also attached to the source data. However, it does not load field data in the language specified in the source row. To overcome this problem, we override the getFieldValues() method and make sure it loads the field data in the same language as specified in the source row.

That's it! You should now be able to run the migration with drush migrate-import --group=example_creature --update. The output should look something like this:

$ drush mi --group=example_creature --update
Processed 9 items (9 created, 0 updated, 0 failed, 0 ignored) - done with 'example_creature_base'
Processed 9 items (9 created, 0 updated, 0 failed, 0 ignored) - done with 'example_creature_i18n'

Note: Keep an eye out for Drupal core updates. If the drupal_migrate module adds support for entity translations, migrating entity translations might become much easier.

Next Steps

May 15 2017
May 15

I train a lot of new Drupal users. Some find it easy-to-use and some find it a daunting maze of forms full of confusing terminology. Sometimes, it just depends on how the admin UI has been configured.

Here are some tips for configuring Drupal so that content editors using your site will love Drupal!

Give Editors Limited Permissions

Often users are overwhelmed by the number of things they can do once they're logged into Drupal. If you take the time to update their permissions and remove un-needed permissions, the administrative interface will be much simpler to use. Content editors probably don't need to modify image styles or manage view modes, so don't give them these permissions.

This is probably to single most important thing you can do to improve the admin UI, and has the added bonus of making your site more secure. It also makes it harder to for editors to break the site by accident by changing a setting they don't understand.

Configure the WYSIWYG Editor

One of the exciting things about Drupal 8 is that the WYSIWYG editor is built-in. But Drupal doesn't know out-of-the-box what HTML you have and who your editors are. That's why you can and should customize the WYSIWYG editor (Configuration > Content Authoring > Text formats and editors).

You can remove unneeded tools and add ones that are really useful (like Paste from Word and Paste as Plain Text). You can also configure the "Styles" and "Format" options that users can add from the WYSIWYG editor. 

Screenshot of WYSIWYG editor configuration

Text Formats

Text formats are one of the keys to content editing success. Remember that text formats are associated with permissions, so your content editors will need to permission to use any given text format. They are also associated with content. If I save a piece of content using Full HTML, the next user who edits the content will also need permission to use that text format. Otherwise, they the text field will be disabled.Screenshot of non-editable body text

So make sure that your content editors have permission to edit all the text formats that will be associated with content that they need to edit.

Field Configuration

The more that you break up your content into nice, manageable fields, the more consistently you can collect and display content on your site. If your content editors are used to one large text box where they enter content on the page, they might not be so excited at first about a set of separate fields. So here are some tips to configuring fields so content editors will like them:

  • Make sure you're using the right field widget. Should you be using an autocomplete instead of a select box? Check out the widget settings on the Manage Form Display tab. 
  • Use help text when needed, especially if you need content in a certain format, or a particular image size.
  • Make required fields required. Don't make your content editors guess what's required for the content to look right.
  • When appropriate, add a default value.
  • Make sure the order of the fields in the admin UI makes sense, and is consistent across different types of content.
  • If you have nested Paragraph fields in your content, try changing the widget to display a preview of each one, instead of an edit form.

Content Type Configuration

Make it easy for content editors to pick the right content type by providing meaningful names and descriptions. Think of this as built-in documentation. Make sure you create different content types for distinct types of data, rather than using catch-all content types. At the same time, don't set up multiple content types with identical fields, since this will add to the administrative overhead of the site. Remember, you can always use taxonomy terms to distinguish different ways that content should be filtered/displayed on the site.

Hide the Cruft

There are lots of elements in the Drupal node edit page, like the 'Sticky at top of lists' checkbox, that can be easily hidden. If you're not using these settings, or if there are legacy fields that are no longer relevant, hide them! It's easy to hide fields from the edit form using the 'Manage Form Display' tab.

Preview

For those of you who haven't tried the Preview button for Drupal 8, it works a whole lot better than it did in Drupal 7. Your content editors might find this really useful. If you're using View Modes to control the display of content in different contexts throughout the site, you'll probably need to provide some documentation/instructions for you content editors, prompting them to switch the view mode when they're previewing.

Screenshot of the preview interface in Drupal 8

Edit a Page with One Click

Ideally, content editors would be able to edit the main content of a page via a single 'Edit' link. If you're creating landing pages that have complex content, this can be difficult. You might be storing some of the page elements as blocks or related nodes.

You can use Paragraphs to set up compound content that's specific to the landing page, or use the Inline Entity Form module to allow users to edit content that's referenced from within your page, and displayed elsewhere on the site.

Create Dashboards or Custom Admin Views

Content editors like to have a landing page they can go to to see the overall state of content on the site. This might take the form of a dashboard, or it might be a series of customized content listing pages (which you can easily build with views). The idea is to give content editors an easy way to search and edit the content, as well as links to the admin pages they'll need most often.

Contrib Modules for Content Editing

The LinkIt module provides a nice interface for inserting links that your content editors will really appreciate.

The media management modules Entity Browser and File Entity Browser together to provide easy file-reuse. This is a usability win for content editors who are working with large libraries of files.

Use Field Group to group related fields together in the content admin UI.

Test

You need to test your content admin UI. Test what it looks like for different types of users. The Masquerade module can help with this. Make sure your list of tests include editing different types of content, making sure that any content that's migrated into Drupal can be edited consistently.

All of this is a lot of work, not a task to do the day before site launch. It's best to start thinking about the content admin experience the day you start building your site.

If you liked this blog post and want more step-by-step tips for setting up your Drupal 8 website, we have several Drupal trainings coming up online and in-person that you might like.

May 08 2017
May 08

Drupal 8 does way more out-of-the-box than previous versions of Drupal. If you're migrating your site from Drupal 6 or Drupal 7, you'll be amazed how many contributed modules you can now do without. 

That being said, there are still a set of handy contrib modules you'll probably use for most of your projects. This isn't a complete list, just a starting point for anyone new to Drupal 8 looking for a useful set of modules to try. 

Admin Toolbar

The Admin Toolbar gives you a dropdown menu to access the sub-items in the toolbar quickly. This is probably the first module to add to your Drupal 8 site.

Admin toolbar dropdown menu

Pathauto

Pathauto is the go-to module for automatically generating nice aliases for all your URLs. You get to define the path patterns for any content on your site that has a path (nodes, users, taxonomy terms...) Works in multiple languages. You need to add Token and Chaos Tools as dependencies.

Screenshot of pathauto pattern editing interface

Redirect

Along with the Pathauto module, most websites benefit from using Redirect to take users to pages if and when the paths change. 

Screenshot of redirect interface

Paragraphs

The Paragraphs module is a favourite for site builders who want to be able to create flexible content types that use compound fields. Want to add a set of calls to action to a landing page? Or mix together some videos, marketing text, and linked images? Or perhaps you need to add a set of time-slots to an event, or a set of editions to a book? Paragraphs to the rescue. Suddenly adding chunks of content within your content is really easy. You need to add Entity Reference Revisions as a dependency.

Screenshot of paragraphs editing interface

Honeypot

If your website has spam, Honeypot is an easy solution that might just fix your spamming issues. It inserts an invisible form element that catches bots that will unknowingly fill it in. 

Add to Any

Add to any is one of a number of options for adding social media links to your content. 

Metatag

Not just for your basic page title and description. Metatag makes sure that your content is going to look good when you share it on Facebook and Twitter too.

Screenshot of Metatag configuration for Drupal 8

Menu Trail by Path

Use Menu Trail by Path to set the active menu trail for your content based on the URL. For example, when you're looking at a blog post, and you want the blog post menu item to be active.

Entity Browser

One of the questions I get most often when I show off Drupal 8's shiny new content authoring features is how to re-use images or files across different pieces of content. Start with the Entity Browser module (entity is a fancy Drupal word for content and this case usually refers to images, videos, and files). You'll want to try this out with the File Entity Browser module. Configure it using the 'Manage Form Display' settings. (Hint: make sure you have all the required libraries installed to get this working.)

Screenshot of entity browser interface

Block Visibility Groups

Block Visibility Groups allows you to control which blocks are displayed on certain types of pages. For example, you can create a set of blocks that will show up on the homepage, and a different set of blocks on the contact page.

Screenshot of block layout with visibility groups settings

Diff

Drupal allows you to track the revisions (or versions) of content each time a user makes an update. The Diff module is a tiny module that allows you to see what's changed. 

Contact storage

If you decide to use the core Contact module, you might notice that contact form submissions get emailed and not saved in the admin UI of the site. If that's something you need, try out the Contact Storage module. For fancier forms, check out Webform.

If you liked this blog post and want some guidance on how to use these modules, we have Drupal trainings coming up online and in-person that you might like.

This is the fun part. Now you get to comment and tell me the essential modules I missed. I promise to try them all and do a follow-up blog post with the highlights.

May 05 2017
May 05

Drupal 8 does way more out-of-the-box than previous versions of Drupal. If you're migrating your site from Drupal 6 or Drupal 7, you'll be amazed how many modules you can now do without. 

That being said, there are still a set of handy modules you'll probably use for most of your projects. This isn't a complete list, just a starting point for anyone new to Drupal 8 looking for a useful set of modules to try. 

Admin Toolbar

The Admin Toolbar gives you a dropdown menu to access the sub-items in the toolbar quickly. This is probably the first module to add to your Drupal 8 site.

Admin toolbar dropdown menu

Pathauto

Pathauto is the go-to module for automatically generating nice aliases for all your URLs. You get to define the path patterns for any content on your site that has a path (nodes, users, taxonomy terms...) Works in multiple languages. You need to add Token and Chaos Tools as dependencies.

Screenshot of pathauto pattern editing interface

Redirect

Along with the Pathauto module, most websites benefit from using Redirect to take users to pages if and when the paths change. 

Screenshot of redirect interface

Paragraphs

The Paragraphs module is a favourite for site builders who want to be able to create flexible content types that use compound fields. Want to add a set of calls to action to a landing page? Or mix together some videos, marketing text, and linked images? Or perhaps you need to add a set of time-slots to an event, or a set of editions to a book? Paragraphs to the rescue. Suddenly adding chunks of content within your content is really easy. You need to add Entity Reference Revisions as a dependency.

Screenshot of paragraphs editing interface

Honeypot

If your website has spam, Honeypot is an easy solution that might just fix your spamming issues. It inserts an invisible form element that catches bots that will unknowingly fill it in. 

Add to Any

Add to any is one of a number of options for adding social media links to your content. 

Metatag

Not just for your basic page title and description. Metatag makes sure that your content is going to look good when you share it on Facebook and Twitter too.

Screenshot of Metatag configuration for Drupal 8

Menu Trail by Path

Use Menu Trail by Path to set the active menu trail for your content based on the URL. For example, when you're looking at a blog post, and you want the blog post menu item to be active.

Entity Browser

One of the questions I get most often when I show off Drupal 8's shiny new content authoring features is how to re-use images or files across different pieces of content. Start with the Entity Browser module (entity is a fancy Drupal word for content and this case usually refers to images, videos, and files). You'll want to try this out with the File Entity Browser module. Configure it using the 'Manage Form Display' settings. (Hint: make sure you have all the required libraries installed to get this working.)

Screenshot of entity browser interface

Block Visibility Groups

Block Visibility Groups allows you to control which blocks are displayed on certain types of pages. For example, you can create a set of blocks that will show up on the homepage, and a different set of blocks on the contact page.

Screenshot of block layout with visibility groups settings

Diff

Drupal allows you to track the revisions (or versions) of content each time a user makes an update. The Diff module is a tiny module that allows you to see what's changed. 

Contact storage

If you decide to use the core Contact module, you might notice that contact form submissions get emailed and not saved in the admin UI of the site. If that's something you need, try out the Contact Storage module. For fancier forms, check out Webform.

If you liked this blog post and want some guidance on how to use these modules, we have Drupal trainings coming up online and in-person that you might like.

This is the fun part. Now you get to comment and tell me the essential modules I missed. I promise to try them all and do a follow-up blog post with the highlights.

May 05 2017
May 05

If you have ever worked with sites that deal with events, you've probably been asked to create some type of calendar display. In this article, we'll discuss how to set up a basic events calendar using the Calendar (8.x-1.x-dev) for Drupal 8.

Configure the event content type

In our example, to handle events, we create a new content type called Event. You can put any content type in a calendar as long as it has a Date field. Though we might need date ranges to handle multi-day events, at the time of writing this article, there is no support for using the date range field with the calendar module, so we will use a simple date field for this example.

Event node formThe Event node form. Right now, events only have a title, description and a date field labelled Schedule.

Configuring the "events" view

With the node type in place, the next step will be to display the nodes using a view, using calendar display settings. To create a view with the calendar settings in place, you can go to Structure > Views > Add view from template page (admin/structure/views/template/list). Here, we choose the template which allows us to create a calendar for our date field.

Screenshot of the "add view from template" pageWe click the Add button corresponding to the date field (which we called Schedule).

The template provides you some options to configure certain aspects of the calendar to be generated, namely:

  • View name
  • Description
  • Base view path: The base path to use for the calendar pages and tabs. In our example, we choose events as the base so the calendar will generate paths like:
    • events/day: For a day-wise view
    • events/week: For a week-wise view
    • events/month: For a month-wise view
    • events/year: For a year-wise view

From the views configuration page, we can also configure the path for our calendar page(s) and create blocks with mini-calendars.

Calendar view generation optionsSome settings for the calendar to be generated.

Once done fine-tuning, we save the view and visit the relevant front-end page, which in this example is events/month. Here's how the calendar looks out of the box with the Bartik theme.

How the calendar looks in front-end

Conclusion

The calendar module will be a great contrib module while working with calendars. However, it may or may not serve your needs depending on your project requirements. Here are certain points (at the time of writing this article) which might affect the usability of this module:

  • No support for date range: Lack of support for date ranges makes it hard to work with multi-day event scenarios.
  • No support for start & end date: Though we can setup two separate date fields for start and end date, multi-day events are not visible as multi-column rows in the calendar.

Pages

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