Jun 14 2017
Jun 14

Being one of the first early adopters of Drupal Commerce 2.x, starting our first project in early 2016 (on alpha2 version) and soon after a second one, I originally planned to write a blog post soon after beta1 was published. Unfortunately, I was too busy at that time. Beta1 was released by the end of September 2016, and I postponed writing the post from one time to another. I wanted to share my experience, giving valuable tips, stating my opinion on maturity and the project's overall quality, etc.

By time of writing, we already have beta7 out and we're approaching the first release candidate. In the past couple of weeks/months, I could observe how the project gathered more and more pace. There's a significant amount of people building Commerce 2.x sites and many great developers are participating in both reporting bugs and features requests, as well as fixing the bugs, developing the features, writing documentation, and so on.

And there's also a number of blog posts, tutorials, and conference speeches out there, so I won't add another one here. If you want to get a quick overview of some of the great improvements and changes in the new Commerce 2.x, I can recommend e.g. this post by Sascha Grossenbacher.

Instead I've decided to write about the personal benefits I've gathered throughout my work on our first Commerce 2.x projects, besides having a great and immense flexible e-commerce framework. Where developers can enjoy working, and actually concentrate on implementing their business logic, to build great solutions for their clients without being limited. This post may get a bit longer (don't say, I haven't warned you before :p)

Decision Making Process

First, we should take a short excursion to the decision making process of our projects, and turn back the time a little bit. In the end of 2015 we signed a deal to re-launch a B2B store, previously running on an outdated Magento version having lots of individual needs, especially when it comes to pricing, shipping calculation, etc. Those are the kind of features in many e-commerce systems that are either not realisable at all, or only in a very time-consuming and inconvenient way. Those are the features where you, while developing, have to work against the system you build on. Staying on Magento was no real option at all, as in version 1.9 some of the feature requests would have been a nightmare to implement. The customer wasn't too much satisfied with their old 1.x at all and the EOL was already visible on the horizon. At that time Magento 2 was quite surprisingly released, after having a long period where development progress stuck a bit. The first insights, however, were there was as its best alpha mature software released stable under a great time pressure. I can't remember any other software where I encountered as many bugs on a test installation in such a short time.

However, we were preferring Drupal Commerce over Magento anyway, as already Commerce 1.x had this great flexibility you need for highly customized projects, so that would have been our logical first choice. But at that time, we have already fully switched the development of websites to Drupal 8, starting with a late beta in autumn and fully switching after rc1 release in October 2015. Although that was a huge change, developing on Drupal 8 was like love at first sight. The new architecture is so great, leaving no limits for fulfilling any wish and offering the necessary base for writing quality code. As I stated in an earlier blog post, to a developer with Java origins Drupal 8 feels far more like "real" programming, quite close to writing Java or .NET applications.

Code review

I had been reading the Commerce Guys blog posts about progress and future plans in the Commerce 2.x project with great interest for the preceding couple for months, and was already quite excited about that. There were many great ideas about architecture and sustainable decisions, such as first building Drupal independent PHP libraries for addressing, currency, taxes and formatting related tasks.

The time had come to have a closer look at the source code - and I was really excited about what I saw. The code base wasn't feature complete at all - and for sure, one or another smaller bug could be hiding somewhere - but the things that already existed, were well considered, well written, cleanly formatted, and greatly covered by unit tests extracting nearly every possible advantage the Drupal 8 and Symfony API is offering. I'd go so far to say that reading Commerce 2.x source code is mostly like reading a teaching book (a good one of course). You hardly find that in other open source projects. Off the top of my head, I could only think of the legendary Spring Framework (ok, to be fair, of course also of great PHP frameworks like Symfony, Laravel,..).

In Commerce Guys We Trust

Beside of the code review, the "Commerce Guys factor" was the most important one. Imho it's essential to assess a module also on its maintainership, especially if the module is playing a central role in your project, and even more if it's not finished and stable at the time of starting your project. And here are some points why I fully trusted in CG:

Their CEO Ryan Szrama can look back on many years of experience in developing Drupal based e-commerce frameworks and solutions. He started the Ubercart project in Drupal 5 and also lead the Drupal 6 version. Then he proved that he won't always go the easy way and he has got a sure feeling for making decisions, that are both challenging but also wise and sustainable. He decided to combine both the lessons learned from Ubercart and the new possibilities Drupal 7 offered and started to write a new e-commerce suite from ground up - Drupal Commerce was born. This was a shift from the encapsulated out-of-the-box solution Ubercart was, to a fully flexible platform utilizing Core improvements (e.g. entity API) as well as the power of contrib modules such as Rules and Views. The success justified this move.

And now again in the Drupal 8 version, brave decisions were taken instead of choosing the easy path. Switching to D8 is especially for bigger and more complex modules tied up with some work anyway. But still many try to just port their functionality 1:1 in order to just get a working D8 version. But the Commerce developers with leading Bojan Živanović the way as new project mastermind and Matt Glaman as his congenial co-maintainer, decided to utilize the unique chance to rewrite the whole project in order to make full use of the opportunities Drupal 8 offers. And again, the new architecture was build up on the results of self-evaluation of Commerce 1.x pros and cons, as well as intensive research on competitors, existing e-commerce platforms, research papers, etc

Especially I'm raising my hat for the incredible consequence the team showed all the time. We all know how time pressure can lead to trade-offs in quality and abandon plans of certain features etc. Although the development of Commerce 2.x took far longer as expected and planned, they never left the right track. They never huddled and committed immature stuff. They never wrote a feature without backing this by tests. They always went the extra mile, if certain lower level functionality that should be rather part of Core or a dedicated contrib module, wasn't present or working as expected, and rather tried to push core APIs or contrib modules forward, instead including a quick custom solution inside Commerce. While Magento tricked the world by releasing and selling an immature and at best alpha state software as stable after being under time pressure, the Commerce Guys kept working honestly to deliver a great piece of quality software at the end. Thank you so much for that!

The Win-Win-Win Situation

Let's return to the actual topic of this post. What I love most on working with open-source software is that, in the best case, every stakeholder benefits: you, your client, and lots of other people in the open source community, when you give and contribute back.

Our clients now have got decent e-commerce solutions tailored to their needs with a long lifespan. We did not only benefit from getting money for doing our work, but also I can proudly say that my Drupal skills improved during my work on Commerce projects. On the one side, it boosted the speed of my Drupal 8 adoption. Although we've implemented already a couple of Drupal 8 websites before, all having some individual requirements, resulting in writing custom modules, custom entity types, etc, working with Commerce showed me an ideal-typical way of how things like service collectors and plugin managers work in Symfony/Drupal 8.  I also learned how to implement certain design patterns in Symfony/Drupal 8 and it showed me some hidden, at that time undocumented, features like some specific properties of entity type annotations, that aren't present in the typical examples. Or simply reminded me to cleanly document every function.

But it wasn't only the coding stuff that helped me to improve. More important is that it somehow got me much more involved into the community than before. I always tried to contribute as much as possible by proposing patches, commenting on issues, founding and maintaining a few smaller modules. But (e.g.) I never used IRC before. I must admit that I missed the access to this rather nerd communication tool. I didn't deal with how to use this (tool support in Windows is rather bad imho), and I didn't see much benefit in using it all. Doing asynchronous communication on issue reports was all I needed. However, there were many things to discuss and coordinate with Bojan especially. So I dove into using IRC, where I since then regularly hang out to both ask for help and help others - as well as in Slack since shortly. And there's one aspect, I've not considered before. That may sound a bit sentimental, but having these direct conversations gives you a lot more of that team feeling, even - or maybe especially because - they are spread all over the world, and you know none of them personally. And you can see that there are also great persons behind that great developers you meet. That said, I should give some shouts out now. To Bojan, who is for sure one of the best PHP developers I encountered so far. To Matt and Ryan, to Jingsheng Wang, who was also one of the very first brave early adopters out there, to Josh Miller, with whom I've worked together on Commerce Wishlist module, to Guy Schneerson, maintainer of Commerce Stock and techno enthusiast *nz nz nz nz* *shaking*, and many others, who work hard for our community.

And finally, some words about the third win. I feel it as my duty to contribute and give something back to the community, because that's how OSS works, and that's especially, why Drupal stands out of other OSS projects. So I'm also quite proud that I'm the author of no less than 22 commits of Drupal Commerce and overall credited in 37 issues of Drupal Commerce over the past 13 months. Of course, there're some smaller issues part of it, but there were also more important ones like implementing the price resolvers. I've also helped to rewrite Commerce Wishlist module - which was rather simple because I could based this on the work of Bojan and Matt in commerce_order, and started three Commerce contrib modules (Commerce order number, Commerce Quantity Increments, Commerce Open Payment Platform), as well as contributed several patches to other contrib modules and also to Core.

I'm looking forward to the forthcoming release candidate. If you haven't tried Commerce 2.x so far, you should definitely try and consider it for your next project. Despite being labelled as "beta" (or soon release candidate), it's very stable already, only missing some UX in certain parts. Trust me, it's better to rely on conservative self-evaluation taking semantic versioning serious than on marketing-focused solutions that just label any immature crap as stable.

original post: https://www.agoradesign.at/blog/how-drupal-commerce-2x-improved-my-skills

Jun 13 2017
Jun 13

As the technological landscape changes, there has emerged a growing discussion amongst developers regarding the best way to go about generating content to be used across multiple applications. There are two trains of thought -- a traditional, coupled Content Management System (CMS) with supporting Application Program Interface (API), tied to both a backend and frontend, OR a headless API-only CMS tied only to a backend. Naturally, as a Drupal web development agency, we look to understand this discussion so that we know where Drupal fits in.

Why does it matter?

We’ve long since moved passed the days of website only content. While websites drive the majority of the digital content we consume, we now have emerging technologies challenging this traditional interface.

As an example, take a smart thermostat in your home. There’s no way you’re going to be viewing the weather network’s website on a small screen that may not have much of a graphical display. So, how does the network provide content to this thermostat? Simple, the thermostat’s software accesses the information via a CMSes API, taking only what it needs and displaying it on the display.

This same API might also be providing information to a weather app on your phone, and your smartwatch, and your car, and … the list goes on.

This is the power of a centralized content system with an API that has the ability to distribute that content to any device that can access the API. If it wasn’t for this, someone would need to generate that content separately for each device, a monumental task.

Coupled vs. Headless CMSes

The first question to understand is: What’s the difference is between these two approaches?

Coupled CMS (with supporting API)

A traditional CMS, such as Drupal, allows content editors to add or edit content and have immediate feedback as to how the content will display. This is because a traditional CMS is tied to a front end.

The front end is what a user sees when viewing an application, which, in Drupal’s primary case, is a website. Marketers and content editors can view the content before it’s publicly available using tools such as inline editing or pre-published previews. Drupal shines in this regard, and it’s graphical interface and available modules allow for quick and relatively easy modification to how the data is displayed on the frontend. This makes it so that a developer isn’t always needed to make simple changes, which can be more efficient for both time and cost, possibly a huge benefit to using a coupled CMS.

