Oct 26 2016
Oct 26


Welcome back to another Top Modules blog post from Mediacurrent. Last year, I wrote the final top Drupal 7 modules list but never fear, we are back again with some great modules for Drupal 8. These are modules I strongly recommend because I use them on most new builds.

One thing worth mentioning is that this list is shorter than usual. One reason being that Drupal 8 is still fairly new (about a year old) and there aren’t as many stable modules in the wild as there are for Drupal 7. For a more extensive list, you can search most installed modules on

The other reason for this being a shorter list is a good one - Drupal 8 provides a lot more functionality out of the box. With Drupal 8 you can launch production-ready sites with fewer contributed modules than ever. This is a win in my view.

For some context, I added some notes towards the end of the post that mention why some modules were left off this list. Some modules were ported to Drupal 8, some are in D8 limbo, others didn’t make the list for other reasons.

Finally for this blog I added Beginner/Intermediate/Advanced labels to each module listed to help you sort through which modules are the best fit for your own level of expertise.

Enjoy! Send your feedback and hate mail to my Twitter account @drupalninja or leave a comment below. Thanks!


  1. Admin Toolbar (Beginner) - The admin toolbar module effectively replaces the popular admin menu module in Drupal 8. You will still get your rollover menus but now the entire menu is responsive.
  2. Backup and Migrate (Beginner) - Backup and migrate is still a useful module to easily schedule database backups for your Drupal site.
  3. Components (Intermediate) - If you are doing any Twig theming this module is going to help you with your Twig file includes.
  4. Config Installer (Advanced) - The config installer module allows you to install a new site using existing configuration. Without this module Drupal would complain about UUIDs not matching. If you are an experienced developer writing custom install profiles this module will be very useful for you. Eventually this logic will be moved into core.
  5. Devel (Intermediate) - Devel has been around a long time and is still a great module for developer debugging.
  6. Field Group (Beginner) - This is a helpful module for cleaning up your content types. You can organize fields into tabs, accordions, etc. to give your content editors a better experience.
  7. Google Analytics (Beginner) - This simple module allows site admins the ability to easily configure Google Analytics in Drupal.
  8. Linkit (Beginner) - Still a great module for linking content with a nice interface for editors.
  9. Metatag (Beginner) - Maintained by Mediacurrent’s very own Damien McKenna, this module is a must have for configuring your site’s meta tags.
  10. Panels / CTools / Page Manager (Intermediate) - Panels has been around for quite a while and has now been completely rebuilt for Drupal 8. If you are going to use one of these modules you are probably using all three. Panels gives you more control over page layouts than you are going to get with the core block layout page.
  11. Paragraphs / Entity Reference Revisions (Intermediate) - The paragraphs module is a Mediacurrent favorite for a couple of reasons. First, it will let you wave goodbye to field collections. Second, it will let you build a more robust content architecture. Paragraphs are like mini-content types that can handle a variety of use cases.
  12. Pathauto / Token (Beginner) - The pathauto module is a must-have module for configuring page path patterns.
  13. Redirect (Beginner) - Almost every new site needs to incorporate 301 redirects for old page URLs. The redirect module gives site admins an easy interface for creating those redirects in Drupal.
  14. Search API (Intermediate) - The Search API suite of modules is a fantastic way to configure your site searches. Now the Drupal 8 module includes the DB API which makes it even easier to get started.
  15. View unpublished (Beginner) - This is a small but handy module that fills a common permissions void in Drupal. Almost every site we do has a role without complete content editing privileges. That role still needs to be able to view unpublished content which you can’t really configure out of the box in Drupal 8.
  16. Simple Sitemap (Intermediate) - A pretty easy to configure module for creating XML sitemaps for search engines.

Modules removed from previous list

The following modules were either ported to Drupal 8 core or replaced by similar functionality in core:

No Drupal 8 stable module yet but would like one:

Other notable mentions

  1. Address field - Replaced by Address in Drupal 8. I haven’t found myself using this module lately.

  2. Commerce - Still a must-have module for commerce sites. I haven’t done as many e-commerce sites lately.

  3. Features / Strongarm - With Drupal 8 configuration management you don’t really need the Features module. There is still a Drupal 8 module but we have replaced it on our projects with D8 configuration and the config_installer profile.

  4. File entity - Still available in Drupal 8. A must-have if you need to add fields to files like images.

  5. Global Redirect - No Drupal 8 module. Some functionality has been ported to the Redirect module.

  6. Image Link Formatter - No Drupal 8 version.

  7. jQuery Update - No Drupal 8 module, could be useful as jQuery will nearly always pace well ahead of D8’s bundled jQuery package.

  8. Media - Broken up into smaller modules in Drupal 8.

  9. Menu Block - Still very handy if you need a slice of a menu.

  10. Nodequeue - No Drupal 8 version and we have used Paragraphs to provide a better experience for content editors.

  11. Panelizer - Another Drupal 7 favorite maintained by Damien McKenna. So far in Drupal 8 we have been able to provide similar functionality with other solutions (e.g. Paragraphs).

  12. Rules - The Rules module is an interesting one. While it does give you a UI for configuring actions and triggers, the same functionality can usually be added via other means.

  13. Smart Trim - Maintained by Mediacurrent’s Mark Casias - this module is still pretty handy if you need more control over your textfield summaries.

  14. Stage file proxy - Still available in Drupal 8, just not using as much.

  15. Webform - No Drupal 8 version and core contact form module gives you similar (although less robust) functionality. One contrib module that is similar in D8 is YAML Form. I haven’t used it yet but it looks like a good replacement for Webform.

Additional Resources

The Great Drupal 8 Debate | eBook
Your Drupal Site is a Platform | Blog Post
Decoupling in Drupal 8 Based on a Proven Model | Blog Post

Oct 26 2016
Oct 26

Anna and Mike are joined by Matt Glaman to discuss his new Drupal 8 Development Cookbook book, the status of Drupal Commerce, using Composer, as well as current news and a pick of the week.


DrupalEasy News

Three Stories


Picks of the Week

Upcoming Events

Follow us on Twitter

Five Questions (answers only)

  1. Photography.
  2. iA Writer.
  3. Buy a new house and move.
  4. Seal.
  5. DrupalCamp Atlanta 2013.

Intro Music


Subscribe to our podcast on iTunes, Google Play or Miro. Listen to our podcast on Stitcher.

If you'd like to leave us a voicemail, call 321-396-2340. Please keep in mind that we might play your voicemail during one of our future podcasts. Feel free to call in with suggestions, rants, questions, or corrections. If you'd rather just send us an email, please use our contact page.

Oct 25 2016
Oct 25

One of the most commonly documented ways for a PHP command line tool to be installed is via the composer global require command. This command is easy to document and easy to run, which explains its popularity. Unfortunately, this convenient function has a darker side that can cause some pretty big problems. The root of the problem is that Composer, by design, manages dependencies on a per-project basis; however, the global command installs everything into a common central project. The upshot of this is that two distinct projects that were never intended to be combined must suddenly share dependencies. In this configuration, it is all-too-common to encounter dependency conflicts that never would have been observed had these applications been installed independently.

The solution to this problem is a little tool called cgr. Cgr is short for “composer global require”, the command it is intended to replace. The cgr tool can be found on GitHub.

When cgr is used to install a PHP command line tool, it will create a separate project directory for each project that it installs. Each project will have its own vendor directory, avoiding the conflicts caused by the composer global require command. When installing tools, cgr ensures that their binaries will be installed to ~/.composer/vendor/binthe same location that composer global require places them. Thus, anyone who has already configured their system for composer global require can switch to using cgr at any time, and no additional configuration will be needed.

Installing the cgr tool is a simple matter of running composer global require consolidation/cgr. Cgr does not have any dependencies of its own, so it will always be safe to do this—even if you still have old projects installed via composer global require still lingering on your system.

The composer global require command still has a place in the php ecosystem, however, as Composer will load plugins from the global project. Therefore, composer global require should still be used to install composer plugins, such as composer versions check, that you want to have available everywhere Composer is used. For any project that does not include a composer plugin, however, the cgr tool is the better option.

Finally, there is a discussion around altering the behavior of the Composer global command, so that the cgr tool will no longer be necessary. It will probably take some time to decide how, exactly, to reconcile the needs of command line tool installation vis-a-vis the needs of Composer plugin needs; if you are interested in the current progress, see the issue in the Composer Github project. In the meantime, you should use the cgr tool to avoid any problems you may encounter with composer global require.

Topics Development, Drupal Planet, Drupal, WordPress
Oct 25 2016
Oct 25

When we left off last time, we’d assembled a definition of what versions are. Now, we’re going to dive into how we use them: comparing them to one another!

The general goal is straightforward enough: we want to know if, say, 6.x-1.0 is less than 6.x-1.1. (Yup!) Or if 6.x-1.0-alpha1 is less than 6.x-1.0. (Also yup!) Let’s rewrite these two examples as tuple comparisons:

{6,1,0,4,0,0} < {6,1,1,4,0,0} = TRUE
{6,1,0,0,0,0} < {6,1,1,0,0,0} = TRUE

To determine if one tuple is less than the other, we proceed pairwise through the tuple’s values, comparing the integers at the same position from each, until we find different values. Whichever tuple’s value at that position is less is considered to be the lesser version. (Uniformity in this comparison operation is why the mapping for prerelease types assigns unstable to 0, rather than 4.)

However, this simple comparison operation doesn’t actually meet Quo’s requirements. Remember, Quo’s crucial question is not whether there are any newer versions, but whether there are newer security releases that are likely to apply to the version we’re investigating.

So, say we’re looking at 6.x-1.1 for a given extension, and there exists a 7.x-2.2 that’s a security release. While the latter is obviously less than the former:

{6,1,1,4,0,0} < {7,2,2,4,0,0} = TRUE

We don’t care, because these releases are on totally different lines of development.

...right? I mean, it’s probably true that whatever security hole existed in 7.x-2.1 doesn’t exist in 6.x-1.1. Maybe? Sort of. Certainly, you can't upgrade to 7.x-2.1 directly from 6.x-1.1, as that's changing major versions. But Quo came to be as part of the D6LTS promise - that IF there are security holes in later versions, we'll backport them to 6.x - so it's certainly possible that the problem might still exist. It all depends on what you take these version numbers to mean.

Yeah, we need to take a detour.

Versions are meaningless

As you become accustomed to a version numbering scheme - Drupal, semver, rpm, whatever - the meanings of the version components gradually work their way to the back of your mind. You don’t really “read” versions, so much as “scan and decode” them, according to these osmosed semantics. This peculiar infection of our subconscious makes it far too easy to forget a simple fact:

Version numbers have absolutely no intrinsic meaning. They have no necessary relationship to the code they describe.

Maybe this is obvious. Maybe it isn’t. If not, consider: what would prevent you from writing a module for Drupal 7 APIs, but then tagging and releasing it as 8.x-1.0? Or, for that matter, writing a module with no functions, but prints “spork” on inclusion of its .module file? (Answer: nothing.) Also, Donald Knuth uses a π-based numbering system for TeX’s versions, adding one more digit with each successive release. The version looks like a number, but the only property that matters is its length. Versions are weird.

This nebulous relationship is both the blessing and curse of versions. The curse is obvious: we can’t actually know anything with certainty about code just by looking at, or comparing, version numbers. But the blessing is more subtle: a well-designed version numbering system provides a framework for consistently encoding all of our intended semantics, together. Both of those words have specific meaning here:

  • “Together,” as in, it combines all the different aspects of changes to code that are important for Quo’s purposes: independent lines of development, Drupal core version compatibility, D6LTS’ own patch addenda, etc.

  • “Consistent,” as in, a numerical coördinate system - rather than an ad-hoc collection of flags, strings, and numbers - is a formal mathematical system without weird, nasty combinations of states.

The blessing outweighs the curse because, even if versions may lie to us about what the code actually is, they provide a formal structure in which it’s easy to understand what it should be. And, in the wild west of organic open source software growth, knowing with certainty about what things should be is a pretty good goal. It makes tasks concrete enough that you can actually build a business and product - like Tag1 Quo! Which takes us back to the main road after our detour - what’s the answer to this question?

{6,1,1,4,0,0} < {7,1,2,4,0,0}

The strictly mathematical answer is “yes.” But, for the question we’re actually interested in. we generally assume that security releases are only necessary when they’re on both the same core version, in the same line of development (major version). So, we say “no” here. And we’d also say “no” if the core version were the same:

{6,1,1,4,0,0} < {6,1,2,4,0,0}

This one is a little iffier, though. While porting from one Drupal core version to the next almost always involves a significant rewrite, that’s not necessarily the case for major versions. The security release may actually apply. It’s the kind of thing we need to investigate when deciding whether or not to release our D6LTS patch versions.

Today, Quo assumes security releases on different lines of development aren’t applicable to one another, but what’s important is that we know that’s an assumption. By representing the versions in a fully abstracted coördinate system as we have, rather than (for example) formally encoding assumptions about e.g. “lines of development” into the data itself, we allow ourselves the flexibility of changing those assumptions if they turn out to be wrong. Being that Quo’s entire business proposition turns on answering questions about versions correctly, it pays to build on a clear, flexible foundation.

This post rounded out the broader theory and big-picture considerations for versions in Quo. In the next post, I’ll get more into the nitty gritty - how Quo implements these ideas in a way that is practical, fast, and scalable.


Oct 25 2016
Oct 25

MDedge is a digital and print publisher providing resources for health industry professionals. The portal currently contains 35 separate properties including medical journals, specialized hubs, and news publications.

The Project

Four Kitchens worked with the MDedge team to…

  • migrate over 130,000 articles, quizzes, and other content from a variety of sources
  • create a two-way integration with their print publication tool, teambase, to enable the desired editorial workflow
  • create custom integrations with a number of 3rd-party vendors to provide powerful advertisement targeting and customer identity management
  • implement a content distribution system between all properties providing a deep level of customization alongside robust automation
  • provide functional test coverage for identified high-value functionality using behat and CircleCI

Timeline and Milestones.

The Discovery phase started in September 2015, with the Design and and Build phases in the following months. The new was deployed in three stages: The first launch included a single property in July 2016—the main site featuring OBG Management. This was fast-followed by a second launch phase that included fifteen properties in September 2016, while the remaining properties were launched in October 2016.

Engineering and development specifics

  • Drupal 7
  • hosted on Pantheon
  • functional test coverage with Behat
  • continuous integration builds on CircleCI
  • code standards enforced with ESLint and PHP_CodeSniffer
  • site migration
  • custom 3rd-party integrations

The Team

Peter Sieg - Technical Lead
Mike Klanac - Project Manager
Mike Minecki - Business Analyst
Caris Hurd - UX Designer
David Diers - Engineer
Randy Oest - Frontend Engineer
Brian Lewis - Frontend Engineer
Joe Tower - Frontend Engineer
with additional support from Alex Hicks and Suzy Bates

James Todd - Engineer
Roberto Cardenas - Engineer
Simon Mora - Engineer
Hans Riemenschneider - Frontend Engineer
Karl Kaufmann - Designer

Oct 25 2016
Oct 25

As Drupal professionals, you and I know that all sites need maintenance and support after they're launched. There's security updates, bugs, minor tweaks and questions to be answered. Clients might not know that, so it's our job to educate them.

We find that it's easiest to discuss this before development starts on their new site, rather than after it's done, but whenever it happens, you'll need to agree to a plan for when things come up.

Most Drupal shops and freelancers default to "hourly as needed". Usually clients will go along with that - or even insist on it!

However, we strongly believe that billing hourly for site maintenance and support is WORSE for clients (and you).

Read more to find why - and learn a better way to do it!

Why clients think they want hourly

There's a couple reasons!

First of all, the project up until now was (probably) billed hourly. It's a familiar model for both client and Drupal shop, making it the path of least resistance.

However, the biggest reason, is that it's hard for clients to envision what sort of things they'll need.

And since they can't think of what things they'll need, it must not be very important, so only paying for a couple hours as needed will (they think) save them money.

However, it's likely that billing hourly will actually create more trouble and headache, while costing them MORE money in the long run.

Every request is a "mini negotiation"

When a new support and maintenance request comes in, you need to tell the client how long you think it'll take, even if that's only an hour or two.

Then they need to consider it, and either move forward, decide not to do it, or question "why something so simple could take so long?" Or worse yet, "why should I have to pay to fix something that should have worked in the first place?"

This creates extra stress and anxiety for the client - and extra work for you (estimates and e-mails don't write themselves)!

A "small change" is never really small

When starting from scratch, a Drupal developer can make huge progress very quickly. The big, broadstrokes are easy. You can build 70% of a site just by enabling and configuring the right modules.

It's the little details that tend to take up the majority of the time, especially little inexplicable bugs, where you think it should just work. As tech savvy people, we know this from experience - waay too much experience. ;-)

So, when a client asks you to make a "small change" and you say it should take 2 hours, but ends up taking 8 - you're not surprised. But the client might be!

This makes the cost of support and maintenance really unpredictible, and difficult to budget for the client - and this can create unnecessary friction in your relationship with them.

We can't get to that until ... next week/month/year

As a Drupal shop or freelancer, you want to keep all your developers (or yourself) billing as close to 100% of your hours as possible. Unbilled time (that isn't invested in internal projects or Open Source contributions or something) is just wasted money.

So, when a support and maintenance request comes in, you're probably focused on making your next project milestone, and might not actually have enough spare developer hours to help them!

With "hourly as needed" it's hard to reserve time to do support and maintenance work, so that when something comes up, you might not be able to help until next week or a couple weeks.

However, from the client's perspective, the website build could have progressed slower (so long as the deadline was met) but it's the support and maintenance request they want you to get done ASAP!

There's a better way!

Billing hourly (or daily or weekly) definitely makes sense when building a new site or feature.

However, we highly recommend selling maintenance and support plans at a fixed monthly fee - and have found that once clients have tried it, they like it better too!

Rather than having to estimate and negotiate for each and every request that comes in, our clients can make unlimited requests (within a specific scope depending on which plan they chose) and it's all just included. This reduces friction, increases trust and allows clients to predict their costs.

It also frees us up to spend as much time as necessary to fix a problem, without worrying about how delivering an invoice for 8 hours for a "small fix" will look to the client. Usually, this means that clients will actually end up paying less over the long-term, than they would if they paid hourly.

And because we have dependable monthly revenue for maintenance and support, we have sufficient developer hours available to handle any requests right away. So, our clients know that we're always ready to help with whatever comes up!

What's your experience with doing Drupal maintenance and support with your clients? Do you do support hourly, or on a monthly subscription? Write a comment below!

Want to sell maintenance and support plans to your customers (because you know they need it) but prefer to keep your developers' time focused on building new sites or features? We can act as your "support department" and provide white-label services to your clients on your behalf!

Oct 25 2016
Oct 25

You may have heard of a variety of Drupal 8 initiatives during the development cycle leading up to Drupal 8.0.0 being released in 2015. These were officially recognized efforts to get a variety of big changes into Drupal 8, and included projects such as configuration management, Views in core, and multilingual improvements. A lot of work from those initiatives is now part of Drupal 8. Not everything got in though, and as time moves on some priorities for new work will always shift.

With Drupal 8 we also changed how we approach future changes in the code base by switching to a new semantic versioning system and revising our development policies to embrace new features in future minor versions of the software. With a formal structure for new features to be rolled out in Drupal 8, many people have continued to push various projects forward. At DrupalCon New Orleans in Dries' keynote, he recognized the continuing efforts for major changes by carrying forward the concept of official initiatives that have been reviewed and approved by the core team. The idea of initiatives appears to be a solid concept that has been successful for our community, so we're going to keep using the same idea and word for post-launch projects as we did for the pre-launch projects.

The new initiatives

During that keynote Dries presented his list of existing and proposed official initiatives to the community. At that time the list he presented consisted of:

  • Migrate (already active)
  • Workflow (planned)
  • Media (proposed)
  • Data Modeling (proposed)
  • Block and Layout (proposed)
  • API-First (proposed)
  • Theme Component Library (proposed)

You'll notice that many of those were categorized as only proposed. That means that either folks in the community had started conversations around these things, or Dries thought these would be good ideas for someone to tackle. A proposed initiative isn't necessarily moving forward, and they do not have a formal team and/or proposed plan for accomplishing the goal. A lot has happened in the 5 months since New Orleans, so I want to take a look at where things are now, just after DrupalCon Dublin. (Note that much of this list is derived from Angie Byron's DrupalCorn keynote and several sessions from DrupalCon Dublin.)

Current active and planned initiatives

Here is a short overview of the current official initiatives for future versions of Drupal 8 (i.e. Drupal 8.3.0 and higher), along with some information about how you can follow the projects or even jump in to help.

  • The Migrate module shipped as an experimental module with Drupal 8 core when it released almost a year ago. Dries noted that this initiative was already in progress in his keynote, and there have been significant improvements to the system in each minor version so far (both Drupal 8.1.0 and 8.2.0). There is still yet more work to do to get it completely stable and feature-rich so there is ongoing work here. You can keep track of the work in the meta issue, Stabilize the older Drupal to newer Drupal migration system.
  • The Content Workflow initiative has moved from planning to fully active. The most significant change so far is that we now have a new experimental module in 8.2, Content Moderation. You can track it in the meta issue linked above, and there is a very nice post by Yoroy, Content workflow initiative, the concept map that defines the scope and areas to be addressed.
  • The API-first initiative is another one that has moved from proposed into fully active. This is currently focused on REST improvements for core. 25% of change records for 8.2 were for the REST module. The next target in sight is to get JSON API in as an experimental module. To learn more about what their plans are, you can see their DrupalCon core conversation.
  • There has been a team of people working on Media in the Drupal contributed space for the last 2 years, including work on a media library, using remote media, WYSIWYG embedding, and re-usability of media. They are now moving out of a proposed initiative with a plan to move these best-of-breed features into Drupal core. You can see the issues they are hammering on in their kanban board. For a complete overview, check out the DrupalCon Dublin core conversation session.
  • The Blocks and Layouts initiative is one that was also a pre-launch project (formerly called the Scotch initiative). There is still work happening on that front in the contributed space, with strategic core issues to pave the way for moving this work into core. The issues are widespread and you can follow them by looking for the D8panels tag in the issue queue.
  • The Usability initiative was not part of Dries' initial list, but there has been a strong UX team working throughout Drupal 8's development. We saw 2 new experimental modules in 8.2, Place block and Settings tray, and there is more coming for 8.3, most notably Quick edit improvements. This team also had a session at DrupalCon Dublin.

Proposed initiatives

These are some new initiatives that have been proposed within the community, and some of Dries' initial list that have not yet been adopted by or planned by anyone yet.

  • The New core theme initiative is moving along quickly with a team formed up and their plan outlined. This is just waiting on a green light from the core committers to move this into an official initiative. You can find out more about the plan from the DrupalCon Dublin core conversation.
  • The Theme component library was on Dries' list, but this one has been put on hold while the new core theme is worked out. To see some of the ideas being sketched out, you can see what's going on in the Zen theme as a proof-of-concept.
  • Both the Data modeling and Cross-channel organization ideas proposed by Dries have not gathered momentum or a team to carry them forward yet.

A Note about experimental modules

You'll notice that in these initiatives "experimental" modules are mentioned a lot. The idea is to get new features into core in various non-stable states (alpha, beta, etc.) and see how they work out. If they work out well then they will eventually become full, stable modules in core. If not, they can always be removed. Due to the fact that they could be removed, it is generally not recommended to use these for production sites, but of course getting people to test them out on real sites gives the feedback needed to evaluate and improve them.

The initiative pipeline

Given the wide variety of projects that are always going on in the Drupal community, how exactly do new initiatives come along, outside of having Dries announce them at a DrupalCon? Dries outlined some basic guidelines in New Orleans, but to make things clearer there is now a new Ideas project and issue queue on You can see everyone's proposals and anyone can work an idea out where the community and core committers can give feedback. As a prototype or game plan is approved, it gets moved into the core issue queue for full implementation.

For a really good look at the changes in Drupal 8 development and the way new features are moving into core, Gábor Hojtsy has a great presentation, Checking on Drupal 8's Rapid Innovation Promises.

Oct 25 2016
Oct 25

If you want to add Google's reCaptcha ( to your Drupal 7 forms programmatically you need to follow these two steps:

1) Install and enable captcha ( and recaptcha ( modules. The best way to do this is to use drush: drush en -y recaptcha

2) Add this snippet to any Drupal form's code you wish to have this captcha on:

  1. $form['captcha'] = array(

  2. '#type' => 'captcha',

  3. '#captcha_type' => 'recaptcha/reCAPTCHA',

  4. );

And you're done! I hope from now on, spam bots will bother you less.

Don't forget to share this little tip if you like it!

Oct 25 2016
Oct 25

CSSgram module supplements Drupal Image styling experience by making Instagram like filters available to your Drupal 8 site images, we do this with help of CSSgram library. 

Beauty of this module is, it simply uses css to beautify your image.


Few CSSGram sample filters applied to an image.

How CSSGram Module works?

CSSGram module uses CSSGram Library for adding filter effects via CSS to the image fields. Module extends Field Formatter Settings to add image filter for that particular field. CSSGram extends field formatter settings and hence these filters can be applied on top of the existing available image formatters and image presets. Allowing you to use your desired image preset along with CSSGram filters.

Using CSSGram

  1. Download and enable CSSGram module (

  2. Visit Manage Display of content type and for the desired image field, click on the setting link under format column.

  3. Select Filter option lets us choose from the available image filters. Just select the desired image filter and hit update button.

  1. Save the settings and visit the content display page.

Developer Support

Devs have the option to use these filters anywhere on the site by just attaching the ‘cssgram/cssgram’ library and then applying any of the available css filter class to the wrapper element.

function mymodule_preprocess_field(&$variables) {
    // Add desired css class.
    $variables['attributes']['class'] = 'kelvin';
    // Attach cssgram library.
    $variables['#attached']['library'][] = 'cssgram/cssgram';
Oct 25 2016
Oct 25

Let’s feel Drupal’s pulse! It looks like the popular site-building platform is doing great. It remains a perfect fit for all kinds of sites. We’ve discussed its benefits for university and ecommerce websites, and made collections of Drupal travel sites and online stores. Being strong, secure, and flexible is exactly what the doctor ordered for any good site! That’s why Drupal is a healthy idea for health care websites as well. Today, we’ve picked some of these health sites for you to take a look at — including, of course, one created by InternetDevels.

Some nice health care Drupal websites

Pediatric Health Care Alliance

This Drupal website lets anyone find a pediatrician for their child, check out doctors’ bios, select the desired clinic offices on the map, pay the bills right on the site, and get a lot of useful info. It also offers a link to the Patient Portal where customers can communicate with their pediatrician's office online.

Some great health care websites built with Drupal

Research to reality

Here is a community for cancer control researchers. Right on the main page, the visitor’s attention is captured by a counter that shows the number of community members, discussion topics and events, so it’s easy to click and join in. Users can register for professional seminars or view past seminars online, check the event calendar, join discussions with filters by category, date range, keywords, name, and more.

Some great health care websites built with Drupal

C.S. Mott Children’s Hospital

On the C.S. Mott Children’s Hospital’s website, it’s possible to browse conditions and treatments, search for a physician, get an appointment, and find maps and directions. Instructions for visiting a hospital, blog posts, and news are also present. Anyone wanting to make a donation can do it online. There is also an option to send a get-well card and lift some patient’s spirits.

Some great health care websites built with Drupal

Allegiance Health

On the main page, there are three main buttons which help 1) to find a doctor by searching with a name, specialty, etc., 2) to find and attend classes and events by type and city, 3) or to get online services. There is also a classification “I am a doctor” and “I am a patient,” where both can get useful info and options. The buttons on the patient’s part —“Talk to someone” and “Read patient stories” — are exactly what people need to see.

Some great health care websites built with Drupal

Lehigh Valley Health Network

The brightly colored block on the main page immediately invites users to make a phone call, chat online, or get directions. Doctors are easily found by using a whole bunch of criteria: name, type of care, region, distance from the user in miles, gender, language spoken, or the willingness to receive new patients. There also are many handy options: browsing a multicolored chart of various conditions, checking a phone directory, paying bills or making donations, sending gifts or flowers, and more. The site is available in English and Spanish.

Some great health care websites built with Drupal

Memorial Sloan Kettering Cancer Center

Here is the only Drupal 8 website in this collection, all the others being built with Drupal 7. On the main page, there is a big handy “How can we help you?” search box. Three main options that grab a visitor's’ attention immediately are “Find a doctor,” “Make an appointment,” and “Find a location.” However, there are many other useful things that users can discover, which are classified into sections: “For adult patients,” “For child and teen patients,” “For health care professionals,” “For research scientists.”

Some great health care websites built with Drupal

Florida Hospital

The Florida Hospital’s site has a nice retro design and a traditional set of options. They include finding a physician, browsing locations and directions, making an appointment, paying a bill online, donating and volunteering, applying for a job, and more. The main page also lets the readers be aware of important things from the news, videos, blog posts, upcoming event announcements with a noticeable data marking. There is also a special “for medical professionals” section.

Some great health care websites built with Drupal

Rush University Medical Center

In addition to the classic medical site options that we have seen in many previous sites, this one has an interesting feature for asking an expert questions right from the homepage. By clicking on this button, users are redirected to the list of doctors. They are also welcome to check out the list of conditions for treatment in alphabetical order — by letter. Health and wellness articles, videos, and upcoming event overviews help visitors stay updated.

Some great health care websites built with Drupal

AttendingDR: created by InternetDevels

And, of course, we couldn’t help but include our own creation on this collection. This is a powerful community for doctors with the features of a social network, where doctors can communicate, create initiative groups, discuss issues, spread information about their clinics and much more. For full-fledged communication between doctors and patients, we integrated with the site, which is a community for patients. Doctors can receive requests from patients about visit appointments via calendars. Doctors can approve or disapprove the appointment time. Other features include an informative dashboard, electronic signature, company directory, articles, blogs, news, forum, and more.

Some great health care websites built with Drupal

That’s been a bunch of nice health care Drupal websites. We hope medicine achievements get more and more advanced to meet any challenge and cure anything! And we also hope IT achievements will be more and more helpful in creating the most effective and attractive sites. If you are interested in one, go ahead and drop us a line.

Dear readers, stay healthy above all!

Oct 25 2016
Oct 25

Drupal has always had excellent support for human-friendly URL’s and SEO in general, from early on we have had the luxury of modules like pathauto offering options to update URL for specific entities, token support and bulk update of URLs. Though bulk update works for most cases, there are some situations where we have to update URLs programmatically, some of the use cases are:

  • Multisite setup -- When your setup has many sites, its inconvenient to use bulk update UI to update aliases for each of your sites. Programmatically updating the aliases is a good choice and can be executed via the update hooks.
  • Conditional Update -- When you wish to update aliases based on certain conditions.


In Drupal 8 Pathauto services.yml file we can see that there is a service named ‘pathauto.generator’ which is what we would need. The class for corresponding to this service, PathautoGenerator provides updateEntityAlias method which is what we would be using here:

public function updateEntityAlias(EntityInterface $entity, $op, array $options = array())


EntityInterface $entity: So, we need to pass the entity (node, taxonomy_term or user) here.
String $op: Operation to be performed on the entity (‘update’, ‘insert’ or ‘bulkupdate’).
$options: An optional array of additional options.

Now all we need is to loop the entities through this function, these entities may be the user, taxonomy_term or node. We will be using entityQuery and entityTypeManager to load entities, similar to the code below

  $entities = [];
  // Load All nodes.
  $result = \Drupal::entityQuery('node')->execute();
  $entity_storage = \Drupal::entityTypeManager()->getStorage('node');
  $entities = array_merge($entities, $entity_storage->loadMultiple($result));

  // Load All taxonomy terms.
  $result = \Drupal::entityQuery('taxonomy_term')->execute();
  $entity_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
  $entities = array_merge($entities, $entity_storage->loadMultiple($result));

  // Load All Users.
  $result = \Drupal::entityQuery('user')->execute();
  $entity_storage = \Drupal::entityTypeManager()->getStorage('user');
  $entities = array_merge($entities, $entity_storage->loadMultiple($result));

  // Update URL aliases.
  foreach ($entities as $entity) {
    \Drupal::service('pathauto.generator')->updateEntityAlias($entity, 'update');

This works fine and could be used on a small site but considering the real world scenarios we generally perform this type of one-time operation in hook_update_N() and for larger sites, we may have memory issues, which we can resolve by involving batch API to run the updates in the batch. 

Using Batch API in hook_update_n()

As the update process in itself a batch process, so we can’t just use batch_set() to execute our batch process for URL alias update, we need to break the task into smaller chunks and use the $sandbox variable which is passed by reference to update function to track the progress.  

The whole process could be broken down into 4 steps:

  • Collect number of nodes / entities we would be updating the URL for.
  • Use the $sandbox to store information needed to track progress.
  • Process nodes in groups of a certain number (say 20, in our case ).
  • And finally setting the finished status based on progress.
function mymodule_update_8100(&$sandbox) {
  $entities = [];
  $entities['node'] = \Drupal::entityQuery('node')->execute();
  $entities['user'] = \Drupal::entityQuery('user')->execute();
  $entities['taxonomy_term'] = \Drupal::entityQuery('taxonomy_term')->execute();
  $result = [];

  foreach ($entities as $type => $entity_list) {
    foreach ($entity_list as $entity_id) {
      $result[] = [
        'entity_type' => $type,
        'id' => $entity_id,

  // Use the sandbox to store the information needed to track progression.
  if (!isset($sandbox['current']))
    // The count of entities visited so far.
    $sandbox['current'] = 0;
    // Total entities that must be visited.
    $sandbox['max'] = count($result);
    // A place to store messages during the run.

  // Process entities by groups of 20.
  // When a group is processed, the batch update engine determines
  // whether it should continue processing in the same request or provide
  // progress feedback to the user and wait for the next request.
  $limit = 20;
  $result = array_slice($result, $sandbox['current'], $limit);

  foreach ($result as $row) {
    $entity_storage = \Drupal::entityTypeManager()->getStorage($row['entity_type']);
    $entity = $entity_storage->load($row['id']);

    // Update Entity URL alias.
    \Drupal::service('pathauto.generator')->updateEntityAlias($entity, 'update');

    // Update our progress information.

  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current'] / $sandbox['max']);

  if ($sandbox['#finished'] >= 1) {
    return t('The batch URL Alias update is finished.');


The process of loading the entities will differ in case we are just updating a single entity type say nodes. In that case, we can use loadMultiple to load all the entities at once per single batch operation. That’s a kind of trade-off we have to do according to our requirements. The crucial part is using sandbox variable and splitting the job into chunks for batch processing.

Oct 25 2016
Oct 25

Last week I had the opportunity of participating in my second BADCamp as part of my tour Around the Drupal world in 140+ days.

My first assistance was in 2012, a lot have changed from that time to now. At that time I was only assistant and was impress for the quality of the event and how vibrant was the community in San Francisco Bay Area.

The event itself doesn't change too much, the same venue, but a little more disperse in my opinion.

What change was my participation with Jesus Manuel Olivas one of my business partners at weKnow. We lead a training about Drupal 8 module development

Slides: []

Also we have a session about how to learn about Drupal 8 via debugging



Distance (Kilometers) San Jose, Costa Rica → Panama, Panama → San Francisco, USA 5.880 Previously 109.137 Total 115.017


Distance (steps) Bay Area 58.408 Previously 1.936.685 Total 1.995.093


Distance (Kilometers) Today 0 Previously 528 Total 528
Distance (Kilometers) Today 796 Previously 2.944 Total 3.740
Oct 24 2016
Oct 24

Last week I returned from the HigherEd Web Conference in Memphis, TN. This is one of my favorite conferences because the community is fantastic, the energy is high, the events are well-attended and create an inclusive atmosphere, and it’s just well-run. It’s also a very heavy Twitter user group . . . attendees love to tweet everything early and often, and each session is given its own hashtag so people can follow along. They also have a coveted award called the “Red Stapler” given for best in each track, culminating in a Best Of Conference award.

As if that wasn’t enough, the keynote speakers each year are amazing! This year, Kimberly Bryant of was the first keynote. The community was so supportive of her organization’s work to bring computer science and code to young girls of color that people were donating money on the spot as she spoke, and tweeting it around to encourage others to keep the donations coming.

The final keynote was LeVar Burton. As the son of an educator, a Star Trek: The Next Generation actor, and Reading Rainbow creator, Mr. Burton is perfectly positioned to speak on the intersection of technology and education. He was funny, engaging, and accommodating. Plus he made everyone cry when talking about the important teachers in his life, and asked us to take a moment to reflect on ours. And kudos to the Reading Rainbow social media team, who were impressively following along with his talk and engaging via Twitter with the audience in real time.

This conference is mostly focused on implementers. It’s a conference of editors, designers, developers, admissions, and IT staff. This is a passionate group of people who want to do better by their schools via the school’s online presence, and I’m continually impressed by how creative the teams get within their limited resources (people, time and money). The smaller schools have the ability to be more nimble around internal politics and the lack of resources than larger institutions, but even the larger schools are making amazing things happen online.

Though this isn’t something that Palantir works in directly, schools and libraries are really getting savvy about social media. There were sessions on how schools were using Pinterest, the success around ways to text students (including admissions acceptances!), Snapchat (again . . . including admissions acceptances!), and more.

Schools are really looking about how to personalize and individualize the experience for students from a visual perspective, understanding that the younger generations are used to a personalized experience via Netflix, Spotify, and Amazon where recommendations can be made based on interests. Schools are responding to this by designing more around creating a “choose your own adventure” feel either through filtering majors and interests, or through messaging and branding in addition to social media.

I also learned a lot about the concerns that schools have in the areas of accessibility, crisis control, and rebuilding trust among faculty and administrators when past web projects either haven’t gone well, or due to internal power struggles over which content gets priority.

Between representing all the factions of a large organization, juggling the needs of multiple audiences, and having to keep up with the constantly changing workspace online, these small teams of web professionals have a lot to handle! And this annual meeting allows them to collaborate, learn from each other, compare notes, and celebrate their hard work.

Some Favorite Sessions

In addition to the Red Stapler winners, there were a lot of great sessions. Videos will be up on the schedule page eventually, but below are links to slides to some noteworthy ones:

My colleague Joe Allen-Black and I were able to give our presentation “Project Management: The Musical!” to this crowd as the last session on Monday. We added one more song since the last conference, and thankfully it all went smoothly without a full rehearsal! Considering the amounts of tweets there were related to the session and feedback we received in person, the attendees seemed to enjoy our musical take on how to get a project moving successfully from start to finish.

I learn so much from this conference every year about what the higher education community’s needs are for their online presence, what they are doing to solve those problems, and how we at Palantir can assist. HEW hosts regional conferences all over the country throughout the year, leading up to the big annual conference next October in Hartford, CT. I don’t yet know what my calendar holds for next year, but I look forward to being able to attend and see the great community of HEW often in 2017.

Stay connected with the latest news on web strategy, design, and development.

Sign up for our newsletter.
Oct 24 2016
Oct 24

During our Board Retreat,  the Staff Board mixer gave us a chance to meet the staff members and the staff members to meet the Board. The staff's commitment and involvement to the project is amazing and definitely needs a pat on the back!

Ryan, Rudy, Neil, Tatiana, Brendan, Mark lead by Tim Lehnen have been working behind the scenes on, bring improvements consistently over the last few months. Key aspects they worked on include:

  1. The Evolution of the DRUPAL.ORG front pages
  2. DrupalCI
  3. Composer
  4. Community Initiative Updates: Documentation Migration, Project Application Process and Drupal 8 User Guide

Tim Constein, Rachel Friesen, Amanda Gonser, Elise Horvat, Kris -

They all play various roles from Event planning, Sponsorships and more to make sure our DrupalCons are executed seamlessly. Rachel is our Con strategist and makes sure they run on budget and has a great experience. Amanda manages all all the content/programming and local events, which means she is working with all of the track chair volunteers, local community members, and other volunteers to bring the magical content to the event. Tim is our Sponsor Fulfillment person. Our sponsors love their experience because he makes sure it is a great one. Elise and Kris Klinkhammer handle AP, fiscal sponsorships, and more. Many of you must have met and interacted with all or most of them at many points during your Drupalcon.

Carrie Lacina is a super power. She runs the revenue team, creates our digital products like Try Drupal and handles Account Management for key accounts. She creates revenue programs that support our mission like the TryDrupal program!

Delona Lang works with our Partners and is the Account Manager Drupal Agencies, Lizz Trudeau takes care of memberships, Bradley Fields our content manager, works on content, social media and more…

Checkout the Association Staff page to know more about them.

Last but not the least, Megan their Executive Director needs a special mention. She has been an inspiration, great team builder and an amazing leader. She has been working closely with the staff to transition many changes in the last 6 months. I truly admire her execution focus, passion for Drupal and the Drupal community.

What has been amazing is that though each staff has a specific role, in the last 6 months they have worked together beyond their stated roles to make Drupal Association meet their goals! Do follow the work of the Association as they publish them at, share your views and encouragement!

Thank you Megan and all the Association staff for all the hard work!

Oct 24 2016
Oct 24
Upload PDF, Excel, Word Files to Drupal Content

An OSTraining member asked how he could attach files such as PDFs, Excel Documents, Word Documents to his content. 

There are many ways to do this in Drupal, but the easiest approach is to use the "File" field.

  • Login to your Drupal site.
  • Go to Structure > Content types.
  • You either add the field to an existing content type, or you can create a new one for specifically adding the files:

A Drupal content type for files

Now you add a field to the content type.

  • Click the blue "Add field" button.

Adding a Drupal field button

  • For the field type, choose "File".
  • Give the field a meaningful label such as "attached file".

Creating a Drupal file field

  • In the field settings, make sure the "Enable Display field" and "Fields displayed by default" options are selected:

Allowed file extensions in Drupal

It is important to make sure that you have added all the required file formats. In this example I will only be using PDF, but you can add as many file extensions you wish here. 


When it comes to the size of file uploads, the maximum upload size is controlled by your server. Often, servers do not allow file uploads larger than 8MB. You will need to check your PHP settings if you want to increase the size of files that can be uploaded.

Now you have configured the content type, you can upload the files.

  • Go to Content > Add content.
  • Upload a file using the field that you created.
  • Your file will show on the front of the site:

A file displayed on a Drupal site

You can also change the display of the file:

  • Go to Structure > Content types > Manage display.

Changing the display settings for a Drupal file

About the author

Daniel is a web designer from UK, who's a friendly and helpful part of the support team here at OSTraining.

View the discussion thread.

Oct 24 2016
Oct 24

In this blog post I will present how, in a recent e-Commerce project built on top of Drupal7 (the former version of the Drupal CMS), we make Drupal7, SearchAPI and Commerce play together to efficiently retrieve grouped results from Solr in SearchAPI, with no indexed data duplication.

We used the SearchAPI and the FacetAPI modules to build a search index for products, so far so good: available products and product-variations can be searched and filtered also by using a set of pre-defined facets. In a subsequent request, a new need arose from our project owner: provide a list of products where the results should include, in addition to the product details, a picture of one of the available product variations, while keep the ability to apply facets on products for the listing. Furthermore, the product variation picture displayed in the list must also match the filter applied by the user: this with the aim of not confusing users, and to provide a better user experience.

An example use case here is simple: allow users to get the list of available products and be able to filter them by the color/size/etc field of the available product variations, while displaying a picture of the available variations, and not a sample picture.

For the sake of simplicity and consistency with Drupal’s Commerce module terminology, I will use the term “Product” to refer to any product-variation, while the term “Model” will be used to refer to a product.

Solr Result Grouping

We decided to use Solr (the well-known, fast and efficient search engine built on top of the Apache Lucene library) as the backend of the eCommerce platform: the reason lies not only in its full-text search features, but also in the possibility to build a fast retrieval system for the huge number of products we were expecting to be available online.

To solve the request about the display of product models, facets and available products, I intended to use the feature offered by Solr called Result-Grouping as it seemed to be suitable for our case: Solr is able to return just a subset of results by grouping them given an “single value” field (previously indexed, of course). The Facets can then be configured to be computed from: the grouped set of results, the ungrouped items or just from the first result of each group.

Such handy feature of Solr can be used in combination with the SearchAPI module by installing the SearchAPI Grouping module. The module allows to return results grouped by a single-valued field, while keeping the building process of the facets on all the results matched by the query, this behavior is configurable.

That allowed us to:

  • group the available products by the referenced model and return just one model;
  • compute the attribute’s facets on the entire collection of available products;
  • reuse the data in the product index for multiple views based on different grouping settings.

Result Grouping in SearchAPI

Due to some limitations of the SearchAPI module and its query building components, such plan was not doable with the current configuration as it would require us to create a copy of the product index just to apply the specific Result Grouping feature for each view.

The reason is that the features implemented by the SearchAPI Grouping are implemented on top of the “Alterations and Processors” functions of SearchAPI. Those are a set of specific functions that can be configured and invoked both at indexing-time and at querying-time by the SearchAPI module. In particular Alterations allows to programmatically alter the contents sent to the underlying index, while the Processors code is executed when a search query is built, executed and the results returned.
Those functions can be defined and configured only per-index.

As visible in the following picture, the SearchAPI Grouping module configuration could be done solely in the Index configuration, but not per-query.

SearchAPI: processor settings

Image 1: SearchAPI configuration for the Grouping Processor.

As the SearchAPI Grouping module is implemented as a SearchAPI Processor (as it needs to be able to alter the query sent to Solr and to handle the returned results), it would force us to create a new index for each different configuration of the result grouping.

Such limitation requires to introduce a lot of (useless) data duplication in the index, with a consequent decrease of performance when products are saved and later indexed in multiple indexes.
In particular, the duplication is more evident as the changes performed by the Processor are merely an alteration of:

  1. the query sent to Solr;
  2. the handling of the raw data returned by Solr.

This shows that there would be no need to index multiple times the same data.

Since the the possibility to define per-query processor sounded really promising and such feature could be used extensively in the same project, a new module has been implemented and published on the SearchAPI Extended Processors module. (thanks to SearchAPI’s maintainer, DrunkenMonkey, for the help and review :) ).

The Drupal SearchAPI Extended Processor

The new module allows to extend the standard SearchAPI behavior for Processors and lets admins configure the execution of SearchAPI Processors per query and not only per-index.

By using the new module, any index can now be used with multiple and different Processors configurations, no new indexes are needed, thus avoiding data duplication.

The new configuration is exposed, as visible in the following picture, while editing a SearchAPI view under “Advanced > Query options”.
The SearchAPI processors can be altered and re-defined for the given view, a checkbox allows to completely override the current index setting rather than providing additional processors.

Drupal SearchAPI: view's extended processor settings

Image 2: View’s “Query options” with the SearchAPI Extended Processors module.

Conclusion: the new SearchAPI Extended Processors module has now been used for a few months in a complex eCommerce project at Liip and allowed us to easily implement new search features without the need to create multiple and separated indexes.
We are able to index Products data in one single (and compact) Solr index, and use it with different grouping strategies to build both product listings, model listings and model-category navigation pages without duplicating any data.
Since all those listings leverages the Solr FilterQuery query parameter to filter the correct set of products to be displayed, Solr can make use of its internal set of caches and specifically the filterCache to speed up subsequent searches and facets. This aspect, in addition to the usage of only one index, allows caches to be shared among multiple listings, and that would not be possible if separate indexes were used.

For further information, questions or curiosity drop me a line, I will be happy to help you configuring Drupal SearchAPI and Solr for your needs.

Oct 24 2016
Oct 24

You’ve built a Drupal distribution for your higher-ed institution: a theme, a base set of content types, views and the modules that drive them. Now you are provisioning sites for all the units on campus with your Drupal distribution. These units will administer their websites, creating content without relying on your centralized web team to continue to build everything. This is the power of Drupal and why your institution chose it. It empowers your campus to own their sites, while still allowing your central web team the ability to control the institution’s digital presence that fits with a broader digital strategy.

But as your institution hums along with Drupal to everyone’s great satisfaction, there are many issues that will arise over time. Without oversight, these issues could become significant risks weighing over your institution’s digital presence.

1. Providing a consistent feature set

Your web team will likely look to provide your institution’s Drupal sites with functionality beyond what ships with Drupal by default. News articles. Event listings. Photo galleries. Accordions. Having standard, repeatable functionality across your institution’s sites will allow your administrators and content authors to build rich, beautiful content across your digital presence.

Much functionality can be built directly in the Drupal UI through CCK, Views, Panels and Display Suite. But unless it is exported to code, these features will have to be built manually on each and every website - an impossible task. Worse yet, if this functionality isn’t in code, when a change or bug fix needs to be applied to them, it must be done on a per site basis.


  • Put your functionality into code and modules so that it can be deployed to multiple sites at once and maintained in one location.
  • Make sure the modules you create providing this functionality are tagged with version numbers just like any module so that you know what site has what version of what functionality in use.
  • Keep modules across your sites using the same version if possible. This simplifies maintenance when every site has the exact same upgrade path for a module should an update be released, and provides a consistent user experience for all your site’s users. Dewy can easily spot how many versions of the same module you are running across your environment.

Version usage in Dewy

2. Content that deviates from your digital strategy

With a distributed network of content authors accross the sites at your higher-ed institution, the content of your digital presence may begin to take on a form that may no longer resemble the intentions of your digital strategy. This is inevitable. Sites go stale. The organization changes.


  • Determine what sites are the first tier of your institution and focus on the quality of content of those sites the most. These would be the sites that are most closely associated with the brand, and the sites that your users visit the most. Google Analytics or Dewy can help you determine what sites are most used at your institution.
  • Sites that aren’t on your first tier can be made more restricted. Possibilities include the amount of customization those second tier sites are entitled to so they have less opportunity to depart from the brand you’ve created, or a different theme that makes explicit to visitors that the institution doesn’t take responsibility for this content.
  • Regular content audits of your first tier of sites. Dewy can help you keep track of what’s considered a first tier site via the site tagging system.
  • Use Dewy to spot outdated and sensitive content across all your sites. An old brand motto? References to the institution’s previous President? Dewy can parse all your content to find the sites with those references.

Content lookup in Dewy

3. Site sprawl

Provisioning sites is easy. Either your team will approach a unit on campus to grant them a Drupal site, or they will come looking to request one from you. To physically spin up a new site, you might be using Pantheon. You may have created a Drupal distribution, or Drush make file that you apply to a blank Drupal site. You may have a script that copies a database and files from a template Drupal site in order to spin up a new site. Or any of the combination of these, really.

What’s much more difficult to deal with is site deprovisioning. The issues with having too many sites at your insitution is obvious - more sites that need security updates, more content that can go out of date, more load on your servers, databases on your server, etc. If you want your institution to stay on curve and be nimble with a digital strategy, carrying less sites along for the ride makes things much easier.


  • Create rules around what is considered an inactive site that will be deprovisioned by your team and communicate these rules transparently to your users when you create a site for them. A good rule is that an administrator of the site must log in to the site every X months to indicate that the site hasn’t been abandoned.
  • Look for sites that have little to no traffic, are seldom modified, haven’t been signed on to in a long time or are in maintenance mode. Dewy can help you define these rules and find sites that match your criteria quickly.

Number of versions

4. Module sprawl

Like site sprawl, having too many modules on your environment makes things difficult. Every module on a site slows down the execution of that site. There are more hooks fired and more parsing of the file system.

More importantly, every module on a site also slows down your web team. Security updates can’t go ignored and more modules on sites means more updates that need to be applied on those sites.


  • Avoid adding modules to your environment only because a site administrator is requesting it. Instead determine what their goal is, because what they may be looking for may not require the module they are requesting.
  • Create a review process so that when a request for a new module is made by one of your site admins, it is compared against existing offerings. For example, the User One module may not be needed if you are already providing the User Protect module.
  • Deprovision modules that may no longer be in use, or only exist for sites that are edge cases in your digital strategy. Dewy can help spot modules that are no longer in use.

Module utilization in Dewy

5. User deprovisioning

You will likely find at your institution that there are many users who have administrative or authoring roles for multiple sites, possibly across several units on campus. You will also find that many of these users leave their roles or end their careers at your institution during the life of the web site. This exposes a risk to your web presence as those who are no longer permitted to have access to update your web sites actually still do. Depending on how many sites


  • Use CAS or another form of single sign-on with Drupal, so that terminating that user’s privilege with your single sign-on service prevents that user from signing on to any of the Drupal sites they once had access to. If Drupal site permissions haven’t been updated to reflect that the user may no longer be with the institution, and they are still set to have edit privileges on your sites, it will no longer matter because your single sign-on provider will fail the authentication before Drupal’s permissions take over.
  • Update that user’s role across all sites they have access to. If the user is no longer with the institution, instead of deleting the account, block the account. Account deletion can have unwanted side effects.
  • Use Dewy to help find what sites that user is on.

User lookup in Dewy

6. Sites that run away in size

Enforcing maximum file upload sizes for any given field is easy. Enforcing a total size for an entire website is difficult. And while diskspace is cheap, it is not always plentiful. At large higher-ed institutions there are always new initiatives finding ever more intensive ways of consuming what diskspace is available. So it’s important to be responsible with your resources.


  • Write a script to periodically check the file size of your sites. This can be done by using the du command but involves knowing where the files and private files directories are for each site (the locations of these directories may be be changed by site administrators that have the permission to do so).
  • Use Dewy to build a filter that shows exactly what sites are using a disk space amount that you aren’t comfortable with.

Site size lookup in Dewy

7. Security

Security matters and you don’t need to be reminded why. In Drupal, it can be very difficult to keep up with all the security updates that are posted - cross site scripting this, request forgery that, the alerts are frequent and it can be time consuming to approach them with the rigor that may be required across your environment.

This problem is exacerbated by the more modules and sites you have, especially when there are lots of sites at your institution that may not always have official eyes on them. The last thing you want is for some dark corner of your digital presence to have actually been a giant Viagra ad for the past several years.


Pending security updates in Dewy

Oct 22 2016
Oct 22

Developers have many tools. We have version control systems, we have dependency management tools, we have build and task automation tools. What is one thing they all have in common? They are command line tools.

However, the command line can be daunting to some and create a barrier to adoption. We’re currently experiencing this in the Drupal community. People are considering Composer a barrier to entry, and I believe it’s just because it’s a command line tool and something new.

Providing a user interface

User interfaces can make tools more usable. Or at least lower the barrier to entry. I like to think of Atlassian's SourceTree. SourceTree is an amazing Git user interface and was my entry into learning how to use Git.

If you work with Java, your IDE provides some sort of user interface for managing your dependencies via Maven.

The PhpStorm IDE provides rudimentary Composer support - initializing a project and adding dependencies - but doesn’t support entire workflows. It’s also proprietary.

Here’s where I introduce Conductor: a standalone Composer user interface built on Electron. The purpose of Conductor is to give users working with PHP projects an interface for managing their projects outside of the command line.

Hello, Conductor

Conductor interfaces

Conductor provides an interface for:

  • Creating a new project based on a Composer project
  • Managing projects to install, update, add, and remove dependencies
  • View dependencies inside of a project
  • Ability to update or remove individual dependencies by reviewing them inside of the project.
  • Run Composer commands from the user interface and review console output.

The project is in initial development, granted by the downtime the Dyn DDoS attack created.

The initial application is now in an above minimal viable product. It works. It can be used. But now it needs feedback from users who feel a barrier by having to use Composer, and code improvements as well.

Head over to GitHub and check out the project: Currently, there are no prebuilt binaries and you'll need to manually build to try it out.

Oct 21 2016
Oct 21

We live in an era where few institutions have Websites and other Internet-based properties that are managed and maintained by one or only a few people. Where these spaces were once controlled by the few who knew how to code in HTML, content management systems have now dramatically lowered (and arguably eliminated) the need to possess extensive HTML knowledge. This means that most organizations have lots of people editing their Web properties, and without some well-defined rules for all those cooks in the kitchen, things get messy quickly.

Whether or not the platform you are using has roles and permissions built into it, a good governance plan will define roles for users and then apply specific permissions to those roles. Based on my experience, here are some common, fairly generic, roles and permissions that many Websites have (or have variations):

  • ROLE: Authenticated User
    • PERMISSIONS: Anyone who has activated an account on the Website, but has no editing or publishing permissions; authenticated users may be able to see content an un-authenticated user may not see.
  • ROLE: Contributor
    • PERMISSIONS: A user with an account who can create new and edit their existing content on the Website, but may not publish or delete any content, including their own, or edit content they have not created.
  • ROLE: Editor
    • PERMISSIONS: A user with an account who can create new and edit existing content on the Website, including content that is not their own; they may or may not publish or delete content.
  • ROLE: Publisher
    • PERMISSIONS: A user with an account who can create new, edit existing, publish, and delete any content on the Website; typically a person who approves and publishes the work of Contributors and Editors.
  • ROLE: Administrator
    • PERMISSIONS: A user with the same permissions as a Publisher, however they may administer accounts, roles, and permissions of other users on the Website, along with managing certain site-wide settings.
  • ROLE: Webmaster
    • PERMISSIONS: A user with full permissions to all aspects of managing and administering the Website, a role typically reserved to the few, most highly trained and experienced users.

These common roles can be modified easily to address the specific needs of your organization. You may also find that they are lacking certain roles you need, in which case I recommend using one of these for the basis of a new role you create to meet your specific requirements. For example, let’s say you have a microsite that is a subset of your main site, and you need to assign a user the role of Administrator ONLY for that micro-site and not the entire main site. Simply take the permissions assigned to Administrators and create a new role call Micro-Site Admin whose permissions as “Administrator” are limited to only the micro-site that role manages.

Here are some questions to consider to help you begin defining the roles your organization will need, along with the permissions each role should have.


  • Who should have an account for accessing your Website?
  • How do users acquire or activate accounts?
  • What are the policies for using accounts?
  • Is sharing an account permissible?
  • What are the conditions under which users may lose their access privileges?

Roles & Permissions

  • Who is permitted to edit content on the Website?
  • Who is permitted to create new content on the Website?
  • Who is permitted to publish content on the Website?
  • Who is permitted to delete content on the Website?
  • Who is permitted to see unpublished content on the Website?
  • Are there users who should have higher levels of administrative access to perform site-wide changes or to administer user accounts?
  • Are there sets of users who need special access to only limited parts or functions within the Website?
  • Are there limitations to the level of access different users should have?
  • Do all users have access to all content?
  • Do some users have access to only the content they create?
  • Do certain users need to approve content before it is published?
  • Does a workflow need to be established for defining how content is produced and published?

This post is part of a larger series of posts, which make up a Guide to Digital Governance Planning. The sections follow a specific order intended to help you start at a high-level of thinking and then focus on greater and greater levels of detail. The sections of the guide are as follows:

  1. Starting at the 10,000ft View – Define the digital ecosystem your governance planning will encompass.
  2. Properties and Platforms – Define all the sites, applications and tools that live in your digital ecosystem.
  3. Ownership – Consider who ultimately owns and is responsible for each site, application and tool.
  4. Intended Use – Establish the fundamental purpose for the use of each site, application and tool.
  5. Roles and Permissions – Define who should be able to do what in each system.
  6. Content – Understand how ownership and permissions should apply to content.
  7. Organization – Establish how the content in your digital properties should be organized and structured.
  8. URLs – Define how URL patterns should be structured in your websites.
  9. Design – Determine who owns and is responsible for the many aspects design plays in digital communications and properties.
  10. Personal Websites – Consider the relationship your organization should have with personal websites of members of your organization.
  11. Private Websites, Intranets and Portals – Determine the policies that should govern site which are not available to the public.
  12. Web-Based Applications – Consider use and ownership of web-based tools and applications.
  13. E-Commerce – Determine the role of e-commerce in your website.
  14. Broadcast Email – Establish guidelines for the use of broadcast email to constituents and customers.
  15. Social Media – Set standards for the establishment and use of social media tools within the organization.
  16. Digital Communications Governance – Keep the guidelines you create updated and relevant.

Stay connected with the latest news on web strategy, design, and development.

Sign up for our newsletter.
Oct 21 2016
Oct 21
     This blog describes how to add date pop-up calender to a custom form in the Drupal 7.

Use date pop-up calendar in custom form - drupal 7

     The use case is if you want to use date pop-up calendar in a custom form, then how you can do it in the drupal 7. Actually, the drupal 7 form API provides lots of form types like textfield, checkbox, checkboxes etc to create a custom form. Similarly, the date module  also provides the form type called date_popup. We can use it in the custom form in order to display the date pop-up in the custom form.

Use date pop-up calendar with the custom form in drupal 7:

   Let consider the below code snippet:

function phponwebsites_menu() {
  $items = array();

  $items['customform'] = array(
    'title' => t('Custom Form'),
    'type' => MENU_CALLBACK,
    'page callback' => 'drupal_get_form',
    'page arguments' => array('phponwebsites_display_date_popup_form'),
    'access callback' => TRUE,

  return $items;

function phponwebsites_display_date_popup_form($form, &$form_state) {
  $form['date'] = array(
    '#type' => 'date_popup',
    '#default_value' => date('Y-m-d'),
    '#date_format'   => 'Y-m-d',
    '#date_year_range' => '0:+5',
    '#datepicker_options' => array('minDate' => 0, 'maxDate' => 0),

  return $form;

      '#date_format'   => 'Y-m-d' if you need to display only date
      '#date_format'   => 'Y-m-d H:i:s' if you need to display date & time
      '#date_year_range' => '0:+5' if you need to display only future 5 years
      '#datepicker_options' => array('minDate' => 0, 'maxDate' => 0) if you want to display only current date. We can hide the future & past dates using this option.

   Please add the above code into your module file and look into the "customform" page. It looks like the below image:

Display only current date in date -pop-up - drupal 7

   Now I've hope you know how to add date pop-up calendar with custom form in the drupal 7.

Related articles:
Remove speical characters from URL alias using pathauto module in Drupal 7
Add new menu item into already created menu in Drupal 7
Add class into menu item in Drupal 7
Create menu tab programmatically in Drupal 7
Add custom fields to search api index in Drupal 7
Clear views cache when insert, update and delete a node in Drupal 7
Create a page without header and footer in Drupal 7
Login using both email and username in Drupal 7
Disable future dates in date pop-up calendar Drupal 7
Oct 21 2016
Oct 21

Last month saw DrupalCon arrive in Dublin – the first European DrupalCon since the release of Drupal 8.

The Ixis team were out in force, exhibiting as a gold sponsor (along with a small army of Druplicon stress-balls) As well as meeting lots of other Drupal developers and businesses deploying open source infrastructure, one of the highlights of the convention was our Technical Director, Mike Carter, being given the opportunity to co-present a Drupal Showcase session, detailing our work with the British Council.

Mike Carter at Drupalcon

(image thanks to Paul Johnson)

With locations on six continents and in more than 100 countries, the British Council is the UK’s international organisation for cultural relations and educational opportunities. Its web infrastructure includes a global site, approximately 110 country websites, 10-15 project websites and various smaller micro-sites.

In 2015, in an effort to improve performance and reliability, the decision was taken to adopt a container-based hosting for this network of sites. After a competitive procurement process we led the migration of the entire network to containers hosted on infrastructure provided by our partner

If you didn’t make it to DrupalCon Dublin or want a recap on the showcase session, our full presentation can be viewed below or you can read the full case study here

Oct 21 2016
Oct 21

Republished from

Nasdaq chooses Drupal 8

I wanted to share the exciting news that Nasdaq Corporate Solutions has selected Drupal 8 as the basis for its next generation Investor Relations Website Platform. About 3,000 of the largest companies in the world use Nasdaq's Corporate Solutions for their investor relations websites. This includes 78 of the Nasdaq 100 Index companies and 63% of the Fortune 500 companies.

What is an IR website? It's a website where public companies share their most sensitive and critical news and information with their shareholders, institutional investors, the media and analysts. This includes everything from financial results to regulatory filings, press releases, and other company news. Examples of IR websites include http://investor.starbucks.com and -- all three companies are listed on Nasdaq.

All IR websites are subject to strict compliance standards, and security and reliability are very important. Nasdaq's use of Drupal 8 is a fantastic testament for Drupal and Open Source. It will raise awareness about Drupal across financial institutions worldwide.

In their announcement, Nasdaq explained that all the publicly listed companies on Nasdaq are eligible to upgrade their sites to the next-gen model "beginning in 2017 using a variety of redesign options, all of which leverage Acquia and the Drupal 8 open source enterprise web content management (WCM) system."

It's exciting that 3,000 of the largest companies in the world, like Starbucks, Apple, Amazon, Google and ExxonMobil, are now eligible to start using Drupal 8 for some of their most critical websites. 

Oct 20 2016
Oct 20

It has been a few years since I have had the opportunity to build a website from the absolute beginning. The most recent project I’m on continues in that vein, but it’s early enough for me to consider ripping it apart and starting all over again. The project is particularly interesting to me, as it’s my first opportunity to use Drupal 8 in earnest. As I’ve got an interest in automating as much as possible, I want to gain a better understanding of the configuration management features which have been introduced in Drupal 8.

Tearing it apart and starting again wasn’t the first thing considered. Being an arrogant Drupal dev, I figured I could simply poke around the GUI and rely on some things I’d seen at Drupalcon and Drupal camps in the past couple of years to see me through. I thought I would find it easy to build a replicated environment so that any new developer could come along, do a git clone, vagrant up, review a file and/or wiki page and they’d be off and running.


This post outlines many of the things that I examined in the process of learning Drupal 8 while adopting a bit of humility. I’ve created a sample project with names changed to protect the innocent. Any comments are welcome.

The structure of the rest of this post is as follows:

Setting up and orientation with Drupal VM

I am a big fan of Jeff Geerling’s Drupal VM vagrant project, so I created a fork of it, and imaginatively called it D8config VM. We will be building a Drupal site with the standard profile which we’ll use to rapidly build a basic prototype using the Drupal GUI - no coding chops necessary. The only contributed module added and enabled is the Devel module at the start, but we will change that quickly.

Here are the prerequisites if you do follow along:

  • familiarity with the command line;
  • familiarity with Vagrant and that it’s installed on your machine (note: the tutorial requires Vagrant 1.8.1+);
  • as well as Vagrant 1.8.1+, you need to have Ansible 2.0.1+ and VirtualBox 5.0.20+ installed;
  • have installed the Vagrant Auto-network plugin with vagrant plugin install vagrant-auto_network. This will help prevent collisions with other virtual networks that may exist on your computer;
  • have installed the Vagrant::Hostsupdater plugin with vagrant plugin install vagrant-hostsupdater, which will manage the host’s /etc/hosts file by adding and removing hostname entries for you;
  • familiarity with git and GitHub;
  • if using Windows, you are comfortable with troubleshooting any issues you might come across, as it’s only been tested on a Mac;
  • familiarity with Drush.

Here is how the D8config VM differs from Drupal VM:

  • the config.yml and drupal.make.yml files have been committed, unlike the normal Drupal VM repo;
  • the hostname and machine name have been changed to and d8config respectively;
  • to take advantage of the auto-network plugin, vagrant_ip is set to The d8config machine will then have an IP address from to;
  • the first synced folder is configured with a relative reference to the Vagrant file itself:
# The first synced folder will be used for the default Drupal installation, if
# build_makefile: is 'true'.
- local_path: ../d8config-site         # Changed from ~/Sites/drupalvm
  destination: /var/www/d8config-site  # Changed from /var/www/drupalvm
  type: nfs
  create: true

I’ll do the same with subsequent shared folders as we progress - it’s a useful way to keep the different repos together in one directory. At the end of the tutorial, you’ll have something like:

└── projects
    ├── another_project
    ├── d8config
    │   ├── d8config_profile
    │   ├── d8config-site
    │   └── d8config-vm
    ├── my_project
    └── top_secret_project


New nice-to-haves (thanks to recent changes in Drupal VM)

If you have used Drupal VM before but haven’t upgraded in a while, there are a load of new features. Here are just two to note:

  • Ansible roles are now installed locally (in ./provisioning/roles) during the first vagrant up;
  • PHP 7 is now an option to be installed. In fact, it’s installed by default. You can select 5.6 if you like by changing php_version in the config.yml file (see PHP 5.6 on Drupal VM).

Now do this

Create a directory where you’re going to keep all of the project assets.

$ mkdir d8config

# Change to that directory in your terminal:
$ cd d8config

Clone the D8config VM repo. Or, feel free to fork D8config VM and clone your version of the repo.

$ git clone

# Change to the `d8config-vm` directory:
$ cd d8config-vm

# Checkout the `CG01` branch of the repo:
$ git checkout CG01

# Bring the vagrant machine up and wait for the provisioning to complete.
$ vagrant up

After successful provisioning you should be able to point your browser at and see your barebones Drupal 8 site. Username: admin; Password: admin.


If you’ve used Drupal VM before, you will want to examine the changes in the latest version. From Drupal VM tag 3.0.0 onwards, the requirements have changed:

  • Vagrant 1.8.1+
  • Ansible 2.0.1+
  • VirtualBox 5.0.20+

One sure sign that you’ll need to upgrade is if you see this message when doing a vagrant up:

ansible provisioner: * The following settings shouldn't exist: galaxy_role_file


Build your prototype

In this section of the tutorial we’re going to start building our prototype. The brief is:

The site is a portfolio site for for a large multinational corporation’s internal use. But hopefully the content architecture is simple enough to keep in your head. The following node types need to be set up: Case study, Client, Team member (the subject matter expert), and Technologies used. Set up a vocabulary called Country for countries served and a second to called Sector classify the information which will contain tags such as Government, Music industry, Manufacturing, Professional services, etc. Delete the existing default content types. You can then delete fields you know you won’t need to avoid confusion - Comments for example - which will then allow you to uninstall the comment module. And, as you might deduce by the modules I’ve selected, it’s to be a multilingual site.

Hopefully this should feel comfortable enough for you, if you are familiar with Drupal site building. There are enough specifics for clarity, yet it’s not too prescriptive that you feel someone is telling you how to do your job. Whereas in one context, you may hear a manager say “don’t bring me problems, bring me solutions”, most engineers would rather say for themselves “don’t bring me solutions, bring me problems”. I hope this brief does the latter.

Have a go at making the changes to your vanilla Drupal 8 site based on the brief.

Beyond the brief

Every ‘site building’ exercise with Drupal is a move further away from the configuration provided by the standard or minimal profiles. In our circumstance, we will enable these modules via the GUI:

  • Responsive Image
  • Syslog
  • Testing
  • BigPipe
  • Devel Generate (Devel was installed due to settings in config.yml in the d8config-vm repo)
  • Devel Kint
  • Devel Node Access
  • Web Profiler
  • Configuration Translation
  • Content Translation
  • Interface Translation
  • Language

I’ve also added a couple of contributed themes via Drush so the site will no longer look like the default site.

# While in your d8config-vm directory:
$ vagrant ssh

# Switch to your Drupal installation:
$ cd /var/www/d8config-site/drupal

# Download and install two themes:
$ drush en integrity adminimal_theme -y

For more details on these themes, see the Integrity theme and the Adminimal theme. As you might expect, I set Integrity as the default theme, and Adminimal as the admin theme via the GUI.

After switching themes, two blocks appeared in the wrong regions. I went to the Block layout page and moved the Footer menu block from the main menu region to the footer first region and the Powered by Drupal block from the Main menu to the Sub footer block.

Due to the multilingual implication, I went to the Languages admin page and added French.


Replicate and automate

At this stage you’ve made quite a lot of changes to a vanilla Drupal site. There are many reasons you should consider automating the building of this site - to save time when bringing other members into the development process, for creating QA, UAT, pre-prod and production environments, etc. We will now start to examine ways of doing just this.

drush make your life easier

In this section we’re going to create a Drush makefile to get the versions of Drupal core, contrib modules and themes we need to build this site as it currently is. This file will be the first file added to the D8config profile repo. Makefiles are not a required part of a profile, and could reside in a repo of their own. However to keep administration down to a minimum, I’ve found that this is a useful way to simplify some of the asset management for site building.

Let’s first tweak the config.yml in the D8config VM repo, so that we have synced folder for the profile. To do so, either:

  1. git checkout CG02 in the d8config-vm directory (where I’ve already made the changes for you), or;
  2. Add the following to the config.yml in the vagrant_synced_folders section:
# This is so the profile repo can be manipulated on the guest or host.
- local_path: ../d8config_profile
  destination: /build/d8config/d8config_profile
  type: nfs
  create: true

After doing either of the above, do a vagrant reload which will both create the directory on the Vagrant host, and mount it from the d8config-vm guest.

Next, let’s generate a basic makefile from the site as it now is.

# From within the d8config vm:
$ cd /var/www/d8config-site/drupal
$ drush generate-makefile /build/d8config/d8config_profile/d8config.make

This makefile is now available in the d8config_profile directory which is at the same level as your d8config-vm directory when viewing on your host machine.

Because we only have Drupal core, two contrib themes and the Devel module, it’s a very simple file and it doesn’t need any tweaking at this stage. I’ve committed it to the D8config profile repo and tagged it as CG01.

Raising our profile

Since we’ve established that the makefile is doing very little on this site, we need to look at completing the rest of the profile which will apply the configuration changes when building the site. The How to Write a Drupal 8 Installation Profile is quite clear and we’ll use that page to guide us.

First, our machine name has already been chosen, as I’ve called the repo d8config_profile.

Rather than writing the file from scratch, let’s duplicate from the standard profile in Drupal core, as that’s what we used to build the vanilla site to begin with. We can then modify it to reflect what we’ve done since.

# From within the /build/d8config/d8config_profile directory in the vagrant machine:
$ cp /var/www/d8config-site/drupal/core/profiles/standard/ .

$ mv

The first five lines of the need to look like this:

name: D8config
type: profile
description: 'For a Capgemini Engineering Blog tutorial.'
core: 8.x

At the end of the file it looks like this, which shows the required core modules and adding the modules and themes we’ve downloaded:

- automated_cron
- responsive_image
- syslog
- simpletest
- big_pipe
- migrate
- migrate_drupal
- migrate_drupal_ui
- devel
- devel_generate
- kint
- devel_node_access
- webprofiler
- config_translation
- content_translation
- locale
- language
- bartik
- seven
- integrity
- adminimal_theme

Also, don’t forget, we uninstalled the comment module, so I’ve also removed that from the dependencies.

You still need moar!

The profile specifies the modules to be enabled, but not how they’re to be configured. Also, what about the new content types we’ve added? And the taxonomies? With previous versions, we relied on the features module, and perhaps strongarm to manage these tasks. But now, we’re finally getting to the subject of the tutorial - Drupal 8 has a configuration system out of the box.

This is available via the GUI, as well as Drush. Either method allows you to export and import the configuration settings for the whole of your site. And if you look further down the profile how-to page, you will see that we can include configuration with installation profiles.

Let’s export our configuration using Drush. This is will be far more efficient than exporting via the GUI, which downloads a *.tar.gz file, which we’d need to extract a copy or move to the config/install directory of the profile.

While logged into the vagrant machine and inside the site’s root directory:

# Create the config/install directory first:
$ mkdir -p /build/d8config/d8config_profile/config/install

# Export!
$ drush config-export --destination="/build/d8config/d8config_profile/config/install"

When I exported my configuration, there were ~215 files created. Try ls -1 | wc -l in the config/install directory to check for yourself.


The reason we’re gathered here today (a brief intermission)…

I hope you are finding this tutorial useful - and also sensible. When I started writing this blog post, I hadn’t realised it would cover quite so much ground. The key thing I thought I would be covering was Drupal 8’s configuration management. It was something I was very excited about, and I still am. To demonstrate some of the fun I’ve had with it is still the central point of this blog. All of the previous steps to get to this point were fun too, don’t get me wrong. From my point of view, there were no surprises.

Spoiler alert

Configuration management, on the other hand - this is true drama. Taking an existing shared development site and recreating it locally using Drush make and a basic profile (without the included config/install directory) is just a trivial soap opera. If you want real fun, visit the configuration-syncing aspect, armed only with knowledge of prior versions of Drupal and don’t RTFM.


No, really. Do it.

The secret sauce in this recipe is…

After doing the export of the configuration in the previous section, I finally started running into the problems that I faced during my real world project - the project mentioned at the beginning of this post. Importing the configuration repeatedly and consistently failed with quite noisy and complex stack trace errors which were difficult to make sense of. Did I mention that perhaps I should have read the manual?

We need to do two things to make the configuration files usable in this tutorial before committing:

# Within the d8config_profile/config/install directory:
$ rm core.extension.yml update.settings.yml
$ find ./ -type f -exec sed -i '/^uuid: /d' {} \;

The removal of those two files was found to be required thanks to reading this and this. At this stage, I can confirm these were the only two files necessary for removal, and perhaps as Drupal 8’s configuration management becomes more sophisticated, this will not be necessary. The second command will recursively remove the lines with the uuid key/value pairs in all files.


Packaging it all up and running with it.

We’ve done all the preparation, and now need to make some small tweaks and commit them so our colleagues can start where we’ve left off. To do so we need to:

  1. add the profile to the makefile;
  2. commit our changes to the d8config_profile repo;
  3. tweak the config.yml file in the d8config-vm repo, to use our makefile and profile during provisioning.

To have the profile be installed by the makefile, add this to the bottom of d8config.make (in the D8config profile):

  type: profile
    type: git
    url: [email protected]:siliconmeadow/d8config_profile.git
    working-copy: true

I’ve committed the changes to the D8Config profile and tagged it as CG02.

Then the last change to make before testing our solution is to tweak the config.yml in the D8config VM repo. Three lines need changing:

# Change the drush_makefile_path:
drush_makefile_path: "/build/d8config/d8config_profile/d8config.make"

# Change the drupal_install_profile:
drupal_install_profile: d8config_profile

# Remove devel from the drupal_enable_modules array:
drupal_enable_modules: []

As you can see, the changes to the vagrant project are all about the profile.

With both the D8Config VM and the D8Config profile in adjacent folders, and confident that this is all going to work, from the host do:

# From the d8config-vm directory
$ vagrant destroy
# Type 'y' when prompted.

# Go!
$ vagrant up

Once the provisioning is complete, you should be able to check that the site is functioning at Once there, check the presence of the custom content types, taxonomy, expected themes, placement of blocks, etc.


Summary and conclusion

The steps we’ve taken in this tutorial have given us an opportunity to look at the latest version of Drupal VM, build a quick-and-dirty prototype in Drupal 8 and make a profile which our colleagues can use to collaborate with us. I’ve pointed out some gotchas and in particular some things you will want to consider regarding exporting and importing Drupal 8 configuration settings.

There are more questions raised as well. For example, why not simply keep the d8config.make file in the d8config-vm repo? And what about the other ways people use Drupal VM in their workflow - for example here and here? Why not use the minimal profile when starting a protoype, and save the step of deleting content types?

Questions or comments? Please let me know. And next time we’ll just use Docker, shall we?

Oct 20 2016
Oct 20

Drupal 8 is here which means I have had the privilege of working on my first D8 projects and the migrations that accompany them. I wanted to share some of the key findings I’ve taken away from the experience.

Migrate in Drupal 8 is awesome as long as you know what you are looking at. It is flexible, powerful and relatively easy to read. But as is the case with most things, a lot of its power is tucked away where it is hard to find if you don't know where to look. This is definitely the case with Migrate Plus XML data process plugin which is presently available only in the dev version of Migrate Plus. It is a pretty solid tool for migrating from a variety of XML based sources and today we are going to talk about how to use it.

The first thing we have to consider is where our data is coming from. Migrate plus expects to have this information fed to it in the form of a url which gives us two options:

  1. our source is from outside the website, like an rss feed; or
  2. it is stored locally.

If you have an external url, all you need to do is plug it into the url’s parameter. If your source is stored locally, you will either need to construct a url for the source or store it in the private file directory, using the private:// stream wrapper. I would go for the latter as it involves less overhead. At this point your migration source should look something like this:

   plugin: url    
   data_fetcher_plugin: http    
   data_parser_plugin: xml   
   urls: private://migration.xml

This brings us to parsing out the XML. All of the selectors we will be talking about are using xpath. The first thing you need to do is define the item selector so migrate can identify the individual items to migrate into your choose destination. For example, if we were migrating posts from a WordPress export it might look something like this:

item_selector: /rss/channel/item[wp:post_type="post"]

Next up we need to map all of our fields to nice, readable machine names that we can use in the process part of the migration. Each field will have a name that will identify it in other parts of the migration, a label for describing what sort of data we will find in that XML element, and a selector so the migration can map that data from the xml file:

    name: title
    label: Content title
    selector: title
    name: post_id
    label: Unique content ID
    selector: wp:post_id
    name: content
    label: Body of the content
    selector: content:encoded
    name: post_tag
    label: Tags assigned to the content item
    selector: 'category[@domain="post_tag"][email protected]'

If you are using anything more complicated than the XML node names, you will need to wrap the selector as a string. The selectors are being passed to xpath in the data processor, so you can get pretty precise in selecting XML nodes.

All that is left to do is define the migration id and you have your source all ready to go:

     type: integer

Put it all together and you should have something that looks something like this:

   plugin: url    
   data_fetcher_plugin: http    
   data_parser_plugin: xml   
   urls: private://migration.xml
   item_selector: /rss/channel/item[wp:post_type="post"]
       name: title
       label: Content title
       selector: title
       name: post_id
       label: Unique content ID
       selector: wp:post_id
       name: content
       label: Body of the content
       selector: content:encoded
       name: post_tag
       label: Tags assigned to the content item
       selector: 'category[@domain="post_tag"][email protected]'
           type: integer

A note on prefixed namespaces: you can see we mixed XML nodes that have prefixes with those that don’t. Sometimes Migrate handles this with no problem at all; sometimes it refuses to fetch data from XML nodes that don’t have prefixes. As far as I can tell, it does this when one of the nodes in the item_selector has a prefix (although it doesn’t seem to have this problem with the filters in the item_selector). If you should have a datasource with a parent prefixed node, you can still get non-prefixed children by using the following syntax:

name: description
label: Content description
selector: '*[local-name()="description"]'

It will allow you to select XML nodes with a given local name regardless of the prefix, which is very handy when you have no prefix at all.

Stay connected with the latest news on web strategy, design, and development.

Sign up for our newsletter.
Oct 20 2016
Oct 20
Website navigation is something you probably use every day but don’t think too much about. This is how you travel from page to page within a website. It is probably the most used part of your website that you spend the least amount of time evaluating, right? I used to feel the same way. A few years ago, I inherited a site navigation that seemed to be working so my team focused on growing other areas of the site. Looking into how our menu was organized was low priority.
Oct 20 2016
Oct 20

When Tag1 decided to build Tag1 Quo, we knew there was one question we’d have to answer over, and over, and over again: is there a security update available for this extension? Answering that question - at scale, for many websites, across many extensions, through all the possible versions they might have - is the heart of what Quo does.

The problem seems simple enough, but doing it at such scale, for “all” versions, and getting it right, has some deceptive difficulties. Given a site with an extension at a particular version, we need to know where it sits on the continuum of all versions that exist for that extension (we often refer to that as the “version universe,”), and whether any of the newer versions contain security fixes.

There are a few different approaches we could’ve taken to this problem. The one we ultimately settled on was a bit more abstracted than what might initially seem necessary. It was also not a “typical” Drupal solution. In this blog series, I’ll cover both the theoretical foundation of the problem, and the approach we took to implementation.

What’s a version?

Let's start at the beginning.

Quo works by having existing Drupal 6 (for now!) sites install an agent module, which periodically sends a JSON message back to the Quo servers indicating what extensions are present on that site, and at what versions. Those “versions” are derived from .info files, using functions fashioned after the ones used in Drupal core. Once that JSON arrives at Quo’s servers, we have to decide how to interpret the version information for each extension.

All versions arrive as strings, and the first decision Quo has to make is whether that string is “valid” or not. Validation, for the most part, means applying the same rules as applied by the release system. Let’s demonstrate that through some examples:


Drupal extension versions are a bit different than most software versions in the wild, because the first component, 6.x, explicitly carries information about compatibility, not with itself, but with its ecosystem: it tells us the version of Drupal core that the extension is supposedly compatible with.

The next part, 1.0, holds two bits of information: the major (1) and minor (0) versions. It’s wholly up to the author to decide what numbers to use there. The only additional meaning layered on is that releases with a 0 major version, like 6.x-0.1, are considered to be prerelease, and thus don’t receive coverage from the security team. Of course, Quo’s raison d’etre is that Drupal 6 is no longer supported by the security team, so that distinction doesn’t really matter anymore.

Now, 6.x-1.0 is an easy example, but it doesn’t cover the range of what’s possible. For example:


This adds the prerelease field - alpha1. This field is optional, but if it does appear, it indicates the version to be some form of prerelease - and thus, as above, not covered by the security team.’s release system also places strong restrictions on the words that can appear there: alpha, beta, rc, and unstable. Additionally, the release system requires that the word must be accompanied by a number - 1, in this case.

There are a couple of notably different forms that valid Drupal versions can come in. There can be dev releases:


Dev releases can only have the compatibility version and a major version, and cannot have a prerelease field. They’re supposed to represent a “line” of development, where that line is then dotted by any individual releases with the same major version.

And of course, Drupal core itself has versions:


Core versions have the same basic structure as the major version/minor version structure in an extension. Here, the 43 is a minor version - a dot along the development line of the 6 core version.

These examples illustrate what’s allowed by the release system, and thus, the shape that all individual extensions’ version universe will have to take. All together, we can say there are five discrete components of a version:

  • Core version
  • Major version
  • Minor version
  • Prerelease type
  • Prerelease number

Viewed in this way, it’s a small step to abstracting the notion of version away from a big stringy blob, and towards those discrete components. Specifically, we want to translate these versions into a 5-dimensional coördinate system, or 5-tuple: {core, major, minor, prerelease_type, prerelease_num}, where each of these dimensions has an integer value. Four of the components are already numbers, so that’s easy, but prerelease type is a string. However, because there’s a finite set of values that can appear for prerelease type, it’s easy to map those strings to integers:

  • Unstable = 0
  • Alpha = 1
  • Beta = 2
  • Rc = 3
  • (N/A - not a prerelease) = 4

With this mapping for prerelease types, we can now represent 6.x-1.0-alpha1 as {6,1,0,1,1}, or 6.x-2.3 as {6,2,3,4,0}.

However, that’s not quite the end of the story. The Quo service is all about delivering on the Drupal 6 Long Term Support (D6LTS) promise: providing and backporting security fixes for Drupal 6 extensions, now that they’re no longer supported by the security team.

Because such fixes are no longer official, we can’t necessarily expect there to be proper releases for them. At the same time, it’s still possible for maintainers to release new versions of 6.x modules, so we can’t just reuse the existing numbering scheme - the maintainer might later release a conflicting version.

For example, if D6LTS providers need to patch version 6.x-1.2 of some module, then we can’t release the patched version as 6.x-1.3, because we don’t have the authority to [get maintainers to] roll official releases (we’re not the security team, even though several members work for Tag1), and the maintainer could release 6.x-1.3 at any time, with or without our fix. Instead, we have to come up with some new notation that works alongside the existing version notation, without interfering with it.

Converting to the coördinate system gives us a nice tip in the right direction, though - we need a sixth dimension to represent the LTS patch version. And “dimension” isn’t metaphorical: for any given version, say {6, 1, 0, 1, 1} (that is, 6.x-1.0-alpha1), we may need to create an LTS patch to it, making it {6, 1, 0, 1, 1, 1}. And then later, maybe we have to create yet another: {6, 1, 0, 1, 1, 2}.

Now, we also have to extend the string syntax to support this sixth dimension - remember, strings are how the agent reports a site’s extension versions! It’s easy enough to say “let’s just add a bit to the end,” like we did with the coördinates, but we’re trying to design a reliable system here - we have to understand the implications of such changes.

Fortunately, this turns out to be quite easy: {6, 1, 0, 1, 1, 1} becomes 6.x-1.0-alpha1-p1; {6, 2, 3, 4, 0, 1} becomes 6.x-2.3-p1. This works well specifically because the strings in the prerelease type field are constrained to unstable, alpha, beta, and rc - unlike in semver, for example:

     A pre-release version MAY be denoted by appending a hyphen and a series
     of dot separated identifiers immediately following the patch version.
     Identifiers MUST comprise only ASCII alphanumerics and hyphen

     ...identifiers consisting of only digits are compared numerically and
     identifiers with letters or hyphens are compared lexically in ASCII
     sort order.

In semver, prerelease information can be any alphanumeric string, can be repeated, and are compared lexicographically (that is, alpha < beta < rc < unstable). If Drupal versions were unbounded in this way, then a -p1 suffix would be indistinguishable from prerelease information, creating ambiguity and making conflicts possible. But they’re not! So, this suffix works just fine.

Now, a coordinate system is fine and dandy, but at the end of the day, it’s just an abstracted system for representing the information in an individual version. That’s important, but the next step is figuring out where a particular version sits in the universe of versions for a given extension. Specifically, the question Quo needs to ask is if there’s a “newer” version of the component available (and if so, whether that version includes security fixes). Basically, we need to know if one version is “less” than another.

And that’s where we’ll pick up in the next post!

Oct 20 2016
Oct 20
Acquia Lift for Content Syndication is an Acquia product that allows you to have a central repository for your content and syndicate it out to various connected sites. All the connected sites are able to send content to the repository for use on any other connected site. In an ideal world, all the connected sites would have matching content type and field machine names. However, in our reality, we had two existing sites where this was not true.
Oct 20 2016
Oct 20

Let me tell you a story. When I joined Acquia in April 2011, the Support group was a small pool of passionate and talented drupalists working day and night to service our customers. And there was Kenny, aka webkenny. The vocal, outspoken and hilarious personality that was going to accompany Tim Millwood and I every morning when we were holding down the fort during EMEA hours, as the company was scaling up.


So, yesterday evening, when we received an email informing us Kenny had passed away, this brought back all those memories, and a deep sadness, because we all fought closely together to make things right and help each other.

It is with great sadness that we learned today that Kenny Silanskas has passed away. This is a terrible loss for Kenny’s family, for us at Acquia, and for the the Drupal community.

Kenny joined Acquia in 2009 and was instrumental into building the Acquia spirit and bringing the energy needed to wake up everyday and start all over again. Not without a lot of laughter.

[embedded content]

...and certainly not without killing it on stage.

[embedded content] [embedded content]

When he decided to take on another challenge, I recommended him on Linkedin and wouldn't change a word today:

Kenny is a natural-born leader who has a passion for sharing knowledge and moving mountains. From Client Advisor to Technical Account Manager and then Support Team Manager, he has always gained respect from his peers both technically and by his positive and energetic attitude. Today I'm better at what I do thanks to the high standards of customer satisfaction Kenny taught me about.

Because, yes, Kenny was quite a character, a generous and kind-hearted man, but also an excellent troubleshooter and technical lead. Maybe you remember his epic DrupalCon London presentation with the 8-bit Dries?

[embedded content]

Life's full of surprises. Kenny had just come back to Acquia. We were so happy. But unfortunately, at the end of September he suddenly resigned. I didn't really understand what was happening and didn't ask questions. So, when he last tweeted a few days ago, I obviously didn't imagine this would mean so much, after all.

Life is not a series of unfortunate events, but change that evolves you with each challenge. And no, that's mine. Not Confucius.

— Kenny Silanskas (@webkenny) October 17, 2016

Acquia's co-founder sums it best.

My heart goes out to the family of @webkenny. He was a force of nature on this earth, and I lament his passing. RIP Kenny. Sing with angels.

— Jay Batson (@jab) October 20, 2016

Never forget that smile. You will be sorely missed, my friend.


A GoFundMe has been set up in his memory. Please consider donating.

Oct 20 2016
Oct 20

Android Permission Provisioning has changed recently, If an app is using Android SDK API level 22 or below, users are asked for all the permissions in bulk at the time of installation i.e. Without granting permission user can not install the app. Now with Android 6's security patch called Run Time Permission (API level 23 and above) the app while in use can request for specific permission when the need arise ( similar to iOS ) e.g. you will be asked for the location's permission when you actually try to access the location of the device.

To work with runtime permissions on Ionic, you would need to install Cordova diagnostic plugin which gives you the function to fetch the status of the native api's exposed to the app. If a certain permission is mandatory for you app you can prompt the user to grant access to proceed. Further you have specific functions for granting permissions.

Install the plugin

cordova plugin add cordova.plugins.diagnostic

To avail the features of Run Time Permission, you have to build the app with Android platform 6.

Check you current Android platform version

ionic platform

If the version of your Android's Platform is below 5, you will need to update it to 5 or above.

Remove android platform:

ionic platform remove android

Install Android platform version 5 or above:

ionic platform add [email protected]

In config.xml, set the target of sdk version to 23

<preference name="android-targetSdkVersion" value="23" />

So far we are all set to ask user's for permission on the fly. We will have to call a functions to fetch the status of particular permission for the app. On the basis of the status we will ask the user to grant permissions or ignore it.

Add the following function in your app.js in $ionicPlatform.ready() function.

This will make $rootScope.checkPermission() global and you can call it whenever you wish to check if the user has given the permission to fetch device's location.

$rootScope.checkPermission = function() {
  setLocationPermission = function() {
    cordova.plugins.diagnostic.requestLocationAuthorization(function(status) {
      switch (status) {
        case cordova.plugins.diagnostic.permissionStatus.NOT_REQUESTED:
        case cordova.plugins.diagnostic.permissionStatus.DENIED:
        case cordova.plugins.diagnostic.permissionStatus.GRANTED:
        case cordova.plugins.diagnostic.permissionStatus.GRANTED_WHEN_IN_USE:
    }, function(error) {}, cordova.plugins.diagnostic.locationAuthorizationMode.ALWAYS);
  cordova.plugins.diagnostic.getPermissionAuthorizationStatus(function(status) {
    switch (status) {
      case cordova.plugins.diagnostic.runtimePermissionStatus.GRANTED:
      case cordova.plugins.diagnostic.runtimePermissionStatus.NOT_REQUESTED:
      case cordova.plugins.diagnostic.runtimePermissionStatus.DENIED:
      case cordova.plugins.diagnostic.runtimePermissionStatus.DENIED_ALWAYS:
  }, function(error) {}, cordova.plugins.diagnostic.runtimePermission.ACCESS_COARSE_LOCATION);
Run time location permission

Here is a link of the code snippet.

Of course, you can choose to skip all this and stick to sdk target version 22, but you will miss out the new cool feature of Android 6 and amazing user experience. 

Oct 20 2016
Oct 20

I saw a post recently about another Drupal 8 site that got launched. It was Rainforest Alliance. Nothing special at first. But then, out of curiosity, I clicked on it and checked it. While I was admiring the impressive pictures of the forests, I suddenly remembered that over a month ago I read an article about city of Boston launching its website on Drupal. Then it hit me. Who are the »big names« that Drupal can show off to the world and say 'These are our most proud members'?

As you may have heard or read or anything else, Drupal is a free and open-source content-management framework that provides a back-end framework for at least 2.2% of all web sites worldwide. To put it in numbers, that's more than a million websites that run on Drupal worldwide. They can be found in form of personal blogs and all the way down to the corporate, political and governmental websites. on Drupal


You can be sure that every government, political party or personal blog doesn't have its Drupal site modified up to date and not everyone is run on its latest version of Drupal, known as Drupal 8. Nobody minds that. However, what are the criteria that labels a company, political party or anything else as a »big name«? Well, we could find a lot of them from a lot of different sources, but I'll just take into account reputation, size and its impact on its field of activity.

Drupal in sports

As a huge sports fun I'll start with sports. I, there is no other way, watched this year's Olympic games as much as I could (the events were, to be fair, not held at the most optimum time for us Europeans to watch). If I didn't watch an event in Rio on television, I checked its outcome on Olympics’ website, which was brought to us by Drupal. Moreover, Drupal provides the Americans … pardon … all internet users, with the information from NBA, Major League Soccer (MLS), NCAA and some NFL teams like Dallas Cowboys.

Rio on Drupal

Drupal in Public sector

Besides city of Boston, cities of London, Austin and Los Angeles all use Drupal. In America some states even use it, like the State of New York and a State of Georgia. We learned that the White House began using it a long time ago and so does the Australian and Belgium government. United Nations, NATO and NASA are also ones not to be overlooked.

White House on Drupal

Drupal in Entertainment and Technology

Drupal is also very active in the entertainment 'sector', where it provides its services for Sony, MTV, PlayStation, Fox, Al Jazeera, NBC, The Economist and Puma. We may think that in cases of high technology Drupal is absent, but it's right the opposite. Tesla Motors, Sensio Labs, Cisco, Amazee Labs, eBay, Twitter and Pinterest are just some of the websites empowered by Drupal.

If you would like to see more websites that use Drupal, you can check Dries Buytaert's list and then potentially show off your Drupal site if you have it.

Oct 20 2016
Oct 20

The Paragraphs module is a very good alternative to a WYSIWYG editor for those who wants to allow Drupal users ans editors to make arrangements of complex pages, combining text, images, video, audio, quote, statement blocks, or any other advanced component.

Rather than let the user to struggle somehow with the text editor to make advanced pages, but never able to reach the level made possible with Paragraphs, we can offer him to compose his page with structured content’s components, each of these components being responsible for rendering the content, according to the settings selected, in a layout keeper under control.

Cite one example among dozens of others (possibility are endless). Rather than offering a simple bulleted list from the text editor, we can create a component that can generate a more refined bulleted list : each item in the bulleted list could for example have a pictogram, a title, a brief description and a possible link, and the content publisher could simply select the number of elements he wishes per row. For example a report of this kind.

Une liste à puces mise en forme avec paragraphs

Offer these components enables an inexperienced user to create complex page layouts, with the only constraint to focus on its content, and only its content.

The different possibles form mode availables for paragraph components

We have several options to display, inside the content edit form, the components created with Paragraphs. we can show them in :

  • Open mode: the edit form of the Paragraph component is open by default
  • Closed mode: the edit form of the Paragraph component is closed by default
  • Preview mode: the paragraph component is displayed as rendered on the front office

Paramètres d'affichage du formulaire d'un composant paragraph

I tend to prefer to retain the default closed mode, on content edit form, to improve editor’s experience. Because if the page consists of many components (and it’s the purpose of Paragraphs module), in open mode the content’s edit form tends to scare the user as the number of form may be important, and also makes it very difficult reorganization of the different components (order change), while the pre-visualization method involves either to integrate theses components inside the administration theme or to opt for using default theme when editing content.

The disadvantage of using the closed mode for editing components

The use of closed mode provides an overview of the different components used on the page (the content), and to rearrange them easily with simple drag / drop. Modification of the various components available is done by uncollapse / collapse them on demand.

Formulaire d'édition d'un contenu composé de paragraphs

With this editing mode, the content’s components are listed and have for title the paragraph’s type used. This can be a major drawback if the content uses many components of the same type, the publisher does not have immediate cues to distinguish which content relates to each component.

Modify the label of paragraph components

We can overcome this issue by creating a small module, which will be responsible for changing the label of each component by retrieving the contents of certain fields of our paragraphs.

The general idea is to alter the content edit form, detect if content contains entity reference revision fields (used by paragraphs), and if so, to recover for each paragraph the value of a field (eg a field whose machine name contains the word title), then change the label used in the edit form for each paragraph with this value.

Let's go to practice and PHP snippet. We will implement hook_form_alter().

 * Implements hook_form_alter().
function MYMODULE_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form_object = $form_state->getFormObject();

  // Paragraphs are only set on ContentEntityForm object.
  if (!$form_object instanceof ContentEntityForm) {

  /** @var \Drupal\Core\Entity\FieldableEntityInterface $entity */
  $entity = $form_object->getEntity();
  // We check that the entity fetched is fieldable.
  if (!$entity instanceof FieldableEntityInterface) {

  // Check if an entity reference revision field is attached to the entity.
  $field_definitions = $entity->getFieldDefinitions();
  /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
  foreach ($field_definitions as $field_name => $field_definition) {
    if ($field_definition instanceof FieldConfigInterface && $field_definition->getType() == 'entity_reference_revisions') {
      // Fetch the paragrahs entities referenced.
      $entities_referenced = $entity->{$field_name}->referencedEntities();
      /** @var \Drupal\Core\Entity\FieldableEntityInterface $entity_referenced */
      foreach ($entities_referenced as $key => $entity_referenced) {
        $fields = $entity_referenced->getFieldDefinitions();
        $title = '';
        $text = '';
        foreach ($fields as $name => $field) {
          if ($field instanceof FieldConfigInterface && $field->getType() == 'string') {
            if (strpos($name, 'title') !== FALSE) {
              $title = $entity_referenced->{$name}->value;
            // Fallback to text string if no title field found.
            elseif (strpos($name, 'text') !== FALSE) {
              $text = $entity_referenced->{$name}->value;
        // Fallback to $text if $title is empty.
        $title = $title ? $title : $text;
        // Override paragraph label only if a title has been found.
        if ($title) {
          $title = (strlen($title) > 50) ? substr($title, 0, 50) . ' (...)' : $title;
          $form[$field_name]['widget'][$key]['top']['paragraph_type_title']['info']['#markup'] = '<strong>' . $title . '</strong>';



Let us review in more detail what we do in this alteration.

First we check that we are on a content entity form, and the entity that we are currently editing is fieldable.

$form_object = $form_state->getFormObject();

// Paragraphs are only set on ContentEntityForm object.
if (!$form_object instanceof ContentEntityForm) {

/** @var \Drupal\Core\Entity\FieldableEntityInterface $entity */
$entity = $form_object->getEntity();
// We check that the entity fetched is fieldable.
if (!$entity instanceof FieldableEntityInterface) {

We check then all the entity’s fields (a node, a content block, or any other content entity) and only treat the entity_reference_revisions  field type that correspond to the field implemented and used by Paragraphs module.

// Check if an entity reference revision field is attached to the entity.
$field_definitions = $entity->getFieldDefinitions();
/** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
foreach ($field_definitions as $field_name => $field_definition) {
  if ($field_definition instanceof FieldConfigInterface && $field_definition->getType() == 'entity_reference_revisions') {
    // Fetch the paragrahs entities referenced.
    $entities_referenced = $entity->{$field_name}->referencedEntities();
    /** @var \Drupal\Core\Entity\FieldableEntityInterface $entity_referenced */
    foreach ($entities_referenced as $key => $entity_referenced) {

      // Stuff.



For each detected Paragraph entities we will then retrieve the value of a field. In our example, we test first if this is a text field type (string), then test whether its machine name contains the word title, or the word text which will serve as fallback if no field containing title in its machine name is found.

$fields = $entity_referenced->getFieldDefinitions();
$title = '';
$text = '';
foreach ($fields as $name => $field) {
  if ($field instanceof FieldConfigInterface && $field->getType() == 'string') {
    if (strpos($name, 'title') !== FALSE) {
      $title = $entity_referenced->{$name}->value;
    // Fallback to text string if no title field found.
    elseif (strpos($name, 'text') !== FALSE) {
      $text = $entity_referenced->{$name}->value;

This example is of course to adapt according to your own context. We could, for example, precisely target a specific field based on the type of paragraph detected. For example :

$bundle = $entity_referenced->bundle();
$title = '';
$text = '';
switch ($bundle) {
  case 'paragraph_imagetext':
    $title = $entity_referenced->field_paragraph_imagetext_title->value;
  case 'other_paragraph_type':
    $title = $entity_referenced->another_field->value;

Finally, we replace the label used by the paragraph type, if we have got a value for our new label.

// Fallback to $text if $title is empty.
$title = $title ? $title : $text;
// Override paragraph label only if a title has been found.
if ($title) {
  $title = (strlen($title) > 50) ? substr($title, 0, 50) . ' (...)' : $title;
  $form[$field_name]['widget'][$key]['top']['paragraph_type_title']['info']['#markup'] = '<strong>' . $title . '</strong>';

A happy user

The result then allows us to offer content publishers and editors a compact and readable edition form where he can immediately identify what content refers to a paragraph type.

Formulaire amélioré d'édition d'un contenu composé de paragraphes

This tiny alteration applied on the content edit form, and specifically on the default paragraph labels, makes it immediately more readable and understandable. It translates technical information, more oriented site builder, in a user-content information, giving him a better understanding and better comfort.

I wonder how this feature could be implemented using a contributed module (or inside the Paragraphs module itself ?), the biggest difficulty living here in the capacity of a Entity Reference Revisions field to target an infinite Paragraphs type, themselves containing a possible infinity fields. If you have an idea I'm interested?

You need a freelance Drupal ? Feel free to contact me.

Oct 19 2016
Oct 19

by Elliot Christenson on October 19, 2016 - 12:35pm

As you may know, Drupal 6 has reached End-of-Life (EOL) which means the Drupal Security Team is no longer doing Security Advisories or working on security patches for Drupal 6 core or contrib modules - but the Drupal 6 LTS vendors are and we're one of them!

Today, there is a Less Critical security release for the Webform module to fix an Access Bypass vulnerability.

When using forms with private file uploads, Webform wasn't explicitly denying access to files it managed which could allow access to be granted by other modules.

You can download the patch for Webform 6.x-3.x.

If you have a Drupal 6 site using the Webform, we recommend you update immediately! We have already deployed the patch for all of our Drupal 6 Long-Term Support clients. :-)

If you'd like all your Drupal 6 modules to receive security updates and have the fixes deployed the same day they're released, please check out our D6LTS plans.

Note: if you use the myDropWizard module (totally free!), you'll be alerted to these and any future security updates, and will be able to use drush to install them (even though they won't necessarily have a release on

Oct 19 2016
Oct 19

Thanks to everyone who participated in this year’s New England Drupal Camp – otherwise known as “NEDCamp.” A special thanks to those of you that attended my session and to the organizers for putting together an excellent conference!

Upon posting my presentation slides online (you can find them here:, I realized they’re not going to be terribly helpful since I am rarely inclined to condense all of my talking points into a slideshow. Therefore, I decided to write a two-part blog that will elaborate on crucial points I made during the presentation; this first post will focus on task prioritization and keeping all your projects and clients straight.

Throughout my presentation, we discussed different things to consider when trying to prioritize multiple projects. Three categories come into play for me when determining overall priority: 1) Client; 2) Tasks, and; 3) Other factors.

In this corner of our industry, we work with individual clients of varying sizes. It‘s therefore essential for us to understand each client’s priority.

There are six factors I take into account when prioritizing my client accounts:

  1. Budget. This is generally the only factor people use in prioritization.
  2. Client Deadlines. In my kick-off meetings, I always talk about deadlines with my clients. Questions such as, “Do you have any contracts ending we need to know about?” “How about internal blackout dates?” “Any launches coming up?” Asking these questions can give us a lot of insight to the client expectations as well as what is important to them. This is also a great start for a candid conversation around those dates and expectations.
  3. Growth potential. If your current project with the client is a proof of concept or one of a series of projects, prioritize it as though you have those additional projects or the proof of concept was successful.
  4. Internal or external. Internal customers are often a bit more flexible with their deadlines and priorities with respect to external customers. Learn where that priority lies, and, if the project is critical to the organization, you need to know that when prioritizing as well.
  5. Partnership potential. This is something that can often be overlooked. If a client has potential for partnership (e.g., sending you more business, being vocal on social media, participating in a case study) take that into consideration when prioritizing.
  6. Relationship. If the relationship with the client is in a bad space, I want to make sure I take that into consideration and use the project as an opportunity to turn things around.

There are four factors for determining overall priority based on tasks:

  1. Importance. We’ll talk a lot more about importance vs. urgency in the next post, but, in short, a task is important if it moves you towards the goal of your project.
  2. Urgency. A lot of people equate urgency with importance, but these are distinct things. Urgency is deadline based and is not related to the project goals.
  3. Value. When picking what task to prioritize, higher value tasks will go to the top.
  4. Effort. If a task is low effort, but still important, those will often get prioritized just to get them complete and out of the way.

Other factors I take into account when looking at my priorities are:

  • Political ramifications
  • Overall impact
  • Overall risk to the project, client, and relationship.

When taking these factors into account, I consider the whole picture when determining my priorities. Going off just one or two of these can lead to dangerous blind spots for your projects.

Another challenge to managing multiple projects is to keep everything straight when it comes to client teams, deadlines, schedules, and resources. For all aspects of your projects, nothing is going to replace hard work. Take the time to learn your projects, teams, deadlines, schedules, and resources. Putting time into this will save time in the long run as well as potential embarrassment in front of your clients.

Be specific in your notes and don’t assume you’ll know what you mean later. It’s easy to fall into the trap of “I’ll remember what I meant,” but don’t take it for granted. If you’ve switched topics and projects three times since your notes, you probably won’t remember. Aim to write your notes as if another team member will be reading them.

For your clients, don’t underestimate the power of face time and building relationships. This not only helps you keep things straight, but also essential to a successful project. While we don’t always have the luxury of traveling to client site, there are things like conferences, hangouts, and Skype to help grow these relationships.

The first thing I do when assigned a project is read the statement of work (SOW) or contract. Knowing the documented details helps me keep things straight and facilitates conversations about changes and expectations.

Schedules, deadlines, and resources often require similar different tactics. For all three of these, I recommend you keep a master calendar. Know who is working on what and when. This will avoid overscheduling as well as insight into your team members’ priorities.

There is a good chance your resources are working on more than just your projects. Get to know your team members’ priorities. Your number one project may be number three for them. Knowing these priorities can help you schedule accordingly.

In the upcoming second half of this series, we’ll discuss common pitfalls to managing multiple projects and how to best utilize your quieter times to make your busy times more manageable.

Like this story? Follow us on Facebook and share your thoughts!

Oct 19 2016
Oct 19
Nasdaq using drupal

I wanted to share the exciting news that Nasdaq Corporate Solutions has selected Acquia and Drupal 8 as the basis for its next generation Investor Relations Website Platform. About 3,000 of the largest companies in the world use Nasdaq's Corporate Solutions for their investor relations websites. This includes 78 of the Nasdaq 100 Index companies and 63% of the Fortune 500 companies.

What is an IR website? It's a website where public companies share their most sensitive and critical news and information with their shareholders, institutional investors, the media and analysts. This includes everything from financial results to regulatory filings, press releases, and other company news. Examples of IR websites include, and -- all three companies are listed on Nasdaq.

All IR websites are subject to strict compliance standards, and security and reliability are very important. Nasdaq's use of Drupal 8 is a fantastic testament for Drupal and Open Source. It will raise awareness about Drupal across financial institutions worldwide.

In their announcement, Nasdaq explained that all the publicly listed companies on Nasdaq are eligible to upgrade their sites to the next-gen model "beginning in 2017 using a variety of redesign options, all of which leverage Acquia and the Drupal 8 open source enterprise web content management (WCM) system."

It's exciting that 3,000 of the largest companies in the world, like Starbucks, Apple, Amazon, Google and Facebook, are now eligible to start using Drupal 8 for some of their most critical websites. If you want to learn more, consider attending Acquia Engage in a few weeks, as Nasdaq's CIO, Brad Peterson, will be presenting.

Oct 19 2016
Oct 19

Drupal + Hybris

Today we're thrilled about releasing our new Hybris Drupal integration module to the Drupal and Hybris communities. The module connects a Drupal site to a Hybris instance. Drupal is a leading open-source web content management platform for content, community and commerce. Hybris is a leading enterprise commerce platform.

Using this module, a Drupal site can:

  • import products as standard Drupal entities,
  • spread product attributes between both systems and keep them synced,
  • allow users to check out and manage their account all in Drupal,
  • and use Hybris as an identity provider for Drupal.

The Hybris Drupal integration module allows for a headless Hybris ecom setup with Drupal on the front end, meaning that Drupal communicates to the end user and Hybris only to Drupal. In essence, Drupal is the glass. These modules were built to scale and fully support global multilingual ecommerce experiences, and are currently in production.

The product was generously sponsored by Benefit Cosmetics, and built by Third & Grove and Benefit Cosmetics. TAG is one of the leading contributors to Drupal and is available for customizations for the Hybris Drupal integration.

Oct 19 2016
Oct 19

Webinar: International SEO + Drupal with Lingotek

If you're a digital marketer, SEO is likely one of your many priorities. Since Google released "Mobilegeddon" last April, your primary focus may have shifted to mobile optimization - but have you noticed a struggle to successfully reach and engage with prospects from across the globe? If you target multiple countries and languages, your site needs to be optimized not just for Mobile SEO, but for International SEO as well. 

Join us for a live webinar to learn more about how Mediacurrent and Lingotek can help you speak the right language to your global audience!

Date: Thursday, October 27
Time: 10:00 am PT / 1:00 pm ET

Key Takeaways of this Webinar Will Include:

  • Why International SEO is important in today's market
  • Tips for optimizing a global SEO strategy
  • Tools that can easily help you translate your site
  • And more!

Presented By:

  • Jen Slemp, Senior Digital Strategist, Mediacurrent
  • Bryan Duncan, Product Marketing, Lingotek


Registration for the webinar is now open - sign up here. We’re looking forward to an informative and engaging discussion. We hope you're able to join us!

Additional Resources
Internationalization and Drupal | Blog
Translating Success in Drupal 8: The Manhattan Associates Story | Video
Manhattan Associates Drupal 8 Redesign | Case Study
Multilingual Translation in Drupal | eBook

Oct 19 2016
Oct 19

I wrote a custom module recently where I needed to programmatically attach a field; similar to how a Body field is added to content types.

If you create a content type, via the “Content types” page, a Body field is automatically added to the content type. If you don’t need the field just delete it, but the default functionality is to have it added.

I needed this same functionality in my custom module; when an entity is created a field is programmatically attached to it.

So I reverse engineered how the Body field gets added to content types. In the Node module, the Body field is exported as and the field is attached using the node_add_body_field function.

I implemented my custom module in a similar fashion and everything worked until all the entity bundles with the custom field were deleted. When a new entity type was created you’d get a fatal error saying the custom field, which was programmatically attached, doesn’t exist.

So what happened?

Change Configuration Yaml

Drupal by default will delete a field if it’s no longer used. Now the fix for this is pretty simple.

Open the field storage yaml for a specific field, look for “”.

Persist with no field

Simply set persist_with_no_fields to TRUE in the yaml file. For example, persist_with_no_fields: true.

Let’s take the Body field as an example. If you open up the field storage yaml file,, you’ll see that the persist_with_no_fields option is set to TRUE. By default Drupal will set it to FALSE.

Don’t Forget to Import the Configuration Change

Once you’ve modified the yaml file don’t forget to import the configuration change. If you want to learn more about configuration manage in Drupal 8, check out page “Managing your site’s configuration“.


I do understand this is a fairly niche problem. But if you want fields to persist then set this option to TRUE and you’re good to go.

Oct 19 2016
Oct 19

Two weeks ago I wrote about routes and controllers in the introduction to namespaces. This week we are going to take a much closer look at routes and controllers. 

If you missed out on the namespace introduction, check it out here: A gentle introduction to namespaces.

So, what exactly is a route and a controller?

When you create a custom page in Drupal with code, you need both a route and a controller. You define the URL for the page with the route. And then you create a controller for that page. This will be responsible for building and returning the content for the page.


A route determines which code should be run to generate the response when a URI is requested. It does this by mapping a URI to a controller class and method. This defines how Drupal deals with a specific URI.

Routes are stored in a YAML file (check out last week's tutorials on YAML files) in the root of the module and use the following naming convention:

  1. modulename.routing.yml

Here is the example from the namespace tutorial:

  1. hello.content:

  2. path: '/hello'

  3. defaults:

  4. _controller: 'Drupal\hello\Controller\HelloController::content'

  5. _title: 'Hello world'

  6. requirements:

  7. _permission: 'access content'

The name of the route is hello.content. The path is /hello, which is the registered URL path. So when a user enters, this route will decide which code should be run to generate a response.

We then have two default configurations specified, the controller and the title.

The controller tells Drupal which method to call when someone goes to the URL for the page (which is defined in the route).

Let’s take a closer look at the path included in _controller.

  1. 'Drupal\hello\Controller\FirstController::content’

This comprises of a namespaces class, a double colon and then the method to call.

Drupal route with a namespace, class and method

The title is the default page title. So when a user goes to /hello, the page title will be ‘Hello world’.

Route title maps to the page title


Controllers take requests or information from the user and decide how to handle the request. For this module, the controller is responsible generating the content (the ‘Hello world’ message) and returning it for the page.

A controller that returns a simple Hello world message looks like this:

  1. <?php

  2. /**

  3.  * @file

  4.  * Contains \Drupal\hello\Controller\HelloController.

  5.  */

  6. namespace Drupal\hello\Controller;

  7. use Drupal\Core\Controller\ControllerBase;

  8. class HelloController extends ControllerBase {

  9. public function content() {

  10. '#type' => 'markup',

  11. '#markup' => t('Hello world'),

  12. );

  13. }

  14. }

The controller is returning a renderable array with “Hello world”. So if you hit /hello once all this is in place, you will get a Drupal page with a Hello world message.

Drupal 8 controller content method maps to content on the page

Drupal 8 module route and controller

The controller lives in a Controller directory within the the src directory of a module.

The controller class in the src controller directory

Putting all of this together

To see this in action, you’re going to combine this all in a new module.

  1. In the /module directory, create a directory called hello
  2. Create in the root of the hello directory
  3. Add the following to

  1. name: Hello

  2. description: An experimental module to build our first Drupal 8 module

  3. package: Custom

  4. type: module

  5. version: 1.0

  6. core: 8.x

  1. Create a directory inside the hello module directory called src, which is short for source
  2. Create a directory within src called Controller
  3. Within the Controller directory, create a file called HelloController.php
  4. Add the following to HelloController.php:

  1. <?php

  2. /**

  3. * @file

  4. * Contains \Drupal\hello\Controller\HelloController.

  5. */

  6. namespace Drupal\hello\Controller;

  7. use Drupal\Core\Controller\ControllerBase;

  8. class HelloController extends ControllerBase {

  9. public function content() {

  10. return array(

  11. '#type' => 'markup',

  12. '#markup' => t('Hello world'),

  13. );

  14. }

  15. }

  1. Create a file called hello.routing.yml in the root of the hello module directory
  2. Add the following code to hello.routing.yml:

  1. hello.content:

  2. path: '/hello'

  3. defaults:

  4. _controller: 'Drupal\hello\Controller\HelloController::content'

  5. _title: 'Hello world'

  6. requirements:

  7. _permission: 'access content'

  1. Enable the hello module
  2. Visit /hello to see the Hello world message

It is good practice to complete these steps manually when you are first learning the concepts in Drupal 8 development, but you can save time by using the Drupal Console to create most of the code in the above steps. To find out how, check out my 7 day email course on the Drupal Console.

Oct 19 2016
Oct 19

Last week I had the opportunity to back to Colombia as para of my tour Around the Drupal world in 140+ days.

To be honest, this stop wasn't planned, during my visit to France the border control officer inform to me about a situation with my passport, I was almost done with the space for new stamps. That situation forces me to try to get a new passport as soon as possible; After checking to Colombian embassy in Costa Rica, I confirm that renew my passport in Costa Rica wasn't an option due the return time. For that reason, I have to travel to Colombia to renew my passport there.

With this un expected trip I tried to use in as many activities I could. In Drupal Side, I participated in a Drupal Meetup organized by Seed, and particularly by Aldibier Morales. They rent and space and organize the event to enable me to talk about Drupal Console and Drupal Community in general, I enjoy the Q & A session, where I could provide some points of view I have about how to handle local communities.

With my new passport on my hands, I start a marathon to visit my mother and father familly located in Bucaramanga, Santader. Was really good because for many years I haven't visit them.

So, as many time in my #enzotour16 I overcome the adversities and transform in something positive as much I could it.


Distance (Kilometers) San Jose, Costa Rica → Bogota, Colombia → San Jose, Costa Rica 2.576 Previously 106.561 Total 109.137


Distance (steps) Dublin 39.597 Previously 1.897.088 Total 1.936.685


Distance (Kilometers) Today 0 Previously 528 Total 528
Distance (Kilometers) Today 796 Previously 2.944 Total 3.740
Oct 18 2016
Oct 18

We are thrilled when clients seek us out to create beautifully designed and highly functional websites. However, we often find ourselves spending a lot of time to convince clients that creating compelling content is a critical component of finding and growing a highly engaged audience. Once they are on board, they begin to realize that creating great content isn’t always easy and can take a lot of time and effort.

It is disheartening to see what can happen when a link is shared on Facebook without proper meta tags, which often results in the wrong image or description being displayed. Not only is this sloppy, but it relies on users to manually correct that information (if the particular social media platform even allows for that flexibility). Worse, your audience is unlikely to take the time to make those same adjustments when they are sharing your content. The solution to this is to leverage HTML meta tags to tell and tailor your story to each social media platform.

A Real Life Example

Imagine you show up at a dinner party. You look around and discover that you don’t know anyone there! You keep scanning the unfamiliar faces when someone bumps into you and strikes a conversation. Inevitably, the other person asks you “so, what do you do for a living?”

Such a simple question, but you probably have anywhere from 2-5 canned responses to pick from depending on the background of the person that asks. If you had an inkling that the person worked in a similar industry or knows of the company you work for, you might provide a somewhat detailed answer going into specific nuances that they might understand and appreciate. On the opposite end of the spectrum, you might overwhelm someone that has no frame of reference. Here you are more likely to give a generic answer, which is why I simply tell my mom “I work with computers” and that’s sufficient to keep the conversation going.

In short, different people get different answers based on what will best support the conversation with that person or audience. We now need to apply those same principles for your content as it is interacted with on different social media platforms.

Part 1: Creating Your Sharing Strategy

Before we discuss the mechanics, it’s important to review your goals for each social media platform. Similar to the dinner party analogy, there are a variety of factors that you need to consider when deciding on what to communicate.

While the following is an overly simplistic breakdown of LinkedIn, Facebook, and Twitter, it will reinforce the need to tailor the messaging to each platform. Typically, Linkedin is geared towards conversations relating to careers, networking, business opportunities, and etc. Facebook started primarily as a way to connect with friends but has rapidly evolved into a mix that depends greatly on how you’ve been using it and what types of connections you already have. Twitter is based on real-time communication and information sharing.

It’s possible to create a piece of content that is useful to share across all 3 platforms at the same time, but it’s unlikely that it’s appropriate to present the content in the same way due to the different audiences and expectations on each platform. In short, posting an adorable picture of my two and a half-year-old daughter is encouraged on Facebook, arguably not something I would do on Twitter, and something I would never, ever do on LinkedIn.

Part 2: The Mechanics

If you’ve never built a website before, it’s unlikely that you’ve peaked under the hood to see the guts of an HTML page. If you’d like to get a very quick overview, here is a basic tutorial to get started. And if you really want to take a deep dive, here’s a comprehensive overview on Wikipedia.

Traditionally, when you share a link to the social media outlets, each platform does its best job to scrape the page’s HTML and try to extract the pertinent details. In general, getting the title of the page is a no-brainer, but the description can be messed up in a variety of ways. Sometimes it will pull the wrong description or give up and show nothing at all. Twitter’s character limit can also cause a truncation that can either change the meaning or not accurately describe the page.

Picking an appropriate image can often feel like a game of Russian roulette. While you may expect the platform to pull an image from within the article, it will sometimes pull an image from a completely unrelated part of the page. Unfortunately, this can not only harm the quality of the share result but sometimes the two juxtaposition can result in an unappealing or inappropriate result. Just imagine an article on depression pulling an image of a specific person’s picture and you may be setting the reader up with the wrong expectation.

This is where meta tags come in. Here we want to provide additional information to essentially tell the different platforms the specific information and media we want it to use instead of having them guess. For example, Facebook uses a protocol called Open Graph, which contains a specific subset of meta tags that live in the head region of the HTML page that is used for share results on their platform. Twitter has its own set of meta  tags that not only let you specify different information, but they also allow you to specify which style of share you would like to use (photo, video, standard, etc). And finally, Linkedin leverages the Facebook OpenGraph meta tags, so you can’t quite delineate the message between the two. Although, it is probably only a matter time before Linkedin creates their own version such that you can specify and tailor it to be a different introduction than Facebook.

Here’s a sample of the 9 lines of code we’ll be using to target our message.

<meta name="title" content="Page Title for Search Engines Results | Website Name" />
<meta name="description" content="Page Description for Search Engine Reults" />
<meta property="og:title" content="Page Title for Facebook" />
<meta property="og:description" content="Page Description for Facebook" />
<meta property="og:image" content="" />
<meta property="twitter:card" content="summary" />
<meta property="twitter:description" content="Page Description for Twitter." />
<meta property="twitter:title" content="Page Title for Twitter" />
<meta property="twitter:image" content="" /><

If you’re using a CMS like Drupal 8, adding these values to any node page is very straightforward. Simply install the metatag module along with the OpenGraph and Twitter submodules. Then visit the configuration menu located at /admin/config/search/metatag. There you can specify the default global values and tokens for each of these meta tag options. You can then override these values on a per node basis by visiting the node edit screen and navigating to the meta tags section.

It’s worth noting that there are more meta tags available that can be used to specify content attributes ranging from a video URL to its  geographical location (i.e. longitude and latitude). Here’s just one list to emphasize the quantity and variety of tags available.

Part 3: The Outcome

Let’s use a real example from the newmedia blog. Several months ago, I published an article titled PCI Compliance & Drupal Commerce: Which Payment Gateway Should I Choose? Given the technical nature of the article for both developers and businesses, LinkedIn and Twitter would be the most appropriate place to share this page.

Without any metadata specified, the share result on Twitter is fairly bland. Here’s a quick screenshot showing it.

A tweet from a URL that contains no meta tags.

Figure 1: A tweet containing a link that lacks HTML Meta Tags for Twitter.

Alternatively, I can provide a very tailored title, image, and description that is far more likely to get someone’s attention and provide them with an accurate representation of the article itself.

A tweet from a URL that contains meta tags.

Figure 2: A tweet containing a link with HTML Meta Tags for Twitter.

It’s important to note that these changes are more than just simple cosmetics. The share result is now taller because the images get more real estate and you’re able to leverage the full length of the description field. Both of these changes makes the tweet stand out more. If I had a video, I could put that in as well, allowing me to have an additional opportunity to communicate with a potential reader before they left Twitter. In short, I’ve dramatically improved my odds of reaching the audience.

Finally, we need to change the message on LinkedIn. By editing the "og:description" field, we could say something along the lines of "Keep your customer's credit card data safe while meeting your PCI compliance obligations for your Drupal Commerce site by using these recommended payment gateways." This way we are focusing more on a businesses need to protect their customers by choosing the appropriate gateways instead of appealing strictly to a security minded developer on Twitter.


As social media platforms continue to become a dominant traffic source for your content, it becomes even more important to put in the small amount of additional effort to ensure your story can connect with each audience. Through the proper use of metadata, you can easily achieve this goal with your existing content as well as make this a part of your editorial process moving forward.

PS. You can use the following preview tools to test what content will look like on Twitter and Facebook.


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