Of course, a coupled CMS must have an API that other applications can interface with. This is more of a secondary feature of a traditional CMS, but that is changing with the times. Drupal 8 has a strong emphasis on providing many API services out of the box (https://www.drupal.org/docs/8/api), and there is a strong push to make sure ongoing development takes an API-first approach.

Headless CMS (the API-only approach)

A headless CMS is considered an API-only approach. It is a content hub only and therefore has no front end. These backend only systems allow marketers, content editors and software to publish content which then gets distributed automatically to any integrated application. Applications must be developed in order to access this content, since there is no coupled front end interface to immediately view the data

A benefit to this approach is that people, or software, generating content don’t need to know anything about development or UI in order to provide the content for their applications. All they need to provide is the data. In this way, teams can be separated and roles can be clearly defined.

The downside, of course, is that without a fully integrated front end, marketers and content editors are limited to what they can do with the content. With no immediate feedback as to how content it will appear before it gets pushed out to the public, trialing and proofing content before can be difficult. Layout can also be a limitation to marketing teams. A developer would need to step in if any application presentation needs to change.

Conclusion - Where does Drupal fit?

Being a big part of the Drupal community (https://www.drupal.org/acro-media-inc) we’re seeing the discussion first hand about where Drupal fits in. Luckily, with Drupal 8, the community has already taken a solid step towards making sure Drupal continues to be a relevant contender as either a coupled OR headless CMS.

We already love and use Drupal as a traditional CMS for building websites. There will always be a use case out there where a headless CMS is best, but, by making sure that there is a strong underlying API that applications can interact with, we get the best of both worlds with a single package. And, for our customers and anyone else hiring a Drupal agency, you also continue to benefit from the massive, dedicated, open source community that is always ready to help. With Drupal, you’re covered.

Jun 12 2017
ao2
Jun 12

Most of the information I have come across about migrating from Drupal 6 to Drupal 8 is about migrating content, however before tackling this problem another one must be solved, maybe it is obvious and hence understated, so let's spell it out loud: preserving the site functionality.

That means checking if the contrib modules need to be ported to Drupal 8, and also checking if the solution used in the previous version of the site can be replaced with a completely different approach in Drupal 8.

Let's take ao2.it as a study case.

When I set up ao2.it back in 2009 I was new to Drupal, I choose it mainly to have a peek at the state of Open Source web platforms.

Bottom line, I ended up using many quick and dirty hacks just to get the blog up and running: local core patches, theme hacks to solve functional problems, and so on.

Moving to Drupal 8 is an opportunity to do things properly and finally pay some technical debt.

For a moment I had even thought about moving away from Drupal completely and use a solution more suited to my usual technical taste (I have a background in C libraries and linux kernel programming) like having the content in git and generate static web pages, but once again I didn't want to miss out on what web frameworks are up to these days, so here I am again getting my hands dirty with this little over-engineered personal Drupal blog, hoping that this time I can at least make it a reproducible little over-engineered personal Drupal blog.

In this series of blog posts I'll try to explain the choices I made when I set up the Drupal 6 blog and how I am re-evaluating them for the migration to Drupal 8.

The front page view

ao2.it was also an experiment about a multi-language blog, but I never intended to translate every content, so it was always a place where some articles would be in English, some in Italian, and the general pages would be actually multi-language.

This posed a problem about what to show on the front page:

  • If every node was shown, there would be duplicates for translated nodes, which can be confusing.
  • If only nodes in the current interface language were shown, the front page would list completely different content across languages, which does not represent the timeline of the blog content.

So a criterion for a front page of a partially multi-lingual site could be something like the following:

  • If a node has a translation in the current interface language, show that;
  • if not, show the original translation.

The “Select translation” module

In Drupal 6 I used the Select translation module which worked fine, but It was not available for Drupal 8.

So I asked the maintainers if they could give me the permission to commit changes to the git repository and I started working on the port myself.

The major problem I had to deal with was that Drupal 6 approached the multi-language problem using by default the mechanism called "Content translations" where separate nodes represented different translations (i.e. different rows in the node table each with its own nid), tied together by a tid field (translation id): different nodes with the same tid are translations of the same content.

Drupal 8 instead works with "Entity translations", so one single node represents all of its translations and is listed only once in the node table, and actual translations are handled at the entity field level in the node_filed_data table.

So the SQL query in Select translation needed to be adjusted to work on the node_filed_data rather than of the node table, as it can be seen in commit 12f70c9bb37c.

While at it I also took the chance to refactor and clean up the code, adding a drush command to test the functionality from the command line.

The code looks better structured thanks to the Plugin infrastructure and now I trust it a little more.

Preserve language

On ao2.it I also played with the conceptual difference between the “Interface language” and the “Content language” but Drupal 6 did not have a clean mechanism to differentiate between the two.

So I used the Preserve language module to be able to only switch the interface language when the language prefix in the URL changed.

It turns out that an external module is not needed anymore for that because in Drupal 8 there can be separate language switchers, one for the interface language and one for the content language.

However there are still some issues about the interaction between them, like reported in Issue #2864055: LanguageNegotiationContentEntity: don't break interface language switcher links, feel free to take a look and comment on possible solutions.

More details about the content language selection in a future blog post.

Jun 04 2017
Jun 04
5 June 2017

This is the last part of a series on improving the way date ranges are presented in Drupal, by creating a field formatter that can omit the day, month or year where appropriate, displaying the date ranges in a nicer, more compact form:

  • 24–25 January 2017
  • 29 January–3 February 2017
  • 9:00am–4:30pm, 1 April 2017

The first post, looked at porting some existing code from Drupal 7 to Drupal 8, adding an automated test along the way. In the second post, we made the format configurable.

There’s currently no administrative interface though, so site builders can’t add and edit formats from Drupal’s UI. We’ll add that in this last post.

Routing

According to the routing overview on drupal.org, a route is a path which is defined for Drupal to return some sort of content on.

For our administrative interface, we want to define a number of routes:

  • /admin/config/regional/date_range_format - show a list of the formats, with links to:
  • /admin/config/regional/date_range_format/add
  • /admin/config/regional/date_range_format/*/edit
  • /admin/config/regional/date_range_format/*/delete

There are two ways in which our module can provide routes. We could include a routing.yml file along with our module. This file contains the same kind of information as would have been in hook_menu in Drupal 7. But it’s a static file—if we want something that’s dynamic we can provide it at runtime using a route provider.

For dealing with entities, it’s often much easier to use Drupal’s bundled AdminHtmlRouteProvider class. This examines various properties on the entity annotation—we’ll look at those next—and provides suitable routes for us automatically.

To use this route provider, we add the following to the entity annotation:

@ConfigEntityType(
  …
  handlers = {
    "route_provider" = {
      "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
    },
  },
  …
)

At this point we need to run the drupal router:rebuild command from Drupal console. We must do this whenever we change a routing.yml file or any of the properties in the entity that affect routes.

The collection view

An entity can define a collection view—typically a page showing a list of entities with links to edit them. Drupal provides a list builder which can be used to show a list of entities with buttons for common add/edit/delete type tasks. We’ll create one of these for our new configuration entity:

<?php
namespace Drupal\daterange_compact;

class DateRangeFormatListBuilder extends ConfigEntityListBuilder {
  function buildHeader() {
    /* return an array of column headings */
  }
  function buildRow(EntityInterface $entity) {
    /* return an array of column values for the given entity */
  }
}

We then associate this list builder with our entity by declaring it within the @ConfigEntityType annotation:

handlers = {
  "list_builder" = "Drupal\daterange_compact\DateRangeFormatListBuilder",
}

The actual list builder is quite a rich, showing examples of different ranges. You can see the full implementation here.

The collection page

Once we have the list builder in place, we can add the collection link to our @ConfigEntityType annotation. The route provider will pick up on this link template and provide a route for the entity collection page automatically.

links = {
  "collection" = "/admin/config/regional/date_range_format"
}

By defining the link, our page appears at the appropriate URL. Note that the add/edit/delete links won’t show just yet—we still have to define those.

The date and time range configuration page, showing a list of available formats The screen for listing date/time range formats, provided by the entity list builder.

Updating the main configuration page

In order to reach this new page, we’ll create a menu link on the main configuration page, within the regional and language section. We do that by supplying a daterange_compact.links.menu.yml file:

entity.date_range_format.collection:
  title: 'Date and time range formats'
  route_name: entity.date_range_format.collection
  description: 'Configure how date and time ranges are displayed.'
  parent: system.admin_config_regional
  weight: 0

That link gives us the starting point for our interface:

The system configuration navigation, showing a link to date and time range formats Date/time range formats are accessed via the main configuration page.

We can now view all the date and time range formats from the main administrative interface in Drupal. Next we’ll build some forms to maintan them, after which the add/edit/delete links should start to appear on our collection page.

Forms

We need a form to be able to edit date range formats. The same form is used to create new ones. Drupal provides a lot of built-in functionality via the EntityForm class which we can extend. Drupal will then take care of loading and saving the entity. We just need to provide the form elements to map values on to our entity’s properties.

Adding & editing

We can add any number of forms, but we only need one to edit an existing format, and we can reuse the same form for adding a new format. This form is defined as a class, and lives in src/Form/DateRangeFormatForm.php:

<?php
namespace Drupal\daterange_compact\Form;

class DateRangeFormatForm extends EntityForm {
  /* implementation */
}

Configuration entities don’t use the field API, so we need to build the form ourselves. Although the form looks quite complicated and has a lot of options, it’s reasonably easy to build—each property in the configuration entity can be populated by a single element, like this:

$form['label'] = [
  '#type' => 'textfield',
  '#title' => $this->t('Label'),
  '#maxlength' => 255,
  '#default_value' => $this->entity->label(),
  '#description' => $this->t("Name of the date time range format."),
  '#required' => TRUE,
];

The full implementation of the form is here.

We also need to tell Drupal about this form, which we can do by adding the following to the @ConfigEntityType annotation:

"form" = {
  "add" = "Drupal\daterange_compact\Form\DateRangeFormatForm",
  "edit" = "Drupal\daterange_compact\Form\DateRangeFormatForm",
}

We also add some links, to match up operations such as add and edit with the new form. These are also defined in the @ConfigEntityType annotation:

links = {
  "add-form" = "/admin/config/regional/date_range_format/add",
  "edit-form" = "/admin/config/regional/date_range_format/{date_range_format}/edit",
}

If we look at the collection view again we see that alongside each format there is a link to edit it. That is because of the edit-form link declared in the annotation.

We also want a link at the top of that page, to add a new format. We can do that by providing an action link that refers to the add-form link. This belongs in the daterange_compact.links.action.yml file:

entity.date_range_format.add_form:
  route_name: 'entity.date_range_format.add_form'
  title: 'Add format'
  appears_on:
    - entity.date_range_format.collection

At this point we have a means of adding and editing formats. Our form looks like this:

The date and time range configuration page, showing our new format for editing The screen for editing date/time range formats.

Deletion

Deleting entities is slightly different. We want to show a confirmation page after a before performing the actual deletion. The EntityDeleteForm class does just that. All we need to do is subclass it and provide the wording for the question:

<?php
namespace Drupal\daterange_compact\Form;

class DateRangeFormatDeleteForm extends EntityDeleteForm {
  public function getQuestion() {
    return $this->t('Are you sure?');
  }
}

We declare this form and link on the @ConfigEntityType annotation in the same way as for add/edit:

"form" = {
  "delete" = "Drupal\foo\Form\DateRangeFormatDeleteForm"
}
links = {
  "delete-form" = "/admin/config/regional/date_range_format/{date_range_format}/delete",
}

Conclusion

That’s it. We’ve got a field formatter to render date and time ranges in a very flexible way. Users can define their own formats thorough the web interface, and these are represented as configuration entities, giving us all the benefits of the configuration management initiative, such as predictable deployments and multilingual support.

The module is available at https://www.drupal.org/project/daterange_compact.

I hope you found this write-up useful.

Want to help?

I’m currently working on getting this module up to scratch in order to have coverage from the Drupal security team. If you want to help make that happen, please review the code following this process and leave a comment on this issue. Thanks :-)

May 31 2017
May 31
May 31st, 2017

In the last post, we created a nested accordion component within Pattern Lab. In this post, we will walk through the basics of integrating this component into Drupal.

Requirements

Even though Emulsify is a ready-made Drupal 8 theme, there are some requirements and background to be aware of when using it.

Emulsify is currently meant to be used as a starterkit. In contrast to a base theme, a starterkit is simply enabled as-is, and tweaked to meet your needs. This is purposeful—your components should match your design requirements, so you should edit/delete example components as needed.

There is currently a dependency for Drupal theming, which is the Components module. This module allows one to define custom namespaces outside of the expected theme /templates directory. Emulsify comes with predefined namespaces for the atomic design directories in Pattern Lab (atoms, molecules, organisms, etc.). Even if you’re not 100% clear currently on what this module does, just know all you have to do is enable the Emulsify theme and the Components module and you’re off to the races.

Components in Drupal

In our last post we built an accordion component. Let’s now integrate this component into our Drupal site. It’s important to understand what individual components you will be working with. For our purposes, we have two: an accordion item (<dt>, <dd>) and an accordion list (<dl>). It’s important to note that these will also correspond to 2 separate Drupal files. Although this can be built in Drupal a variety of ways, in the example below, each accordion item will be a node and the accordion list will be a view.

Accordion Item

You will first want to create an Accordion content type (machine name: accordion), and we will use the title as the <dt> and the body as the <dd>. Once you’ve done this (and added some Accordion content items), let’s add our node template Twig file for the accordion item by duplicating templates/content/node.html.twig into templates/content/node--accordion.html.twig. In place of the default include function in that file, place the following:

{% include "@molecules/accordion-item/accordion-item.twig"
   with {
      "accordion_term": label,
      "accordion_def": content.body,
   }
%}

As you can see, this is a direct copy of the include statement in our accordion component file except the variables have been replaced. Makes sense, right? We want Drupal to replace those static variables with its dynamic ones, in this case label (the node title) and content.body. If you visit your accordion node in the browser (note: you will need to rebuild cache when adding new template files), you will now see your styled accordion item!

But something’s missing, right? When you click on the title, the body field should collapse, which comes from our JavaScript functionality. While JavaScript in the Pattern Lab component will automatically work because Emulsify compiles it to a single file loaded for all components, we want to use Drupal’s built-in aggregation mechanisms for adding JavaScript responsibly. To do so, we need to add a library to the theme. This means adding the following code into emulsify.libraries.yml:

accordion:
  js:
    components/_patterns/02-molecules/accordion-item/accordion-item.js: {}

Once you’ve done that and rebuilt the cache, you can now use the following snippet in any Drupal Twig file to load that library [NB: read more about attach_library]:

{{ attach_library('emulsify/accordion') }}

So, once you’ve added that function to your node–accordion.html.twig file, you should have a working accordion item. Not only does this function load your accordion JavaScript, but it does so in a way that only loads it when that Twig file is used, and also takes advantage of Drupal’s JavaScript aggregation system. Win-win!

Accordion List

So, now that our individual accordion item works as it should, let’s build our accordion list. For this, I’ve created a view called Accordion (machine name: accordion) that shows “Content of Type: Accordion” and a page display that shows an unformatted list of full posts.

Now that the view has been created, let’s copy views-view-unformatted.html.twig from our parent Stable theme (/core/themes/stable/templates/views) and rename it views-view-unformatted--accordion.html.twig. Inside of that file, we will write our include statement for the accordion <dl> component. But before we do that, we need to make a key change to that component file. If you go back to the contents of that file, you’ll notice that it has a for loop built to pass in Pattern Lab data and nest the accordion items themselves:

<dl class="accordion-item">
  {% for listItem in listItems.four %}
    {% include "@molecules/accordion-item/accordion-item.twig"
      with {
        "accordion_item": listItem.headline.short,
        "accordion_def": listItem.excerpt.long
      }
    %}
  {% endfor %}
</dl>

In Drupal, we don’t want to iterate over this static list; all we need to do is provide a single variable for the  Views rows to be passed into. Let’s tweak our code a bit to allow for that:

<dl class="accordion-item">
  {% if drupal == true %}
    {{ accordion_items }}
  {% else %}
    {% for listItem in listItems.four %}
      {% include "@molecules/accordion-item/accordion-item.twig"
        with {
          "accordion_term": listItem.headline.short,
          "accordion_def": listItem.excerpt.long
        }
      %}
    {% endfor %}
  {% endif %}
</dl>

You’ll notice that we’ve added an if statement to check whether “drupal” is true—this variable can actually be anything Pattern Lab doesn’t recognize (see the next code snippet). Finally, in views-view-unformatted--accordion.html.twig let’s put the following:

{% set drupal = true %}
{% include "@organisms/accordion/accordion.twig"
  with {
    "accordion_items": rows,
  }
%}

At the view level, all we need is this outer <dl> wrapper and to just pass in our Views rows (which will contain our already component-ized nodes). Rebuild the cache, visit your view page and voila! You now have a fully working accordion!

Conclusion

We have now not only created a more complex nested component that uses JavaScript… we have done it in Drupal! Your HTML, CSS and JavaScript are where they belong (in the components themselves), and you are merely passing Drupal’s dynamic data into those files.

There’s definitely a lot more to learn; below is a list of posts and webinars to continue your education and get involved in the future of component-driven development and our tool, Emulsify.

Recommended Posts

  • Shared Principles There is no question that the frontend space has exploded in the past decade, having gone from the seemingly novice aspect of web development to a first-class specialization.…
  • Webinar presented by Brian Lewis and Evan Willhite 15-March-2017, 1pm-2pm CDT Modern web applications are not built of pages, but are better thought of as a collection of components, assembled…
  • Welcome to Part Three of our frontend miniseries on style guides! In this installment, we cover the bits and pieces of atomic design using Pattern Lab.
Evan Willhite
Evan Willhite

Evan Willhite is a frontend engineer at Four Kitchens who thrives on creating delightful digital experiences for users, clients, and fellow engineers. He enjoys running, hot chicken, playing music, and being a homebody with his family.

Development

Blog posts about backend engineering, frontend code work, programming tricks and tips, systems architecture, apps, APIs, microservices, and the technical side of Four Kitchens.

Read more Development
May 31 2017
May 31

Drupal Commerce Marketing

We are prepping hard this week for IRCE 2017, the big internet retailer show June 6-9th in Chicago, which means readying demos, writing marketing material and practicing pitches. If you will be attending IRCE 2017, come see us at booth 1948 and we'll show you what we've been upto.

While Drupal Commerce offers great features and flexibility, I find people don't know all of its capabilities because the people involved are great at coding, but maybe not so great at marketing. On that note, I thought I would share some of the marketing collateral we've done up for IRCE, all of which we will be providing back to the community so anyone can use it to help sell Drupal Commerce. Our big goal is to have lots of nice web content and even somewhat of a "press kit" that everyone can use to pitch Drupal Commerce to their clients, bosses, friends, family, casual acquaintences, etc.

We have a whole bunch of material written up, as well as a nice Commerce 2.x demo. We're still in the mad rush of finishing it up, so it isn't all available yet, but it will be available over the next few weeks (stay tuned).

Without further rambling, here is our first go at a feature list for Drupal Commerce 2.x. I have provided a PDF and source text at the bottom of this article, should you want to use this content in your own marketing. Also, if you have any feedback, feel free to email, tweet @shawnmmccabe, yell at me on the street or use our contact form.

acro_DC_feature_sheet-1.jpg

acro_DC_feature_sheet-2.jpg

May 30 2017
May 30

You’re not short on choice when it comes to debugging a Drupal website.

You can install Devel and use Kint to print variables to the screen. Or you could use Web Profiler to add a toolbar at the bottom of your site to see how things are performing.

If you’re looking for a proper debugger look no further than Xdebug. It integrates with a lot of IDEs and text editors and I’d recommend you try it out if you’ve never used it.

I recorded a webinar about Drupal 8 debugging which you can watch above.

Here is what I covered in the video:

  • Turn off caching (02:01)
  • Twig debugging (08:26)
  • Using Kint (19:25)
  • Print variables using Kint in Twig template (21:16)
  • Using WebProfiler (22:15)
  • WebProfiler IDE link (26:37)
  • Drupal console debugging commands (31:41)
  • Adding breakpoints to PhpStorm (39:14)
  • Adding breakpoints to Twig templates (43:48)
  • Drupal integration with PhpStorm (45:26)
  • PhpStorm plugins (47:52)

PHP Functions

PHP has two handy functions which can be used to print variables, objects and arrays to the screen.

print_r()

var_dump()

Drupal core comes with its own function: debug().

Devel Module

Devel has been around for as long as I’ve been using Drupal. It comes with a bunch of helper functions for module developers and it has a few handy sub-modules.

The two sub-modules worth mentioning are Kint and Web Profiler.

Kint

This module integrates the Kint library into Drupal and allows you to print variables using the PHP functions: ksm() and kint().

You can also print variables in Twig templates using {{ kint() }}.

Click here to learn how to use Kint in Drupal 8.

Web Profiler

The Web Profiler sub-module adds a toolbar at the bottom of your site and displays useful stats about the number of queries, memory usage and more.

The toolbar gives valuable insight into what’s happening in your Drupal site.

If you want to learn more about Web Profiler, check out our tutorial on using Web Profiler in Drupal 8.

Drupal Console

Drupal Console is a CLI tool for Drupal. It’s implemented using the Symfony Console component. It can be used to provision new Drupal sites, generate boilerplate code and debug Drupal.

Drupal Console comes with a bunch of debug commands. Just search for any command with the term “debug”.

drupal list | grep "debug"

The two that I found most useful are router:debug and container:debug.

Drupal Settings

Drupal 8 caches a lot more things than Drupal 7. Individual rendered elements like a block for example will be cached. Even if you’re logged in or not.

Rendered Twig templates are also cached. This makes Drupal 8 fast, but it can complicate things when you’re writing code. You don’t want to rebuild the site cache every time you make a change in a template or a rendered array.

Most of this caching can be turned off by disabling them in a settings file.

Drupal.org has a good page: “Disable Drupal 8 caching during development”.

Twig Template Discovery

To turn on Twig debugging, make sure you follow the link above. Then add the following into development.services.yml:

parameters:
  twig.config:
    debug: true
    auto_reload: true
    cache: false

The debug: true parameter turns on Twig’s debugging, Twig will display information such as which template it used and its path. It does this my adding HTML comments.

Use the HTML comments to figure out which Twig template you should override and its file name.

PhpStorm

PhpStorm is a commercial IDE which is popular with PHP and Drupal developers. It integrates nicely with Xdebug and the Drupal code base.

Xdebug

Using PhpStorm, you can add a breakpoint somewhere in PHP code and step through as the Drupal request is executed. You can also see what variables are available.

Learn how to configure Xdebug in PhpStorm.

Drupal Integration

PhpStorm also offers Drupal integration and when enabled it allows autocomplete functionality for hooks. No longer will you have to remember a specific hook and its arguments.

Make sure you turn on the integration by searching for “drupal” in the Preferences section.

Extra PhpStorm Plugins

Drupal 8 uses the YAML format for a lot of things throughout its code base; services, routing, permissions, etc…

And in these files you’ll see references to classes and methods.

Take for example this route:

node.add:
  path: '/node/add/{node_type}'
  defaults:
    _controller: '\Drupal\node\Controller\NodeController::add'
    _title_callback: '\Drupal\node\Controller\NodeController::addPageTitle'

There’s no easy way to navigate to the NodeController other than searching for the class name.

However, if you install these three PhpStorm plugins, you’ll be able to navigate to the class or method by pressing command or control then clicking on the reference.

Once you’ve downloaded these plugins, enable them and then enable “Symfony integration”.

Then you should be able to navigate to classes by clicking on the reference while pressing command or control.

Summary

As you can see, you have options when it comes to debugging. If you’re looking for something simple then use Kint. If you prefer a proper debugger then look at Xdebug.

What’s your preferred technique? Leave a comment below.

May 25 2017
May 25

The Weekly Updates are Back!

As you probably noticed, the Commerce weekly updates were on hiatus. I have officially pawned off all my difficult work to other staff, so I can get back to doing these! So much to talk about with Commerce 2 on the home stretch and how community contrib has really picked up speed, I will get back to doing these every week.

Commerce POS

https://www.drupal.org/project/commerce_pos

We're nearly at Release Candidate 1, which should release by the end of the month. We have only 5 remaining blockers that need to be finished.

https://www.drupal.org/project/issues/search/commerce_pos?project_issue_...

After that, we plan to start work on the Drupal 8 version. I have Bojan, from Commerce Guys, tentatively lined up to give us some help with architecture, so hopefully it will mesh very nicely with Commerce 2.x.

Commerce Migrate

https://www.drupal.org/project/commerce_migrate

u/quietone did a bunch of work on this and, although she is finishing off a client project right now, she will be back on full time contrib shortly and remain so for the rest of the year. Since she works on migrate for core a lot, she's been making really good progress on this.  Bojan and I were shooting for a stable version around late July when Commerce 2.x is expected to release. Right now it has working, but rough, implementations for Ubercart 6, Ubercart 7 and Commerce 1.x. We hope to have versions for Shopify and Magento as well, and there are prototypes already finished.

Commerce Licensing/Recurring

https://www.drupal.org/project/commerce_license

u/Kazanir is working on this, as he wrote the licensing stuff for 1.x and is doing the port to 2.x.  He's newer to Drupal 8 and Commerce 2.x and it's kicking his butt a bit, but he's getting there.  We should be getting an alpha probably within a month.

Commerce 2.x

Some of our new hires are going to be working on this as they are on their last phase of training. They do contrib for a few weeks before jumping into teams to do client work.

Commerce XLS Import

https://www.drupal.org/project/commerce_xls_import

There are a number of patches that have been submitted by other people in the community that need review. I have reviewed a few, but more waiting. Hopefully I get those finished before we leave for IRCE.

May 24 2017
May 24
May 24th, 2017

In the last post, we introduced Emulsify and spoke a little about the history that went into its creation. In this post, we will walk through the basics of Emulsify to get you building lovely, organized components automatically added to Pattern Lab.

Prototyping

Emulsify is at its most basic level a prototyping tool. Assuming you’ve met the requirements and have installed Emulsify, running the tool is as simple as navigating to the directory and running `npm start`. This task takes care of building your Pattern Lab website, compiling Sass to minified CSS, linting and minifying JavaScript.

Also, this single command will start a watch task and open your Pattern Lab instance automatically in a browser. So now when you save a file, it will run the appropriate task and refresh the browser to show your latest changes. In other words, it is an end-to-end prototyping tool meant to allow a developer to start creating components quickly with a solid backbone of automation.

Component-Based Theming

Emulsify, like Pattern Lab, expects the developer to use a component-based building approach. This approach is elegantly simple: write your DRY components, including your Sass and JavaScript, in a single directory. Automation takes care of the Sass compilation to a single CSS file and JavaScript to a single JavaScript file for viewing functionality in Pattern Lab.

Because Emulsify leverages the Twig templating engine, you can build each component HTML(Twig) file and then use the Twig functions include, embed and extends to combine components into full-scale layouts. Sound confusing? No need to worry—there are multiple examples pre-built in Emulsify. Let’s take a look at one below.

Simple Accordion

Below is a simple but common user experience—the accordion. Let’s look at the markup for a single FAQ accordion item component:

<dt class="accordion-item__term">What is Emulsify?</dt>
<dd class="accordion-item__def">A Pattern Lab prototyping tool and Drupal 8 base theme.</dd>

If you look in the components/_patterns/02-molecules/accordion-item directory, you’ll find this Twig file as well as the CSS and JavaScript files that provide the default styling and open/close functionality respectively. (You’ll also see a YAML file, which is used to provide data for the component in Pattern Lab.)

But an accordion typically has multiple items, and HTML definitions should have a dl wrapper, right? Let’s take a look at the emulsify/components/_patterns/03-organisms/accordion/accordion.twig markup:

<dl class="accordion-item">
  {% for listItem in listItems.four %}
    {% include "@molecules/accordion-item/accordion-item.twig"
      with {
        "accordion_item": listItem.headline.short,
        "accordion_def": listItem.excerpt.long
      }
    %}
  {% endfor %}
</dl>

Here you can see that the only HTML added is the dl wrapper. Inside of that, we have a Twig for loop that will loop through our list items and for each one include our single accordion item component above. The rest of the component syntax is Pattern Lab specific (e.g., listItems, headline.short, excerpt.long).

Conclusion

If you are following along in your own local Emulsify installation, you can view this accordion in action inside your Pattern Lab installation. With this example, we’ve introduced not only the basics of component-based theming, but we’ve also seen an example of inheriting templates using the Twig include function. Using this example as well as the other pre-built components in Emulsify, we have what we need to start prototyping!

In the next article, we’ll dive into how to implement Emulsify as a Drupal 8 theme and start building a component-based Drupal 8 project. You can also view a recording of a webinar we made in March. Until then, see you next week!

Recommended Posts

  • Webinar presented by Brian Lewis and Evan Willhite 15-March-2017, 1pm-2pm CDT Modern web applications are not built of pages, but are better thought of as a collection of components, assembled…
  • Welcome to the final post of our frontend miniseries on style guides! In this installment, the Web Chefs talk through how we chose Pattern Lab over KSS Node for Four…
  • Shared Principles There is no question that the frontend space has exploded in the past decade, having gone from the seemingly novice aspect of web development to a first-class specialization.…
Evan Willhite
Evan Willhite

Evan Willhite is a frontend engineer at Four Kitchens who thrives on creating delightful digital experiences for users, clients, and fellow engineers. He enjoys running, hot chicken, playing music, and being a homebody with his family.

Development

Blog posts about backend engineering, frontend code work, programming tricks and tips, systems architecture, apps, APIs, microservices, and the technical side of Four Kitchens.

Read more Development
May 24 2017
May 24

WordPress and Drupal

President of Mobomo, Ken Fang, recently sat down with Clutch for a Q and A about all things WordPress and Drupal.

What should people consider when choosing a CMS or a website platform?

They should probably consider ease of use. We like open-source because of the pricing, and pricing is another thing they should take into account. Finally, for us, a lot of it revolves around how popular that particular type of technology is. Being able to find developers or even content editors that are used to that technology or CMS is important.

Could you speak about what differentiates Drupal and WordPress from each other?

Both of them are open-source platforms, and they’re probably the most popular CMS’s out there. WordPress is probably the most popular, with Drupal running a close second. Drupal is more popular in our federal space. I think the main difference is that WordPress started off more as a blogging platform, so it was typically for smaller sites. Whereas Drupal was considered to be more enterprise-grade, and therefore a lot of the larger commercial clients and larger federal clients would go with Drupal implementation.

They’ve obviously both grown a lot over the years. We’re now finding that both of the platforms are pretty comparable. WordPress has built a lot of enterprise functionality, and Drupal has built in a lot more ease of use. They’re getting closer and closer together. We still see that main segregation, with WordPress being for smaller sites, easier to use, and then Drupal for more enterprise-grade.

Could you describe the ideal client for each platform? What type of client would you recommend each platform for?

Definitely on the federal side, Drupal is a much more popular platform. Federal and enterprise clients should move to the Drupal platform, especially if they have other systems they want to integrate with, or more complex workflow and capability. WordPress we see much more on the commercial side, smaller sites. The nice thing about WordPress is that it’s pretty quick to get up and running. It’s a lot easier for the end user because of its limited capability. If you want to get something up more cost-effectively, that’s pretty simple, WordPress is a good way to go.

Could you speak about the importance of technical coding knowledge when building a website on either platform, from a client’s perspective?

Most of these main CMS’s are actually built in PHP, and most of them have a technology stack that requires different skillsets. So, on the frontend side, both of them require theming. It’s not only knowing HTML, CSS, and JavaScript, but it’s also understanding how each of the content management systems incorporate that into a theme. You usually start off with a base theme, and then you customize it as each client wants. As such, you need either WordPress or Drupal themers to do that frontend work. For any backend development, you do need PHP developers. For Drupal, it’s called modules. There are open-source modules that people contribute that you can just use, you can customize them, or you can even build your own custom modules from scratch. For WordPress, they’re called plugins, but it’s a very similar process. You can incorporate a plugin, customize it, or write your own custom plugin.

In between all of this, because it is a content management framework and platform, there are site builders or site configurators. The nice part about that is that you can literally fire up a Drupal website and not have to know any PHP coding or whatever. If you’re just doing a plain vanilla website, you can get everything up and running through the administrative interface. A Drupal or WordPress site builder can basically do that, provided they are savvy with how the system actually works form an administration standpoint. So, those are the technical skills that we typically see, that clients would need to have. In many cases, we’ll build out a website and they’ll want to maintain it. They’ll need somebody in-house, at least a Drupal site builder or a themer, or something like that.

Do you have any terms or any codes that clients should be aware of or should know prior to trying to launch a project in Drupal or WordPress?

PHP is definitely the main language they should know, and then HTML, JavaScript, and CSS for the frontend stuff. Drupal 8 has some newer technologies. Twig is used for theming as an example, so there’s a set of technologies associated with Drupal 8 they need to know as well.

Is there a particular feature of WordPress or Drupal that impressed you and potential users should know about?

I’m going to lean a little more into the Drupal world because a lot of people are starting to move to Drupal 8, which was a big rewrite. There are now a lot of sites starting to use that in production. They did quite a bit of overhaul on it. It is more API-driven now. Everything you do in Drupal 8 can be published as a web service. You can even do a lot of what they call headless Drupal implementations. That means you can use some of the more sexy frameworks, like Angular or React, to build out more intricate frontends, and still use Drupal as a CMS, but really as a web service.

Are there any features of the two platforms that could be improved to make it a better CMS?

I think they’re pretty evolved CMS’s. On both of them, platforms are getting into place to build right on the CMS’s without having to install them. Platforms like Acquia, WordPress.com, Automaticc. These platforms are profitable because from an enterprise standpoint right now, it is hard doing multisite implementations at that scale, managing all of the architecture, and stuff like that. From a technical standpoint, if you get into an enterprise, clients who says they want to be able to run a thousand sites on a single platform, that becomes difficult to do from a technical perspective. They both have the ability to support multisite implementations, but advancements in there to make those types of implementations easier to use and deploy would be a significant advancement for both platforms.

What should companies and clients expect in terms of cost for setting up a website, maintaining it, and adding new features?

For a very basic site, where you’re just taking things off the shelf – implementing the site with a theme that’s already built, and using basic content – I would say a customer can get up and running anywhere from two to six weeks, $20,000-30,000. Typically, those implementations are for very small sites. We’ve seen implementations that have run into the millions, that are pretty complex. These are sites that receive millions of hits a day; they have award-winning user experience and design, custom theming, integration with a lot of backend systems, etc. Those can take anywhere from six to twelve months, and $500,000 to $1 million to get up and running.

Can you give some insight into SEO and security when building a website?

The nice thing about Drupal and WordPress is that there are a lot of modules and plugins that will manage that, from Google Analytics to HubSpot, all sort of SEO engines. You can pretty much plug and play those things. It doesn’t replace the need for your traditional content marketing, analyzing those results and then making sure your pages have the appropriate content and keywords driving traffic into them, or whatever funnel you want. All your analytic tools usually have some sort of module or plugin, whether it’s Google, Salesforce, Pardot, or whatever. A lot of those things are already pretty baked in. You can easily get it up and running. That’s the nice thing about the SEO portion of it.

The other nice thing about it being open-source is that there are constant updates on sort of security. Using these CMS systems, because they tie to all the open-source projects, if you download a module, anytime there’s a security update for it, you’ll get alerted within your administrative interface. It’s usually just a one-click installation to install that upgrade for security patches. That’s nice, as you’re literally talking hundreds of thousands of modules and millions of users. They’re usually found and patched pretty quickly. As long as you stay on that security patching cycle, you should be okay. You could still do stupid stuff as an administrator. You could leave the default password, and somebody could get in, so you still have to manage those things. From a software perspective, as long as you’re using highly-active, contributed modules and the core, security patches and findings come out pretty regularly on those things.

As a company, because we do stuff with some regulated industries like banking and federal agencies, we usually have to go a level above on security. Take a WordPress site or whatever, we would actually remove that form the public so it couldn’t be hit from outside of a VPN or internal network, and then have it publish out actual content and static pages so the outside just doesn’t even connect to the back-end system. That does take some custom programming and specialty to do. Most people just implement your regular website with the appropriate security controls, and it’s not a big issue.

Are there any additional aspects of building a website or dealing with a CMS that you’d like to mention? Or any other CMS platforms you’d like to give some insight on?

For us, because we are such a big mobile player, we typically would say that, whatever you build, your CMS, obviously focus on user experience. Most people are doing a good job of that these days. One of the areas that is still a little weak is this whole idea of a content syndication. There’s still a big push where the content editors build webpages, and they want to control the layout, pages, etc. They get measured by the number of visitors to the website and all that stuff. I’m not saying that’s not important; however, we’re trying to push an idea of a web service content syndication. So, how you use these CMS’s to do that, so your content gets syndicated worldwide. It doesn’t necessarily have to be measured by how many people hit your website. It should be measured by the number of impressions.

For instance, with the work we’ve done at NASA, they announced the TRAPPIST-1 discovery of potential Earth-like planets. That drove a huge amount of traffic to the website, probably close to nine million hits that day. If you look at the actual reach of that content and NASA’s message – through the CMS’s integration with social media, with API’s that other websites were taking, with Flickr, that sort of thing – it hit over 2.5 billion social media posts. That’s an important thing to measure. How are you using your content management system more as a content syndication platform, opposed to just building webpages? USGS has also done a really solid job of this ‘create once, publish everywhere’ philosophy. I think people should be looking at content management systems as content management systems, not as website management systems.

We ask that you rate Drupal and WordPress on a scale of 1 – 5, with 5 being the best score.

How would you rate them for their functionalities and available features?

Drupal – 5 – We have a bias towards Drupal because it’s more enterprise-grade. It fits what a lot of our clients need. I think they’ve come a long way with both the 7 and 8 versions and have really brought down the cost of implementation and improved the ease of use.

WordPress – 4 – I think it’s fantastic. It’s obviously extremely popular and very easy to set up and use. I give it a 4 and not a 5 because it’s not as easy to extend to enterprise-grade implementations. For some functionalities, you still have to dig into core, and nobody wants to be modifying core modules.

How would you rate them for ease of use and ease of implementation?

Drupal – 4.5 for ease of use, because it’s not as easy as WordPress, and 4.5 for ease of installation.WordPress – 5 for ease of use, and 4 for ease of implementation. If you want to go out of the box, it’s a little more difficult. Configuring multisite is a real difficulty in WordPress.

How would you rate them for support, as in the response of their team and the helpfulness of available online resources?

Drupal – 4

WordPress – 4

Being open-source projects, there are a ton of people contributing. They’re very active, so you usually can get your answers. In many cases, to get something embedded into core, it does have to get reviewed by the organization, which is a bunch of volunteers for the most part. Because of that, it does take a while for things to get embedded.

How likely are you to recommend each platform for a client?

Drupal – 5

WordPress – 5

I think they’re the strongest CMS’s out there for the price.

How likely are you to recommend each platform for a user to build their own DIY website?

Drupal – 3

WordPress – 4  

If you’re going to build your own website, and you have zero technical skills, you might want to look into a Weebly, Wix, or something like that. There is a need to know how to do site-building if you use Drupal or WordPress. Somebody has to configure it and understand it.

How would you rate your overall satisfaction collaborating with each platform?

Drupal – 5

WordPress – 5

We implement on both of them regularly, and they’re really great. They solve the need for a lot of our clients to migrate from much more expensive legacy systems.

Clutch.co interview: https://clutch.co/website-builders/expert-interview/interview-mobomo-dru...

May 24 2017
May 24
Drupal logo used in Ashday Blog

In Drupal 7, site deployments could be rather difficult on ambitious sites. Some database level elements were worth programming out in hook_updates (turning on modules, reverting views, etc) and some usually weren't (block placement, contrib module configuration). I remember days where a deployment involved following a three page long Google doc of clicks that had to be carefully replicated. Ugh.

A New Hope

So if you've taken the dive into Drupal 8, you'll quickly discover one of it's most prominent features - Configuration Management. Drupal 8's ability to manage configuration with yml files is absolutely amazing! It's nearly akin to watching Star Wars and thinking "Hey, I can do anything with a lightsaber! Fight bad guys, cut holes in doors, remove my hand cuffs. Sweet!"

The Empire Strikes Back

Here's the rub. Managing Drupal 8 configuration in complex real world apps is akin to building a real world laser sword after watching Star Wars only to promptly burn your face off and lose two limbs as soon as you try to fight with it. "Ambitious digital experiences" essentially equates to "arduous development concerns" and even config management can't save the day simply by existing. You must use it for good. You must unlearn what you have learned. I blogged a bit on this shortly after Drupal 8 released, but oh how much I learned since then!

We've been doing Drupal 8 pretty heavy for about a year and a half here at Ashday and had both the fortune and misfortune of needing to manage a more complex set up which quickly revealed our deficiencies in understanding how to properly manage config.

Here's the scenario: A client needs a site that will become the model for many sites, but they don't want them to be a single site with multiple domains and they also don't want it to be costly or complicated to keep them mostly similar from a functional perspective. Given that our preferred hosting solution is Pantheon, this quickly turned into an obvious Upstream project. And that means figuring out a new way to manage D8 config other than just import/export of the whole site.

If you aren't familiar, a Pantheon Upstream works nearly identical to their core updates - you have a remote repository that, upon code getting pushed to it, notifies you through the dashboard of your updates where you can apply them in the same way you do Pantheon core updates. It's pretty slick because it provides an easy way to have a big shared chunk of code and apply updates to many sites with a few clicks (well, except when nearly every update is major and requires hands-on management - but I'm not bitter).

The Phantom Menace

Our first try at this was to give the Features module a go, but at the time the interface was just too buggy to give us enough confidence to rely on it, it auto-selected what we didn't want and didn't select what we did, and it didn't support some key things we needed like permissions. As a result we decided to home brew our own solution. We knew these sites were going to have a lot of config in common, and a lot of config unique, and we needed to deploy to many of them all in different states without tragedy striking. So to accomplish this, we concocted the following procedure that we would run at deployment time, all from a single drush command.

  • Export the current site's live config (using drush) to the config sync folder
  • Copy all config files (with uuids removed) in our cross-site custom module over top of the config sync directory
  • Copy all config files (with uuids removed) in our site-specific custom module over top of the config sync directory
  • Import all config.

What this allowed us was the ability to allow each upstream site to stray a bit as they needed to, but we could be assured the config we cared about was prioritized in the proper stacking order. The approach ultimately wasn't that different than the goal of Features, but we were in control of the process, it was all live and it was relatively quick. And you know what? It worked! For a while...

And then it didn't. You see, the method we used caused Drupal to see every config file we were tracking (upwards of 300) as changed simply because of the missing uuid. So if only 8 config files changed in a deployment, Drupal was attempting to import hundreds of config files every time. This meant that it started to slow significantly over time as the site grew in complexity and eventually, we started having timeout issues and long deployments. We also started to run into issues when there was a significant core update (ie: 8.3) because so much config was being imported unnecessarily that wasn't compatible in that moment with the new code because db updates hadn't run yet. Not good. It was time for something else.

Return of the Jedi

The Jedi in question here is again the Features module. Or maybe it's Mike Potter. At least it's not me anyways. At DrupalCon Baltimore, I was set on speaking with Mike about how we were handling config because I simply knew there was a better way. If you don't know, Mike is one of the founders of the Features module and ran a great BOF on config management in Baltimore.

So I found this delightful man and laid out what we were doing and he reacted exactly as I had hoped. He didn't say that what we were doing was terribly wrong, but it made him visibly uneasy. After a chat, I discovered that Features had come a long way since we initially tried to use it and we should really give it another shot. He also explained some of the configuration of Features to help me better understand how to use it.

So we returned to Features now and are much happier for it. The thing is though that I don't think I would have really known how to manage it if we hadn't taken the deep dive into config and figured out how it needed to work. It all helped us a lot to decide how to incorporate Features properly for this particular situation so that I actually feel good about relying on it again. And that's how most good Drupal development goes. You really should know how something works before simply relying on a contrib module or someone else's code to take care of everything because otherwise you won't really know how to deal with problems - heck, you might not even know you have a problem! I personally don't prefer spending weeks writing code and then depending at a critical moment on a mysterious piece to make it all successfully roll out to production.

So as it all played out, we now understand what Drupal puts in config, what we care about and don't, what belongs in the upstream vs our site-specific modules vs no where, etc. Here is our current process after this 6 month long journey.

  • Revert the global base feature
  • If needed, revert the site specific feature
  • Run our previous script outlined above, but now on only the 5 or 6 role config files so we handle the permissions in the same fashion

So there you have it! For how long-winded this turned out to be, I'm glossing over a lot of details that are pretty critical to understanding Drupal 8 configuration (ex: blocks are a mix of config and content), but I recommend you do the same thing we did and really get your hands dirty and understand what's going on so that you don't get bit at rollout. After all of this, we feel even moreso that Configuration Management is an astoundingly useful component of Drupal 8 and now we find ourselves a bit sad when we update our Drupal 7 sites (a version we absolutely loved!) where we don't have this amazing tool. 

So good luck and don't hesitate to drop us a note if you have any questions or thoughts on this stuff. I'll probably change my mind on all of it anyways tomorrow. That's why this job is awesome.

P.S. I apologize that I didn't find room to incorporate Attack of the Clones, Revenge of the Sith, The Force Awakens or Rogue One, but the reality is that I just didn't have time to modify our whole approach to configuration in order to make this blog post more cohesive.

Offer for a free consultation with an Ashday expert

May 17 2017
May 17
May 17th, 2017

Shared Principles

There is no question that the frontend space has exploded in the past decade, having gone from the seemingly novice aspect of web development to a first-class specialization. At the smaller agency level, being a frontend engineer typically involves a balancing act between a general knowledge of web development and keeping up with frontend best practices. This makes it all the more important for agency frontend teams to take a step back and determine some shared principles. We at Four Kitchens did this through late last summer and into fall, and here’s what we came up with. A system working from shared principles must be:

1. Backend Agnostic

Even within Four Kitchens, we build websites and applications using a variety of backend languages and database structures, and this is only a microcosm of the massive diversity in modern web development. Our frontend team strives to choose and build tools that are portable between backend systems. Not only is this a smart goal internally but it’s also an important deliverable for our clients as well.

2. Modular

It seems to me the frontend community has spent the past few years trying to find ways to incorporate best practices that have a rich history in backend programming languages. We’ve realized we, too, need to be able to build code structures that can scale without brittleness or bloat. For this reason, the Four Kitchens frontend team has rallied around component-based theming and approaches like BEM syntax. Put simply, we want the UI pieces we build to be as portable as the structure itself: flexible, removable, DRY.

3. Easy to Learn

Because we are aiming to build tools that aren’t married to backend systems and are modular, this in turn should make them much more approachable. We want to build tools that help a frontend engineer who works in any language to quickly build logically organized component-based prototypes quickly and with little ramp-up.

4. Open Source

Four Kitchens has been devoted to the culture of open-source software from the beginning, and we as a frontend team want to continue that commitment by leveraging and building tools that do the same.

Introducing Emulsify

Knowing all this, we are proud to introduce Emulsify—a Pattern Lab prototyping tool and Drupal 8 starterkit theme. Wait… Drupal 8 starterkit you say? What happened to backend agnostic? Well, we still build a lot in Drupal, and the overhead of it being a starterkit theme is tiny and unintrusive to the prototyping process. More on this in the next post.
[NB: Check back next week for our next Emulsify post!]

With these shared values, we knew we had enough of a foundation to build a tool that would both hold us accountable to these values and help instill them as we grow and onboard new developers. We also are excited about the flexibility that this opens up in our process by having a prototyping tool that allows any frontend engineer with knowledge in any backend system (or none) to focus on building a great UI for a project.

Next in the series, we’ll go through the basics of Emulsify and explain its out-of-the-box strengths that will get you prototyping in Pattern Lab and/or creating a Drupal 8 theme quickly.

Recommended Posts

Evan Willhite
Evan Willhite

Evan Willhite is a frontend engineer at Four Kitchens who thrives on creating delightful digital experiences for users, clients, and fellow engineers. He enjoys running, hot chicken, playing music, and being a homebody with his family.

Development

Blog posts about backend engineering, frontend code work, programming tricks and tips, systems architecture, apps, APIs, microservices, and the technical side of Four Kitchens.

Read more Development
May 17 2017
May 17

10 years ago (at the end of 2006), Drush appeared to make it easy for Drupal developers to do some common tasks, it wasn’t immediately popular as it was a Command-LIne tool and a lot of people didn’t appreciate the idea, but year after year it’s popularity grew as did its functionality.

By the time Drupal 7 came out it was unimaginable for most developers to build a site without Drush because of the incredible boost they got in their development process and the option of generating a site from a makefile and avoiding the need to add in their project contrib code or risk of people hacking the behaviour of this module and unfortunately this was a common practice.

But Drush with the makefile wasn’t good enough, if they update some module the makefile won’t show any update, sometimes some releases breaks other modules and it wasn’t a clear way to say “I need up to this version of that module”, indeed the whole update process itself wasn’t very automated at all, and it was only useful for download a specific version of a module and with his dependencies (it gets the latest version of them without check if they are compatible)

In parallel, 5 years ago the PHP community started development of “Composer“, a tool for dependency management of  open source PHP libraries. It quickly became very popular, and big frameworks like Symfony adopted Composer the same year it was released (Symfony 2.1.0 was the first version to use it, but nowadays all PHP frameworks use it as default install method). This tool addressed all the dependency issues that Drush had and also implemented Autoloading.

When Drupal 8 come out in 2015 it tried to use Composer in a very non-intrusive way, as a result Composer was hardly worth using. It was very slow, every new version override the composers files, and had a few other disadvantages but at least we got autoloading (finally!!). However things changed once the GitHub project “drupal-composer/drupal-project” appeared, suddenly it was possible to create a Drupal site and add/remove/update modules very easy without the help of any external tools other than Composer.

How Composer works

Composer uses a JSON file where you define the setup of your project and a lock file that contains the exact versions of installed packages when you last run composer update, or when this lock file is generated. This file is especially useful to make sure deployed versions of dependencies are the same on every build and deployment. This file is commonly committed into version control.

When you execute ‘composer install’ it first reads the lock file and installs everything from there, if this file doesn’t exist it reads the JSON file and  installs the latest version that is specified there and then generates the lock file.

Executing ‘composer update’ ignores the lock file in order to get the latest version of what you specified in the JSON file so it’s a very similar process to when you execute the install without the lock file.

Composer does more things than just download packages, it also provides an autoload for all the namespaces, and you can also define custom namespaces for your project, for example a namespace for your tests.

You have also the option to add hooks (pre, post, etc..) on the scripts commands to further automate your application build process.

Configuring Composer

Repositories

This is probably one of the most important to understand for Drupal developers.

Composer by default uses packagist as a unique source of packages and Drupal is available under “packages.drupal.org/8”. If we have some custom module, profile or theme in another place like GitHub, Bitbucket, your own packagist account or any other private repository we are going to have to add them as a custom repository.

Composer lets you define settings for repositories, such as the type of a repository For more information read this documentation.

Dev mode

In the JSON file you can define libraries and namespaces that are going to be used only for development, in this way you can deploy minimal code to Production while in your development environments you can have that plus some test frameworks and debugging tools while defining everything in the same file.

By default Composer uses the dev mode but you can add –no-dev to install only your Production libraries.

Scripts

You can create custom commands, which are very useful for things like  providing an alias for very common commands, or running multiple commands with a single command, or aggregating commands before or after execute. You can find more documentation here.

Config option

In config you can add tokens for a private repo, or change the default behavior of Composer, most of them are really useful to avoid having to add parameters when you execute any Composer command. The official documentation of this section can be found here.

Conclusion

Composer is not a replacement for Drush or Drupal Console, but Composer has so many other great benefits that it’s worth persevering with it and adopting it more widely across the Drupal and PHP communities as the base of development workflows.

It has a very intuitive standard and you can build an amazing easy deployment process, which is easy to understand for other developers and use it in CI/CD tools.

So don’t be afraid of Composer, start using it today and find out for yourself how useful it can be!

Also posted in here

Share this:

Like this:

Like Loading...
May 12 2017
May 12

Two weeks ago, I presented our story of rebuilding rednoseday.com on Drupal 8 at DrupalCon Baltimore, Drupal’s largest gathering with an attendance of over 3000!

I talked about our journey of building a product to power all our editorial websites at Comic Relief (see my previous blog post), and focused on three topics: editor experience, automation & streamlining, and using decoupled services.

So far, our product ecosystem proudly powers www.rednoseday.com, and the upcoming Red Nose Day USA Campaign, and we are currently working hard to bring www.comicrelief.com on board as well!

Check out the video of my presentation (audio+slides),

[embedded content]

or the slides only.

I’d be happy to hear your thoughts, questions and feedback below.

Featured image by Jeff Geerling

Share this:

Like this:

Like Loading...
May 10 2017
May 10
May 9th, 2017

DrupalCon is many things to many people. For me, this year’s North America DrupalCon in Baltimore was a chance to connect with my remote co-workers in the same place, help share knowledge while learning things myself, and celebrate all the things that Drupal makes possible.

The Drupal 8 with React.js and Waterwheel Training

Our first big event was “API First Drupal 8 with React.js and Waterwheel Training”, where Web Chef Luke Herrington took a canonical JavaScript application—a todo list built with React—and hooked it up to Drupal 8 through a new JavaScript library called Waterwheel.js. Todos were stored in a headless Drupal site via the JSON API module, and we even provided a login page and a `like` button for todos. Although we had a small army of Web Chefs available to help, Luke had created such a great training that our extra support wasn’t needed, and the attendees were really able to dive deep into how everything worked.

Future of the CMS: Decoupled

“I’ve completely rewritten my talk,” said Todd, the Four Kitchens CEO, at the team dinner on Monday night. I’ve seen him give this talk before but this declaration really piqued my curiosity.

There were a lot of talks at DrupalCon about the “how” of decoupling, but Todd’s revised talk is a great summary of the “why”. In it, Todd talks about the differences between CMSes being “content management systems” versus “website management systems” and about how that content can be managed so that it is reuseable on all categories of devices. Because the technology is always changing, it’s a talk he rewrites at least once a year, and I’m glad I got to see this version of the 2017 talk when I did.

Supercharge Your Next Web App with Electron

To show off his work in Electron, Web Chef James Todd brought two drawing robots to DrupalCon that he set up in our booth. Each machine was powered by RoboPaint, a packaged-up web app. I’ve been curious about Electron for a while, and when I learned that James was giving a talk on the subject I immediately reached out to help him build his slide deck so that I could learn more. His presentation was thorough and entertaining, and he encouraged people to “experiment and play with it, it’ll be fun”.

Drinks with a Mission

The Drupal community believes that open source technology has the power to improve the lives of others, so instead of the usual DrupalCon party, this year, Four Kitchens teamed up with Kalamuna and Manatí to host “Drinks with a Mission”.

We started the night by asking, “If you had a magic wand that would fix a problem, what problems would you fix?” Answers were written down on post-it notes, which were then sorted into groupings, and finally assigned to teams. Each team took their topic, such as How to Better Connect with Nature, and had to come up with solutions to the topic problem. Great ideas can begin in unexpected places, and the ensuing solutions were as thoughtful as they were hilarious.

Watch the recorded stream of the event: Part 1, Part 2

Taking the Train Home

In the last few years I’ve started to become enamored with the concept of “taking the train”. So at the end of DrupalCon I got my wish, and instead of flying, I spent an entire day traveling by rail: from Baltimore, through Philadelphia’s gorgeous train station, and then on to home in the middle of Pennsylvania.

Recommended Posts

  • A mostly full report on what went down last week in the Big Easy, gonzo journalism -style.
  • Fun & Games DrupalCon Baltimore is next week and we’re so excited to get back together in Baltimore! As the official Drupal Games sponsors, we take fun very seriously and…
  • "API First" or, as some may call it, "Decoupled Drupal", remains a topic of much discussion among the Drupal community. Here are just a few sessions being presented at Drupalcon…
Randy Oest
Randy Oest

Randy Oest is an avid Star Trek fan, plays too many board games, and bought his mother an iPad so that he wouldn't have to fix her computer anymore.

May 04 2017
May 04

Busy as all hell to get this out before DrupalCon, so this will just be a lot of quick housekeeping and some announcements.

New Releases

Commerce Authorize.net

Updates to use the new API endpoints as required by authorize.net, recommended to update promptly as the old endpoints will be discontinued by June 1st 2016. This release also contains a number of bugfixes.

https://www.drupal.org/node/2715593

Commerce Features

Commerce Checkout Panes and Commerce Payment Rules are both exportable now.

https://www.drupal.org/node/2716159

Issue of the Week

Compatibility settings other than "all" causes Discount+Coupon to be removed

Could use some extra testing and feedback on this patch to finally get compatibility fixed up on Commerce Discounts.

https://www.drupal.org/node/2621526

DrupalCon Reminder

DrupalCon New Orleans next week! We’ve got a booth (#623 to be exact) right by the Commerce Guys and Platform.sh, in the Commerce Quarter.

We’re Going Sprinting!

So the Commerce Guys are coming up to Kelowna in July to do some hardcore sprinting on Drupal Commerce 2.x with us, check out our blog post on it.

Commerce 2.x

So gonna cheat a little and include some 2.x news, Alpha4 released late last week and it has checkout! Imagine that, ecommerce with checkout :) Seriously though, it is a big jump and worth checking out. We’re going to try to have a follow-up UX post in a week or two, but right now it’s mostly just framework and not all sexed up yet. Big shoutout to Matt and Bojan at Commerce Guys who have been rocking a ton of Commerce 2.x work as of late.

May 04 2017
May 04

A candid talk from our CTO Shawn McCabe and Senior Developer Josh Miller on how they have identified their own personality traits and what they do to create new habits that help them overcome their communications weaknesses.

Josh Miller, a long time contributor to the Drupal community, will document what the large distributed team he works with does to identify team member’s personalities and smokescreens using various tools. Some of the tools that will be discussed:

  • The DISC* spectrum (Dominance, Influence, Support, and Caution) A way of defining dominant personality traits and suggestions on how an I (Josh) and a D (Shawn) can communicate effectively.
  • BAT** (Behaviour, Attitude, Technique) method for determining how you view and how your peers view your modus operandi.
  • EDP*** (Employee Development Plan) method for annual reviews of progress.

Shawn McCabe, the CTO of the same distributed team, will share how recognizing his own personality flaws have led to huge gains in communication and overall success in his position of leading multiple teams of developers. As someone who struggles with empathy and understanding others, he will discuss how he daily recognizes his weak points and deliberately does certain things even though they feel silly or like a waste of time, but ultimately bridges the gap between his personality and the successful outcomes we all want.

At the end of the session, we hope that sharing this positive case study and the tools we use will spread the idea that we can identify ourselves without judgement and learn a few new tricks to help ourselves and those around us cope.

May 04 2017
May 04

Our very own Shawn McCabe hosted a great session in regards to Drupal Commerce Performance at last week’s DrupalCon Baltimore.

We run some high volume Drupal Commerce sites, taking upwards of 10,000 orders an hour and have done a lot of performance work to get these values. Commerce traditionally can't be cached and tuned the same way an unauthenticated content site can, and normal tricks like varnish and other static caching are of limited use.

Shawn’s session provides an overview of performance problems with Drupal Commerce and Drupal 7 and ways to fix or mitigate them.

  • Caching with authenticated users
  • Caching with dynamic content
  • Scaling Orders
  • Database Locking
  • Order Locking
  • PHP 7 benefits specific to Commerce
  • Scaling Attributes and Options

He will also touch on changes coming with Commerce 2.x for Drupal 8 and how this will affect performance in Drupal, especially related to cache contexts and bigpipe.

After this talk, Commerce site admins should be able to increase their order throughput hopefully by a factor or 3x or more, depending what their existing site setup is.

May 02 2017
May 02
3 May 2017

This is the second part of a series on improving the way date ranges are presented in Drupal, by creating a field formatter that can omit the day, month or year where appropriate, displaying the date ranges in a nicer, more compact form, e.g.:

  • 24–25 January 2017
  • 29 January–3 February 2017
  • 9:00am–4:30pm, 1 April 2017

The first post dealt with porting some existing code from Drupal 7 to Drupal 8, adding an automated test along the way.

In this post, we’ll do some of the work to make the the format customisable:

  • a new config entity to store formats
  • moving the rendering logic into a service

This is a long post, and we’ll cover a lot of ground. You may want to make a cup of tea before we start.

Configurable formats

Drupal’s core date formats are stored as configuration entities. Each one consists of a single pattern made up of PHP’s date & time formatting symbols. We’ll create another type of configuration entity for date range formats. Each format will need several different patterns:

  • a default date pattern. This is used to show the full single date if the start and end dates are the same. It’s also used to show both dates fully where the range spans several years.
  • patterns for the start and end dates, where a range spans several days within the same month
  • patterns for the start and end dates, where a range spans several months within the same year

We can also support times in a similar fashion:

  • a default pattern. This is used to show the full single date & time if the start and end values are the same. It’s also used to show both dates & times fully if the range spans several days.
  • optional patterns for the start and end values, where we have a range contained within a single day

All of these 8 patterns can be stored within a single configuration entity, alongside custom separator text.

Defining a configuration entity

To create the configuration entity, we need some custom code. We can use Drupal console to generate a certain amount of boilerplate code as a starting point. Be aware that Drupal console will produce a lot of code all in one go, including the admin interface which we’ll look at in part 3.

I find it helpful to generate this boilerplate into a temporary location, then copy the files over one at a time, editing them as I go. It slows things down in a good way, and forces me to understand the code I’m going to be responsible for maintaining.

Entity class and definition

Let’s start with the entity class, which lives in src/Entity/DateRangeFormat.php:

<?php
namespace Drupal\daterange_compact\Entity;

class DateRangeFormat extends ConfigEntityBase implements DateRangeFormatInterface {
  /* implementation */
}

In order to tell Drupal that this is a configuration entity, we need to add an annotation to the class. Similar to the annotation on the field formatter in part 1, we’re telling Drupal about the existence of a new date range format configuration entity, plus some information about it.

/**
 * @ConfigEntityType(
 *   id = "date_range_format",
 *   label = @Translation("Date range format"),
 *   config_prefix = "date_range_format",
 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "label",
 *     "uuid" = "uuid"
 *   }
 * )
 */
class DateRangeFormat...

The class adheres to a corresponding DateRangeFormatInterface. We’ll refer to the interface, rather than the entity class directly, elsewhere in the code.

The complete implementation is here.

Schema

End users will create instances of the configuration entity—one per format. These can be represented as a single YAML file, and imported and exported as such. The schema describes the structure of these YAML files, dictating the type of data we’re storing inside the entity.

The schema definition is itself a YAML file, and lives in config/schema/daterange_compact.schema.yml:

daterange_compact.date_range_format.*:
  type: config_entity
  label: 'Date range format config'
  mapping:
    # properties of the config entity

The complete schema implementation is here.

Updating entity definitions

If we look at the status report of our site, we’ll see that there is an error: Mismatched entity and/or field definitions. Each time we add or change code that defines entities, we need to update Drupal’s internal copy of the definitions. We can do this with the drush entup command, and we should get the following output:

The following updates are pending:
date_range_format entity type :
  The Date range format entity type needs to be installed.

Do you wish to run all pending updates? (y/n): y
 [success] Cache rebuild complete.
 [success] Finished performing updates.

That’s the bare minimum for defining a config entity. Right now the only way to manage them is by editing YAML files by hand, but that’s enough to start working on the improved functionality for now. In the next post we’ll look at an administrative interface for editing these formats.

Providing a default entity

Any Drupal module can provide configuration entities as part of their install process. The contact module is a good example—enabling the module will create the feedback and personal contact forms, each configuration entities. You can then change those forms, remove them or add new ones.

Let’s make our module provide a date range format called Medium, following the same naming convention as Drupal’s standard date formats. We do that by providing a file called {$modulename}.{$config_entity_type}.{$machine_name}.yml in the config/install directory.

So the module will contain a config/install/daterange_compact.date_range_format.medium.yml file that looks like the following. You’ll see the properties follow the schema defined earlier. The patterns are made up of PHP date & time formatting symbols.

langcode: en
status: true
dependencies: {  }
id: medium
label: Medium
date_settings:
  default_pattern: 'j F Y'
  separator: ' - '
  same_month_start_pattern: j
  same_month_end_pattern: 'j F Y'
  same_year_start_pattern: 'j F'
  same_year_end_pattern: 'j F Y'
datetime_settings:
  default_pattern: 'j F Y H:i'
  separator: ' - '
  same_day_start_pattern: 'j F Y H:i'
  same_day_end_pattern: 'H:i'

We’ll need to re-install the module for this to take effect, but if we do, and then export the site configuration, we should get a copy of this YAML file along with the rest of the configuration.

A note on cacheability

Normally, whenever we produce some sort of output in Drupal 8, we need to provide its cacheability metdata, which describes how it may be cached. Whenever something changes, the render cache can be examined and anything that depended on it can be cleared.

Certain items, like date formats, are so widely used they a treated differently. From drupal.org:

The DateFormat config entity type entity type affects rendered content all over the place: it’s used pretty much everywhere. It seems appropriate in this case to not set cache tags that bubble up, but to just clear the entire render cache. Especially because it hardly ever changes: it’s a set-and-forget thing.

Invalidating the rendered cache tag should be done sparingly. It’s a very expensive thing to do, clearing the entire render cache. But it’s appropriate here to follow what the core date format entity does.

We need to add this to the @ConfigEntity annotation:

list_cache_tags = { "rendered" }

and this to the DateRangeFormat class:

public function getCacheTagsToInvalidate() {
  return ['rendered'];
}

Refactoring

Until now, the code for rendering date ranges has been part of the field formatter. As it’s getting more complicated, it makes sense to move it out of there into it’s own, distinct location. That means we’ll be able to use it outside of the context of a field.

We’ll use a Drupal service for this. A service is a separate class in which we can handle the business logic independently of field formatters. When Drupal manages a request, it will take care of creating an instance of the service class and making it available to other parts of the system.

Our service class it quite straightforward:

<?php
namespace Drupal\daterange_compact;

class DateRangeFormatter implements DateRangeFormatterInterface {

  function __construct(…) {
    /* implementation */
  }

  function formatDateRange($start_timestamp, $end_timestamp, $type = 'medium', …) {
    /* implementation */
  }

  function formatDateTimeRange($start_timestamp, $end_timestamp, $type = 'medium', …) {
  /* implementation */
  }

}

The complete implementation of DateRangeFormatter is here.

We then tell Drupal about the service by including it in the module’s daterange_compact.services.yml file. We can also specify dependencies on other services, and these will be passed to our object’s constructor.

services:
  daterange_compact.date_range.formatter:
    class: Drupal\daterange_compact\DateRangeFormatter
    arguments: ['@entity_type.manager', '@date.formatter']

Now our formatting functions are available to use within other parts of Drupal via the daterange_compact.date_range.formatter service. We’ll access it from the field formatter next.

You can find more documentation about Drupal 8 services on drupal.org.

Pulling it all together

We need to revisit the field formatter and make a couple of changes. First we remove the hardcoded formatting logic that was there previously, and instead delegate that work to the service. Second, we need a way to let the site builder choose a particular format.

Dependency injection

The field formatter needs to be able access to the new service. Drupal 8 makes use of dependency injection for this sort of thing—a way to access dependencies at runtime without being tied to any particular implementation.

There are a few steps involved in getting to use our service this way:

First, we want it for the lifetime of the field formatter, so it needs to be in the constructor. The constructor for FieldFormatterBase takes quite a lot of parameters. We need to accept them all as well, plus our formatter. Some of the other parameters are hidden with here for clarity.

function __construct(, DateRangeFormatterInterface $date_range_formatter) {
  parent::__construct();

  $this->dateRangeFormatter = $date_range_formatter;
}

Next, we need to state that this formatter makes use of dependency injection. We do that by making the class implement ContainerFactoryPluginInterface, which declares a create function that should be used to create instances. The create function is passed the container, an object from which we can get services by name. In the create function we get the service by name and pass it to the constructor:

static function create(ContainerInterface $container, ) {
  return new static(,
    $container->get('daterange_compact.date_range.formatter')
);

Now we will always have access to a formatter via the $this-dateRangeFormatter variable.

Field formatter settings

Whenever we use this formatter, we can choose a particular date range format. We store that choice in the field formatter settings, once for each time a field is displayed.

Adding field formatter settings is documented quite thoroughly on drupal.org, but it involves a YAML file describing the type of data we want to store, some default settings, a form and a summary.

The YAML file is named field.formatter.settings.{$formatter_name}:

field.formatter.settings.daterange_compact:
  type: mapping
  label: 'Date/time range compact display format settings'
  mapping:
    format_type:
      type: string
      label: 'Date/time range format'

The extra functions we need to implement in the DateRangeCompactFormatter class are as follows:

public static function defaultSettings() {
  /* an array of default values for the settings */
}

public function settingsForm(array $form, FormStateInterface $form_state) {
  /* form from which to choose from a list of formats */
}

public function settingsSummary() {
  /* text describing what format will be used */
}

Now when anyone opts to use the compact formatter to render a date range field, they will be prompted to choose a date range format.

Display

Finally, we have everything we need to render the date range using the chosen format. We can change the viewElements function, removing the hardcoded stuff we had before, and delegating to our date range formatter service:

$format = $settings['format_type'];
$formatter = $this->dateRangeFormatter;
$output = $formatter->formatDate($start_timestamp, $end_timestamp, $format, );

The complete implementation of the formatter is here

Test it!

We’ve added substantial functionality, so we need to make sure there have been no regressions on what we had before. We also want to test the new configurable formats.

The test should pass as before, with one small tweak. In the setUp function, we need to load the configuration for the daterange_compact module, so that the medium format is present.

We’ll also define a new usa format, for US-style month, day, year display. That is created in the setUp function:

protected function setUp() {
  parent::setUp();
  /* existing set up code */
  /* create a new date range format called "usa" */
}

We’ll add another test specifically for rendering the USA format:

function testUSAFormats() {
  $all_data = [
  ['start' => '2017-01-01', 'end' => '2017-01-01', 'expected' => 'Jan 1, 2017'],
  ['start' => '2017-01-02', 'end' => '2017-01-03', 'expected' => 'Jan 2–3, 2017'],
  ['start' => '2017-01-04', 'end' => '2017-02-05', 'expected' => 'Jan 4–Feb 5, 2017'],
  ['start' => '2017-01-06', 'end' => '2018-02-07', 'expected' => 'Jan 6, 2017–Feb 7, 2018'],
];

  foreach ($all_data as $data) {
    /* 1. programmatically create an entity and populate start/end dates */
    /* 2. programmatically render the entity */
    /* 3. assert that the output contains the expected text */
  }
}

Whilst the goal should be to have as much test coverage as possible, is isn’t feasible to cover every combination of dates, formats and settings. But we should try to test lots of variations of date and datetime ranges, edge cases, possible formats and results that would vary by timezone. And if something doesn’t behave as expected later, we can write a test to demonstrate it before changing code. Later we can verify any fixes via the new test, and make sure there are no other regressions too!

You can find the full test implementation here.

Phew, that was a lot!

In the final post, we’ll provide an admin interface for editing the date range formats and look at some implications of using this in a multilingual environment.

Apr 28 2017
Apr 28

Don’t panic! If you don’t use Content Moderation- and Layout Plugin-based components (like Display Suite, Panels, Panelizer and Contexts) then you’ll be fine upgrading to Drupal 8.3. If you do, there are just a few things you need to know first.

“It looks insanely complicated, and this is one of the reasons why the snug plastic cover it fitted into has the words Don’t Panic printed on it in large friendly letters.” – The Hitchhiker’s Guide to the Galaxy

One of our Drupal 8 projects relies on the core experimental module Content Moderation. The module has been partially re-written with Drupal 8.3, becoming dependent on the new core experimental module Workflows, so we decided to put some effort into updating to this latest minor version and studying all the changes.

An initial upgrade path workflow

We’ve been aware of Content Moderation changes for a while, thanks to the change record “Experimental Workflows module added to core”, circulating since the beginning of the year. The section on “Important upgrade information” was as scary as it was useful: “you will need to uninstall it before updating the codebase and re-install after”. And of course, “as this is an ALPHA experimental module data upgrade paths are not supported”.

We decided to experiment with what the best upgrade path would have been for our scenario, and came up with a pretty strong workflow:

  • Put website in maintenance mode.
  • Approve/Reject all the content waiting for approval. The only allowed states are Published or Draft/Unpublished. This is because after uninstalling Content Moderation, Published and Unpublished are the only states Drupal will recognise.
  • Delete content_moderation_state entities (/admin/modules/uninstall/entity/content_moderation_state).
  • Uninstall Content Moderation and dependencies, if any.
  • Upgrade Drupal codebase to 8.3 latest version.
  • Run database updates.
  • Re-install Content Moderation and dependents, if any.
  • Re-create the moderation States and Transitions from the new Workflow based UI. If you use the same name machines, you probably don’t need to update any of your custom code or views.
  • Restore the website, disabling Maintenance Mode.

After doing this, you check some random pages… and you notice something is wrong.

What’s the problem?

Visiting one of your content types’ custom display modes, made with Display Suite, may show you some fields have been disabled (they’ve either been moved to the Disabled region, or they’re missing altogether)!

Or you may notice your custom Layout theme suggestions are not loaded for your Panels.
Shame on you. You haven’t read the other 8.3 Change Records, nor the full 8.3.0 release notes.

Layouts, layouts everywhere…

The Layout Plugin contrib modules, used by modules like Display Suite and Panels, has been dropped. Instead, we have the Layout subsystem and a new experimental module, Layout Discovery, in core.

The reason for this is to unify the way contrib and custom modules (and themes) can define their own layouts, and enable them to reuse layouts created with all the modules implementing the Layout API. Putting it in core is an incentive for doing it once and doing it well.

Both Display Suite and Panels suggest using brand new branches with Drupal 8.3 (as now they both make use of the new Layout subsystem). Though apparently, you could still use your original versions, with a bit of custom effort/code. It doesn’t work for me no matter what I do, as most of the fields are still missing on my display modes which are managed through a Display Suite layout.

Let’s update those modules

Display Suite needs to be updated to version 3.0 or higher, Panels and Page Manager to 4.0 or higher. Running database updates will uninstall Layout Plugin contrib and install the Layout Discovery core module replacement, enabling the new Layout subsystem.

The Display Suite issues queue is full of people experiencing problems at this point of the process. Missing Fields, Fields in the wrong regions or Disabled, Fields settings reverted to default values. The guys are doing a wonderful job of trying to fix the bugs, and explain the best solutions for a full recovery.

DS 3.0-beta3 contains most of these fixes, and restored most of my fields and settings.

You’ll still need to review ALL your form and view display modes, because here or there, there could still be glitches.

In my scenario, I have six content types and around four custom display modes for each, so it took me around an hour to re-configure all the fields in the right way. For this reason, I do suggest going through this review process in a staging environment, before exporting the configuration and re-importing it in Production. Much quicker and safer.

Dude, where’s my layout?

You may notice that something still looks weird on a Panel or when viewing content. You think it might be related to the template, and then you remember that that specific node type or page uses a custom template, through a template suggestion.

The file is there, twig debug tells you the suggestion is on the list and so should be considered, but the file is not loaded. This is a bug (and there is already an issue for it).

Layouts used in Display Suite displays should not be affected by this bug as long as, when you define the layout on your mytheme.layouts.yml, you set the class property to ‘\Drupal\ds\Plugin\DsLayout’.

i.e.

custom_1col_hero:
  label: Custom one column layout with hero (fixed)
  category: Custom
  template: templates/layouts/custom-1col-hero
  class: '\Drupal\ds\Plugin\DsLayout'
  regions:
    hero:
      label: Hero
    main:
      label: Main
    footer:
      label: Footer

This is a workaround made for and by Display Suite. For websites using any other Layout-based contrib modules like Panels, there’s currently no solution, other than patching the core codebase.

Conclusion

The big lesson here is about contrib modules: updating core to the new version is a requirement for developers and site-builders. But forcing websites to use the unstable branches or experimental modules is as problematic as it is dangerous. Unstable code is, by definition, unstable, possibly unsecure and isn’t easy to update.

Implementing new features and surfing the new trends is essential for staying relevant. But to do that, site owners should really be given the option of choosing between stable and experimental modules.

Here are some useful links to more info:

Apr 27 2017
Apr 27

My blog post from last week was very well received and sparked a conversation in the Drupal community about the future of Drupal. That conversation has continued this week at DrupalCon Baltimore.

Yesterday during the opening keynote, Dries touched on some of the issues raised in my blog post. Later in the day we held an unofficial BoF. The turn out was smaller than I expected, but we had a great discussion.

Drupal moving from a hobbyist and business tool to being an enterprise CMS for creating "ambitious digital experiences" was raised in the Driesnote and in other conversations including the BoF. We need to acknowledge that this has happened and consider it an achievement. Some people have been left behind as Drupal has grown up. There is probably more we can do to help these people. Do we need more resources to help them skill up? Should we direct them towards WordPress, backdrop, squarespace, wix etc? Is it is possible to build smaller sites that eventually grow into larger sites?

In my original blog post I talked about "peak Drupal" and used metrics that supported this assertion. One metric missing from that post is dollars spent on Drupal. It is clear that the picture is very different when measuring success using budgets. There is a general sense that a lot of money is being spent on high end Drupal sites. This has resulted in less sites doing more with Drupal 8.

As often happens when trying to solve problems with Drupal during the BoF descended into talking technical solutions. Technical solutions and implementation detail have a place. I think it is important for the community to move beyond this and start talking about Drupal as a product.

In my mind Drupal core should be a content management framework and content hub service for building compelling digital experiences. For the record, I am not arguing Drupal should become API only. Larger users will take this and build their digital stack on top of this platform. This same platform should support an ecosystem of Drupal "distros". These product focused projects target specific use cases. Great examples of such distros include Lightning, Thunder, Open Social, aGov and Drupal Commerce. For smaller agencies and sites a distro can provide a great starting point for building new Drupal 8 sites.

The biggest challenge I see is continuing this conversation as a community. The majority of the community toolkit is focused on facilitating technical discussions and implementations. These tools will be valuable as we move from talking to doing, but right now we need tools and processes for engaging in silver discussions so we can build platinum level products.

Share this post

Apr 25 2017
Apr 25

About five years ago I was made tech lead on a Drupal 7 project. The organisation I worked for had an extremely restrictive corporate IT policy, but I was sufficiently curious to install Drupal on my own laptop and play around with it. I also went to DrupalCamp London over a weekend in March. This impressed the senior managers enough to give me a fancy-sounding job title (though in truth it involved rather a lot more meetings than it did actually writing code). I’ve gone on from there through a variety of senior Drupal developer positions, but my dirty secret is, I’ve never really contributed back to Drupal. Until the last few weeks, that is. So, I thought I’d take the time to write about why that is, and what’s changed.

Rookie mistakes

While I was learning to use Drupal, I also started learning to use StackExchange. Naively, I asked a couple of questions and got the kind of terse responses noobs who haven’t really read the contribution guidelines often get. My interior monologue said, “Well, screw those guys. I tried my best to ask constructive questions and this is what I get?”

In reality, I think I’d asked a not-particularly constructive question that at least one person had asked before, but hey, why let details get in the way of a self-righteous sense of grievance?

Fast-forward to… DrupalCon

My company sent me to DrupalCon, I think probably because I’d had the nouse to go to DrupalCamp. Amongst other things, I went to a session on the Media Module. The guy presenting said something to the effect of, we know large organisations use this, but we don’t really know how any of them use it. I put my hand up and said, well I’m the Drupal lead at a large organisation, and I’d be happy to work on some use cases for you. Someone else in the audience (I felt slightly witheringly) said, “well, yeah, but if we just do it for one organisation we’ll lose half the developers who are contributing.”

“But… but… that wasn’t even what I was suggesting,” my interior monologue wailed. “And besides, it wasn’t even me that suggested it. I was just trying to help. Screw those guys.”

Fast forward to… Drupal Global Sprint Weekend

Manifesto ran a sprint weekend a few months ago. Despite my previous experiences, I decided I’d go. I looked around for issues for a while until I found one. It was a test, so I ran it. It looked good, so I moved it into ‘Reviewed and Tested’. Almost straight away, someone moved it back.

“Well what was the point of that?” my interior monologue fulminated. “If you’re not going to trust other people to review things then why even bother?”

Actually, looking back through the issue, I realise it was perfectly reasonable to push it back to ‘Needs Work’. The issue was far from simple and the subsequent discussion covered lots of things I’d not even really thought about.

That afternoon I found another, slightly fiddly issue that needed a test. It’d been open for months, so I tested it and put it into ‘Reviewed and Tested by the Community’. I left feeling fairly negative about the whole experience. I’d spent a day mostly just looking at bug lists and the one thing I’d managed to do just got nixed straight away. “I cost £1000 a day,” said my interior monologue (actually I have no idea what my day rate is, but facts, schmacts, right?) “I donate a day of my time and this is what I get for it?”

I think we can all agree my interior monologue is sometimes kind of a dick.

Fast forward to… DrupalCamp (again)

We had DrupalCamp London a few weeks later. I went along. Amongst other things I went along to a session by @rachel_norfolk on mentoring and contribution. She talked about false starts, and even the great big unmentionable – that sometimes, especially early on, contributing might not be particularly rewarding. But she also talked about the responsibility to contribute. And about how all these people – all these organisations – are making whole careers off the back of this amazing, free thing. And if they’re not making the time to help build and maintain that thing, well, that’s pretty bad.

My inner monologue sulked a bit. “She’s right”, it said, grudgingly. “But still. Screw those guys. Let’s get a beer.”

Fast forward to… my first contribution

The following Monday morning, I logged into my Drupal.org account. And I saw that one of my issues from the Sprint day had a comment. “Chof,” said my interior monologue. “Probably just someone telling you you’ve done it wrong”. But it wasn’t. It was @xjm, closing an issue that I’d worked on and thanking me, specifically, for taking the time to document my test steps. It might not look like a whole lot, but it really felt like a big deal to me. And it made me decide to try to contribute again.

That evening when I got home, I decided to pick up another one of the issues I’d looked at at the sprint day. To be honest, I still didn’t really understand what it was about. But I tried my best to put my questions into a constructive form, and added them to the ticket.

Not long after, @wim-leers replied with answers to my questions. It moved me on just enough, and I resolved to carry on working on the ticket. Then, you know, life stuff happened and we went through a busy spell at work and I didn’t really have any time to do anything for a while. @vaplas jumped in and finished off a chunk of the work. Initially I was a bit annoyed – I’d been hoping that, having taken the time to understand what the issue was about, I’d get to complete the solution. My interior monologue was just getting ready to say something dickish when I spotted that @alexpott had credited me on the patch, and written a message saying that although I’d not written any code, I’d helped to clarify the issue.

And again, it felt pretty amazing. So I picked up another one of the tickets in the same group. Again, I didn’t have time to do as much as I would have liked, and @vaplas wrote a large chunk of the patch. But there were some bits missing, and I helped to fill them in, and @vaplas really helped me to understand what I was doing. All of a sudden, I was submitting a patch for review! Plus, I’d learned how functional tests work in Drupal 8!

And that, readers, is how I got to contributing my first core patch.

Conclusion

I guess I learned the following things:

There’s a fine line between being a help vampire and asking constructive questions

But if you try to show your working, it might help someone else, and that’s really what it’s all about. You’re also, I think, allowed to ask for help when you’re contributing in a way that maybe you’re not when you’re just looking for a solution to your own problem. In fact, I’ve learned recently it’s not unusual to upload incomplete patches, or patches that you know will fail, so that they can be discussed.

Even a small amount of acknowledgement really means a lot

Say thank you. It’s totally worth it, and it makes everyone involved feel good about themselves, and about contributing. The help and encouragement I got from Wim, Vaplas and XJM has been completely instrumental in getting me to come back and to keep on trying, and I’m very grateful to all of them.

The community’s focus on collaboration over competition isn’t just a handy, alliterative slogan

They really mean it. If you help even a little bit there’s a good chance you might get credited, and people are genuinely respectful of the effort you’re making, even if you’re just making the effort to understand.

Persistence is important

Don’t get downhearted if someone pushes an issue you’ve updated back down to its previous status. They’ve probably got a good reason for it. Don’t worry if you get too busy at work or in your life. Your ticket might move along, or it might get finished, but there will still be ways for you to help. And they’re always worth it, no matter how small they might seem.

You start to get into a rhythm

You think you won’t have time to contribute, but once you’ve found an issue or group of issues to work on, it’s quite easy to do half an hour here and there.

And lastly, if your interior monologue is anything like mine, you should probably learn to ignore it.

Apr 24 2017
Apr 24
April 24th, 2017

Making Huge Strides Back to Desktop

So what is this Electron thing everyone keeps talking about? Even if you haven’t heard of it, you may have used it! With over 4 millions daily users on Slack’s business oriented chat system, their cross-platform desktop application helps them reach their users outside of browsers, but these systems are in fact part of the same thing.

Back in May 2014, prolific bastions of open source and $2b valuated company, GitHub, took the custom application wrapper it originally created for its Atom code editor and released into the world—and Electron was born. Rebranded from “Atom Shell” in 2015, Electron began to take off almost immediately, allowing regular web developers the ability to make native-like, high performance desktop applications using the exact same HTML, CSS, and JavaScript technologies they use to make the rest of the web.

Piggybacking on the huge wave of API first work in Drupal 8 utilized via the Waterwheel client wrapper, building with Electron allows you to create nearly native desktop experiences using frameworks like React, Redux, Angular, or anything else that your team can construct to run in a web browser. Beyond even that, Electron gives JavaScript direct access to low level Node.js and operating system APIs, allowing your application direct file access, running custom binaries for data processing, execution of alternative scripting languages, serial port or hardware access, and tons more.

Supercharge Your Next Web App

This year at DrupalCon Baltimore, we present “Supercharge Your Next Web App with Electron”, a session that digs deep and covers everything you need in order to dip into the waters of Electron. We’ll talk about what big companies have already taken the plunge and even provide a checklist for when not to move from the web to a desktop app.

Though an Electron app may not be the right choice for your next application, knowing what tools are available to you—and understanding their incredible possibilities—is going to serve you anytime you’re  considering user-oriented frameworks. Don’t miss out on this interesting view into a future of low-energy/high-return desktop applications in the DrupalCon Horizons track this year.

And, during active exposition hours, make sure to come over to the Four Kitchens booth to see a live demo of an Electron app powered by JavaScript—we build a robot artist!

Four Kitchens: We make content go

Recommended Posts

  • In this issue: Launching the new EW.com, MeteorJS; plus Sane Stack, Herp Derpsum, and switching to Sublime Text 3.
  • Fun & Games DrupalCon Baltimore is next week and we’re so excited to get back together in Baltimore! As the official Drupal Games sponsors, we take fun very seriously and…
  • "API First" or, as some may call it, "Decoupled Drupal", remains a topic of much discussion among the Drupal community. Here are just a few sessions being presented at Drupalcon…
James Todd
James Todd

James tinkers with hardware, software, and everything in between.

Events

Blog posts about ephemeral news, events, parties, conferences, talks—anything with a date attached to it.

Read more Events
Apr 21 2017
Apr 21

WOW! The response to my blog post on the future of Drupal earlier this week has been phenomenal. My blog saw more traffic in 24 hours than it normally sees in a 2 to 3 week period. Around 30 comments have been left by readers. My tweet announcing the post was the top Drupal tweet for a day. Some 50 hours later it is still number 4.

It seems to really connected with many people in the community. I am still reflecting on everyone's contributions. There is a lot to take in. Rather than rush a follow up that responds to the issues raised, I will take some time to gather my thoughts.

One thing that is clear is that many people want to use DrupalCon Baltimore next week to discuss this issue. I encourage people to turn up with an open mind and engage in the conversation there.

A few people have suggested a BoF. Unfortunately all of the official BoF slots are full. Rather than that be a blocker, I've decided to run an unofficial BoF on the first day. I hope this helps facilitate the conversation.

Unofficial BoF: The Future of Drupal

When: Tuesday 25 April 2017 @ 12:30-1:30pm
Where: Exhibit Hall - meet at the Digital Echidna booth (#402) to be directed to the group
What: High level discussion about the direction people think Drupal should take.
UPDATE: An earlier version of this post had this scheduled for Monday. It is definitely happening on Tuesday.

I hope to see you in Baltimore.

Share this post

Apr 20 2017
Apr 20
21 April 2017

A while ago I wanted to present events with a date range on a Drupal 7 site. Drupal’s contributed date module provided a way to store the data, but the display wasn’t to my liking, always showing the complete start and end date.

Wouldn’t it be nice to show the dates in a more compact fashion, by not repeating the day, month or year where they aren’t necessary? Like this:

  • 24–25 January 2017
  • 29 January–3 February 2017
  • 9:00am–4:30pm, 1 April 2017

(and yes, those are en dashes!)

There didn’t seem to be a contributed module available, so I wrote some bespoke code for the project. It only supports one particular UK-specific date format, and there’s no support for different languages.

Over the last few days, I’ve spent some time porting it to Drupal 8 and improving it, suitable for release as a new contributed module. I thought I’d write about this process in the form of a tutorial over a few posts. I hope you’ll find it useful.

Let’s port this to Drupal 8

Firstly, as of Drupal 8.3, there’s an experimental core date range module, so we’re no longer reliant on another contributed module for data storage.

As mentioned, the original code doesn’t offer much in the way of customisation. Neither are there any guarantees about what will happens when different languages and timezones are introduced. While there are lots of things we can improve on later, for now let’s get what was there before working with Drupal 8.

This module consists of a field formatter. These are well documented on drupal.org, and make for quite a gentle introduction to Drupal 8 development.

It’s helpful to think of field formatters in two parts—a definition, describing what it is, and an implementation, concerned with how it works. This is quite a common pattern in Drupal. In D7, we’d see this pattern implemented as two hook functions; in D8, as a plugin and annotation.

D7 .module file → D8 plugin

In Drupal 7, lots of code lives in a single, monolithic .module file. Drupal 8 makes use of object oriented programming, so individual components such as field formatters are each defined in their own classes. A plugin is a class that implements particular functionality and is discoverable at runtime.

Our plugin is defined in src/Plugin/Field/FieldFormatter/DateRangeCompactFormatter.php and looks like this:

<?php
namespace Drupal\daterange_compact\Plugin\Field\FieldFormatter;

class DateRangeCompactFormatter extends FormatterBase {
  /* implementation */
}

D7 info hook → D8 annotation

Our Drupal 7 implementation has a hook function that specifies there is a formatter called daterange_compact (and labelled Compact), that is suitable for date/time fields:

/**
 * Implements hook_field_formatter_info().
 */
function daterange_compact_field_formatter_info() {
  $info['daterange_compact'] = array(
    'label' => t('Compact'),
    'field types' => array('datetime'),
    'settings' => array(),
  );
  return $info;
}

In Drupal 8, we supply the same information but using an annotation. Note the change of field type, Drupal 8.3 comes with a an experimental date range field type that’s separate from the singular date field.

/**
 * @FieldFormatter(
 *   id = "daterange_compact",
 *   label = @Translation("Compact"),
 *   field_types = {"daterange"}
 * )
 */
class DateRangeCompactFormatter...

D7 → D8 implementation

In Drupal 7, the formatting itself happens in another hook, that gets passed the field values (via the $items parameter) and returns the desired output. I’ve left out the actual implementation for brevity; complete versions are available here (D7) and here (D8).

/**
 * Implements hook_field_formatter_view().
 */
function daterange_compact_field_formatter_view($entity_type, $entity,
      $field, $instance, $langcode, $items, $display) {
  /* given the field values, return a render array */
}

This is really similar in Drupal 8, except that we define a function called viewElements in our class, and the field values are accessible through an object.

function viewElements(FieldItemListInterface $items, $langcode) {
  /* given the field values, return a render array */
}

Test it!

To see this in action, let’s set up a content type with a field of type date range. The field is date only—at the moment this formatter doesn’t support times (something we’ll change later). We’ll populate the field with four pairs of values, all of which should appear differently:

  • 1 January 2017 (start and end date are the same)
  • 2–3 January 2017 (same month)
  • 4 January–5 February 2017 (different months, same year)
  • 6 January 2017–7 January 2018 (different years)

A quick check reveals the output is as expected, so we’ve successfully ported the formatter to Drupal 8!

Now is an ideal time to automate that check with a unit test. We’re going to be adding more functionality to this module, during which we may well inadvertently introduce regressions. The test will help flag those up.

Writing a test in D8

Testing field formatters is done with PHPUnit. The timestamp formatter does a similar thing to our formatter, so we can examine that to see how it works. There is a TimestampFormatterTest class that extends KernelTestBase, so let’s create a similar class in modules/daterange_compact/src/Tests/DateRangeCompactFormatterTest.php:

<?php
namespace Drupal\daterange_compact\Tests;

class DateRangeCompactFormatterTest extends KernelTestBase {
  /* implementation */
}

The setUp function will create an arbitrary entity type with fields. It makes use of the entity_test module to define that entity and bundle, to which we create an appropriate daterange field and define it’s default display settings.

protected function setUp() {
  parent::setUp();
  /* 1. install the entity_test schema */
  /* 2. programmatically create a field of type daterange */
  /* 3. programmatically create a field instance based on the above */
  /* 4. set the display settings to use our new formatter */
}

Each function whose name begins with test___ corresponds to a single test. Within each test we can iterate through a set of values, populating an entity, rendering it and comparing the expected output with the actual output.

function testCompactFormatter() {
  $all_data = [
    ['start' => '2017-01-01', 'end' => '2017-01-01', 'expected' => '1 January 2017'],
    ['start' => '2017-01-02', 'end' => '2017-01-03', 'expected' => '2–3 January 2017'],
    ['start' => '2017-01-04', 'end' => '2017-02-05', 'expected' => '4 January–5 February 2017'],
    ['start' => '2017-01-06', 'end' => '2018-02-07', 'expected' => '6 January 2017–7 February 2018'],
  ];

  foreach ($all_data as $data) {
    /* 1. programmatically create an entity and populate start/end dates */
    /* 2. programmatically render the entity */
    /* 3. assert that the output contains the expected text */
  }

You can see the full implementation of the test class here.

This test won’t stop bugs, but it will mean that if the behaviour changes in such a way that the given dates start producing different output, we’ll have a way of knowing. At that point, either the code or the test might need some work.

Running the test

The run PHPUnit, we need to set it up by creating a phpunit.xml file in the core directory. This is documented on drupal.org, and there’s an example file provided.

We also need a database (different to the one used for the site itself).

To run all the tests in our module, run the following command from the core directory:

../vendor/bin/phpunit ../modules/custom/daterange_compact/

If everything worked, we should get a result like the following:

PHPUnit 4.8.27 by Sebastian Bergmann and contributors.

.

Time: 4.92 seconds, Memory: 6.75Mb

OK (1 test, 6 assertions)

The test passed! That’s a good first version of our updated contrib module.

In the next post we’ll look at some improvements, namely making the format configurable and adding support for times.

Apr 19 2017
Apr 19

Update 21 April: I've published a followup post with details of the BoF to be held at DrupalCon Baltimore on Tuesday 25 April. I hope to see you there so we can continue the conversation.

Drupal has a problem. No, not that problem.

We live in a post peak Drupal world. Drupal peaked some time during the Drupal 8 development cycle. I’ve had conversations with quite a few people who feel that we’ve lost momentum. DrupalCon attendances peaked in 2014, Google search impressions haven’t returned to their 2009 level, core downloads have trended down since 2015. We need to accept this and talk about what it means for the future of Drupal.

Technically Drupal 8 is impressive. Unfortunately the uptake has been very slow. A factor in this slow uptake is that from a developer's perspective, Drupal 8 is a new application. The upgrade path from Drupal 7 to 8 is another factor.

In the five years Drupal 8 was being developed there was a fundamental shift in software architecture. During this time we witnessed the rise of microservices. Drupal is a monolithic application that tries to do everything. Don't worry this isn't trying to rekindle the smallcore debate from last decade.

Today it is more common to see an application that is built using a handful of Laravel micro services, a couple of golang services and one built with nodejs. These applications often have multiple frontends; web (react, vuejs etc), mobile apps and an API. This is more effort to build out, but it likely to be less effort maintaining it long term.

I have heard so many excuses for why Drupal 8 adoption is so slow. After a year I think it is safe to say the community is in denial. Drupal 8 won't be as popular as D7.

Why isn't this being talked about publicly? Is it because there is a commercial interest in perpetuating the myth? Are the businesses built on offering Drupal services worried about scaring away customers? Adobe, Sitecore and others would point to such blog posts to attack Drupal. Sure, admitting we have a problem could cause some short term pain. But if we don't have the conversation we will go the way of Joomla; an irrelevant product that continues its slow decline.

Drupal needs to decide what is its future. The community is full of smart people, we should be talking about the future. This needs to be a public conversation, not something that is discussed in small groups in dark corners.

I don't think we will ever see Drupal become a collection of microservices, but I do think we need to become more modular. It is time for Drupal to pivot. I think we need to cut features and decouple the components. I think it is time for us to get back to our roots, but modernise at the same time.

Drupal has always been a content management system. It does not need to be a content delivery system. This goes beyond "Decoupled (Headless) Drupal". Drupal should become a "content hub" with pluggable workflows for creating and managing that content.

We should adopt the unix approach, do one thing and do it well. This approach would allow Drupal to be "just another service" that compliments the application.

What do you think is needed to arrest the decline of Drupal? What should Drupal 9 look like? Let's have the conversation.

Share this post

Apr 18 2017
Apr 18
April 18th, 2017

Fun & Games

DrupalCon Baltimore is next week and we’re so excited to get back together in Baltimore! As the official Drupal Games sponsors, we take fun very seriously and this year you can be sure to find some exciting things to do at our booth—we won’t spoil the surprise but let’s just say you’ll get to see some of us IRL and IVRL.

And if you visited us last year, you know we are all about that Free Throw game. Our undefeated Web Chef, Brian Lewis, will be there to take on any challenger. We’ve all been practicing and we are READY. Are you?

We’ll also have some of our widely-enjoyed Lightning Talks during lunch intervals right at our booth! Learn something new in just a few minutes, howbowdat? Stop by our booth to check out the schedule.

Web Chef Talks

It’s been an exciting year and the Web Chefs are ready to drop some knowledge, including:

Future of the CMS: Decoupled, Multichannel, and Content-as-a-Service, presented by Four Kitchens Co-Founder and CEO, Todd Ross Nienkerk.

Supercharge Your Next Web App with Electron, presented by Web Chef engineer, James Todd.

Why Klingon Matters for Content: The Secret Power of Language, presented by our content specialist, Douglas Bigham.

Training: API First Drupal 8 with React.js and Waterwheel, a training with JavaScript engineer, Luke Herrington.

Party with a Purpose

Last—but definitely not least—you’re cordially invited to our official DrupalCon gathering, Drinks with a Mission, hosted by Four Kitchens and our friends at Kalamuna and Manatí.

Join us on April 25th at Peter’s Pour House from 6-9pm for lively conversation, free-flowing libations, and a structured forum for hashing out ideas on how to use Drupal to overcome the challenges many of our communities face in today’s national and global political climate.

RSVP here!

See you in BMD!

Oh! The kittens are coming along to Baltimore as well—four of them to be exact—and we can’t wait to reveal this year’s DrupalCon t-shirt design. We’re not kitten around. We wish we could show you right meow.

P.S. Check out the 10-day Baltimore weather forecast.

Recommended Posts

Lucy Weinmeister
Lucy Weinmeister

Lucy Weinmeister is the marketing coordinator at Four Kitchens. She loves to share all the new and exciting things the Web Chefs are cooking up at 4K. She is forever reading a book.

Events

Blog posts about ephemeral news, events, parties, conferences, talks—anything with a date attached to it.

Read more Events
Apr 18 2017
Apr 18

Prefer watching a video?

Click here to sign up to our newsletter and watch an exclusive video on Image Widget Crop and Focal Point.

If you’ve done any Drupal site building, I’m sure you’ve experienced the following issue. You create an image style with the “Scale and crop” effect and everything is going great until an editor uploads an image with a different aspect ratio.

Now instead of images getting cropped correctly, they’re getting cut in half, or the top part is chopped off, and images are not displaying nicely.

You could fix this problem by tweaking the image style to handle different aspect ratios, but it’ll never be the perfect solution.

The best option is to crop images directly in Drupal, and this is what you’ll learn today.

In this tutorial, you’ll learn how to avoid these situations by using Crop API.

Now, Crop API doesn’t offer any interface on its own; it’s just an API. The two modules that provide an interface are Image Widget Crop and Focal Point. We’ll take a look at these modules in detail, in this tutorial.

Image Widget Crop gives an editor the most flexibility by allowing them to crop images directly within Drupal.

The only downside is they’ll need to manually crop an image every time they upload an image which is okay if you only have a single crop. But it can be cumbersome if you have multiple crops.

If you want full control over how the image is resized then look at using this module.

Focal Point lets an editor select a point on an image and Drupal will crop around it. It’s more automated but doesn’t give you absolute control like Image Widget Crop.

If all you want to do is make sure a particular region of the image is cropped then look at using this module.

Caching

If you’re using some reverse proxy or CDN such as Varnish or CloudFront, you will have issues with images not changing after being cropped. I can’t offer a solution in this tutorial because every case is different so this won’t be covered.

If you know of a good workaround to handle invalidating images, then leave a comment.

Getting Started

Before we begin, go download Crop API, Image Widget Crop and Focal point. For the first part, we’ll only install “Image Widget Crop.”

Using Drush:

$ drush dl crop image_widget_crop focal_point

Crop Images using Image Widget Crop

We’ll start things off my using Image Widget Crop to allow content editors to crop the image on the Article content type.

First, make sure you installed the “ImageWidgetCrop” module.

Create Crop Type

1. Go to Configuration, Crop types and click on “Add crop type”.

2. Enter in Large into Name and “Used to crop the Large image style.” into Description.

3. In Aspect Ratio add 1:1.

This will make it easier to select a crop because the aspect ratio will stay the same.

4. Once completed click on “Save crop type”.

What’s a Soft Limit and Hard Limit?

When you set a soft limit, the select region will change color indicating the soft limit has been reached. But the user can still resize the crop area smaller.

Hard limit, on the other hand, will stop a user from selecting a crop smaller than what’s been defined.

Configure Image Style

Now that we’re created a crop type. The next bit of work we need to do is configure an image style.

In this example, we’ll use the “Large (480×480)” image style which comes with the Standard installation profile.

1. Go to Configuration, “Image styles” and click on Edit on the image style named “Large (480×480)”.

2. Select “Manual crop” from the “Select a new effect” drop-down and click on Add.

3. Select Large from the “Crop type” and click on “Add effect”.

4. Re-order the effect, so it’s above “Scale 480×480” and click on “Update style”.

Let’s recap what we’ve done.

We added a manual crop effect which use the Large crop type we defined earlier. The image style will first process what’s been cropped manually, and then it’ll scale the image to 480×480.

The last effect, “Scale 480×480” is still necessary because the cropped size can be anything greater than 480×480.

Configure the Image Widget Crop

So far we’ve created a crop type and tweaked the Large image style to use the crop. Now let’s set up Image Widget Crop on the image field.

1. Go to Structure, “Content types” and click on “Manage form display” on the Article row.

2. From the Widget drop-down on the Image row, select “ImageWidget crop”.

If you can’t see the option make sure you’ve installed Image Widget Crop module.

3. Click on the cog-wheel and select Large from within the “Crop Type” drop-down.

If you can’t see your crop type make sure you’ve added it to an image style. You can’t just create a crop type; it must be added to an image style for it to appear here.

4. Click on Update to close the “Widget settings”, then scroll to the bottom and click on Save.

Test Image Cropping

Create a test article or modify an existing one. Upload an image, and you should see a collapsed fieldset called “Crop image”, click on it.

Select your crop and click on Save.

Now if you go to the article page the Large image style should display the cropped region.

Automatic Crop using Focal Point

In the last section, you learnt how to manually crop images. The problem, however, is that cropping an image is a manual process. An editor will have to crop each image they upload. It’s okay if you only have one, but on large projects, you could have a couple of crop types. Manually cropping images could be tedious.

Focal Point takes the manual work away and automatically crops around a defined focal point.

Select a focal point once, when you upload an image, and Drupal will handle the rest.

If you’re following along, go ahead and install Focal Point. We’ll configure Focal Point on the Large and Medium image style.

Set Focal Point

Go to any image field widget, and you should see a crosshair on the image. You’re not required to configure a custom image widget. Focal Point takes over the standard image widget.

The only bit of configuring we need to do is modify the Large and Medium image style.

1. Go to Configuration, “Image styles”

2. Click Edit on the Large row.

3. Select “Focal Point Scale and Crop” from the “Select a new effect” drop-down and click on Add.

4. Enter 480 into widget and height.

5. Delete the “Scale 480×480” effect.

6. Click on “Update style”.

Do the same thing for the medium image style. But instead of adding 480 to the width and height, add 220.

Image Widget

Focal Point will only work if you’re using the standard Image widget. You can’t use Focal Point and Image Widget Crop at the same time.

Preview Focal Point

Once the image styles have been configured, you can preview what the crop will look like.

Just go back to an image field and click on the Preview link.

Set Focal Point

To select a focal point just move the crosshair to where you want the focal point and save the form. Drupal will handle the rest.

Summary

Drupal has always been great at manipulating images but Crop API gives power back to the content editors and offers a flexible solution. No longer are you required to hardcode widths and heights into image styles.

Let the editor choose how they want their images cropped.

FAQs

Q: Can I use Image Widget Crop and Focal Point together?

No.

Q: I can’t select a crop from the “Crop type” drop-down even though I created a crop type.

You need to add a crop to an image style for it to appear in the drop-down.

Q: I re-cropped an image, but it hasn’t updated.

Try performing a hard refresh, ctrl+f5 on Windows or cmd + shift + r on Mac.

Apr 12 2017
Apr 12

As a Swiss-based Drupal Agency, we have to create a lot of multilingual sites. Since Switzerland has three official languages (German, French, Italian) and even one more national language (Rumantsch), we are used to this requirement and we found our way with Drupal to make this an easy task (usually). We mainly used node translations in Drupal 7 for maximum flexibility. We used to separate languages from each other using the various i18n modules, language specific menus, blocks, URL-patterns, terms and so on.

With Drupal 8, things changed.
I struggled a little doing multilingual sites in Drupal 8 the same way I was used to in Drupal 7 because node translation is not available anymore (which is good) so I had to find another way to achieve the same easy to handle translations system. For us and for our clients. Let me explain, what I have learned.

Drupal 8 multilanguage

Image: drupal8multilingual.org

Drupal 8 issues multilanguage challenges

Challenge 1: Node add / edit menu handling

The main challenge I had using Drupal 8, was the ease to build your menus directly from the node creation page. You can do it, but only for the initial language. If you try to add a translated node to another menu or rename the item, it always ends up moving / renaming the source node instead of adding a link to the translation. So it can become quite confusing building a navigation directly from the node creation page or to add translations to the menu. A workaround was to add all navigation items manually in the menu administration if you are using a menu per language. With lots of languages and menus / items, this is not really a convenient task. Fortunately, translations from the node creation page have been implemented with a later release of Drupal 8.

Challenge 2: Untranslated Nodes show up in Menu

Another thing which bothered me was that untranslated nodes show up in the navigation (if you use only one menu). This can be quite confusing since most of the times not every page is translated in every language. Or in some languages, you need a little more than in others. You can read a lot about this topic and the reasons behind (e.g. here and here). However you do it, it’s always wrong in some situations and perfectly fine in others. But to be “limited” and “locked in” to a certain way is not nice and you have to deal with it. To sum up, once a node is put into a menu, it will show up everywhere. Regardless if there are translations or not.

Challenge 3: Language Switcher shows all languages – always.

Somewhat confusing is the Language Switcher. In Drupal 7, a language link was not available or strikethrough if there was no translation available. In Drupal 8, every language is always visible and linked. So if you look on a German page which is only available in German, the language switcher will present you all language links to the same node. A click on those language links mainly changes the interface language but the node content remains the same (since not translated). Usually also with a drupalish URL (node/xxxx) because there is no translation for the node and therefore also no URL alias available. This behavior is confusing and wrong in my point of view

An example to illustrate the above-written challenges.

multilanguage issues with Drupal 8

English Front-Page with mixed navigation items.

The screen above shows an installation with 2 languages (English and German). The English Page is a basic page which has a translation. English is selected. If you choose Deutsch on the language switcher, the English Page becomes Deutsche Seite (see image below) and shows the German content. So far so good. But the second menu item you see with the title Über uns (nur Deutsch) should not appear here since it’s only available in German. But it does. And if you actually go on this page, you will see the German text with everything English around it and no URL-Alias (/node/2 in this example). This is usually not very useful for us.

multilanguage issues with Drupal 8

German only Page – Language Switcher visible.

Also, the language switcher shown in the image above is from my point of view wrong or not very useful. It shows a link to the English version, but there is no English translation for this node. So why is it there? To see a German page with English decoration? Not sure. But I want to get rid of this link or at least modify it to be stroked through if the language is not available.

How to fix improve this?

Luckily, the Drupal community is always good for help. After some “research” on the web, I finally found (besides lots of discussions and comments in the issue queues) a way to achieve the desired setup.

To sum up again: I want to see only menu items which are available in my language and only see a link to another language, if a translation is available.

Since there is no patch and still some ongoing discussions on drupal.org you need to implement it on your own. Implement the following two modules.

Hide untranslated menu items

Code from https://www.drupal.org/node/2466553#comment-11991690. Credits go to michaelkoehne.

<?php use Drupal\Core\Menu\MenuLinkInterface; use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent; use Drupal\Core\Language\LanguageInterface; /** * Implements hook_preprocess_menu(). */ function MYMODULE_preprocess_menu(&$variables) { if ($variables['menu_name'] == 'main') { $language = Drupal::languageManager() ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT) ->getId(); foreach ($variables['items'] as $key => $item) { if (!$variables['items'][$key] = MYMODULE_checkForMenuItemTranslation($item, $language)) { unset($variables['items'][$key]); } } } } function MYMODULE_checkForMenuItemTranslation($item, $language) { $menuLinkEntity = MYMODULE_load_link_entity_by_link($item['original_link']); if ($menuLinkEntity != NULL) { $languages = $menuLinkEntity->getTranslationLanguages(); // Remove links which are not translated to the current language. if (!array_key_exists($language, $languages)) { return FALSE; } else { if (count($item['below']) > 0) { foreach ($item['below'] as $subkey => $subitem) { if (!$item['below'][$subkey] = MYMODULE_checkForMenuItemTranslation($subitem, $language)) { unset($item['below'][$subkey]); } } } return $item; } } } function MYMODULE_load_link_entity_by_link(MenuLinkInterface $menuLinkContentPlugin) { $entity = NULL; if ($menuLinkContentPlugin instanceof MenuLinkContent) { $menu_link = explode(':', $menuLinkContentPlugin->getPluginId(), 2); $uuid = $menu_link[1]; $entity = \Drupal::service('entity.repository') ->loadEntityByUuid('menu_link_content', $uuid); } return $entity; }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

<?php

use Drupal\Core\Menu\MenuLinkInterface;

use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent;

use Drupal\Core\Language\LanguageInterface;

/**

* Implements hook_preprocess_menu().

*/

function MYMODULE_preprocess_menu(&$variables) {

  if ($variables['menu_name'] == 'main') {

    $language = Drupal::languageManager()

      ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)

      ->getId();

    foreach ($variables['items'] as $key => $item) {

      if (!$variables['items'][$key] = MYMODULE_checkForMenuItemTranslation($item, $language)) {

        unset($variables['items'][$key]);

      }

    }

  }

}

function MYMODULE_checkForMenuItemTranslation($item, $language) {

  $menuLinkEntity = MYMODULE_load_link_entity_by_link($item['original_link']);

  if ($menuLinkEntity != NULL) {

    $languages = $menuLinkEntity->getTranslationLanguages();

    // Remove links which are not translated to the current language.

    if (!array_key_exists($language, $languages)) {

      return FALSE;

    }

    else {

      if (count($item['below']) > 0) {

        foreach ($item['below'] as $subkey => $subitem) {

          if (!$item['below'][$subkey] = MYMODULE_checkForMenuItemTranslation($subitem, $language)) {

            unset($item['below'][$subkey]);

          }

        }

      }

      return $item;

    }

  }

}

function MYMODULE_load_link_entity_by_link(MenuLinkInterface $menuLinkContentPlugin) {

  $entity = NULL;

  if ($menuLinkContentPlugin instanceof MenuLinkContent) {

    $menu_link = explode(':', $menuLinkContentPlugin->getPluginId(), 2);

    $uuid = $menu_link[1];

    $entity = \Drupal::service('entity.repository')

      ->loadEntityByUuid('menu_link_content', $uuid);

  }

  return $entity;

}

Hide untranslated languages in language switcher

Code from https://www.drupal.org/node/2791231#comment-12004615 (slightly adapted. Links get a class, not removed by default). Credits to Leon Kessler.

<?php /** * @file * Hide language switcher links for untranslated languages on an entity. */ use Drupal\Core\Entity\ContentEntityInterface; /** * Implements hook_language_switch_links_alter(). */ function MYOTHERMODULE_language_switch_links_alter(array &$links, $type, $path) { if ($entity = MYOTHERMODULE_get_page_entity()) { $new_links = array(); foreach ($links as $lang_code => $link) { try { if ($entity->getTranslation($lang_code)->access('view')) { $new_links[$lang_code] = $link; } } catch (\InvalidArgumentException $e) { // This language is untranslated so do not add it to the links. $link['attributes']['class'][] = 'not-translated'; $new_links[$lang_code] = $link; } } $links = $new_links; // If we're left with less than 2 links, then there's nothing to switch. // Hide the language switcher. if (count($links) < 2) { $links = array(); } } } /** * Retrieve the current page entity. * * @return Drupal\Core\Entity\ContentEntityInterface * The retrieved entity, or FALSE if none found. */ function MYOTHERMODULE_get_page_entity() { $params = \Drupal::routeMatch()->getParameters()->all(); $entity = reset($params); if ($entity instanceof ContentEntityInterface) { return $entity; } return FALSE; }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

<?php

/**

* @file

* Hide language switcher links for untranslated languages on an entity.

*/

use Drupal\Core\Entity\ContentEntityInterface;

/**

* Implements hook_language_switch_links_alter().

*/

function MYOTHERMODULE_language_switch_links_alter(array &$links, $type, $path) {

  if ($entity = MYOTHERMODULE_get_page_entity()) {

    $new_links = array();

    foreach ($links as $lang_code => $link) {

      try {

        if ($entity->getTranslation($lang_code)->access('view')) {

          $new_links[$lang_code] = $link;

        }

      }

      catch (\InvalidArgumentException $e) {

        // This language is untranslated so do not add it to the links.

        $link['attributes']['class'][] = 'not-translated';

        $new_links[$lang_code] = $link;

      }

    }

    $links = $new_links;

    // If we're left with less than 2 links, then there's nothing to switch.

    // Hide the language switcher.

    if (count($links) < 2) {

      $links = array();

    }

  }

}

/**

* Retrieve the current page entity.

*

* @return Drupal\Core\Entity\ContentEntityInterface

*   The retrieved entity, or FALSE if none found.

*/

function MYOTHERMODULE_get_page_entity() {

  $params = \Drupal::routeMatch()->getParameters()->all();

  $entity = reset($params);

  if ($entity instanceof ContentEntityInterface) {

    return $entity;

  }

  return FALSE;

}

Please note: The code above is from Drupal.org and therefore thanks to the original authors linked above.

Enable those two modules and you’re all set!

I did not encounter any issues yet using those two modules. If ever something changes in the way Drupal handles those cases, you just need to switch off the modules and everything should be back to normal. So nothing to lose right?

There are other attempts to this by altering the menu block. One of them is Menu Block Current Language but I had no luck with this one. On my most recent project, it worked with one menu but not if you separate your menu by two blocks (different starting levels).

I would love to hear how you guys handle those cases or how you deal with I18N in general. I’m sure there are a gazillion other ways to do it.

Apr 07 2017
Apr 07

After implementing some larger enterprise Drupal 8 websites, I would like to share some insights, how to solve common issues in the deployment workflow with Drupal 8 CMI.

Introduction to Drupal CMI

First of all, you need to understand, how the configuration management in Drupal 8 works. CMI allows you to export all configurations and its dependencies from the database into yml text files. To make sure, you never end up in an inconsistent state, CMI always exports everything. By default, you cannot exclude certain configurations.

Example:

If you change some configuration on the live database, these configurations will be reverted in the next deployment when you use

drush config-import

1

drush config-import

This is helpful and will make sure, you have the same configuration on all your systems.

How can I have different configurations on local / stage / live environments?

Sometimes, you want to have different configurations on your environments. For example, we have installed a “devel” module only on our local environment but we want to have it disabled on the live environment.

This can be achieved by using the configuration split module: https://www.drupal.org/project/config_split

What does Configuration Split?

This module slightly modifies the CMI by implementing a Config Filter (https://www.drupal.org/project/config_filter). Importing and exporting works the same way as before, except some configuration is read from and written to different directories. Importing configuration still removes configuration not present in the files. Thus, the robustness and predictability of the configuration management remains. And the best thing is: You still can use the same drush commands if you have at least Drush 8.1.10 installed.

Configuration Split Example / Installation Guide

Install config_split using composer. You need need at least “8.x-1.0-beta4” and > drush 8.1.10 for this guide.

composer require drupal/config_split "^1.0"

1

composer require drupal/config_split "^1.0"

Enable config_split and navigate to “admin/config/development/configuration/config-split”

drush en config_split -y

1

drush en config_split -y

Optional: Installing the chosen module will make the selection of blacklists / greylists way more easier. You can enable chosen only on admin pages.

composer require drupal/chosen "^1.0"

1

composer require drupal/chosen "^1.0"

I recommend you to create an “environments” subfolder in your config folder. Inside this folder you will have a separate directory for every environment:

Drupal 8 Configuration Management Folders

Now you can configure your environments:

Config Split in Drupal 8 Configuration Management

The most important thing is, that you set every environment to “Inactive”. We will later activate them according to the environment via settings.php

Config Split settings with the Drupal 8 Configuration Management

Here is my example where I enable the devel module on local:

Dev Environment Example

Activate the environments via settings.php

This is the most important part of the whole setup up. Normally, we never commit the settings.php into git. But we have a [environment]-settings.php in git for every environment:

settings.php (not in git) variables-dev.php (in git and included in the settings.php of dev) variables-live.php (in git and included in the settings.php of live) settings.local.php (in git and included locally)

settings.php (not in git)

variables-dev.php (in git and included in the settings.php of dev)

variables-live.php (in git and included in the settings.php of live)

settings.local.php (in git and included locally)

You need to add the following line to the variables-[environment].php. Please change the variable name according to your environment machine name:

// This enables the config_split module $config['config_split.config_split.dev']['status'] = TRUE;

// This enables the config_split module

$config['config_split.config_split.dev']['status'] = TRUE;

If you have done everything correctly and cleared the cache you will see “active (overriden)” in the config_split overview next to the current environment.

Now you can continue using

drush config-import -y drush config-export -y

drush config-import -y

drush config-export -y

and config_split will do the magic.

How can I exclude certain Config Files and prevent them to be overridden / deleted on my live environment?

The most prominent candidates for this workflow are webforms and contact forms. In Drupal 7, webforms are nodes and you were able to give your CMS administrator the opportunity to create their own forms.

In Drupal 8 webforms are config entities, which means that they will be deleted while deploying if the yml files are not in git.

After testing a lot of different modules / drush scripts, I finally came up with an easy to use workflow to solve this issue and give CMS administrators the possibility to create webforms without git knowledge:

Set up an “Excluded” environment

First of all, we need an “excluded” environment. I created a subfolder in my config-folder and added a .htaccess file to protect the content. You can copy the .htaccess from an existing environment, if you are lazy. Don’t forget to deploy this folder to your live system before you do the next steps.

Folders

Excluded

Now you can exclude some config files to be excluded / grey-listed on your live environment:

webform.webform.* contact.form.*

webform.webform.*

contact.form.*

Greylist Webform in Config Split

Set the excluded environment to “Inactive”. We will later enable it on the live / dev environment via settings.php.

Enable “excluded” environment and adapt deployment workflow

We enable the “excluded” environment on the live system via variables-live.php (see above):

// This will allow module config per environment and exclude webforms from being overridden $config['config_split.config_split.excluded']['status'] = TRUE;

// This will allow module config per environment and exclude webforms from being overridden

$config['config_split.config_split.excluded']['status'] = TRUE;

In your deployment workflow / script you need to add the following line before you do a drush config-import:

#execute some drush commands echo "-----------------------------------------------------------" echo "Exporting excluded config" drush @live config-split-export -y excluded echo "-----------------------------------------------------------" echo "Importing configuration" drush @live config-import -y

1

2

3

4

5

6

7

8

#execute some drush commands

echo "-----------------------------------------------------------"

echo "Exporting excluded config"

drush @live config-split-export -y excluded

echo "-----------------------------------------------------------"

echo "Importing configuration"

drush @live config-import -y

The drush command “drush @live config-split-export -y excluded” will export all webforms and contact forms created by your CMS administrators into the folder “excluded”. The “drush config-import” command will therefore not delete them and your administrators can happily create their custom forms.

Benefit of disable “excluded” on local environment

We usually disable the “excluded” environment on our local environment. This allows us to create complex webforms on our local machine for our clients and deploy them as usual. In the end you can have a mix of customer created webforms and your own webforms which is quite helpful.

Final note

The CMI is a great tool and I would like to thank the maintainers of the config_split module for their great extension. This is a huge step forward making Drupal 8 a real Enterprise CMS Tool.

If you have any questions, don’t hesitate to post a comment.

Apr 06 2017
Apr 06

Living in the middle of nowhere and working most of my hours in the evenings I have few opportunities to attend events in person, let alone deliver presentations. As someone who likes to share knowledge and present at events this is a problem. My work around has been presenting remotely. Many of my talks are available on playlist on my youtube channel.

I've been doing remote presentations for many years. During this time I have learned a lot about what it takes to make a remote presentation sucessful.

Preparation

When scheduling a remote session you should make sure there is enough time for a test before your scheduled slot. Personally I prefer presenting after lunch as it allows an hour or so for dealing with any gremlins. The test presentation should use the same machines and connections you'll be using for your presentation.

I prefer using Hangouts On Air for my presentations. This allows me to stream my session to the world and have it recorded for future reference. I review every one of my recorded talks to see what I can do better next time.

Both sides of the connection should use wired connections. WiFi, especially at conferences can be flakely. Organisers should ensure that all presentation machines are using Ethernet, and if possible it should be on a separate VLAN.

Tips for Presenters

Presenting to a remote audience is very different to presenting in front of a live audience. When presenting in person you're able to focus on people in the audience who seem to be really engaged with your presentation or scan the crowd to see if you're putting people to sleep. Even if there is a webcam on the audience it is likely to be grainy and in a fixed position. It is also difficult to pace when presenting remotely.

When presenting in person your slides will be diplayed in full screen mode, often with a presenter view in your application of choice. Most tools don't allow you to run your slides in full screen mode. This makes it more difficult as a presenter. Transitions won't work, videos won't autoplay and any links Keynote (and PowerPoint) open will open in a new window that isn't being shared which makes demos trickier. If you don't hide the slide thumbnails to remind you of what is coming next, the audience will see them too. Recently I worked out printing thumbnails avoids revealing the punchlines prematurely.

Find out as much information as possible about the room your presentation will be held in. How big is it? What is the seating configuration? Where is the screen relative to where the podium is?

Tips for Organisers

Event organisers are usually flat out on the day of the event. Having to deal with a remote presenter adds to the workload. Some preparation can make life easier for the organisers. Well before the event day make sure someone is nominated to be the point of contact for the presenter. If possible share the details (name, email and mobile number) for the primary contact and a fallback. This avoids the presenter chasing random people from the organising team.

On the day of the event communicate delays/schedule changes to the presenter. This allows them to be ready to go at the right time.

It is always nice for the speaker to receive a swag bag and name tag in the mail. If you can afford to send this, your speaker will always appreciate it.

Need a Speaker?

Are you looking for a speaker to talk about Drupal, automation, devops, workflows or open source? I'd be happy to consider speaking at your event. If your event doesn't have a travel budget to fly me in, then I can present remotely. To discuss this futher please get in touch using my contact form.

Share this post

Apr 05 2017
Apr 05

In the past we used a Drupal 7 multi-site powering at least 3 different sites at the same time with all our business logic bundled inside of various massive custom modules shared along all the sites and some of them with dependencies of external modules (like Message Broker) and each site was using a different version of these modules.

We were restricted to deploying the work of a large team every one or two weeks. When something broke because of the number of changes we’d just deployed together with everything, we were unable to immediately know the source of the issue and sometimes we had to wait till the next scheduled deployment in order to fix the problem.

We needed to undertake a sanity test of the whole site on every deployment because a simple core update could shut down the whole site or one change in the javascript could break all the apps in one go. Every time we felt like we were delivering a Pandora’s box.

The Dream

We still wanted a Drupal 8 site that deals with the content and users, and the other functionality is decoupled into small services with the most appropriate technology/framework for that service. This means that if a service becomes unavailable the other services will still be working and it is easier to spot the bug because the project is smaller. Obviously we’d rather nothing went wrong but inevitably it will, so being able to isolate an issue and possibly take one service down to fix is much better than having no site or apps available at all.

We wanted to deploy automatically more often and create less work and get instant feedback once our work is done.

We are moving parts of our workflow/apps to other services so we can focus on improving our expertise in CI/CD, using tools like platforms.sh, travis CI, Concourse CI, etc. and get experience from the PHP world and their best practices and try to apply them in our big apps, so we can improve our workflow.

Our way

Drupal profiles

We decided to create a profile that powers a basic config and modules to all our sites so in this way is easier to maintain/update all the sites

Continuous Delivery

Our last project was a symfony 3 app, for which we started implementing our new standard pipeline that looks like this on Concourse CI:

Pipeline

Basically on each pull request (PR) we run all the unit tests to make sure that everything looks “fine”. Once the PR gets merge it tries to deploy to a test environment and it does a full sanity test in order to guarantee that nothing breaks and then we repeat the same process to the staging environment. We usually let it deploy to production then too unless we are expecting an event that would, for instance, substantially increase traffic and in that case we have the control to delay and push it when we are ready.

All the way to production can be done in less than an hour and I’d dare to say that the release is ready in the exact moment you press the merge button.

Container ecosystem

All our projects have a docker-compose file with the same image as our site so everyone has the same environment no matter what operating system are they using. We also added all the necessary commands grouped by utility as composer scripts so it is easier to remember and we don’t need to create bin/bash files

TDD

We prefer to do TDD because our tests are like the specification of the task, so when it passes, it is done. In a non-TDD environment, the goal is usually not very clear and changes can be hard to understand and test.

For covering that we decided to experiment with PHPSpec, which is a great developer-friendly testing tool that encourages Test Driven Development and also creates the initial code structure for the functionality.

Conclusion

I think everyone in the team is happy with this new way of doing things because it gives us more security, flexibility, and the freedom to learn and refactor things without fear. We have improved our deployment timescale from weeks to minutes, which is a huge achievement.

Share this:

Like this:

Like Loading...
Mar 14 2017
Mar 14

There's a lot to say about Drupal Configuration Management. Many contrib modules have emerged to address the shortcomings in core and I agree that most of them are clearly solving a need. I even have colleagues claiming "there's a CM-related article every week on Drupal Planet!". Here's one more :-)

Still, I'm trying to work with what core has to offer unless forced to do otherwise. And you can already do a ton. Seriously. What I think is crucial with CM is the possibility to 'productize' or 'featurize' a site's configuration. Think building an app from scratch through automation. Think SaaS. Put differently, it's all about being able to build a specific feature (e.g. content type, form/view mode, etc.) and ship it to any other D8 instance.

Yes, the idea here is not to solve the dev to stage to prod deployment issues but to primarily spin up a new D8 dev instance and configure it like a full-featured application. And core does that very well out of the box.

Building the app

Back in 2014 when I started learning D8 and built a PoC of a REST-based D8 endpoint, I had to wipe my test site almost daily and create it from scratch again as core was constantly changing. Then I realized CM was perfect for this use case. Back then I had to work around UUID issues. Allow a site to be installed from existing configuration demonstrates our headache isn't over just yet. But the concept was essentially the same as it is today:

  • Spin up a new D8 instance
  • Enable all required contrib/custom modules/themes
  • Export your site's configuration
  • Version-control your CM sync directory
  • Add all CM files under version control
  • Build a simple feature (e.g. content type)
  • Export your site's configuration
  • Copy the new/modified files for later use (thanks git diff)
  • Add all new/modified CM files under version control
  • Rinse & repeat

With this simple workflow, you'll be able to incrementally build a list of files to re-use when building a new D8 instance from scratch. Oh, and why would we even bother creating a module for that? This works great as it is, granted you'll be extra careful (TL;DR use git) about every change you make.

Spinning up a new app

To test setting up your app, the workflow then becomes:

  • Spin up a new D8 instance
  • Enable all required contrib/custom modules/themes
  • Export your site's configuration
  • Version-control your CM directory
  • Add all CM files under version control
  • Copy your previously backed up configuration files to the sync directory
  • Import your new configuration

Looking back to how life was before Drupal 8, you will likely not disagree this is much better already. Here's an example for building an app from scratch. All of this could obviously be scripted.

$ cd /path/to/sync/dir
$ for i in module1, module2, module3, module4, module5 ; do drush @site.env en -y $i ; done
$ drush @site.env cex -y
$ git init
$ git add --all && git commit -m "Initial configuration"
$ cp /path/to/configuration/backup/*.yml .
$ git status
$ drush @site.env cim -y
$ git add --all && git commit -m "New configuration"

Now, here's a real-life example, summarized through the bit we're interested in: building the app from scratch through config-import.

$ drush @d8.local cim -y
    Config                                           Operation                                                                                             
    field.storage.node.field_inline_client              create 
    field.storage.node.field_email                      create 
    field.storage.node.field_address                    create 
    node.type.client                                    create 
    field.field.node.client.field_email                 create 
    field.field.node.client.field_address               create 
    core.base_field_override.node.client.title          create 
    node.type.contract                                  create 
    field.field.node.contract.field_inline_client       create 
    core.base_field_override.node.contract.title        create 
    core.base_field_override.node.contract.promote      create 
    field.storage.paragraph.field_unit                  create 
    field.storage.paragraph.field_reference             create 
    field.storage.paragraph.field_quantite              create 
    field.storage.paragraph.field_price                 create 
    field.storage.node.field_service                    create 
    field.field.node.contract.field_service             create 
    core.entity_form_display.node.contract.default      create 
    paragraphs.paragraphs_type.service                  create 
    field.field.paragraph.service.field_unit            create 
    field.field.paragraph.service.field_reference       create 
    field.field.paragraph.service.field_quantite        create 
    field.field.paragraph.service.field_price           create 
    field.storage.node.field_telephone                  create 
    field.field.node.client.field_telephone             create 
    core.entity_form_display.node.client.default        create 
    field.storage.paragraph.field_description           create 
    field.field.paragraph.service.field_description     create 
    core.entity_view_display.paragraph.service.default  create 
    core.entity_form_display.paragraph.service.default  create 
    core.entity_view_display.node.contract.teaser       create 
    core.entity_view_display.node.contract.default      create 
    core.entity_view_display.node.client.default        create 
    user.role.editor                                    create 
    system.action.user_remove_role_action.editor        create 
    system.action.user_add_role_action.editor           create 
    auto_entitylabel.settings                           create
Import the listed configuration changes? (y/n): y  
 [notice] Synchronized configuration: create field.storage.node.field_inline_client.
 [notice] Synchronized configuration: create field.storage.node.field_email.
 [notice] Synchronized configuration: create field.storage.node.field_address.
 [notice] Synchronized configuration: create node.type.client.
 [notice] Synchronized configuration: create field.field.node.client.field_email.
 [notice] Synchronized configuration: create field.field.node.client.field_address.
 [notice] Synchronized configuration: create core.base_field_override.node.client.title.
 [notice] Synchronized configuration: create node.type.contract.
 [notice] Synchronized configuration: create field.field.node.contract.field_inline_client.
 [notice] Synchronized configuration: create core.base_field_override.node.contract.title.
 [notice] Synchronized configuration: create core.base_field_override.node.contract.promote.
 [notice] Synchronized configuration: create field.storage.paragraph.field_unit.
 [notice] Synchronized configuration: create field.storage.paragraph.field_reference.
 [notice] Synchronized configuration: create field.storage.paragraph.field_quantite.
 [notice] Synchronized configuration: create field.storage.paragraph.field_price.
 [notice] Synchronized configuration: create field.storage.node.field_service.
 [notice] Synchronized configuration: create field.field.node.contract.field_service.
 [notice] Synchronized configuration: create core.entity_form_display.node.contract.default.
 [notice] Synchronized configuration: create paragraphs.paragraphs_type.service.
 [notice] Synchronized configuration: create field.field.paragraph.service.field_unit.
 [notice] Synchronized configuration: create field.field.paragraph.service.field_reference.
 [notice] Synchronized configuration: create field.field.paragraph.service.field_quantite.
 [notice] Synchronized configuration: create field.field.paragraph.service.field_price.
 [notice] Synchronized configuration: create field.storage.node.field_telephone.
 [notice] Synchronized configuration: create field.field.node.client.field_telephone.
 [notice] Synchronized configuration: create core.entity_form_display.node.client.default.
 [notice] Synchronized configuration: create field.storage.paragraph.field_description.
 [notice] Synchronized configuration: create field.field.paragraph.service.field_description.
 [notice] Synchronized configuration: create core.entity_view_display.paragraph.service.default.
 [notice] Synchronized configuration: create core.entity_form_display.paragraph.service.default.
 [notice] Synchronized configuration: create core.entity_view_display.node.contract.teaser.
 [notice] Synchronized configuration: create core.entity_view_display.node.contract.default.
 [notice] Synchronized configuration: create core.entity_view_display.node.client.default.
 [notice] Synchronized configuration: create user.role.editor.
 [notice] Synchronized configuration: create system.action.user_remove_role_action.editor.
 [notice] Synchronized configuration: create system.action.user_add_role_action.editor.
 [notice] Synchronized configuration: create auto_entitylabel.settings.
 [notice] Finalizing configuration synchronization.
 [success] The configuration was imported successfully.

If the import was successful, reload your site and observe everything shows up like magic: site configuration, content types, custom fields, view/form modes, module configuration, views, etc.

Sure you could argue that doing so is very prone to errors, but remember that a) it's primarily for development needs and b) you need to version-control all of this to be able to go back to the last working commit and revert if necessary.

Wrapping up

Two other use cases I very much like are:

  • When I want to demonstrate an issue, I can simply share some files for someone else to import and quickly reproduce the issue with little efforts and no room for configuration mismatch.
  • When building a new feature (e.g. a Flag and a View), I can do so in dev, then export only the files I need, and import in stage or prod when I'm ready.

Building an app will obviously take much more than that but, as I hear more and more frustration about how Configuration Management was designed, I thought I'd set the record straight on how it solves my biggest problems when developing an app.

Mar 11 2017
Mar 11

Drupal 8

Drupal 8

I carried out a empathy mapping exercise at Drupal Camp London 2017 to capture the community’s perspective towards Drupal 8

The community perspective from Drupal Camp London towards Drupal 8:

Drupal 8 Empathy mapping the community's perspective 2017

Drupal 8 Empathy mapping the community's perspective 2017

I would encourage you to download the template, use it capture the community perspectives at your own Camps and meetups. The template can be downloaded here, and is best printed out as an A1 poster. 

Additionally please use the hashtag #D8Empathy to broadcast your findings. So that we can compare maps across camps to improve our understanding of the community and Drupal 8’s impact on it.

……

Lastly, If you got value from what I have shared please consider giving back by contributing towardsPeace Through Prosperity, you can follow, broadcast or donate.

Peace Through Prosperity improves the local/domestic environment for peace by nurturing prosperity in conflict affected geographies. We work to alleviate poverty, prevent radicalisation by empowering micro-entrepreneurs from marginalised communities. 

Peace Through Prosperity is innovating social transformation design and delivery using Agile frameworks to create and deliver low cost, high impact social development programs in ‘at risk’ communities.

Mar 09 2017
Mar 09

DrupalCamp London 2017 was the best camp I ever attended. “You come for the code, you stay for the community” is the Drupal motto, and this camp lived up to it with great keynotes, talks and an atmosphere which really encouraged collaboration. It also gave me the chance to share my thoughts on configuration deployment in Drupal 8 in a dedicated session.

Configuration Deployment in Drupal 8

This session was an attempt to demystify and counter the idea that deploying configuration in D8 is a nightmare. I made a comparison of tools which help you in the deployment process and ran an exercise on how to improve it.

Here are the slides:

There’s already lots of literature about CMI, and the number of contrib modules and drush extensions which aim to improve configuration management grows every month.

But as Acquia’s JAM said in his keynote, we should stop focusing on the ‘What’: ‘What we do’; ‘What this contrib module does’. We should instead focus on the ‘Why’, by getting out of the developer mindset and thinking about the user experience.

The main problem is that CMI imports/exports a monolithic configuration containing all your website settings. It will overwrite, or even destroy, everything in the destination if it doesn’t exist in the settings being imported/exported.

For a simple website this can be enough, but for medium-large projects you want to tailor the process, selecting what can be deleted, what needs to be overridden and what must remain untouched.

Segmenting Drupal 8 configurations for better configuration deployment

My exercise was to identify common patterns between the contrib modules and what a site builder needs when importing the configuration. I spotted four recurring segments from the original monolithic block:

Primary: this segment comprises the main structure of your website: Content Types, Fields, Core Settings. When imported/exported its settings need to override the destination, and missing ones need to be deleted.

Secondary: this segment contains all the new stuff which needs to remain untouched. It contains client new instances of e.g. Webforms, Views, Page Manager. The settings on this segment do not have to be deleted nor overridden.

Initial: this is the one-time only segment. On import/export we “suggest” its settings. The destination will accept the configuration if it does not already exist. Otherwise it will be skipped. Think about the Site settings’ email value. During development you put yours, but then in Production the client can change it. So we “offer” it the first time, but we won’t overwrite it during following imports.

Devel: this is not a real segment, not an important one at least. It’s more a placeholder for any environment-configuration we require. The name I used refers to a hypothetical ‘Devel’-only configuration settings segment, where we want to keep the configuration of e.g. Devel, Stage File Proxy, Web Profiler contrib modules. But this is just an example. Outside of its context (the environment) this segment doesn’t have any value.

In the slide deck you’ll find the segment details. Below is a matrix (also in the deck) comparing how the most popular config-related contrib modules can (or can NOT) work with the PSI segments.

Drupal 8 configuration deployment solutions

Continuing the CMI conversation

The audience at my talk seemed to like the approach and the naming convention. As I kept saying “naming things makes them less scary”.

I hope this convention can become the first drop of a waterfall of positive thoughts and improvements on the CMI world. I’ll see you at DrupalDevDays in Seville to continue the discussion, but in the meantime, please add your comments, thoughts and questions below.

Mar 07 2017
Mar 07

First and foremost thank you to all who made the time to attend my session on Empathy Driven Content Strategy at Drupal Camp London 2017. Thank you for sharing your time and perspectives.

This session was an evolution of two previous sessions:

There is a difference between walking in someone else’s footsteps and walking in their shoes!

‘Empathy Driven Content Strategy’ explores the transformation in content consumption, purpose, generation and how it impacts us. Looking at how empathy, touch points, sentiment analysis and emotional intelligence can be harnessed to create richer, more personalized experiences for people. With the purpose of motivating others to share the journey with us with content that is pertinent to and addresses their needs over the course of the journey.

We have seen how, over the past year empathy driven content, the use of sentiment analysis and knowing which touchpoint to invest in has played its role in both Brexit and the Trump campaigns. There are lessons behind their success for all regardless of which side of the campaign divide we may sit on.

As for getting started with Empathy maps, you can download examples and a blank canvas from the resources section below. Bear in mind the key takeaway is to ‘talk to people’ treat them as people first (customers later), to engage for the sake of understanding and keep our instinct to react in check… only when we understand can we respond.

Resources mentioned during the session:

Sentiment Analysis
Further reading

…………………..

Lastly, If you got value from what I have shared please consider giving back by contributing to @BringPTP, you can follow, broadcast or donate.

Peace Through Prosperity (PTP) improves the local/domestic environment for peace by nurturing prosperity in conflict affected geographies. We work to alleviate poverty, prevent radicalisation through empowering micro-entrepreneurs with knowledge, skills, ability and increasing their access to income and opportunities. We support small businesses, owned/managed by vulnerable and marginalised individuals/groups in society.

Peace Through Prosperity (PTP) is innovating social transformation design and delivery by using Agile frameworks to create and deliver low cost, immediate and lasting impact social development programs in ‘at risk’ communities.

Mar 07 2017
Mar 07

This weekend’s DrupalCamp London wasn’t my first Drupal event at all, I’ve been to 3 DrupalCon Europe, 4 DrupalCamp Dublin, and a few other DrupalCamps in Ireland and lots of meetups, but in this case I experienced a lot of ‘first times’ that I want to share.

This was the first time I’d attended a Drupal event representing a sponsor organisation, and as a result the way I experienced it was completely different.

Firstly, you focus more on your company’s goals, rather than your personal aims. In this case I was helping Capgemini UK to engage and recruit people for our open positions. This allowed me to socialise more and try to connect with people. We also had T-shirts so it was easier to attract people if you have something free for them. I was also able to have conversations with other sponsors to see why did they sponsor the event, some were also recruiting, but most of them were selling their solutions to prospective clients, Drupal developers and agencies.

The best of this experience was the people I found in other companies and the attendees approaching us for a T-shirt or a job opportunity.

New member of Capgemini UK perspective

As a new joiner in the Capgemini UK Drupal team I attended this event when I wasn’t even a month old in the company, and I am glad I could attend this event at such short notice in my new position, I think this tells a lot about the focus on training and career development Capgemini has and how much they care about Drupal.

As a new employee of the company this event allowed me to meet more colleagues from different departments or teams and meet them in a non-working environment. Again the best of this experience was the people I met and the relations I made.

I joined Capgemini from Ireland, so I was also new to the London Drupal community, and the DrupalCamp gave me the opportunity to connect and create relationships with other members of the Drupal community. Of course they were busy organising this great event, but I was able to contact some of the members, and I have to say they were very friendly when I approached any of the crew or other local members attending the event. I am very happy to have met some friendly people and I am committed to help and volunteer my time in future events, so this was a very good starting point. And again the best were the people I met.

Non-session perspective

As I had other duties I couldn’t attend all sessions. But I was able to attend some sessions and the Keynotes, with special mention to the Saturday keynote from Matt Glaman, it was very motivational and made me think anyone could evolve as a developer if they try and search the resources to get the knowledge. And the closing keynote from Danese Cooper was very inspirational as well about what Open Source is and what should be, and that we, the developers, have the power to make it happen. And we could also enjoy Malcom Young’s presentation about Code Reviews.

Conclusion

Closing this article I would like to come back to the best part of the DrupalCamp for me this year, which was the people. They are always the best part of the social events. I was able to catch up with old friends from Ireland, engage with people considering a position at Capgemini and introduce myself to the London Drupal community, so overall I am very happy with this DrupalCamp London and I will be happy to return next year. In the meantime I will be attending some Drupal meetups and trying to get involve in the community, so don’t hesitate to contact me if you have any question or you need my help.

Mar 06 2017
Mar 06

Creating and publishing quality content within time constraints is a common challenge for many content authors. As web engineers, we are focused on helping our clients overcome this challenge by delivering systems that are intuitive, stable, and a pleasure to operate.

During the architectural phase, it’s critical to craft the editorial experience to the specific needs of content authors to ensure the best content editing experience possible. Drupal 8 makes it even easier than previous versions for digital agencies to empower content creators and editors with the right tools to get the job done efficiently, and more enjoyably.

Our five tips to enhance the content editing experience with Drupal 8 are:

1. Don’t make authors guess - use structured content

2. Configure the WYSIWYG editor responsibly

3. Empower your editorial team with Quick-Edit

4. Enrich content with Media Embeds

5. Simplify content linking with LinkIt

1. Don’t make authors guess - use structured content

The abundance of different devices, screen sizes and form factors warrants the use of structured content. Structured content is content separated into distinct parts, each of which has a clearly defined purpose and can be edited and presented independently from one another according to context.

“How does that relate to a content editor’s experience?” - you may ask.

In years past, it was very popular to give content editors an ability to create “pages” using one big “MS Word-like” text box for writing their articles, news releases, product descriptions, etc. This approach produced content that was not reusable and was presented in one strict way. Who wants to navigate within one enormous text area to move images around?

Though those days are long behind us, and even though we all know about the importance of structured content, sometimes we still fail to utilize the concept correctly.

Drupal was one of the first Content Management Systems (CMS) to introduce the concept of structured content (node system - Drupal 3 in 2001). In fact, Drupal is no-doubt the best CMS for implementing the concept of structured content, but its ability to provide a good content authoring experience lagged behind this solid foundation.

Today, in Drupal 8, editing structured content is a joy!

With the WYSIWYG (What You See Is What You Get) editor and Quick Edit functionality in Drupal core, we can equip our content editors with the best of class authoring experience and workflow!

You can see the difference between unstructured and structured D8 content below. Instead of only one field containing all text, images, etc., the structured content stores each definitive piece of information in it’s own field, making content entry fast and presentation flexible!

Structured vs unstructured content

The benefits of Drupal 8 structured content approach:

  • The author clearly understands where each piece of information should reside and does not have to factor in markup, layout, and design while editing (see tip #2). Content entry becomes remarkably efficient and allows the author to concentrate on the essence of their message instead of format.
  • The publishing platform is easier to maintain while supporting system scalability.
  • The modular nature of structured content makes migrations between CMS versions or to a completely different CMS much more streamlined. A huge plus for those long-term thinkers!

2. Configure the WYSIWYG editor responsibly

Drupal 8 ships with WYSIWYG text editor in core. The editor even works great on mobile! In a society that is so dependent on our mobile devices - who wouldn’t like to be able to quickly edit a missed typo right from your phone?

Drupal 8 provides superior enhancements to the UX (User Experience) for content authors and editors out of the box. However, with a little configuration, things can be further improved.

When establishing the UI (User Interface) for content authors, site builders should focus on refining rather than whole-sale adoption of the available features. Customizing the WYSIWYG editor is the perfect example of subtle improvements that can immediately make a big difference.

The WYSIWYG text editor is an effective tool for simple content entry since it does not require the end user to be aware of HTML markup or CSS styles. Many great functions like text formatting options (font family, size, color, and background color), source code viewing, and indentation are available at our fingertips, but as site builders we should think twice before adding all those options to the text editor toolbar!

With great power comes great responsibility! Sometimes, when you give content editors control over the final appearance of the published content (e.g. text color, font family and size, image resizing, etc.), it can lead to an inconsistent color schemes, skewed image ratios, and unpredictable typography choices.

How do we help our content authors in avoiding common design / formatting mistakes? Simple!

Use a minimalist approach when configuring the WYSIWYG text editor. Give authors access to the most essential text formatting options that they will need for the type of content they create and nothing more. If the piece of content edited should not contain images or tables - do not include those buttons in the editor. The text editor should be used only for sections of text, not for the page layout.

A properly configured CMS should not allow content editors the ability to change the size of the text or play with image positioning within the text section or the ability to add H1 headers within auxiliary content.

Below is an example of a bad vs. good WYSIWYG configuration.

WYSIWYG editor configuration compared

Benefits of the minimal (thoughtful) WYSIWYG configuration:

  • Easy to use
  • Less confusion (though there are edge cases, most editors don’t use all the buttons)
  • Better usability on mobile devices
  • Less risk of breaking established website design

Let’s keep our content editors happy and not overcrowd their interfaces when it’s absolutely not necessary. It is our duty as software engineers to deliver systems that are easy to use, intuitive, scalable and uphold design consistency.

3. Empower your editorial team with Quick-Edit

The Quick Edit module is one of the most exciting new features that is included in Drupal 8 core. It allows content authors and editors to make updates to their content without ever leaving the page.

The days of clicking “Edit” and waiting for a separate page to load just to fix a tiny typo are gone! The Quick Edit module eliminates that extra step and allows content editors to save a great deal of time on updating content. As an added bonus - content editors can instantly see how updated content will look within the page flow.

Here’s the Quick Edit functionality in action.

Quick Edit module demo

Quick Edit configuration tip for back-end and front-end developers

To make use of the Quick Edit functionality within the website pages, entities have to be rendered on the page via View Modes and not as separate fields.

This restriction presents a challenge when there’s a needs to provide Quick Edit functionality for a page constructed by the Views module. More often than not, Views are used to single out and output individual fields from the entities. The most used Views formats are “Table” and “Grid”. They currently do not support Quick Edit functionality for usability reasons.

A workaround for this issue is to use the custom View modes for Entities and create custom Twig templates for each View mode that should be outputted by Views in order to accommodate custom layout options.

4. Enrich content with Media Embeds

In the era of social media, content editors can’t imagine their daily routine without being able to embed their Tweets or videos into the stories they publish on their sites. In Drupal 6 and the early days of Drupal 7, it was pretty challenging to provide this functionality within the WYSIWYG editor. Developers had to configure many different plugins and modules and ask them politely to cooperate.

The Drupal 8 Media initiative has placed the content author’s experience and needs at the forefront of community efforts. As a result, we have access to a great solution for handling external media - CKEditor Media Embed Module. It allows content editors to embed external resources such as videos, images, tweets, etc. via WYSIWYG editor. Here’s an example of the Tweet embed – the end result looks beautiful and requires minimal effort.

"If you're going to build a new site, build it in D8." - someone who knows what they're talking about quotes @jrbeaton @TriDUG pic.twitter.com/8w9GAuuARu

— Savas Labs (@Savas_Labs) January 27, 2017

With all this media goodness available to us, there is no reason why we shouldn’t go the extra mile and configure the CKEditor Media Embed module for our content authors!

5. Simplify content linking with LinkIt

Linking to content has always been a clumsy experience for content editors, especially when linking internally within the same site.

There was always the risk of accidentally navigating away from the page that you were actively editing (and losing any unsaved information) while searching for the page to link to. Also, the default CKEditor link button allowed editors to insert a link, assign it a target value, title, maybe an anchor name, but that was about it. If the link to the internal content changed, there was no way for the page to update and links throughout the website would end up broken.

Let’s not put our content editors through that horrible experience again. LinkIt module for Drupal 8 to the rescue!

With the LinkIt module the user does not have to copy / paste the URL or remember it. LinkIt provides a search for internal content with autocomplete field. Users can link not only to pages, but also to files that are stored within Drupal CMS.

The new and improved linking method is much more sustainable, as it recognizes when the URL of the linked content changes, and automatically produces the correct link within the page without the need to update that content manually.

LinkIt File link demo

Linking to files with LinkIt

My personal favorite feature of the LinkIt module is the flexible configuration options. The LinkIt module makes it possible to limit the type of entities (pages, posts, files) that are searchable via the link field. You can also create a custom configuration of the LinkIt autocomplete dialog for each WYSIWYG editor profile configured on your site. Plus, it is fully integrated with Drupal 8 configuration synchronization.

Final Thoughts

As site builders, there are many improvements that we can make in order to streamline the process of content authoring.

With the right mix of forethought and understanding, Drupal 8 allows web engineers to deliver content publishing platforms that are unique to the client’s specific needs, while making web authoring a productive and satisfying experience.

Mar 05 2017
Mar 05
5 March 2017

This weekend I’ve been at the fifth DrupalCamp London - a gathering of 500 or so designers, developers and business owners using Drupal.

I blogged previously about the CxO day on Friday and day 2 on Saturday. Today was the final day!

Breakfast time!! #drupal #dclondon pic.twitter.com/2EPGgkisZU

— DrupalCamp London (@DrupalCampLDN) March 5, 2017

We kicked off with Jeffrey “jam” McGuire, who’s work involves advising companies on the value that open source and contribution can bring.

This keynote presented a challenge to the audience: selling Drupal isn’t enough anymore. We need to provide value to businesses at a higher level.

There was much concern over whether Drupal 8 would make things “too hard” and alienate users with small sites. But those technical aspects aren’t really the problem. Increasingly, IT is becoming commoditised. Work that was previously high value is now much more readily available. WordPress, Squarespace and Shopify all provide a means to get a website online for no or very low cost. Medium and Facebook take things one step further - you can have an online presence without a website at all.

Jam referred to a TED talk by Simon Sinek on the what, how and why:

  • what - “do what I ask”
  • how - “help me to think”
  • why - “think for me”

By focusing on the why at the center of this circle, we can begin to create more value for clients.

Going to the "why" before the "what".. Reversing our way of thinking and understanding more. Inspirational keynote by @HornCologne #dclondon pic.twitter.com/sXc3L8Z5Dl

— Tawny Bartlett (@littlepixiez) March 5, 2017

This idea is something I’ve been thinking about for a while, and had some a discussions on in yesterday’s freelancers’ BoF. I’m keen to explore ways to diversify my Drupal offering to clients, perhaps with training, workshops or research.

After a coffee break, I heard Florian Lorétan speak on Elasticsearch. I don’t have any experience with this, but as a volunteer at DrupalCamp I was monitoring the room, and sometimes that means getting to hear talks that you otherwise wouldn’t have thought about going to.

Elasticsearch looked interesting - more widely used than Solr, and with a developer-friendly RESTful API. Florian showed an example of using it with Drupal’s serialization API to provide the search index with appropriate content.

ElasticSearch is new to me, and some of what was covered went over my head. But I’ve seen enough to pique my interest, particularly with regard to saved searches. I hope to play around with it more in future.

Next up was Mark Conroy on all too common scenario of a client signing off a Photoshop design, without considering real content or the variety of devices on which the site is browsed.

Mark’s most hated design tool is Photoshop, and his rant against it was a fun moment towards the end of the weekend. But it was good to have someone articulate the problem with using Photoshop for web design, and I found his explanation of how browsers and operating systems render fonts differently, and definition of a PSD as an approximation of how a website might look a helpful way I can in turn explain this to people.

Mark followed that up with an explanation of atomic design, and demonstrated using Pattern Lab with Drupal.

The weekend finished with a closing keynote by Danese Cooper. Danese has been involved with open source since 1999 and is currently chair of the Node.js foundation.

Danese gave a history of open source, and some of the pioneers of various projects - Larry Wall (Perl), Richard Stallman (GNU), Ian Murdock (Debian), Mitchell Baker (Mozilla) amongst others. People had to fight to get open source taken seriously, but now that they do, there is a new generation of developers who take that for granted. Many younger developers don’t know or care about the “open source vs free software” debate, for example.

Keynote by @DivaDanese at #dclondon pic.twitter.com/3g7183uWrv

— tvn (@tvnweb) March 5, 2017

Transparency is non-negotiable, however companies like to control things and people need to be reminded of that from time to time.

New recruits often don’t know when to push back, they expect code to always be transparent and aren’t aware of what rights they have because of open source. We need to stand up for things that we believe are wrong, both social (bullying etc), and technical - but be sure to support your argument.

I thought of the popularity of React at this point and it’s controversial licence.

We need to keep embracing the community, which is big in Drupal. It’s important to have a variety of people involved any open source project, and Danese referenced an article by Josh Berkus on how to destroy a community if we aren’t careful.

There are no “open source companies” per-se. Any for-profit company will always assess open source as a strategic move. But everyone needs to water the grass for projects to be sustainable, and companies must encouraged and given painless ways to financially support projects.

Ultimately, open source is about people.

To wrap up, I had a wonderful time at DrupalCamp London. It’s been the biggest DrupalCamp in the world (and it had the biggest cake).

A huge thanks to the speakers, sponsors, volunteers and core team that organised such a fantastic event!

See you next year for DrupalCamp London 2018?

Mar 04 2017
Mar 04
4 March 2017

This weekend I’ve been at the fifth DrupalCamp London - a gathering of 500 or so designers, developers and business owners using Drupal.

Friday was the CxO day, which I blogged about earlier. Saturday and Sunday are more technically focussed.

Cake is ready! Come grab some by ELG01. #dclondon pic.twitter.com/hAzZ8FhPSi

— DrupalCamp London (@DrupalCampLDN) March 4, 2017

The day kicked off with a keynote by Matt Glaman - a US based developer working on the Drupal Commerce project. Matt spoke on open source, what it is, and the impact it’s had on his life and career.

@nmdmatt from @CommerceGuys kicks off #dclondon 2017 to a record breaking crowd #drupal pic.twitter.com/3eQDywrnsM

— Paul Johnson (@pdjohnson) March 4, 2017

Matt’s Drupal journey began while working in a bar, using Drupal as a hobbyist by night. With no formal education in programming, Matt taught himself to program using open source, via the mentors he was able to find through the Drupal community.

Community is vital to any open source project. We all have things to contribute, not just code but support, inspiration and mentoring. Open source creates a demand for skills, and creates opportunities for people to learn and teach each other.

#opensource: "Be as knowledgeable as you choose to be." @nmdmatt #dclondon keynote. pic.twitter.com/F6a36pp0eE

— Jeffrey A. McGuire (@HornCologne) March 4, 2017

After coffee, the rest of the day was broken down into parallel talks.

Phil Wolstenholme spoke about accessibility, and demonstrated some of the improvements that had gone into Drupal 8. I really liked the new announce feature, used to audibly announce new content that appears outside of a full page request. Phil showed it working in conjunction with an autocomplete field, where a list of suggested results appears as you type the first few letters.

In web development you can inadvertently make something that’s difficult or impossible to use by those people who have some form of disability or impairment. I asked Phil what resources he’d advise people to look at to learn more about how to avoid this. WebAIM is a great place to start, but also learn how to use a screenreader like VoiceOver, which gives you a totally different perspective on your site.

Next, I gave my offline first talk. I’ve enjoyed doing this talk at various events over the last year. The audience asked a lot of questions which I’ll take as a good sign! There’s obviously an interest in this topic and I’m keen to see how we can use it with Drupal in the near future.

For anyone contemplating speaking at an event like this, I’d recommend it. I wrote some thoughts on this recently.

@erikerskine on Offline First - how to deliver good user experience on poor on intermittent internet https://t.co/inINg6iBOF #DCLondon pic.twitter.com/ZR0FgESkMT

— Paul Johnson (@pdjohnson) March 4, 2017

After lunch, Justine Pocock shared some basic design principles for developers. This was really helpful for me, although I don’t do a lot of design work, I still want to be able to make things that look presentable and it’s useful to have some constraints to work within. Justine took the DrupalCamp website apart and showed how just a few hours work (speeded up to a few minutes) made a huge improvement, using:

  • contrast, to make elements stand out and catch the eye
  • repetition, to bring uniformity and consistency
  • alignment, to organise and keep things tidy, like Tetris
  • proximity, to delineate things according to information architecture

Learn the rules like a pro, so you can break them like an artist

—Pablo Picasso

I followed that with a meaty technical talk on microservices by Ronald Ashri. Ronald explained how, rather than being about size, microservices are individual components each with a clear, well-defined scope and purpose.

With microservices, every part of the system does one thing well, with a defined, bounded context in which it operates. Different components can then be composed together to create a larger system. The goal is to make a system that makes change easy, safely and at scale.

OO has traditionally focused on objects, but the messages between them are arguably more important. Roland advised not to start by designing a data model, rather focus on business capabilities.

I finished the day with a BoF for freelancers. A BoF is a “birds of a feather” session - often arranged on the spur of the moment with no set agenda, by like-minded people who “flock together”. It was great to chat to others and get perspectives from those contracting as well as companies that employ freelancers. Thanks to Farez for organising!

At the end of the day we retired to the Blacksmith & Toffeemaker pub round the corner to continue the great conversations over a well earned pint.

Looking forward to tomorrow!

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