Mar 19 2019
Mar 19

Drupal 8.6 became one of the most interesting releases in Drupal 8’s history. It brought us the oEmbed feature, the Media Library, the Workspaces module, and more. But it’s time to move forward, and in May 2019 we expect Drupal 8.7. Its “alpha” version has just been released. Although an alpha version is not a final one, we will gladly take a look at it and discuss what to expect in Drupal 8.7.

Drupal 8.7: the alpha version

Drupal 8.7.0-alpha1 has come out on March 14, 2019. Alpha versions are far from being ready for production sites. They are just preliminary releases that allow developers to do a good testing, receive feedback, make final preparations, and fix bugs.

After the “alpha,” will are supposed to see the “beta” version of Drupal 8.7 in the week of March 25. Next, the RC (release candidate) phase will begin in mid April.

When everything is tested thoroughly and polished to perfection, we will enjoy the stable Drupal 8.7 on May 1! Let’s see what to expect in Drupal 8.7 now that we are looking at Drupal 8.7.0-alpha1.

Expected features of Drupal 8.7

  • End of support for PHP 5.5 and 5.6

Websites are officially becoming lighter and faster due to the use of PHP 7.1+. Drupal 8.6 was the last release to support PHP 5.5 and PHP 5.6. Drupal 8.7 is definitely the time to say goodbye to these obsolete versions of the programming language.

According to Drupal 8.7 alpha 1 release notes, they will officially stop being supported in Drupal 8.7 beta. So those who are using PHP 5.5 and PHP 5.6 will need to upgrade to PHP 7.1 or higher, and our Drupal support team can help.

  • End of support for Internet Explorer 9

The support for Internet Explorer 9 and 10 had been stopped back in Drupal 8.4. However, there was a workaround left in Drupal 8.5 and Drupal 8.6 that allowed 32+ stylesheets to be included.

Drupal 8.7 has now officially removed this workaround, so goodbye to Internet Explorer 9. Those who rely on it will need to enable CSS aggregation or install the IE9 Compatibility Drupal module.

  • Stabilization and new UI for the Media Library module

The Media Library module lets you save various multimedia and use them in your content to make it more engaging. It’s possible to embed multimedia directly into content types using the “media” field.

The Media Library works together with the Media module that is stable already. Among the expected features of Drupal 8.7 is the stable Media Library. We don’t yet see it as stable in alpha 1 admin dashboard.

However, a few hours ago, a new and interesting Media admin interface for Drupal 8.7 was presented. It didn’t make it into the alpha 1 version, but we should see it in 8.7.0-alpha2/beta1.

New Media Library admin UI for Drupal 8.7New Media Library admin UI for Drupal 8.7
  • Adding JSON:API to Drupal 8 core

The JSON:API contributed module is meant for creating high-performance APIs to expose Drupal data in JSON. It immediately creates API endpoints and requires no configuration. The module instantly accesses all Drupal entities.

According to Drupal development roadmap, JSON:API is meant to join the core in Drupal 8.7. JSON:API will look great in Drupal core’s ecosystem of web services that are responsible for third-party integration.

Joining Drupal core is a serious step for any module, especially for a complex one like JSON:API. There has been a hard work done on fixing the last issues related to adding JSON:API to Drupal 8.7 core, and all are fixed now.

Although we don’t yet see the module in the Drupal 8.7 alpha 1 admin dashboard, the issue thread shows that we may see it there very soon. So congrats to JSON:API!

  • Improvements and stabilization for the Layout Builder 

The Layout Builder module in Drupal 8 core allows you to build layouts like Legos by using ready multi-column layouts and Drupal blocks. 

These can be layouts for content, users, contact forms, and other fieldable entities. You can have a specific layout for a content type (e.g. all articles), for an individual node (e.g. one article), or for a display mode (e.g. article’s teaser).

The module arrived in Drupal 8.5 core marked as “experimental,” which means it needs some work yet. For Drupal 8.7, it has received important bug fixes in the area of saving layouts for the default content layouts and individual nodes, saving layout overrides, using layouts for different display modes, and more. CSS classes have also been renamed to meet the BEM standards.

Drupal development roadmap has the Layout Builder moving from experimental to stable in Drupal 8.7. We don’t see this happening yet in Drupal 8.7 alpha 1, but let’s expect this in the future.

Layout Builder in Drupal 8
  • Updates to the Guzzle library

The Guzzle HTTP client library arrived in Drupal 8 to replace drupal_http_request() function in Drupal 7. It makes the process of communicating with RESTful web services easier.

Guzzle offers a modern way of making HTTP requests. It is extensible with plugins, easy in use, and based on object-oriented architecture.

In Drupal 8.7, Guzzle has been updated from 6.3.0 to 6.3.3 and http_client service has begun to support empty headers. Additional updates are also planned in Drupal 8.7 beta.

  • Changes to the Stable and Classy themes

The Stable or Classy are among the Drupal core themes in addition to Bartik, Seven, and Stark. If your website’ theme has been created as a subtheme of the Stable or Classy themes, you will need to pay attention to their changes in Drupal 8.7.

They are related to JavaScript message template and pagination header CSS ID. Specifically, if your theme overrides the messaging or pagination templates, you will need some manual changes, and our Drupal experts are ready to provide them.

  • Better Symfony 4 and 5 compatibility

Drupal 8 includes Symfony components for more modern and fast web development. Drupal 9 will completely move to the new Symfony 5.

Drupal 8.7 is getting ready for it. It is providing better compatibility with both Symfony 5 and Symfony 4. This includes changes in the Container and TranslatorInterface Symfony components, as well as resolving critical compatibility issues.

Be ready for a smooth update to Drupal 8.7!

So we now know in a nutshell what to expect in Drupal 8.7 that is coming in May 2019. Of course, you can rely on our Drupal team for a smooth update. 

In the meantime, we can help your website prepare for it, if there is a need to:

  1. update to PHP 7.1+
  2. take care of Internet Explorer 9 issues
  3. apply changes to your Stable and Classy subthemes
  4. check the compatibility of any other website components 

Contact our Drupal team!

Mar 19 2019
Mar 19

Late last year, we started a series of posts that tell the story of what makes Agiledrop the company that it is today. In the first chapter, we presented our unique workflow, while the second and third chapter dealt with the major challenges that arose from such a workflow and our very efficient solutions to them.

This final chapter of the series will tie things together, diving into our company culture which strongly promotes cooperation and knowledge-sharing. This ensures that our clients always benefit from the collective knowledge and skillsets of the entire Agiledrop team.

Well, let’s get right down to it!

Basing our company culture on cooperation and knowledge-sharing

What makes Agiledrop stand out is our strong culture of support and knowledge-sharing among developers. We make it a priority to integrate new employees into our A-team, make them feel welcome and help them become fully-fledged members of the team as soon as possible. Creating a collaborative and welcoming working environment is the responsibility of every person on the team and something we all participate in. 

The onboarding and mentoring of new developers is a prime example of our company culture - but it doesn’t stop there. We promote and encourage knowledge-sharing between all members of the team, no matter their status within the company or the amount of time spent with us.

Our development leads are always available to help developers weather through any obstacles they might encounter - be they considerable or negligible ones. In this way, we are able to find solutions much faster, which results in fewer working hours spent on a specific issue and, in consequence, significantly lower costs for the client.

We also have a Slack workspace dedicated exclusively to obstacles encountered by developers during their work. Every member of the team participates, no matter their physical location. It’s a place where the real knowledge exchange is allowed to happen. One of the best things to see there is when a newly recruited junior developer who is still dealing with their onboarding project helps out a senior developer with one of their issues - and it happens more often than you’d think!

In short, when working at Agiledrop, you are never given the impression that your lack of knowledge is detrimental to anyone on the team or the company as a whole; rather, it’s an opportunity to learn something new or revisit something already learned. 

Balancing the happiness of clients and developers

It’s not always easy to sustain such a well-defined and inclusive company culture. On the one hand, the development leads in the mentor roles must possess an innate pedagogical capacity in addition to extensive technical knowledge and a knack for spotting and solving problems. On the other hand, however, we must take great care to understand the positions of both the developer and client when a problem arises, and not simply look for scapegoats.

In order to catch and resolve issues in the early stages of a project and not after a month, we do weekly reports every Friday. These reports are done in two directions: our resource manager collects feedback from the clients, while the development director checks the issues that were raised by developers, such as not getting enough tasks or sufficient information to fulfill a task.

Issues raised by the clients are not something we punish; instead, we aim to provide constructive feedback to improve on the mistake, not just sanction it. The development director will speak with developers and suggest any improvements to their work. Likewise, the resource manager will notify the client about issues raised by developers so that they can do certain things differently in the future. 

Such a system ensures constant smooth communication between everyone involved in the projects, making it easier to find solutions and improvements while also keeping each side satisfied and up-to-date on any new projects and developments. 

Boosting morale and keeping the team motivated

We understand that a motivated team is more committed and able to deliver better results. It’s easier for people to give their best and be satisfied with their job when they know that their work makes a difference. The appreciation of their peers and superiors gives them the confidence needed to get through even the most difficult days.

For this reason, we hold weekly meetings every Monday and monthly meetings every first Thursday of the month; these meetings are essentially weekly and monthly reviews where we go through our new and ongoing projects. But, most importantly, they are an opportunity to congratulate people for the good work they’ve been doing, which helps boost the morale of the entire team. 

We also frequently organize various educational and sports activities that bring the whole team together, which results in new friendships and another level of knowledge-exchange. Besides our free Drupal courses where we train wannabe Drupal developers (who often go on to become full members of our team!), we also:

  • Organize TechTalks, which we call AgileTalks, on developers’ own initiative,
  • Attend tech conferences and other Drupal-related events,
  • Promote and reward any additional activities of developers, such as the organization of an aforementioned AgileTalk or writing a blog post on a topic of their choosing,
  • Organize teambuildings,
  • Organize differently-themed common lunches,
  • Enable flexible working hours that ensure a healthy work-life balance for developers.

Additionally, we also collect feedback through Officevibe surveys, which makes for a better overview of the week-to-week satisfaction of our employees and enables us to constantly improve the way we do things. A pleasant working environment and a good team spirit are key to a strong company culture.   

Providing clients with our collective knowledge

Because we base our company culture on collaboration and knowledge-exchange, we are in a unique position where we can offer our clients not just individual, but the collective knowledge of the entire Agiledrop team. By exchanging ideas and sharing resources, we are much more productive and consequently able to provide solutions faster and more efficiently. 

If you’ve read the other posts in this series (and we suggest you do!), you’ll notice that the values outlined in this post are intrinsically tied to and realized in all aspects of the work we do. We take the same understanding and inclusive approach with developers and clients alike, and we believe this is what lies at the heart of our success. 

We truly operate as a team, having each other’s back and valuing the input of each and every member. As a result, we managed to strike the perfect balance between the wants and needs of our clients and developers. This balance guarantees, on the one hand, that our developers work for a company that helps them grow, on projects they can take pride in; and, on the other, it ensures the satisfaction of our clients and helps establish ourselves as trustworthy partners that never fail to deliver.

This is evidenced by our fast, but stable growth: in just one year, we doubled the size of our team, opening offices in a new location in Maribor, with plans for a third Slovenian office this year. In addition to that, we are now taking on a number of new and exciting projects for a wide range of different international clients, making for a stable market share. You can dive into the numbers a little bit more by reading our review of 2018.

(This is not) a conclusion

Last year, we thought “Wow - 2018 really is our year”. But, seeing how it’s only the middle of March and there are already so many exciting things going on and planned for later in the year, we might have to reevaluate our previous assessment. Perhaps 2019 will be our year; besides all the new teammates and exciting projects, there’s also a major change for us on the horizon (keep following our blog posts to find out more about it!).

Or, maybe, it’s not about the year at all. Maybe we’ve arrived at the point where we’ve finally realized our vision - maybe, if we keep following in the footsteps that we’ve set for ourselves, every year will be our year. 

And, hopefully, an insight into how we do things at Agiledrop will help other businesses who are dealing with the same obstacles as we did, giving them proof that, yes, it is possible to start and successfully scale the kind of company you’d be proud working for!

So, this was the story of how we transformed Agiledrop into what it is today - a company one can take pride to work at and work with. We hope this series has given you some ideas on how to kill two birds with one stone by keeping your employees and clients happy. If you’re interested in working with us, give us a shout out!

Other posts in this series:

Mar 19 2019
Mar 19

In preparation for his fourth DrupalCon, Chris O’Donnell, Digital Strategist, for Promet Source shared his views on the vibe of this annual conference, as well as Drupal’s current standing within the ecosystem of enterprise-level CMS platforms.  

What are you looking forward to at Drupalcon this year?

One of the best parts of DrupalCon for me is the community. It’s an opportunity to connect with people who I might only get to see once a year -- colleagues from other Drupal development companies, previous clients, current clients, and like-minded people from all over the country. There’s a ton of training and all of the sessions are driven by community involvement -- people who are just sharing their knowledge for the fun of it, or as a way to give back to the community.

Last year at DrupalCon, there was a proprietary software company exhibiting for the first time. They seemed really confused by world  where a development company was on the stage with some of its best customers. Why would anyone share great information with potential competitors? They were really confused by the entire thing - competitors coming together to openly share knowledge just didn't compute for them.

How would you explain it?

DrupalCon is more like a Drupal community celebration than a tech industry trade show. 

I think it was President Kennedy who said, “A rising tide lifts all boats,” and the same principle applies within the Drupal Community, or any open source community. The more brain power that goes into it, the better it is for everybody. As an open-source CMS, the Drupal community is driven by the community and the needs of users. Anything that anyone does to improve or add to Drupal is freely available to all. 

I joined the Drupal community in 2014, and I love being among hundreds of thousands of people around the world who contribute to the community in various ways. 

What are your observations on how DrupalCon has evolved?

There has been a pretty big shift this year as the Con has been organized around specific tracks. Drupal 8 ushered in an orientation toward more of an enterprise-level focus, and that’s been reflected in the kind of training that’s offered and an expanded sphere of people who are attending.

With so much going on, what's your advice for attendees for getting the most out of DrupalCon?

Use the schedule builder feature on the DrupalCon website to build yourself a schedule of sessions you want to be sure to catch. Don’t forget to look at the Birds of a Feather events, which tend to be smaller and more informal. However, don’t schedule yourself so tight that you miss out on the hallway track. My most interesting conversations at DrupalCon usually happen in the hallways and at evening social events.

How would you characterize Drupal’s position today within the world of web content management platforms?

Drupal is an enterprise-level content management platform that delivers much of the functionality you would expect from some of the million dollar proprietary CMS platforms, while still retaining the freedom and flexibility inherent in its open-source roots.

What are your thoughts on when, why or how Drupal has achieved this status?

I think it was a coordinated effort related to the Drupal 8 rollout. D8 was a total rewrite of the CMS, with the goal of producing an enterprise-grade CMS that would be on par with the established and expensive proprietary platforms. The momentum is now really strong for Drupal as an enterprise CMS.

What sets Drupal apart from other web content management platforms?

The freedom, flexibility, and lack of license fees that come with open source set it apart from all the proprietary options. It’s different from any other open-source CMS in that it has strong corporate sponsorship, a dedicated security team, and an enterprise heavy install base.

What will the extent of your participation in DrupalCon be this year?

I’m excited about attending the GovSummit on Monday, April 8, and will be presenting in the Builder Track at 3:15 on Wednesday, April 10, in Room 608. Otherwise, I’ll be in and out of sessions and at the Promet Booth (#308) for the rest of the event. This is Promet’s 12th year as an attendee and 11th year as a sponsor. Once again, we’ll be all over DrupalCon. The entire senior leadership team will be there, along with some of our senior developers and our entire sales and marketing team. I’m particularly excited about the addition of Mindy League to our leadership team this year. The Human Centered Design team that she is heading represents an exciting expansion for Promet. I definitely recommend that anyone who is interested in the very latest in design thinking for digital experiences make it a point to grab some time with Mindy. 

How would you characterize Promet’s client base for whom Drupal proves to be the right solution?

Very much in line with what Dries Buytaert, the founder of Drupal said at DrupalCon twy years ago: “Drupal is for organizations that are looking to build ambitious digital experiences.” It’s not so much about the size of the company or the team, it’s about the reach and impact that the site needs to have. 

The fact is, I spend very little time selling Drupal websites. I sell e-commerce solutions that will generate more revenue. I sell accessibility, more streamlined user experiences, sites that are better targeted to the needs of customers, and sites that more effectively reflect an organization brand image.

Stop by booth #308 at Drupalcon in Seattle, April 8-12, or Contact Us Today for a conversation about how Promet can create an ambitious digital experience for your organization. 


Mar 18 2019
Mar 18


How do you migrate webforms and submissions from previous versions of Drupal and other form builders?

The answer is Drupal's Migrate API, which is incredibly powerful but can feel overwhelming. When I migrated from Drupal 6 to Drupal 8, the Migrate API was just being introduced into Drupal 8 core, and I felt more comfortable writing a custom migration script instead of using code that was still under development. Migrate API is now stable and if you are an experienced Drupal developer, you should use it.

Certain aspects of Drupal require some expertise.

The level of expertise required to build and maintain a Drupal 8 website has changed from Drupal 7, mainly because we are creating more ambitious digital experiences. The Drupal community struggles to simplify our flexible and sometimes complex product. My approach is to make the Webform module as flexible and robust as possible, while not forgetting that people need a simple way to start building a form. This is exactly why I include an introduction video on the Webform module's main page. Besides making the Webform module an awesome tool for experienced Drupal site builders, the Webform module needs to be welcoming to new users and make it easy for them to move their existing forms to Drupal.

Either an organization is starting from scratch and building a new Drupal site, or more commonly an organization has decided they need to provide a more ambitious digital experience and they have chosen to switch to Drupal. In both situations, we need to make it easy for someone to switch from other form builders to Webform.

The problem that needs to be addressed is…

How can we make it easy for an organization to migrate existing forms with submissions to the Webform module?


The simplest way to migrate to the Webform module is to rebuild an external form and then import the existing data. Building a webform is fun and easy, forms are a critical aspect to most websites; it is worth taking the time needed to rebuild an existing form, and take full advantage of all the cool elements and features available in the Webform module. The only missing feature from the Webform module is an easy and fast way to import existing submission data.

The Webform module already makes it easy to export submissions. There is a 'Download' tab under the Results section that generates a CSV (comma separated values) which can be opened in Excel or Google Sheets.

The solution is to make it extremely easy for anyone to import submissions using a CSV.

Importing a CSV containing submission data should be a simple process where a site builder uploads a CSV, which is prepared, reviewed, validated, and submitted to a webform.

Below are the steps which one might take to import CSV data:

  • Build a webform
  • Populate webform with some test submissions
  • Download the test submissions using the CSV export
  • Examine the CSV export
  • Populate the CSV export with external data
  • Upload and import the CSV export
  • Review imported data

Being able to export and import submission data as needed has the added bonus that site builders can download all the existing submissions, bulk edit them using Excel or Google Sheets, and then upload them back into the database. Submissions can now be migrated from one server to another. There is only one caveat, and it is not required, but it helps to make sure all exported and imported CSV records have a UUID (universally unique identifier).


The below notes are pulled directly for the Webform module's CSV upload form:

  • All submission properties and data is optional.
  • If UUIDs are included, existing submissions will always be updated.
  • If UUIDs are not included, already imported and unchanged records will not create duplication submissions.
  • File uploads must use publicly access URLs which begin with http:// or https://.
  • Entity references can use UUIDs or entity IDs.
  • Composite (single) values are annotated using double underscores. (e.g. ELEMENT_KEY__SUB_ELEMENT_KEY)
  • Multiple values are comma delimited with any nested commas URI escaped (%2E).
  • Multiple composite values are formatted using inline YAML.
  • Import maximum execution time limit is 6 hours.

For those hardcore developers out there, the answer is…

Yes!!! There is even a drush:webform:import command.


To make sure no one feels overwhelmed, I created the below video to help people feel more comfortable with this new functionality.

Supporting organization

This awesome new feature was sponsored by Kennesaw State University. Kaleem Clarkson (kclarkson), Operations Manager @ Center for Excellence in Teaching & Learning at Kennesaw State University, and I scoped out this ticket on via Issue #2902977: Provide a straight forward tool for importing submissions from a CSV document.

I previously talked about Coming to an agreement within the Drupal community and sponsoring a Webform feature, and it is challenging working out the process for a paid feature. I have discovered that scoping out all paid Webform feature requests on the has worked out to be the most transparent process. Even when a potentially sponsored feature agreement falls through, the scoped out work remains in the Webform issues queue. I feel better knowing the research and work I did for the feature request is not a complete loss. I have even seen a feature request sit in the queue for a few months and then someone like Michael Feranda (mferanda) appears out of nowhere and helps complete a feature like Issue #2888862: Provide a mechanism to lock a webform submission.

Getting Involved

Kaleem Clarkson (kclarkson) and Michael Feranda (mferanda) contributions show there are multiple ways to get involved in helping to support the Webform module and Drupal. Michael found a task in the Webform issue queue and started contributing code back to the Drupal community. Kaleem is not a coder, he is more of a 'master' site builder and community leader, so he found a requirement from his project, convinced Kennesaw State University about the value of contributing back to the Drupal, and they sponsored a pretty awesome improvement, which helps everyone who is adopting the Webform module and Drupal.

Sponsor a Feature

Sponsored a feature is a challenging but needed enhancement to the process of building and maintaining the Webform module. I have had some success implementing a few paid features.

Open Collective provides a transparent platform that might make 'Sponsor a feature' more natural and accessible for the Drupal community. Paying for a feature using Open Collective's payment system which provides standardized invoices could make it easier and justifiable for large organizations to financially contribute to Webform, Drupal, and Open Source.

At the same time, I still feel it is also okay to not pay Open Collective's 13-14% overhead and execute a paid feature request via a direct transaction. Either way, I am absolutely committed to scoping out all feature requests transparently on

If you have a features request, please create a ticket in the Webform module's issue queue.

Backing the Webform module

Open Collective is providing us, Drupal and Open Source, with a platform to experiment and improve Open Source sustainability. If you appreciate and value what you are getting from the Webform module, please consider becoming a backer of the Webform module's Open Collective.

Become a Backer

Almost done…

We just sent you an email. Please click the link in the email to confirm your subscription!

OKSubscriptions powered by Strikingly

Mar 18 2019
Mar 18

The opening talk as DrupalCamp Paris 2019 was a presentation given by Thomas Jolliet (FranceTV) and yours truly about how we rebuilt FranceTV Sport to a Symfony 4 / headless Drupal 8 combo.

The most salient points of the talk are probably the "defense in depth" mechanisms we built for scalability and fault tolerance, and the business results, like -85% full page load time or +50 iOS users.

Mar 18 2019
Mar 18

At Third & Grove, we believe that Drupal is the best technology for most projects (here are 15 things Drupal can do to beat or achieve parity with AEM), but there are three use cases where AEM is likely a better fit:

  1. Institutional investment in the Java programming language. If your organization has decided that Java is the only programming language you’ll use, then AEM is likely a better fit for you. Standardizing the programming language has many drawbacks, but just as many benefits. By focusing on one language, you have an elastic resource pool within your organization that will allow you to move engineers between projects as needed, a single hiring pipeline of Java talent to draw from, and, likely, Java contractors who are ready to be mercenaries no matter the theater of war.

  2. Campaign management. While Drupal can be used successfully in any campaign effort, AEM has superior support for robust, large-scale, complex campaigns. If your organization operates campaigns at high levels of complexity, AEM is likely a better choice than Drupal.

  3. Integration with other Adobe tools. If your organization has already invested in other Adobe technologies, you may find institutional approval for deploying AEM is easier than Drupal, despite Drupal’s established compatibility with Adobe’s toolset. As an example, Adobe has a great stock photo management tool that is part of their Creative Cloud. Not only does Adobe Stock integrate well with Creative Cloud, but as an Adobe product, it also integrates seamlessly with Adobe Experience Manager, a completely different product set than Creative Cloud.

Conversely, if time to market, cost, the value of open source, and security are priority concerns at your organization, Drupal is likely to be more successful than AEM.

Drupal’s robust open source ecosystem of free system extensions and generally less-complex technical footprint result in lower levels of effort, which decreases cost, improves time to market, and reduces overall risk. A combination of more people, with fewer conflicts of interest, working to improve the core Drupal software in a culture of security prioritization generally means Drupal is the more secure, better-supported platform.

Budget and ROI

The primary total cost of implementation between AEM and Drupal is largely impacted by three factors:

  1. Licensing fees

  2. General platform technical complexity

  3. The extension ecosystem

A typical enterprise Acquia Drupal project would usually have an implementation budget of $250,000-$350,000, while an AEM budget would start north of $500,000 (and that isn’t including the licensing fee you need to pay Adobe). When you add hosting, the first year total spend for an organization to redesign, build, and host an enterprise Acquia Drupal site is likely around $500,000 while in AEM you are looking at $750,000-$1 million.

AEM often describes Drupal’s open source status as free like a puppy—meaning Drupal is free, but it takes a terrific amount of work to build into a compelling digital platform. This is partly true, in that Drupal is more a content management framework (as opposed to a content management system), and can thus be adapted to address many use cases. But so is AEM.

Savings for picking Drupal over AEM come not just from a lack of licensing fees but also from Drupal’s open source community, which has promoted a far more extensive network of free extensions that add functionality to Drupal. AEM’s extension ecosystem is far smaller, and thus less impactful when it comes to accelerating website build efforts.

While AEM and Drupal have robust internal technical architectures that can scale to meet the digital demands of most organizations, the general consensus is that the “technical weight” of AEM is heavier, and thus builds are slower. At Third & Grove, we have seen this first-hand when working with a publicly-traded client with billions in revenue. We created a stir by migrating one of this company’s brand sites to Drupal in less than two months. The internal mandate from the global CTO was to use AEM, but the AEM team needed nine months for the migration we achieved in just six weeks.

Return on investment (ROI) is a different matter. Drupal’s generally smaller implementation budgets mean more value has to be derived from a comparable AEM site to achieve the same ROI. Out of the gate, Drupal has an unfair advantage. Still, the reality of digital technology investment is that when you are choosing between the two or three top platforms in any problem space (in this case, the digital experience space) the value you derive has little to do with the platform you choose and everything to do with how effective it is in helping achieve institutional goals. The reality of IT—that it is simultaneously as critical to the business’s success as it is irrelevant to the business strategy—is just as true for digital investments.

What Your Team Will Think

Your team’s opinion will depend largely on which platform you choose and, often most critically, their past experiences with the platform. One would hope that your team would embrace the platform that best serves the myriad needs of your organization, the overall strategy, IT goals, and marketing goals. However, the reality is that your team’s acceptance of the editorial experience of both platforms by is going to be driven mostly by factors unrelated to the platforms themselves. Instead, it’s more driven by past experiences, job frustrations, and a culture of blame (should one exist).

We’ve worked with many enterprise teams that leverage Acquia Drupal. Here’s what we’ve noticed from working with them:

  • Engineering. Your engineering team may complain about having to write PHP, which they may view as an inferior programming language. (See our article on misconceptions on Drupal for more information on why this assessment is based on years-old information.) If your engineering team already embraces open source solutions, they will be excited by all the open source components that make Drupal great. Moreover, an engineering team with a culture of learning will thrive in the developer-centric ecosystem that uniquely defines Drupal in the CMS space.

  • Marketing. Your marketing team might be anxious about the page-building experience. Older versions of Drupal offered an inferior page-building experience to AEM, which may be the source of this platform anxiety. We have watched many marketers become excited to use a platform with high developer velocity, because that, in turn, allows them to become agile marketers.

And here’s what you might expect if you adopt AEM:

  • Engineering. Your engineering team will probably be excited to use Java, an enterprise-grade programming language with a reputation for scale and stability that is used widely among large companies. But there are drawbacks that will hurt any engineer. The AEM platform requires technical debt to achieve scale and develop integrations. Not least, there is no AEM equivalent of Drupal’s open-source modules, which can elevate a digital experience—or at least remove the pain of resolving problems that have already been solved.

  • Marketing. If we had to guess, your marketing team would likely be impressed by AEM’s slick page-building experience and seamless integration with Adobe tools like Analytics. Even though they will have better resources they might be concerned about the reduced developer velocity in adding new features and making site changes. Agile marketing is the goal of every cutting-edge marketing team, and often a point of frustration as teams try to grow.

Organizations can reduce resistance by working to align the true needs of individual marketing team members to the goals of the marketing organization and the business overall. Both AEM and Drupal can be implemented to make your team feel like they are being set up for success—or failure; the deciding factor is effort.

Evaluation Chart for AEM vs. Drupal

To us, there are four main considerations in choosing AEM vs. Drupal: cost, time to market, cloud platform, and campaign management. We’ve outlined all considerations that we go through with our clients, which help identify an objective decision.


Adobe Experience Manager

Acquia Drupal



AEM requires a licensing fee and often higher implementation budgets than Drupal


Drupal is free to use and implementation budgets are generally lower

Time to market



Since implementation budgets are generally lower than AEM, time to market is generally faster

Fully managed outsourced cloud platform

+/- 0

Adobe now has a cloud platform for AEM, but the platform is just over a year old


Acquia is the enterprise cloud platform for Drupal and is more than ten years old, so their platform is mature, battle-tested, and feature rich

Campaign management


AEM leads for complex, robust campaign management needs

+/- 0

Drupal can power complex customer journeys, but support is not as seamless as it is for AEM. Acquia’s new Journey software is likely to improve support dramatically

Institutional investment in Java resources and the desire to stay within Java


+/- 0

Institutional investment in PHP resources and the desire to stay within PHP

+/- 0


Open source solutions are valued for their scalability, security, transparency, and community value

+/- 0

AEM is closed source and only Adobe employees can enhance the software


Drupal is open source, and benefits from thousands of developers in the community making the product better every day

Large, complex site with many integrations


AEM runs large, complex sites for major organizations like and


Drupal runs large, complex sites for major organizations like Wendy',, and FEMA

Integration with Adobe products like Creative Cloud, Adobe Analytics, Test & Target


AEM integrates well with its own marketing cloud products


Acquia Drupal can integrate with many of the Adobe tools, but nothing beats native integration

Asset management


AEM has slick support for asset management

+/- 0

Acquia Drupal has strong support for asset management, but AEM tends to be better executed out-of-the-box

Running multiple websites, large and small


AEM has strong support for running multiple websites


Acquia Drupal, especially using Acquia Site Factory, has strong support for running multiple websites

Custom reporting capabilities


AEM has many good reports available out-of-the-box


Acquia Drupal provides the powerful Views module (built into Drupal core) that allows non-technical users to use an intuitive GUI to make powerful custom reports for all kinds of data in the system

At the end of the day, it’s not about the best platform—it’s about the right tool for the job. Just make sure that the tool you pick will still be relevant for years to come, otherwise, you’re going to be kicking yourself down the road.

Mar 17 2019
Mar 17

Ryan Price, Principal Engineer, Drupal and Web with Autodesk joins Mike Anello to discuss the hurdles involved with implementing a continuous integration system, OpenDevShop, improving hook_help(), a Drupal 8 Feeds-like module, and DrupalCon Seattle!


DrupalEasy News

Upcoming events


  • Drupal Aid - Drupal support and maintenance services. Get unlimited support, monthly maintenance, and unlimited small jobs starting at $99/mo.
  • - devPanel.

Follow us on Twitter


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.

Mar 16 2019
Mar 16

Drush 9 has removed dynamic site aliases. Site aliases are hardcoded in YAML files rather than declared in PHP. Sadly, that means that many tricks you could do with the declaration of the site aliases are no longer available.

The only grouping possible is based on the YAML filename. So for example, with the Acquia Cloud Site Factory site aliases generated by the 'blt recipes:aliases:init:acquia' command, you can run a command on the same site across different environments.

But what you can't do is run a command on all the sites in one environment.

One use case for this is checking whether a module is enabled on any sites, so you know that it's safe to remove it from the codebase.

Currently, this is quite a laborious process, as 'drush pm-list' needs to be run for each site.

With environment aliases, this would be a one liner:

drush @hypothetical-env-alias pm-list | ag some_module

('ag' is the very useful silver searcher unix command, which is almost the same as the also excellent 'ack' but faster, and both are much better than grep.)

While site aliases are fixed, they can be altered with Drush hooks. I considered that these might allow something to dynamically declare aliases, or a command option. There's an example of altering aliases with a hook in the Drush code.

In the meantime, a much simpler solution is to use xargs, which I have recently found is extremely useful in all sorts of situations. Because this allows you to run one command multiple times with a set of parameters, all you need to do is pass it a list of site aliases. Fortunately, the 'drush sa' command has lots of formatting options, and one of them gives us just what we need, a list of aliases with one on each line:

drush sa --format=list 

That gives us all the aliases, and we probably don't want that. So here's where ag first comes in to play, as we can filter the list, for example, to only run on live sites (I'm using my ACSF aliases here as an example):

drush sa --format=list| ag 01live

Now we have a filtered list of aliases, and we can feed that into xargs:

drush sa --format=list| ag 01live | xargs -I % drush % pm-list

Normally, xargs puts the input parameter at the end of its command, but here we want it inserted just after the 'drush' command. The -I parameter allows us to specify a placeholder where the input parameter goes, so:

xargs -I % drush % pm-list

says that we want the site name to go where the '%' is, and means that that xargs will run:

drush SITE-ALIAS pm-list

with each value it receives, in this case, each site alias.

Another thing we will do with xargs is set the -t parameter, which outputs each actual command it executes on STDERR. That acts as a heading in the output, so we can clearly see which site is outputting what.

Finally, we can use ag a second time to filter the module list down to just the module we want to find out about:

drush sa --format=list | ag live | xargs -t -I % drush % pml | ag some_module 

The nice thing about the -t parameter is that as it's STDERR, it's not affected by the final pipe to ag for filtering output. So the output will consist of the drush command for the site, followed by the filtered output.

And hey presto.

In conclusion: dynamic site aliases in Drush were nice, but the maintainers removed them (as far as I can gather) because they were a mess to implement, and removing them vastly simplified things. Doing the equivalent with xargs took a bit of figuring out, but once you know how to do it, it's actually a much more powerful way to work with multiple sites at once.

Mar 16 2019
Mar 16

Planning to build a social network with Drupal? A business community maybe? A team or department collaborating on an intranet or portal? Or a network grouping multiple registered users that should be able to create and edit their own content and share their knowledge? What are those key Drupal 8 modules that would help you get started?

That would help you lay the groundwork...

And there are lots of social networking apps in Drupal core and powerful third-party modules that you could leverage, but first you need to set up your essential kit.

To give you a hand with that, we've selected:

5 modules in Drupal 8, plus a Drupal distribution, that you'll need to start a perfectly functional social networking website, with all the must-have content management features and knowledge sharing tools.

Before You Get Started: A Few Things to Take Care Of

First of all, let me guess the features on your must-have list:

  • articles
  • groups
  • photos
  • user profiles
  • groups
  • forums

It should feature pages with dynamic content leveraging a fine-grained access system and social media hubs, right?

Well, now that we've agreed on this, here are the preliminary steps to take before you get actually started, installing your key modules and so on:

  • configure your “Taxonomy” categories after you've installed the Forum module
  • set up a custom content type for Blog posts 
  • set up your thumbnail settings for the Article nodes
  • create your key user roles (admin, content author, paid subscriptions)
  • use the PathAuto module to define your URL path structure
  • define your Article nodes' thumbnail settings and remember to upload an anchor image, as well

Panels and Views make a “power team” to rely on for setting up pages with dynamic content for your social networking site.

What makes it a must-have module to add to your essential kit when you build a social network with Drupal? 

It enables you to create custom layouts for multiple uses.

You get to use it to set up your website's homepage, one featuring multiple Views blocks with dynamic content retrieved from forums, articles, blogs...

Feel free to add a top slideshow image, to go for multiple-tiled stacked layout, including views from forum, blog and article posts...

In short: the Panels module empowers you to get as creative as possible when setting up fine-tuned layouts for your landing pages displaying dynamic content.

Not only that it enables you to present content to your social network's registered users in pretty much any form you might think of — tables, lists, blocks, forum posts, galleries, reports, graphs — but it also:

  • enables you to display related content (e.g. display a list of the community members along with their pieces of content)
  • enables you to use contextual filters

It'll turn out to be one of the handiest Drupal 8 modules in your toolbox when you need to create and display dynamic content from:

  • forums
  • blocks
  • blogs

Yet, maybe one of the most common use cases for the Views module on a social networking website is that of:

Setting up a (Views) page listing all the article posts.

Another module you'll most certainly want to add to your social networking website as it:

  • enables both single and multi-user blogs
  • empowers authorized site members to maintain it

Speaking of which, blog entries can be either public or private for a specific user, depending on the role he/she's assigned with.

And it's precisely that system of user roles and corresponding permissions set up on your website that will determine whether a member can:

  • access the “Create Content” link or not
  • access a “My Blog” section or... not

You can further leverage this Blog module to add a “Recent blog posts” block to your webpages, in addition to the “Blogs” navigation link on your main navigation menu.

4. Profile, a Must-Have Module to Build a Social Network with Drupal

You just imagine that you could build a social network with Drupal without a module enabling you to create registration page fields, now can you?

Well, here it is: the Profile module.

And here are its “superpowers”:

  • it enables configurable user profiles
  • it enables expanded fields on the user registration page
  • it provides social network members with two different links, one for their account settings, one for their user profiles
  • it provides private profile fields (that only the admin and that specific user can access)
  • it enables you to set up different profile types for different user roles with... different permissions granted 

The sky is the limit in terms of what the Group module enables you to do when you build a social network with Drupal:

  • it powers pretty much any scenario you can think of, from subgroups to specific per-group behavior, to access permissions...
  • it enables you to put together content collections on your website and grant access to it based on your user roles and permissions policy
  • it enables you to easily add relevant metadata to define the group & content relationships on your site
  • it enables you to control all your settings via a user-friendly admin UI; no need to write custom code to determine what each group is allowed and not allowed to do on your social network

I just couldn't help it...

Even though this was supposed to be a roundup of those essential modules you'll need to build a social network with Drupal, I had to add this Drupal distribution, as well.

Open Social is that out-of-the-box solution that you can leverage to get your online user community up and running in no time.

An open source software with all the needed features and functionality already pre-built, so that you can enable members on your network to:

  • work together
  • share knowledge
  • organize events

Convenience at its best when you want to start a social networking website without worrying much about:

  • installing a whole collection of modules
  • doing custom work in the “backstage”. 

The END!

This is the minimal kit you'll need to build your online community website with Drupal.

Would you have added other essential modules to the list?

Mar 15 2019
Mar 15

The business world is competitive by nature. An organization’s intellectual property and the custom software that costs valuable time and money to develop is an incredibly prized possession - one that’s important to protect. That’s why the idea of procuring an open source solution (free software that can be used by anyone) can be such a foreign and challenging concept for many in the business world.

In this article, we’ll walk through some of the most common questions that clients have about procuring open source software, so that you’ll understand how this software is licensed, what you can and can't do with it, and hopefully help you make an informed decision about procuring and extending open source software services.

How does open source licensing work, exactly?

Open source software turns the traditional software licensing model on its head by allowing users to modify and freely redistribute software. Open source is defined by criteria intended to promote and protect software freedom, and support the communities which contribute to the success of open source projects.

Are there any laws that prevent someone from making changes to the software and repackaging the entire thing for sale?

Many open source projects are able to survive and thrive because there are protections in place that prevent someone from turning the project into something proprietary. Drupal and many other open source projects are covered under the GNU Public License or GPL, one of the most common open source licenses. The GPL prevents anyone from distributing the software that it covers without also sharing its source code. This ensures that the project covered by the GPL remains open source.

Does this mean that if I pay a contractor for custom code to be developed that adds to an existing GPL-covered open source project, I’ll be required to release that work to the public for free?

The short answer is simply “no”. If you work on or pay for someone to work on custom code that modifies a GPL-covered open source project, you won’t be required to give that work away to the community at large.

The GPL only requires that you release your source code if you plan to sell or release (“distribute”) your custom code. If you’re just planning to use the code internally, or as part of a hosted solution that you control, there’s no need to share it with the world.

But shouldn’t I share the code? Isn’t that how open source works?

Many users of open source software do decide to share their source code with the world through contributions to the open source project in question, such as a contributed module in Drupal. There is no requirement to do this, but there are some advantages.

Source code is the actual text document that a software developer creates. It’s uncompiled, meaning that it’s written in programming language that can be read and edited by a human. The reason that distinction is important here is that source code is raw and can be inspected and modified. This practice helps improve both the security and the usability of the software.

By sharing your source code, other people may decide to improve on it and fix it for free, because it’s mutually beneficial. It’s much harder to staff a team of internal developers to keep your code tested, maintained, and bug-free while planning an improvement roadmap to add new features and create new software integrations. Having others work on your code means it is made better both for you and for them. Sometimes the advantage of having software that works really well and has updates and features added more quickly outweighs the advantage of keeping your innovation secret from your competitors.

Curious if open source software is right for your business? Read our post on how you can save money using open source technologies.

Mar 15 2019
Mar 15

Keynote: Learning @ Work

Join Palantir's CEO, Tiffany Farriss, for the keynote at this year's DrupalCorn Camp. With tech still struggling to achieve its diversity and inclusion goals and average job tenure down to less than 3 years, we need to transform how we think about our organizational cultures.

How do we create environments that succeed because of the teams, but where that success is not dependent on any one person? How do we align the company and individual interests so that everyone benefits from however much time that they work together? This presentation explores the role that culture and learning have for organizations and individuals as they work to answering those questions.

  • Date: Friday, September 28, 2018
  • Time: 9:00am
  • Location: Gym - lecture room 2nd floor

Update: Recording of this session is now available on

Mar 15 2019
Mar 15

With the announcement that the Google Search Appliance was End of Life, many universities started looking around for replacement options. At Palantir, we wanted to provide an open source option that could solve the following needs:

  • A simple way to store, retrieve, and parse content.
  • A cross-platform search application.
  • A speedy, usable, responsive front-end.
  • A flexible, extensible, reusable model.
  • A drop-in replacement for deprecated Google Products

Working with the University of Michigan, we architected and developed a solution. Join Ken Rickard to learn more about Federated Search and to see a live demo.

  • Date: Saturday, February 16
  • Time: 11:00am to 11:45am
  • Location: Room 179 

Update: Video of this session is now available on

Mar 15 2019
Mar 15

A lot of effort goes into engaging your visitors to ‘Sign-up’ or ‘Contact’ you. You send them a warm and fuzzy invitation to complete the form, tell them all the great reasons why they should complete the form… but who likes to complete a form?  Guarantee a smooth sign-up process and increase the completion rate of your webforms with these six tips. 

#1 Make it Flow

Before you begin designing that web form, it is always good to create a User Flowchart. Working to establish the form completion process from start to finish, a flowchart will help you: 

  • Determine what information is needed (and when)
  • Decide what actions and interactions are appropriate
  • Determine the order of actions
  • Make considerations for new patterns to aid the completion process

A User Flowchart can begin with a simple Flow Outline, which can then be placed in a flowchart diagram and later illustrated using low fidelity paper prototypes to find the most natural set of actions. When creating the outline consider the following:

The Business Objective

  • What is the main objective of the website for achieving successful completion of the form? (ie, we want to gather as many email addresses as possible.)
  • What is the required information needed from the person completing the form? (ie, we need their name and email, and since our site is only for adults we also need their birth date.)

The User Persona

  • Take advantage of the information gained from the User Personas to focus on the user’s various needs and considerations. What problem do they want to solve and how can this form help them?

  • What devices do they access most frequently to complete webforms? It’s good to know in advance if most of the users complete forms on their mobile phones and/or if they have inferior internet connectivity.

The Entry Point

When designing a User Flowchart, keep in mind the point of entry. Perhaps they arrive after clicking the Call to Action on the homepage. Often webforms are a part of an email or social media campaign, or the user arrives at the form after an organic search. The users should be treated differently based on where they come from, and may need extra context to reiterate the goal of the form to help them get orientated when they arrive. Consider all possibilities.

#2 Keep it Short and Sweet

Don’t ask for information that’s not needed. Your subscription or contact form — or any form that gathers basic information — should only ask for the bare necessities needed in order to accomplish that goal. People will usually stick around long enough to enter their name, email address and password. Anything more than that should be the absolute minimum amount of information needed, with further data obtained in follow-up communications or by implementing a multi-step form (see tip #3). No one enjoys completing a form, so keep it as simple as possible! Neil Patel found that three form fields was the optimal number.  Pegasystems, a Mediacurrent client, leveraged third-party integrations on their Drupal 8 site to pre-fill form fields with data and improved the user experience for returning visitors. 

Reducing the number of form fields can increase conversion rates by 26 percent. 

Email Address

  • Forward thinking email form fields provide suggestions for fixes when the email address has been entered incorrectly. … Did you mean
  • If you include an auto fix for mistyped email addresses you won’t need to require the user to enter it twice. Otherwise, it’s is a good approach to provide the extra guarantee that they’ve got it right.
  • When the form is for creating an account or signing up for a newsletter, a current practice is to use the email address for the account instead of providing a separate username. This will cause less frustration with creating one that is not already in use, as well as remembering it every time they login.


The person’s name is really only needed in instances where account personalization or custom communication is used. A frequent approach is to provide one field for their full name. This is a bonus since some users may have more than two words that make up their full name, and one field takes less time to complete (especially on mobile devices). Check first to see if the system requires the first name to be isolated for marketing purposes.


  • Enough with the 'confirm password' already! They will lower your conversion rates. Give the user the option to actually SEE the password they’re entering with a ‘show password’ toggle, and they won’t have to enter it twice.
  • Include a Password Strength Indicator. You can get creative with messaging to encourage users to try harder when creating a more secure password like Geeklist does: “Crack Time: 5 minutes”
  • Depending on the level of site security, another time-saving feature is the ability to never have to enter their password again with the ‘Remember Me’ feature.

#3 Multi-step Forms

Single step forms are the most common type of form found on a website. Sometimes, however, using the minimum amount of fields will not accomplish the goal of capturing essential user data. Instead of simply adding more fields to your one-page form you should be aware of an important point: 

Multi-step forms have been found to increase conversions by as much as 300% (without increasing website traffic). 

Multi-step forms convert well for several reasons:


Through the use of progressive disclosure design techniques, we can improve usability when only the minimum data required for a task is presented to the user. Multi-step forms provide the ability to break up a longer form into manageable steps so the user is not visually overwhelmed with requirements at the beginning or during the process. By including only one or two questions per step with a manageable number of steps overall will improve the user experience and significantly increase the chance they will complete it. 

Reduced Psychological Friction

Multi-steps with a simplified interface allow opportunity to use low-friction language in order to reduce psychological friction. In order to encourage the user to become immersed with an energized focus on the activity, we must always seek to minimize disruptions and use language that puts them in a positive state of mind. 


Progress bars encourage form completion. The most common use of visual progress trackers are when conducting an online purchase since those are often broken into a multiple step process. It answers the questions the user may have during completion:

  •  How long will the form take?
  • What comes next?
  • Is anything happening?

Displaying the steps required to complete the form along with where the user currently is at in the process will help manage their expectations and keep them oriented throughout.


By using the approach of requesting general information at the beginning of the form and moving towards more sensitive information requests towards the end of the form, the user feels more invested and is therefore more likely to complete.

Conditional Logic

Longer forms will sometimes benefit by using conditional logic in order to personalize the experience. The user is provided with specific questions based on certain responses therefore eliminating irrelevant information retrieval while simultaneously obtaining more targeted data. Save them valuable time and customize their experience, and they will likely reward you by clicking the submit button.

#4 Make it Easy to Read

Including the labels and inputs, consider the context being used for all text on the page and work to ensure your font sizes are large enough to be legible on all devices. The amount of content on the page should be considered while also using best practices for accessibility. 

  • Recent trends are a 14px font size at minimum.
  • When specifying a 16px font size for mobile devices, iOS will not zoom in when the user taps the field, because it’s not needed. This approach can be less distracting especially when there are multiple form fields on the page.
  • Consider the maximum amount of characters that will be needed in all cases to ensure enough room is provided to complete each field. For example, some zip codes in other countries use a varying number of digits.

#5 Inform Everything

Label All Things

The label of the form field you want the user to complete should ALWAYS remain visible. The labels can be placed outside of the field near the top, right, or left — or even better — use the Infield Top Aligned Label. This popular approach has been found to be the quickest to scan, has the best flow, and takes up less real estate. The labels are placed inside of the field, jumping to the top left corner as the user begins typing. Either way, at no point should the user lose sight of the information that’s needed inside of the field.

Inline Form Validation

  • Inform the user as they progress if anything has been entered incorrectly or if a field is missing information. Don’t make them click the ‘Submit’ button at the end of the form only to receive a bunch of red text telling them what they have to re-do.
  • Micro interactions such as a simple green check or a red ‘X’ along with a brief message as the user completes the form will improve the workflow.
  • Tell them if their CAPS LOCK IS ON.

Required or Optional?

Inform the user which fields are required and which are optional for the form to be accepted. An asterisk is often used to designate required information, but they are ignored by screen readers so make sure the required fields include the HTML5 ‘required’ attribute or the aria-required set to true.

Field Details

Explaining the information needed for each field is another great approach. If your Registration Sign-up Form will require a password with at least 6 unique characters with 2 of them numbers, tell them! Does the phone number field require a +, or a country code, or an area code? Tell them or show them.

Progress Bar

  • A form that’s broken into logical steps is easier to complete. If there are multiple steps that require multiple screens to complete, add a progress bar so the user knows where they are in the process.
  • If possible, add a link to the completed steps in the progress bar so the user can go back if needed.


  • Make your users feel safe during sign-up by informing them about your terms, policies, or rules.
  • Ensure them you will not share their information or spam their email.
  • Provide an easy way to cancel or opt out at any time, without much effort.

#6 Must be Mobile

While optimizing your site for mobile devices, any forms on your site should also be carefully considered. Not only are the screens smaller, but often the connections are slower, and entering text can be a bit tricky, so reducing the number of required fields is especially important. Luckily, recent innovation for mobile forms have provided modern solutions and compression techniques that could actually encourage sign-up on a mobile device:

Predefined DropDowns

  • Whenever possible, avoid open input fields and provide a dropdown list instead for easier completion.
  • Dropdown selections should be written as they would normally display (ie, Credit Card expiry date: 01/20).

Collapsible Menus

This really helps when multiple offerings are available with details for each.

Predictive Search Fields

As the user begins typing the keyword, a list of possible results is provided. 

Calendar Tools

Choose a calendar that is easy to use, with big targets that help to avoid user input errors

Combine Inputs When Possible

Providing only one field for a ‘Full Name’ instead of one for ‘First Name’ and one for ‘Last Name’ will speed up the form completion process and reduce user frustration. 

Automatic Advance

The system should recognize when a date or email has been entered and take the user to the next field automatically, whenever possible.

Buttons That Engage

  • The ‘submit’ button should use a strong command verb that provokes emotion or enthusiasm, such as ‘Sign-Up Now!’
  • Use bright, engaging (and accessible) color combinations. Color changes on tap add even more visual information about the progress.
  • Ensure the tap target is large enough for users with big fingers or who have difficulty being accurate. Apple's iPhone Human Interface Guidelines recommends a minimum target size of 44 pixels wide 44 pixels tall.

Final Word

Achieving a smart form design isn't always easy, but it's well worth the effort. 

What are some great examples of forms you've seen? 

Editor’s note: This post was originally published on November 14, 2016, and has been updated for accuracy and comprehensiveness.

Mar 15 2019
Mar 15

In this post we’ll see how to save temporary values from a form and how to retrieve or process them later in a controller. To do that, we’ll use the Form API and the private tempstore (the temporary store storage system of Drupal 8).

The use case is the following: we need to build a simple RSS reader (a form) where the user could introduce the URL of an RSS file and the number of items to retrieve from that file.  Next, in a new page (a controller), the application should display the list of items with a link to each syndicated page .

The easiest way to achieve it would be to retrieve the values in our buildForm() method, process them and display the result thought a specific field of the form. But that’s not our use case.

To process the form’s values and to display the results in another page, we’ll first need to store the form's values and retrieve them later in a controller. But how and where to store and retrieve those values?

Long story short: Store and retrieve data with the Private Tempstore System of Drupal 8

Drupal 8 has a powerful key/value system to temporarily store user-specific data and to keep them available between multiple requests even if the user is not logged in. This is the Private Tempstore system.

// 1. Get the private tempstore factory, inject this in your form, controller or service.
$tempstore = \Drupal::service('tempstore.private');
// Get the store collection. 
$store = $tempstore->get('my_module_collection');
// Set the key/value pair.
$store->set('key_name', $value);

// 2. Get the value somewhere else in the app.
$tempstore = \Drupal::service('tempstore.private');
// Get the store collection. 
$store = $tempstore->get('my_module_collection');
// Get the key/value pair.
$value = $store->get('key_name');

// Delete the entry. Not mandatory since the data will be removed after a week.

Fairly simple, isn't it? As you can see, the Private Tempstore is a simple key/value pair storage organized with collections (we usually give the name of our module to the collection) to maintain data available temporarily across multiple page requests for a specific user.

Now, that you have the recipe, we can go back to our use case where we are now going to figure out, how and where we could store and retrieve the values of our form.

Long story: Illustrate the Private Tempstore system in Drupal 8

For the long story part, we are going to create a module with a form and a controller to first get the data form the user, store the form’s data in a private tempstore and redirect the form to a controller where we’ll retrieve the data from the tempstore and process them.

This is the form.


And this is the controller.


You can find and download the code of this companion module here.

Types of data storage in Drupal 8

In Drupal 8 we have various APIs for data storage:

Database API  - To interact directly with the database.
State API - A key/value storage to store data related to the state or individual environment (dev., staging, production) of a Drupal installation, like external API keys or the last time cron was run.
UserData API - A storage to store data related to an individual environment but specific to a given user, like a flag or some user preferences.
TempStore API - A key/value storage to keep temporary data (private o shared) across several page requests.
Entity API - Used to store content (node, user, comment …) or configuration (views, roles, …) data.
TypedData API - A low level API to create and describe data in a consistent way.    

Our use case refers to user-specific data we need for a short period of time, data that is also not specific to one environment, so the best fit is certainly the TempStore API but in its private flavour because the data and the results are different for each user.

The only difference between private and shared tempstore is that the private tempstore entries strictly belong to a single user whereas with shared tempstore, the entries can be shared between several users.

Storing the form's values with the Private TempStore storage

Our goal is to build a form where user can introduce an RSS file URL and a number of items to retrieve from that file, next we need to store temporarily those values to retrieve them later in a controller.

Let’s now take a closer look at how we could store (or save) our form’s values. As we get the data (url and items to retrieve) from a form, it’s clear that we are going to store the data in the submitForm() method since this method is called when the form is validated and submitted.

Here is the code of our form.


namespace Drupal\ex_form_values\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
// DI.
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;

 * Class WithControllerForm.
 * Get the url of a RSS file and the number of items to retrieve
 * from this file.
 * Store those two fields (url and items) to a PrivateTempStore object
 * to use them in a controller for processing and displaying
 * the information of the RSS file.
class WithStoreForm extends FormBase {

   * Drupal\Core\Messenger\MessengerInterface definition.
   * @var \Drupal\Core\Messenger\MessengerInterface
  protected $messenger;
   * Drupal\Core\Logger\LoggerChannelFactoryInterface definition.
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
  protected $loggerFactory;

   * Drupal\Core\Cache\CacheTagsInvalidatorInterface definition.
   * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
  private $cacheTagsInvalidator;

   * Drupal\Core\TempStore\PrivateTempStoreFactory definition.
   * @var \Drupal\Core\TempStore\PrivateTempStoreFactory
  private $tempStoreFactory;

   * Constructs a new WithControllerForm object.
  public function __construct(
    MessengerInterface $messenger,
    LoggerChannelFactoryInterface $logger_factory,
    CacheTagsInvalidatorInterface $cacheTagsInvalidator,
    PrivateTempStoreFactory $tempStoreFactory
  ) {
    $this->messenger = $messenger;
    $this->loggerFactory = $logger_factory;
    $this->cacheTagsInvalidator = $cacheTagsInvalidator;
    $this->tempStoreFactory = $tempStoreFactory;

   * {@inheritdoc}
  public static function create(ContainerInterface $container) {
    return new static(

   * {@inheritdoc}
  public function getFormId() {
    return 'with_state_form';

   * {@inheritdoc}
  public function buildForm(array $form, FormStateInterface $form_state) {

    $form['url'] = [
      '#type' => 'url',
      '#title' => $this->t('Url'),
      '#description' => $this->t('Enter the url of the RSS file'),
      '#default_value' => '',
      '#weight' => '0',

    $form['items'] = [
      '#type' => 'select',
      '#title' => $this->t('# of items'),
      '#description' => $this->t('Enter the number of items to retrieve'),
      '#options' => [
        '5' => $this->t('5'),
        '10' => $this->t('10'),
        '15' => $this->t('15'),
      '#default_value' => 5,
      '#weight' => '0',

    $form['actions'] = [
      '#type' => 'actions',
      '#weight' => '0',

    // Add a submit button that handles the submission of the form.
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),

    return $form;

   * Submit the form and redirect to a controller.
   * 1. Invalidate the cache of the render array of the target controller
   * 2. Save the values of the form into the $params array
   * 3. Create a PrivateTempStore object
   * 4. Store the $params array in the PrivateTempStore object
   * 5. Redirect to the controller for processing.
   * {@inheritdoc}
  public function submitForm(array &$form, FormStateInterface $form_state) {

    // 1. Invalidate the cache of the render array of the controller
    // for anonymous users.

    // 2. Set the $params array with the values of the form
    // to save those values in the store.
    $params['url'] = $form_state->getValue('url');
    $params['items'] = $form_state->getValue('items');

    // 3. Create a PrivateTempStore object with the collection 'ex_form_values'.
    $tempstore = $this->tempStoreFactory->get('ex_form_values');

    // 4. Store the $params array with the key 'params'.
    try {
      $tempstore->set('params', $params);
      // 5. Redirect to the simple controller.
    catch (\Exception $error) {
      // Store this error in the log.
      $this->loggerFactory->get('ex_form_values')->alert(t('@err', ['@err' => $error]));
      // Show the user a message.
      $this->messenger->addWarning(t('Unable to proceed, please try again.'));


In the submitForm() method we can see two lines where we deal with the private tempstore in step 3 and 4.

$tempstore = $this->tempStoreFactory->get('ex_form_values');
$tempstore->set('params', $params);

In the first line we call the PrivateTempStoreFactory to instantiate a new PrivateTempStore object trough its get() method. As you can see, we get the factory by DI. We also define the name of our collection (ex_form_values) with the same name as our module (by convention) and pass it to the get() method. So, at this time we created a new PrivateTempStore object for a collection named "ex_form_values".

In the second line we use the set() method of the PrivateTempStore object which will store the key/value pair we need to save, in our case, the key is 'params' and the value is the $params array that contains our form’s values.

The PrivateTempStoreFactory uses a storage based on the KeyValueStoreExpirableInterface, this storage is a key/value storage with an expiration date that allows automatic removal of old entities and this storage uses the default DatabaseStorageExpirable storage to save the entries in the key_value_expire table.

Here is the structure of this table:


The PrivateTempStore object has the following protected properties, all passed to the form by DI:
$storage - The key/value storage object used for this data.
$lockBackend - The lock object used for this data.
$currentUser - The current user who owned the data. If he's anonymous, the session ID will be used.
$requestStack - Service to start a session for anonymous user
$expire - The time to live for the entry in seconds. By default, entries are stored for one week (604800 seconds) before expiring as defined in the KeyValueStoreExpirableInterface.

We can’t set any of those values, they are all set by the KeyValueStoreExpirableInterface when we instantiate the new PrivateTempStore object.

The PrivateTempStore object method we are interested at this time is the set() method which will store the key/value we need to save, in our case, the key is 'params' and the value is the $params array that contains our form’s values. You can find the code of this method here and below, the beginning of this method:

public function set($key, $value) {

  // Ensure that an anonymous user has a session created for them, as
  // otherwise subsequent page loads will not be able to retrieve their
  // tempstore data.
  if ($this->currentUser
    ->isAnonymous()) {

    // @todo when is resolved, use force
    //   start session API rather than setting an arbitrary value directly.
      ->set('core.tempstore.private', TRUE);
  // ....

As you can see at the beginning of this method, we ensure that an anonymous user has a session created for him, thanks to this, we can also retrieve a session ID that we will use to identify him. If it’s an authenticated user, we will use his UID. You can confirm that in the getOwner() method of the PrivateTempStore object.

When we submit the form, thanks to these two lines, we’ll save the form's values in the database. If you look at the key_value_expire table, you can see that there are other records, most of them with update information of our app., but also new records with the collection value of tempstore.private.ex_form_values. Here is a query on this collection when an anonymous and the admin user use the form.


We didn’t output the column 'value' because it’s too large. But you can see now how our form's values are stored in the database and particularly for anonymous users with their session ID.

At this time, we know how to store temporarily the values of a form in the privatetempstore of Drupal. This was not so hard, wasn’t it? Yes, Drupal is a great framework and it saves us a lot of time when developing a web application.

Now let’s see how to retrieve and process the values in a controller.

Retrieve our form's values from the privatetempstore

To retrieve the data, process them and display the results, we’ll need to redirect our form to a controller. Here is the code of this controller.

namespace Drupal\ex_form_values\Controller;
use Drupal\Core\Controller\ControllerBase;
// DI.
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\ex_form_values\MyServices;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use GuzzleHttp\ClientInterface;
// Other.
use Drupal\Core\Url;
 * Target controller of the WithStoreForm.php .
class SimpleController extends ControllerBase {
   * Tempstore service.
   * @var \Drupal\Core\TempStore\PrivateTempStoreFactory
  protected $tempStoreFactory;
   * GuzzleHttp\ClientInterface definition.
   * @var \GuzzleHttp\ClientInterface
  protected $clientRequest;
   * Messenger service.
   * @var \\Drupal\Core\Messenger\MessengerInterface
  protected $messenger;
   * Custom service.
   * @var \Drupal\ex_form_values\MyServices
  private $myServices;
   * Inject services.
  public function __construct(PrivateTempStoreFactory $tempStoreFactory,
                              ClientInterface $clientRequest,
                              MessengerInterface $messenger,
                              MyServices $myServices) {
    $this->tempStoreFactory = $tempStoreFactory;
    $this->clientRequest = $clientRequest;
    $this->messenger = $messenger;
    $this->myServices = $myServices;
   * {@inheritdoc}
  public static function create(ContainerInterface $container) {
    return new static(
   * Target method of the the WithStoreForm.php.
   * 1. Get the parameters from the tempstore for this user
   * 2. Delete the PrivateTempStore data from the database (not mandatory)
   * 3. Display a simple message with the data retrieved from the tempstore
   * 4. Get the items from the rss file in a renderable array
   * 5. Create a link back to the form
   * 6. Render the array.
   * @return array
   *   An render array.
  public function showRssItems() {
    // 1. Get the parameters from the tempstore.
    $tempstore = $this->tempStoreFactory->get('ex_form_values');
    $params = $tempstore->get('params');
    $url = $params['url'];
    $items = $params['items'];
    // 2. We can now delete the data in the temp storage
    // Its not mandatory since the record in the key_value_expire table
    // will expire normally in a week.
    // We comment this task for the moment, so we can see the values
    // stored in the key_value_expire table.
    try {
    catch (\Exception $error) {
      $this->loggerFactory->get('ex_form_values')->alert(t('@err',['@err' => $error]));
    // 3. Display a simple message with the data retrieved from the tempstore
    // Set a cache tag, so when an anonymous user enter in the form
    // we can invalidate this cache.
    $build[]['message'] = [
      '#type' => 'markup',
      '#markup' => t("Url: @url - Items: @items", ['@url' => $url, '@items' => $items]),
      '#cache' => [
        'tags' => [
    // 4. Get the items from the rss file in a renderable array.
    if ($articles = $this->myServices->getItemFromRss($url, $items)) {
      // Create a render array with the results.
      $build[]['data_table'] = $this->myServices->buildTheRender($articles);
    // 5. Create a link back to the form.
    $build[]['back'] = [
      '#type' => 'link',
      '#title' => 'Back to the form',
      '#url' => URL::fromRoute('ex_form_values.with_store_form'),
    // 6. Render the array.
    return $build;

First we inject all the services we need and also a custom service MyServices.php used to retrieve the RSS file and the required number of items.

This controller has a simple method called showRssItems(). This method performs six tasks:

1. Get the data we need from the PrivateTempstore
2. Delete the PrivateTempStore data from the database (not mandatory)
3. Display a simple message with the data retrieved from the tempstore
4. Get the items from the rss file in a render array
5. Create a link back to the form
6. Render the array.

The tasks that interest us are the first and the second one, where we deal with the tempstore.

$tempstore = $this->tempStoreFactory->get('ex_form_values');

This line is now straightforward for us, since we know that the get() method of the PrivateTempStoreFactory instantiate a new PrivateTempStore object for the collection 'ex_form_values'. Nothing new here.

$params = $tempstore->get('params');

In the line above, we just retrieve the value of the key 'params' from the storage collection into the variable $params. Remember that we are using the privatetempstorage, as we retrieve the value, we’ll also check if it's the same user with the getOwner() method of the PrivateTempStore object.

The second task is deleting the data from the tempstore, this is not mandatory since we are working with a temporary store where the data will be deleted automatically after a week by default. But if we expect a heavy use of our form, it could be a good idea since we won’t normally need the data anymore.

try {
catch (\Exception $error) {
  $this->loggerFactory->get('ex_form_values')->alert(t('@err',['@err' => $error]));

As the delete() method of our privatetempstore object can trow an error, we’ll catch it in a 'try catch' block. For learning purpose I’ll suggest to comment those lines to see how the data are stored in the key_value_expire table.

The rest of the controller is pretty straightforward, we are going to pass the data to small methods of our custom service to retrieve the RSS file and the number of items we need, build a render array with the results as you can see in task number four. Next, we’ll create a simple link back to our form and render the entire array. Nothing strange here.


We wanted, trough a form, to get a RSS file URL, the number of items to retrieve from, and display this information in a controller. To do so, we needed to store the information of the form, retrieve it and process it later in a controller.

We decided to use the Private TempSore system of Drupal because:
- The information doesn’t belong to a specific environment or a particular state of our application (see State API for that case)
- The information is not specific to a user and doesn’t need to be stored with its profile (see UserData API for that case). On the other hand, anonymous users should also have access and use the form
- We need the information temporarily, for a short period of time
- It has to be private because the information belongs to each user (anonymous or authenticated)

To store the data, we used the submit() method of our form and the following lines:

$tempstore = $this->tempStoreFactory->get('ex_form_values') - to instantiate a new PrivateTempStore object with a collection name 'ex_form_values' that refers to our module in this case.

$tempstore->set('params', $params) - to save the value of the variable $params in the database with the key 'params'. Remember that as we use a private storage, Drupal will retrieve the user ID or its session ID if anonymous, and concatenate it with the key value in the 'name' row of the 'key_value_expire' table.

To retrieve the information in our controller’s showRssItems() method, we used the following code:

$tempstore = $this->tempStoreFactory->get('ex_form_values') - to instantiate a new PrivateTempStore object with a collection name 'ex_form_values' that refers to our module in this case.

$params = $tempstore->get('params') - to retrieve the value stored in the keyed 'params' record of this collection and for this particular user.

Yes! Once again, through this simple example, we can see how powerful Drupal is, and how its framework is easy to use.

And you? In which situation do you think we could use the privatetempstore? Please, share your ideas with the community.

Mar 15 2019
Mar 15

Adam stood in the middle of the garden, enveloped in exquisite beauty. The world was there to delight him, succulent fruit, dignified trees, green meadows, sprinkling pool and species of all kinds. Yet he stood contemplating the nature, he felt certain loneliness and thus the Lord said 

It is not good that man is alone. I shall make him a compatible helper.

With the creation of other species, both male and female sprang up the same time. If the beginning of the entire universe was chosen to be this way, how can business be any good without clients and a strong relationship with them, Right? 

 Image of two hands where the upper one is offering an apple to the lower one

The productivity and enduring relationship not only provides value to clients that are consistent but also constructs a healthy connection in every business venture. 

Though there are times when you get stuck in a rut with clients and the relationship starts to rot. 

So, how do you change it? 

Maybe with some strategies or maybe with the help of some plan. Well, whatever it may be here are some of the approaches which you can adapt to sweet up that sour relationship and add more productivity to a particular project.  

But how can perfect client relationship get ruined?

Under perfect circumstances, organizations and big enterprises treat their clients right. However, there might be times when they are under pressure to sell more or retain those paying customers, chances are that they might deviate from their standards. Resulting in sorrowful client satisfaction. 

With this context here are some of the actions which can kill a perfect build client relationship:

Saying yes to a client when you should not 

There is no shame in accepting the fact that your organization can meet only a level of expectations and not beyond it. Taking up those clients who are not a good match is foolishness.  If a particular organization knows that they going to hate dealing with a client or they might fail to meet their quality standards, the money is not worth the inevitable breakdown.  


When there is a wide gap between expectations and reality - it results in disappointment. If you are selling software or a product for that matter, don’t promise the integration which will take a week or so and won’t work perfectly. Give those commitments that you know are humanly and technically feasible. Overpromising results in fears. 

Not addressing the key details 

When you are serving a client, it is necessary to include each and every detail about the project. You leaving details out by omission is one thing. If you leave out details intentionally, you will screw up relationships. Thus, address to each and every key detail. 

Being unauthentic 

If you are focusing only on yourself, what works for you and whatever you do then spending your time considering what's best for your team, company, or business partnership is a waste. Adopt an all-or-nothing attitude, acting however is needed to win favor, seal a deal, or make a sale, even if it means lying or misrepresenting your position is a call for a sour relationship. 

Image showing a handset in red color with text as “The Customer”. There are arrows that are connected to it and many doodles depicting important factors

Taking These Few Important Steps for an Enduring Relationship 

We all know that a huge amount of time and effort is employed on acquiring clients, yet very few businesses spend the same energy nurturing the relationship. Here are some of the tips that would help you endure your client relationship.  

Communication is the key 

Clients depend on you to keep them informed. Having constant communication with them should be the top priorities. This includes updating them on various projects, as well as making them understand about any kind of bumps that you may encounter in the product delivering journey.

Information distribution

Don’t delay to share knowledge that might be useful to the clients, whether or not it benefits your organization in a way. The more value you present, the more a client attains to depend on you. There should not be a hesitation to share important and crucial data. 


If you are not honest to your client and vice-versa, no long term relationship survives. In addition to producing a product or service, your client requires you to show a chief responsibility towards all the dealings. Nowadays clients are really intelligent, they understand when they are being deceived or misled. Speaking a “ white lie” about why you failed can ruin your reputation. And without a reputation in terms of integrity, you can fail to cultivate the kind of long-term relationships that your business stands on.

Encourage multi-player team involvement 

The success of any project depends on the contribution of every member of the team.  Encouraging multi-player team with the involvement of the dev team can bring laurels to your project. This way the team members have a sense of ownership in a group project and they believe that their contributions are valued. They feel motivated to share their best work.


There might be times when you would feel that you and your client are not on the same page. You have your own objective and your client has there's.  The solution to this common issue is to set mutual goals. 

And as soon as you start your new project and get engaged and committed to the deadlines, you help the client with vital product or services that might not be available in time to meet his or her needs. Set mutual goals from the very beginning to avoid any kind of friction later in the future.

Work for a strong partnership 

If you are building a relationship in all the appropriate ways and of course providing the products and services to your client needs, you can operate on developing a partnership with the client, something that is ahead of the project development. 

A client who determines that the organization that is serving them is in it for the long haul and that it motivates to help them succeed soon starts to view them as more than just a vendor or supplier. You become a partner in their enterprise and someone they grow to value today, tomorrow and in the years to come

Looking into the performance 

Re-examine the cost 

If you have been working with a particular customer for a long time, re-examine what it really costs you to do so. It would not be feasible to cut your price if it becomes cheaper to serve them.

Perceiving the Product 

Instead of thinking about what it is or what it does, you should infuse how it makes them feel. Even if you sell software, your software may relieve the stressful feeling of trying to get work done in a limited amount of time. It may make them feel confident in doing the job right.

Modify the strategy of budget 

Modify what you sell from a capital cost into an expense if your customer’s CEO won’t approve your product. Often, capital spending is prohibited but monthly expenses continue to be budgeted.

Finding an efficient distributor 

Sell your wares through a distributor if customers start to need smaller quantities or more service. Perhaps your service has declined as you pursued larger customers. If so, get a third party to sell and service your customer properly. You sure don’t need to make as much if you are doing less.

Selling your Service 

If they won’t buy your service by the unit, sell it by the hour or the result. So many times buyers are told to cut costs by cutting inventory.

Grant with a warranty if your product is at fault 

If your product or service was deficient, offer some kind of insurance to assure your customer it won’t be a problem next time.

Managing the departments 

The reasons customers buy your from you can change over time. A purchasing department can make decisions until its company has legal or customer problems, at which time their finance or marketing departments may now have the final say.

Managing projects with the help of various methods 

  • Waterfall: One of the more traditional project management methodologies, Waterfall is a linear, sequential design approach where progress flows downwards in one direction like a waterfall.
  • Agile development:  Agile is best suited for projects that are iterative and incremental. It’s a type of process where demands and solutions evolve through the collaborative effort of self-organizing and cross-functional teams and their customers
  • Scrum: Scrum is comprised of five values: commitment, courage, focus, openness, and respect. Its goal is to develop, deliver, and sustain complex products through collaboration, accountability, and iterative progress. 
  • Kanban: Kanban is another popular Agile framework that, similar to Scrum, focuses on early releases with collaborative and self-managing teams.
  • Six Sigma: It aims to improve quality by reducing the number of errors in a process by identifying what is not working and then removing it from the process.

Case Studies 

Ivey Business Journal 

A three-year cross-industry study by Ivey business journal explained how poor business strategy, inappropriate communication or damaged working relationships between partners account for 94 percent of all broken and failed alliances. On their own, poor or damaged working relationships account for 52 percent of all broken alliances. 

There are several reasons due to which an alliance is broken. Issues like impersonal problems, failure of team members communicating, high attrition rates, and most importantly the failure to reach a milestone.

When an alliance is recognized as broken, there are many critical tasks to perform and many separate decisions to be made. Partners require to diagnose why the alliance has broken down, examine and interpret the existing obstacles, disputes or tensions, and create a specific procedure to master these problems. They must furnish themselves to uphold a long-term relationship.

To relaunch your relationship with your client a three-step process can be followed:

  • Audit the relationship diagnosing the root causes
  • The partnership can succeed only if both organizations are fully persuaded that the alliance is the most effective means to meet their goals.
  • Conduct relationship planning build a joint contract and deal understanding
Image of a pie chart where 52% is red in color, 37% is blue in color and 11% is green in color. The pie chart shows the causes of partnership failure

OEM Profitability and Supplier Relations 

OEM Profitability and Supplier Relations - which is based in part on data gathered over the past 13 years from the annual Working Relations Index Study published by consultancy Planning Perspectives - found the better the relationship an automotive manufacturer has with its suppliers, the greater its profits are.

It explained the relationship “quantifies the economic value of suppliers’. This includes a supplier sharing new technology, providing the best team to support to the manufacturer, and providing support that goes beyond the supplier's contractual obligation.
The report added the research “establishes the fact that the economic value of the suppliers’ non-price benefits can greatly exceed the economic benefit realized from suppliers’ price concessions”. On average, this can be up to four to five times greater, according to the research.


To get customer loyalty in today’s rapidly changing competitive world, companies need to rethink.

  • How do they engage customers?
  • Do they have the appetite required to build loyal relationships?
  • Is it even the right strategy for them in the first place?

Determine what your business and shareholders need first. If it’s short-term financial gains, then customer loyalty should not be a stated goal. Client seeks relationships, with their vendor. They want a place to be heard, a place to be appreciated and a place to connect. 

At Opensense Labs, we use social technologies and services that allow us to take relationships with customers to higher levels. Connecting with customers’ personal values helps in placing ahead of the competition in winning the hearts and minds of your customers.

Ping us now at [email protected] now. 

Mar 15 2019
Mar 15

As Community Liaison, I find it important to liaise face-to-face whenever I can, and an opportunity presented itself to visit a community I have not been able to spend time with until now; that in India.

This was going to not only be the first time I’ve worked with the community in India but also my first time in India. I couldn’t help but wonder, “Will I see any elephants?”

Think Indian!

I found myself sat on a motorbike at the side of a road in Goa, India and about to plunge into the traffic for the first time. At home, I’m an experienced motorcyclist but here, everything is different. I have to learn fast…

Waiting for a gap in the stream of vehicles that will never come, I shout at myself, “Come on Rachel, think Indian!” I just need to adjust how I think and accept that the traffic conditions here are not better or worse, just different, and to “go with the flow”. I take the plunge and catch up with Surabhi Gokte and Manjit Singh (the extremely generous community member who loaned me his beautiful Royal Enfield, pictured here) on their scooter and we disappear into the night.

Manjit's beautiful Royal Enfield Classic 350
Manjit's beautiful Royal Enfield Classic 350 - quite a change from my own BMW...

I learned a lot about India riding Manjit’s motorbike over the next couple of days (yes, sorry Manjit - I may have added another 250Km to the clock!) and at the marvellous Drupal Camp Goa that I had flown out to join.

Drupal Camp Goa was a great place to meet the Drupal community in India and I was determined to find out as much as I could about what was going on there. What I learned was that the community is hugely vibrant and doing amazing things —at a scale I simply never grasped before.

I was invited to do an opening talk at the beginning of the weekend and I chose to speak about community, as is my want, and how we can ensure that the whole World is aware of the community here. It is well documented in Dries’ blog posts that the contributions to the project from India are significant; they are, after all, the second most prolific country in code contributions after the USA, and then only by a small margin.

Graph showing the most active countiries contributing code to Drupal
Code contributions to Drupal, by country. Taken from 

What struck me, though, was that I didn’t know the amazing individuals here and I don’t see them featured enough in the global Drupal conversation. I talked about how we recognise the contributions made but we all have a responsibility to ensure that we facilitate people outside of places like the USA and Europe moving into “positions of influence” in our global community; places like the track chairs of global Drupal conferences, our many working groups and so on. I would very much like every lead of every Drupal working group to be asking themselves, “If 13% of our code contributions come from India, do we have at least 13% of our group’s leadership represented by Indians and, if not, why not?”

I was particularly struck at the quality of the sessions that I attended, and the scope of the things they were discussing.

Two sessions stuck out in my mind: The first was one on machine learning and its applications in Drupal, by Akanksha Singh. She not only described much of the history behind machine learning and explained how it may be used for many applications, she described a Drupal module she is finishing developing (on very soon!) that will allow sentiment analysis of content via tools like IBM Watson. I can think of a thousand uses for this!!

I very much enjoyed a session on “college leaver” education in Drupal by Sharmila Kumaran. It seems that she has developed a system by which they spend time exposing a lot of students to Drupal and then identify those who they think have potential to move into Drupal careers. Pretty standard stuff but then they mentioned the scale of the operation and I sat up: In 2019, they are expecting to have exposed over 6,000 (yes, six thousand) college-aged people to Drupal and how it works. Is there anyone else, anywhere in the World, educating people in Drupal at this scale??

The whole camp was full of people doing amazing things. The organisers were doing a fantastic job, the food was awesome, and I left with an overwhelming feeling that region including India will power the growth of Drupal for a long time.

Shout out to all the Volunteers and Speakers of @DrupalcampGoa 2019 - We are happy to give you credits on as you have contributed to #DCG19. Here is the link -, please add comments to justify your contribution :)

— DrupalCamp Goa (@DrupalcampGoa) March 12, 2019

In the Mountains

We all highly appreciate the contributions Drupal community members make by becoming individual members of the Drupal Association, especially as it directly finances my ability to see people face to face at camps and meetups. I make every possible effort to spend that contribution wisely. So, on the return from India, I called off at Drupal Mountain Camp in Switzerland, where I had been invited to moderate a keynote panel on “The Future of Communities”, also involving Nick Veenhof, Imre Gmelig Meijling, Yauhen Zenko and Vincent Maucorps.

A recurring theme of the panel discussion was one of collaboration between the local associations, their members and each other. At the Drupal Association, we are working to aid that collaboration as much as possible and I was hugely impressed by the panel conversations. I learned more about how the local associations in Europe work with their members and each other to promote Drupal and facilitate growth. Truly a model to emulate across our global community.

One other thing - I very much appreciate that the event, thinking about its location, supplied a wonderful woolly hat rather than the usual t-shirt as a freebie. I know I'm not the only one who is aggrieved every time she is told "Oh, we only have straight fit t-shirts". Thanks Drupal Mountain Camp!

Drupal Mountain Camp woolly hat

But what about the elephants?

I never did manage to find any elephants whilst exploring India, or even in Switzerland. I did learn about a two “elephants in the room”, though:

  1. The Drupal community in India is extraordinary, doing great things, and I wasn’t aware enough of this. That is my fault and I intend to change that. I think we should all be looking to how we can learn more, too. It is very obvious that Drupal is in a state of growth in India and we should be cultivating that - I wouldn’t be surprised at all if the next webchick or xjm is already in India. We all gain by helping her grow.

  2. The Drupal communities in Europe are organising themselves in some really professional ways; using their established local associations to promote the project and members through tools like press releases, hosting local Splash Awards etc. These local associations in Europe are shining examples to other countries around the World.

Mar 15 2019
Mar 15

As always at this time of the year, we set our course on DrupalCamp London 2019. DrupalCamp London is the event most awaited by us. This year our team was somewhat bigger. Grzesiek and Maciek were joined by Jaro. As always, we had great expectations and thirst for knowledge – and as always, we were fully satisfied.

Wykład Macka na DrupalCamp London 2019

High level of DrupalCamp London

The conference began with the inaugural presentation of a valued Google Chrome programmer, Rowan Merewood. Due to this, the participants gained a solid amount of knowledge regarding user experience and website optimisation at the start of the conference already. The level of successive lectures was rising higher and higher – a trend maintained to the very end.

Session Jaro DCL 2019

What's more, we are incredibly proud and satisfied with our own presentations. There were as many as six lectures delivered by Droptica this year! But more about it below:)

6 Droptica lectures

After the last DrupalCamp London 2018, we became convinced that one should never give up. Where did this come from? Last year we have failed to get to deliver even one lecture during the conference. We drew conclusions and moved forward. The objective? Gaining a chance to present our – quite considerable – knowledge during DrupalCamp 2019.

Grzesiek session DrupalCamp London 2019

We did it! In the end, DrupalCamp London has accepted as many as six of the presentations proposed by Droptica. We are bursting with pride! The conclusion? Obstinacy,company development, constant enhancement of knowledge and better preparation yielded better results then we have ever expected. As always, every small or big success gives us even more energy and motivation.

Jaro DrupalCamp London 2019

Below are the topics that we presented during the conference.

1. Maciej Łukiański:

  • Droopler distribution - How can you save even 100 man-days during development of a new website with Drupal.
  • Continuous integration in a Drupal project (docker, ansible, jenkins, …).

2. Grzegorz Bartman:

  • Workflow in distributed Drupal agency.
  • Scrum everywhere - how we implemented Scrum not only in software development projects.

3. Jarosław Bartman:

  • Drupal 8 SEO.
  • How to make Drupal editor-friendly.

Maciek session DrupalCamp London 2019

We are particularly proud of the distinction given to Jaro's presentation about Drupal 8 SEO during the conference's summary carried out by Richard Dewick from Drupal Centric. You can read more about it here.

DrupalCamp London 2019 with Droptica until the next year

The conference is over. The emotions slowly subside. Droptica would like to thank DrupalCamp London for a great event. The sponsors – for bringing the event to life, and
the organisers – for the effort put into its preparation. We are glad that during the conference we had a chance to meet many Drupal-buddies and make many new relationships.

Gadgets DrupalCamp London 2019

DrupalCamp London 2019 is getting better year by year. It makes us happy, because – as the proverb goes – the appetite comes with eating. We start the countdown to the next conference while keeping the practical and impressive conference gadgets with us for the time being. See you at the next DrupalCamp London!

Mar 14 2019
Mar 14

Day one

The weather was snowy and cold and caused some transportation delays. Though I arrived later than planned, I was able to attend afternoon workshops and work on some Drupal Contribution projects. The day finished with an Apéro, where everyone gathered for good drinks and great conversations. To finish the night, the Amazee team left to have dinner together.


Day two

The 2nd day of Drupal Mountain Camp began with a discussion by a panel made up of Nick Veenhof, Imre Gmelig Meijling, Yauhen Zenko and Vincent Maucorps, to discuss the future of Drupal communities. The panel was moderated by Rachel Lawson. They took questions from the audience members, which included:

  • How can we attract young talent?
    By targeting students, as they have the most time. Having a DrupalCamp in a university shows them what the community has and can to offer. This can also be achieved by getting Universities to add Drupal to the course curriculum. Another way is offering a training initiative or talking to agencies.
  • What can we do about International collaborations?
    Related to the previous question, maybe offer a base camp or training day. This allows those who wouldn’t be able to attend a larger event to learn. Live streaming is a good option for those not able to attend in person.
  • What are the benefits of sponsoring events, such as Drupal Mountain Camp?
    Sponsoring is a great way to find talent and increase brand recognition, particularly to companies that are new.

GraphQL 101: What, Why, How

This session was presented by fellow colleague Maria Comas, as a beginner’s guide to GraphQL. Throughout the presentation, it became clear why GraphQL is so powerful. I really liked the abbreviation WYGISWAF (What You Get Is What You Asked For), because that is essentially what GraphQL does. It will return only the data that you need. Maria showed us how this is achieved through demo code, before letting people know that this is already available in Drupal through the GraphQL module. As it was International Women’s Day, it was fitting that Maria ended the session with the following quote by computer scientist, Grace Hopper.

The most damaging phrase in the language is "We’ve always done it this way!"
- Grace Hopper

Maria Comas

Mob Programming: An interactive session

Next was Daniel Lemon, whose session was all about mob programming. Having already introduced a scrum team to mob programming, Daniel wanted to share the experience. This presentation gave a broad overview of mob programming. What impressed me most about this session was that Daniel didn't just want to explain to the audience what mob programming is, but got members of the audience to participate in a live mob session. This meant that those involved and those watching could see how mob programming works.

Participants were tasked with creating a gallery page and menu to the Drupal Mountain Camp site, within 15 minutes, taking turns of 2 minutes each, being the driver or navigator. After introducing the task, the 5 participants were able to create a basic implementation of the gallery page. The session ended with a quick retrospective, in which participants were truly motivated to try this within their own company. Many felt it was a nice switch from the ordinary single-developer experience, but some observed it could be difficult to keep up especially in the role of the driver.

On stage

Splash awards, fondue, sledding, and drinks!

The Splash Awards is about awarding the best Drupal projects of the year. Amazee Labs won an award for in the category of Design/UX.

During the awards, Jeffrey McGuire treated us to sounds from the Alphorn, which I, personally, had never heard before. The sound produced was truly beautiful. After the awards, everyone made their way to the funicular station to collect their sleds and made their way up to the Belle Epoque restaurant. I was unable to go sledding as I didn’t have the right footwear, so I went to eat fondue with fellow colleagues Victor, Bastian, and Michael. There really is nothing better than ending the day with fondue.

Splash Awards

Day three

Day three started with a keynote, presented by Matthew Grill about the Drupal Admin UI & JavaScript Modernisation initiative, in which he informed us about the current progress of the administration. After the initial showing at DrupalEurope, it was clear that existing modules wouldn’t be compatible. This led to the team creating extension points, which would allow current modules to bundle and transpile the JavaScript to be used with the AdminUI, without having an extra build step.

It was clear that this was still a work in progress but nonetheless, it was nice to hear the latest update about the initiative. After the session, everyone was invited to the group photo. Say “Drupal”!

Group Photo

Current state of the Drupal Admin UI Redesign

The next session was again about the Drupal Admin UI, however, this time about the design. This was given by Sascha Eggenberger and Cristina Chumillas, they both explained and showcased the new design system, wireframes, and the current state of designs the initiative is proposing. It was clear that the design process was long and opinionated after they explained that designing a button wasn’t as straightforward as expected, due to many states and types. The team are hoping for a release in Drupal 8.7. but it was clear, after someone asked, that it seems to be a slow process, that this might not happen in time. It was noted that they also need help from contributors.

If you want to help or just know more about the above, head to the Admin UI & JavaScript Modernisation initiative.

Optimise your JavaScript

Saša Nikolić gave his session on optimising JavaScript. After a short history of the internet, in which I learned that Drupal came before Facebook. Saša also covered data loading. Loading lots of data, with lots of data manipulation is not a good idea for the user as this will slow down page loads.

The session also explained how to address various scenarios and the general rules that every JavaScript developer should be familiar with in order to boost your site’s performance. This includes using tools like Google Chrome dev tools, and Lighthouse. Tree shaking was another suggestion, by including only the functions that are needed. I also came to learn about prepack, a JavaScript bundle optimiser. Another useful piece of advice was to utilise CSS. Why use JavaScript for animations when CSS can take care of this? If unsupported browsers are the reason, leave it out, and make it look graceful as possible. I also enjoyed the joke about “eval() = bad”.

Network was the bottleneck, now it’s JavaScript.
- Saša Nikolić

Open source contribution

This was my favourite session of the day in which I learned about the opinions of Christina Chumillas, Miro Dietiker, Kevin Wenger, Michael Schmid, and Lukas Smith about everything to do with open source. This was an open forum, moderated by Josef Dabernig, in which an audience member was encouraged to ask a question they had about open source.

  • What motivates you to contribute to open source?
    It is concrete, you can see what you have done. People will code review, this will not only help make it better but will make oneself better. On a side note, people should just work together, join forces, this is the mindset of Drupal.
  • What is the advantage of open source software over proprietary software?
    Not only does it help with the maintenance of the code, but having different backgrounds, helps with the innovation of the code. Proprietary software means being on your own, which sometimes is not productive.
  • What is a good way to avoid maintainer burnout?
    Having a coach is a good way to let them, and other people, know of any problems and get help from them. Avoid those that don't have your best interest at heart. Share the knowledge, don't let one person do everything, and don’t let yourself be only one to complete someone just for the credit.

It was really nice to hear those answers and I couldn’t agree more. As someone who loves to contribute to open source, I think the biggest benefit is that your code will only become stronger if you share your code with others. After all, two heads are better than one.


Lukas Smith gave a very thought-provoking and inspiring closing session titled "Diversity & Inclusion: Why and How?". Lukas shared personal insights into becoming active in improving diversity and inclusiveness. He challenged the audience with some shocking statistics on the low amount of female to male programmers across Switzerland and the United States and then revealed that in open-source this percentage is even lower.

What can we do to better ourselves and improve Diversity? He also finished off the session with several tips to improve Diversity, some of which I find important to highlight:

  • Challenge your cognitive biases.
  • Consider following specifically people from marginalized communities in your chosen field.
  • Believe when members of marginalized communities point out issues with bias even if you have never encountered them.
  • Work on using inclusive language.

While talking about inclusion, I, along with everyone who attended, was happy to see that there were three sign language interpreters at the event. This meant that those who are deaf or with hearing difficulties were not excluded from the camp. This was another reason why this camp was exceptional.

If someone points out an offensive statement, make an effort to not become defensive. Listen, learn, move on.
- Lukas Kahwe Smith

After the closing everyone was invited for the ice hockey match between HC Davos and Rapperswil. This was my first time watching an ice hockey game, so it was wonderful to attend. It was a great match, with both a great atmosphere and great people. With that ended the great weekend that was Drupal Mountain Camp. I can honestly say that I had such a great time, especially spending time with my team and the Drupal community.

Finally, you hear it all the time, “thank you to all the sponsors”, but honestly, it cannot be expressed enough. Without them, great camps like Drupal Mountain Camp wouldn’t be possible.

The Game

Mar 14 2019
Mar 14

Using Drupal as your default CMS undoubtedly has advantages, however it also comes with its negative sides. The price you have to pay for its customizability, is the complexity and steep learning curve. Here at Sooperthemes, we have thought of you and developed an easy-to-use solution for you: Glazed Builder. With this visual Drupal page builder, you and your team of content creators and marketeers will be able to create rich content and beautiful web pages for your business, without having to touch a line of code.

In this article, I present to you 8 ways through which a visual page builder like Glazed Builder can further create value for your business.


1. Cut in half your landing page costs and time-to-market

Having a good landing page is paramount to the success of your business. However, it takes plenty of time and money to find the right people and tools to do it. With Glazed Builder as your Drupal 8 page builder however, creating a landing page has never been easier, cheaper and faster. Content creators and marketeers will be able to to create a visually stunning landing page in a matter of minutes, without having to rely on the IT department.

2. Stress less: Reduce employee turnover in your content team with true WYSIWYG

Are your employees stressed that the webpage they are building is going to look completely different than they imagined? Well, with Glazed Builder, your content creators will experience true WYSIWYG (what you see is what you get). That means that whatever they have imagined for your webpage is going to be their final result. No more senseless stress for your content creating team.

3. Get twice as much Drupal site-building work done by your most expensive staff: Developers

Developers, they are the most expensive members of your staff. However, they do not get work done as fast as you would like. The way to increase productivity is to have developers use Glazed Builder as your default Drupal page builder to build dynamic pages and dashboards that leverage drupal's block and views systems. This way, you will make their job easier while also increasing their productivity.

4. Same-day web design and publishing by using the pre-built templates

You need to launch a webpage in a matter of hours and you don’t have the inspiration necessary to design a layout? Fret not, Glazed Builder, the Drupal page builder, has you covered. With a plethora of templates available, you just have to select the right template for your business, insert your content, and post it. It has never been easier.

5. Content creators will produce better, more effective content than your competitors.

Do you want to stand-out from your competition in terms of content creation? Glazed Builder can help you and your content creators unleash their creativity. With an endless amount of customizability, Glazed Builder is sure to provide the right tools and power for your content creators to achieve their wildest dreams. When it comes to customizability, with Glazed Builder, the sky's the limit.

6. Reduce onboarding time and training costs: Reduce Drupal’s steep learning curve for content creators and marketeers

Every time there is a new tool introduced to your business, you have to pay a large amount of money for training your employees. The same is applicable for Drupal, since it is a highly complex CMS, it has a steep learning curve and requires highly skilled developers to be able to make it truly shine. However, Glazed Builder was engineered to be able to be used by even the most non-tech savvy of its users. This way, your staff will be able to quickly understand how to operate the visual builder and you will be able to reduce the time and money spent on training your personnel.

7. Save thousands on cloud hosting costs with a frontend tool that runs in your browser, not in your cloud

If you're thinking that a Drupal 8 website with the additional features of Glazed Builder requires a beefy server, you're wrong! 90% of Glazed Builder's magic is happening in the browser. Even our Drupal 8 demo sites with hundreds of demo content items run perfectly fine on affordable shared hosting solutions like our favorite Drupal hosting A2Hosting.

8. Better performance attracts a bigger number of visitors on your webpage

Even if you have top-notch content on your website, it’s irrelevant when it takes a long time to load. Most site visitors don’t have patience when it comes to loading a webpage, they would simply exit and visit the next one if it takes too much time. However, Drupal is the fastest out of the bunch when it comes to speed. It takes the least amount of time to load a page, which means that the likelihood of visitors leaving significantly drops.


Conclusion on Drupal Page Builder

Now that you know all of this, what are you waiting for?

Start improving your business today by using our visual page like Glazed Builder.

Mar 14 2019
Mar 14

TEN7 is a full-service digital firm, and our tagline is “We create and care for Drupal-powered websites.” Creating and building a website is the sexy visible part, but caring for a website over time is the just-as-important maintenance work. Keeping your site code updated, backed up, secure and performing well is the job of a support team.

Most of the clients we design and build websites for also ask us to support their site after it’s built, which we happily do. But clients with sites built by other companies often approach us to support their site as well. However, we don’t take on support clients lightly.

Why You Can’t Just Pay Us to Be a Support Client

If you want to pay us to support your site, why wouldn’t we just do it? Well, when we were just starting out, there was a time when we’d take on whoever came along and offered us cash.

We took on support clients without knowing anything about what was “under the hood” of their site. We had to scramble to figure out how a site worked as support issues came in, which led to increased problem-solving times. This resulted in subpar support of the client, and subpar support led to real unhappiness for our team members.

As you might have guessed, the impetus for a change in the way we did business was a particularly difficult client and their site. It took two years to effectively end the relationship. The experience was a turning point in our company’s existence: it led me to think about what we’d done wrong, and reverse-engineer a way to prevent it from happening again. You can hear more about this experience in my Drupal Camp talk, “Know Yourself First.”

As we’ve grown and matured as a company, we’ve learned the value of recognizing the right clients and building the right process to support their sites. This ensures that we do work that meets our high standards, that our team is respected and happy, and that there’s a good vibe between all parties. Our multi-step onboarding process for new support clients lets us accomplish all these goals.

The Audit → Improve → Care Process

Each step in this process is a separate engagement, and has its own pricing and contract. When a step is completed, either party can quit with no hard feelings. The three steps are:

  1. TEN7Audit: We perform a comprehensive site audit and present a report of findings and recommendations.
  2. TEN7Improve: We implement selected recommendations from the audit report (at minimum the most critical ones) based on budget and need.
  3. TEN7Care: This is the final part of the process, an annual support agreement.

Let’s learn more about each step.

Step 1: TEN7Audit

Before we’ll agree to support your site, we need to know what we’re dealing with.

To figure this out, we perform a complete audit for a flat fee of $2,500. We settled on this cost because while it’s not exorbitant, it’s high enough that it will disqualify anyone who isn’t serious. The entire process can take up to six weeks, from when a client first expresses interest until the day we present our findings report.

Site Audit and Analysis

The site audit starts with us making an exact replica of the site so that it can be examined without affecting its live operation. We run Healthcheck, a Drupal module sponsored and maintained by TEN7, to generate a baseline report for review.

Healthcheck is like your Drupal site's own personal physician and can run continuously after installation to keep tabs on the health of the site over time (hence its name!) It has a user-friendly, action-oriented dashboard that shows you issues, ranked in terms of urgency. We install Healthcheck on sites we support.

In the TEN7Audit process, Healthcheck provides the initial lay of the land and identifies things like whether module updates are required, or whether the site has been hacked or modified. Next, we get humans involved to take a deeper look at where the site is hosted, whether there is a version control workflow, whether continuous integration and automation exist, how the infrastructure is configured and more. For example, a Healthcheck-identified performance issue (slow page load speed) could have numerous causes, from giant images to caching being disabled. Humans have the best chance of ascertaining and reporting the causes.

Audit Results

When the TEN7Audit process is complete, we present a report of findings with a prioritized list of issues and recommendations. We define critical issues that need the most attention, as well as recommendations for repair and optimization:

  • Tier 1 - Critical: Issues that need to be fixed as soon as possible for site security
  • Tier 2 - Best Practices: Improvements that will reduce technical debt, optimize the site, and won’t negatively affect the site if not immediately done
  • Tier 3 - Nice to haves: Long-term improvement goals you should consider for the sustainability and success of your site

Here’s an example of a TEN7Audit Findings Report.

What’s Next?

After a TEN7Audit has been completed, the next step involves determining which recommendations from the report should be implemented, and then doing so to improve your site. Of course, this also gives us an opportunity to evaluate our relationship with you and decide whether it makes sense for us to continue (and if not, no hard feelings!)

Step 2: TEN7Improve

You’ve decided you’d like to have TEN7 work on the improvements identified in the TEN7Audit, and we’ve also decided that we’d like to work with you to help improve your site.

The recommendations in the TEN7Audit report will be accompanied by an estimated number of hours to fix each issue. The total cost for TEN7Improve varies for every site, and is calculated by multiplying the number of hours estimated to fix chosen issues and our hourly rate at the time of the site audit. A budget for TEN7Improve starts at around $3,000 for a site with minor issues and can go up to $10,000 or more for a site in bad shape.

If we’re going to put ourselves in a position to care for your site in the long run, you'll expect consistent, high quality work. We require Tier 1 Critical Issues to be fixed to proceed with the TEN7Improve step, but we also highly recommend fixing Tier 2 Best Practice issues as well (and most clients do).

If you have budget constraints, items in the recommendations list can be cherry picked, and you can determine the order in which they should be addressed. Occasionally there will be issues found in the audit that can’t be fixed at any time—they may be so big, or so entrenched in the site infrastructure that it would take an enormous effort to fix. In such rare cases, a complete site rebuild is warranted and recommended.

What’s Next?

By this point, the hard work has been done—your site has had performance and infrastructure issues fixed, Drupal core and modules are up to date, and the site is as secure as we can make it. We’re now more comfortable with your code; we have a better idea about how the site is built and how it works. Hopefully we’ve been able to make a real difference in the infrastructure, security, performance and usability of your site.

After this longer engagement, we also have more information about what it’s like to work with the you: how you communicate, how pleasant or demanding you are, and how quickly you pay your bills. You also know what it’s like working with us: how responsive we are, how important you feel, how much value you’re receiving.

We should now be in a position to offer a TEN7Care Support Agreement, in which we support a site we’ve audited, improved and are familiar with. It gives us the opportunity to take care of a site that we didn’t build, but that we feel comfortable being wholly responsible for. In some cases, we may not offer a support agreement, and of course, you may not wish to pursue one either.

Step 3: TEN7Care

Since we are now comfortable with the inner workings of your site, we can estimate how many hours per year will be required for site monitoring and maintenance. This includes time for periodic site updates, security patches, uptime monitoring and regular backups and archiving.

The TEN7Care Support Agreement starts at five hours per month, billed on a monthly basis. The agreement typically covers:

  • Drupal site maintenance: maintain and update core and contributed Drupal modules
  • 24x7 site uptime monitoring and response
  • Regular backups and archiving: automated nightly backups, weekly and monthly snapshots backed up to two offsite servers
  • Monthly traffic analytics insights
  • Guaranteed availability of your business’ critical paths after updates
  • Installation and use of a versioning system to manage multiple site environments
  • Regular releases of code with automated release notes
  • Support availability during business hours via email, video conference or Slack

Here’s an example of a TEN7Care Support Agreement.

What’s Next?

Yes there is a next, even here! Six weeks before the end of a TEN7Care Support Agreement, we meet internally to review the last year of work: how many hours we billed and how much work your site required. We’ll discuss whether to adjust the hours for the coming year, and whether a rate change is due, amongst other things.

That’s How You Become a Support Client!

As a company, we strive to do our best for our clients, and we set a high bar for quality work. I believe our success is directly proportional to our clients’ satisfaction with our work. Moreover, as a team, we have to be happy doing that work. If either of these two things don’t happen, we aren’t going to do our best, and there won’t be satisfaction in what we’ve created.

I think our TEN7Audit → TEN7Improve → TEN7Care process helps us accomplish all these goals.

Would You Like to Work With Us?

Do you have a Drupal site that needs support? We can help! Send an email to [email protected] and we'll take it from there.

Mar 14 2019
Mar 14

When loading or interacting with entities in Drupal 8, we often use the EntityTypeManagerInterface interface, which is the brains behind the entity_type.manager service that is provided in many of the Drupal core base classes.

This often appears in one of the following ways:



Either approach returns an instance of EntityStorageInterface. Each entity type can define a class that extends EntityStorageBase and adds additional custom methods that are applicable to a given entity type.

The node entity type uses this pattern in \Drupal\node\NodeStorage to provide many of its commonly used methods such as revisionIds() and userRevisionIds().

The benefits of adding custom storage methods becomes more apparent when you begin to work with custom entities. For example, if you have a recipe entity type, you could have a loadAllChocolateRecipes() method that abstracts the query and conditions needed to load a subset of Recipe entities.

The resulting call would look like this:

/* @var $recipes \Drupal\recipe_module\Entity\Recipe[] */
$recipes = `$this->entityTypeManager

A custom storage handler class is integrated with an entity via the annotated comments in the entity class.


 * Define the Recipe entity.
 * @ContentEntityType(
 *   id = "recipe",
 *   label = @Translation("Recipe"),
 *   handlers = {
 *     "storage" = "Drupal\recipe_module\RecipeStorage",

Then in the storage handler class, custom methods can be added and existing methods can be overridden as needed.

 * Defines the storage handler class for Recipe entities.
class RecipeStorage extends SqlContentEntityStorage {

   * Load all recipes that include chocolate.
   * @return \Drupal\example\Entity\Recipe[]
   * .  An array of recipe entities.
  public function loadAllChocolateRecipes() {
    return $this->loadByProperties([
      'field_main_ingredient' => 'chocolate`,

Manual SQL queries can also be performed using the already provided database connection in $this->database. Explore the Drupal\Core\Entity\Sql\SqlContentEntityStorage class to see the many properties and methods that you can override or leverage in your own methods.

Again, the NodeStorage and TermStorage offer many great examples and will demystify how many of the “magic” methods on these entities work behind the scenes.

For example, if you ever wondered how the Term::nodeCount() method works, this is where the magic happens.


 * {@inheritdoc}
public function nodeCount($vid) {
  $query = $this->database->select('taxonomy_index', 'ti');
  $query->addExpression('COUNT(DISTINCT ti.nid)');
  $query->leftJoin($this->getBaseTable(), 'td', 'ti.tid = td.tid');
  $query->condition('td.vid', $vid);
  return $query->execute()->fetchField();

The next time you need to write a method that returns data specific to an entity type, explore the use of a storage handler. It beats stuffing query logic into a custom Symfony service where you are likely violating single responsibility principles with an overly broad class.

This potentially removes your dependency on a custom service, removing the need for extra dependency injection and circular service dependencies. It also adheres to a Drupal core design pattern, so it is a win, win, win, or something like that.

Mar 14 2019
Mar 14

Drupal comes with its own built in cron. This means that you can add your own job to the list of jobs that are executed when the Drupal cron runs.

Drupal runs all of these jobs at the same time. What happens if you want to run one particular cron job really frequently? You have to change your cron settings to run ALL of them that frequently. It’s an all or nothing affair and you end up running all the cron jobs as often as your most frequent job. That can put a lot of pressure on your web server.

A second problem is if you have a job that requires a lot of heavy lifting. With these jobs, you might want to run them overnight when traffic to your site is lighter and there is less pressure on the web server. But with Drupal’s built in cron, you can’t do that either because of the all or nothing nature of it. You run it once or not at all.

To solve this problem, you need a way to separate cron jobs so that you can run each job, or groups of jobs, at different times. There are two main options to achieve that - Elysia Cron and Ultimate Cron. In this article, we are going to look at Ultimate Cron because that is available for Drupal 7 and 8, where as Elysia Cron is Drupal 7 only.

Download and install the module

In Drupal 8, the recommended way to add a new module to your project is to use composer. The following composer command will download Ultimate Cron and add it to the list of dependencies.

composer require drupal/ultimate_cron

You can then enable the module manually by going to the Extend admin menu item, or by using Drush.

Create a new job

You can create a new job by implementing hook_cron() in a custom module. The following example implements hook_cron() in a module called custom_utility. When this job is run, it will log a message to Drupal’s logs.

function custom_utility_cron() {
  \Drupal::logger('custom_utility')->notice('Cron ran');

You can change the code in the function to execute what you need. The call to log a message is purely to demonstrate that this cron job is actually running.

Discover the job

Head over to configuration -> cron in the admin menu (/admin/config/system/cron/jobs). You should see a list of jobs from various core modules.

Hit the Discover jobs button and the job you created above will appear on the list.

Ultimate cron jobs

To test that this works, click Run. Then head over to recent log messages (admin/reports/dblog) and you should see the message.

Message in log from ultimate cron

To edit the frequency of the job, click on the arrow to the right of the Run button and click edit. In the scheduler tab you can change the frequency in the Run cron every X minutes drop down to.

Export the configuration

At this point, you can export the configuration using Drupal’s standard configuration export. You can then import the configuration if you use a staging and production site. If you are unsure how to export and import configuration, check out the configuration management documentation on

Adding more than one job for a module

If your custom module only needs to support one cron job, then you have enough to do that. You can add additional code to your implementation of hook_cron() (see custom_utility_cron() above) and that will run when your cron job runs at the scheduled time.

But what if you want to have more than one cron job running at different times all from this one custom module?

You can do this by defining each multiple cron job with their own call back function. The call back function is used instead of hook_cron().

The settings for each Ultimate Cron job is stored in its own configuration file. Drupal uses YAML for configuration files, and you’ll need to create these files. The following steps will outline how to do this.

Steps to add a cron job

  1. In the admin menu, go to Configuration -> Configuration synchronisation (/admin/config/development/configuration)
  2. Click on the Export tab and then the Single item sub-tab (/admin/config/development/configuration/single/export)
  3. Change Configuration type to Cron job
  4. Change Configuration name to Default cron handler with the name of your custom module. In my case, this is  Default cron handler (custom_utility_cron).
  5. Copy the configuration code to your clipboard

In your custom module:

  1. Create a config directory in the root of your custom module’s directory
  2. Create a new file: ultimate_cron.job.jobname.yml (change jobname to the name of your job)
  3. Paste the configuration code you copied earlier

Here is an example of what this code will look like:

uuid: fa40bf2b-f544-4e22-b4b9-dda9cc0efbfe
langcode: en
status: true
    - custom_utility
title: 'Default cron handler'
id: custom_utility_cron
weight: 0
module: custom_utility
callback: custom_utility_cron
  id: simple
      - '*/[email protected] * * * *'
  id: serial
      lock_timeout: 3600
      thread: 0
  id: database
    method: '3'
    expire: 1209600
    retain: 1000

There are a couple of adjustments to make to this file:

  • Remove the uuid line (the first line)
  • Change the id to something unique e.g. id: custom_utility_cron_job1
  • Change the title to something meaningful so that you can distinguish this job in the cron admin page

This file is creating a new job for Drupal to run. Let’s break it down:

  • callback: custom_utilty_cron - this is the call back function that will be run when this job runs.
  • module: - this is your custom module. This is also the module where you should add your call back function
  • scheduler: - this is the schedule to which this job will run, which for this one is every 15 minutes

The next thing to do is to add the callback to the .module file in your module.

Here is an example:

 * The callback for the cron job.
function custom_utility_callback() {
  \Drupal::logger('custom_utility')->notice('Cron ran');

This call back function will be run every time this job is executed.

And then go back to the configuration file from above and change the callback function to point to this function. In my example, this means changing this line:

callback: custom_utility_cron


callback: custom_utility_callback


You can then repeat these steps for any additional cron jobs that you need, with a new configuration YAML file and call back function for each.

Import the new config

In order for this to work, you need to import the configuration that you set up above. This can be done with the following command (change custom_utility to the name of your module):

drush config-import --source=modules/custom/custom_utility/config --partial -y

Wrapping up

Separating cron jobs out is often necessary to give you the control you need to run jobs at different times. Ultimate Cron is a wonderful module that allows you to do just that.

Mar 14 2019
Mar 14

There have been a lot of people that are very much interested in the “DevOps” concept and when I sat down with some of these, the direction of the conversation went down to many interesting paths. 

They started talking about deployment best practices, rollbacks, hot deployment etc. 

Two blue screws placed vertically where the middle text has dev in one and ops in other

But, when there were some mentions about “Blue-Green Deployment” - complete silence. 

Therefore, this gave me an idea to tell the rest of the world that with all the microservices, native cloud and what not technology, blue-green deployment is not a silver bullet, but it is an element to usefulness.


Well, you got to read ahead. 

What do we understand by blue-green deployment?

A blue-green deployment is a management approach for releasing software code. 

Two identical hardware environments are configured in the exact same way in Blue-green deployments, which is also known as A/B deployments 

Only one of the environments is live at a single time, where the live environment serves all the production traffic. For example, if blue is currently live then green would be idle and vice-versa.

Blue-green deployments are usually utilized for consumer-facing applications and the applications which have critical uptime requirements. The new code is delivered to the inactive environment, where it is completely tested. 

How it reduces the risk?

Achieving automation and continuous delivery at any level of production is a holy grail, and avoiding downtimes and risks are high up on the list of priorities. Blue-green deployment provides you with simple ways of achieving these goals by eliminating risks that are witnessed in the deployment. 

  • You will never encounter surprise errors

When you fill a particular form online, what all credentials do you fill? Your name, phone number, address, street and probably your bank details if you are making an online purchase. Right?

You press the “pay now” button and check on the “receive spam emails” but unfortunately, your order wasn’t able to get processed as you desired. If you are lucky enough you get an error message equivalent to “application is offline for maintenance” all your efforts and time goes in vain. But with blue-green deployment, you never have to worry about this maintenance screen. 

There is a list of item’s upon one click and upon next click, you are eligible to see the new menu that you add. This would keep furious emails about error screen from flooding your inbox. 

  • Testing the production environment 

Ensuring that your pre-production environment is as close to your production environment as possible is not only important but essential too. With the help of blue-green deployment, this task is easily achievable. The user can test any application while it is disconnected from the main traffic. The team has the eligibility to even load the test if they desire too. 

  • Makes sure that the traffic is seamless 

Customer needs and desires are more global than ever and there is no longer an essential good time to do deployment, especially if you work in an enterprise where the business needs to be running around the clock. If you have a customer facing application then there are chances that they might switch their platform to some other website, if they don’t find what they desire. This means a decrease in sale and business. 

Blue-green deployment assures that your traffic never stops. That customer can place their order just fine without disruption. Which means that the employees overseas continue to do their job without any interruption, saving companies money. 

  • Easy Recovery 

You might witness times where you would get introduced to bugs and viruses. We can either spend a lot of money on its fix or we can inevitably find them and recover them. With the help of blue-green deployment, we have our older and more stable version of our applications to come back online at a moment’s notice by evading the pain to roll back a deployment.

Image of an object that is connected to a yellow object that says router which is connected to a chart that is divided into three halves.Source: Martin Fowler

How does this process work?

As we know that blue-green deployment technique involves running two identical production environments where they are configured in the same way, therefore, let us assume that the current deployment is in the green environment in 2.3 release. The next deployment which would take place would be in a blue environment that would be in 2.4 release.  

The environment would then be tested and evaluated until it is confirmed to be stable and responding. Once it is in production the server would be redirected, thus becoming the new production environment that the users are routed to.

The entire design is used to provide fast rollbacks in a case a deployment fails or does not pass a QA. When deployment fails or critical bugs are identified, a rollback to the green environment will be initiated. Once the bugs are fixed the version is re-deployed to the blue environment and the traffic is rerouted back the moment it is stable. 

While deploying the preceding version i.e version 2.5, the deployment would switch to the green environment and would be extensively be tested and evaluated. Traffic would be rerouted to the green zone once it passes the quality assessment.

This way both green and blue environment are regularly cycled between live versions and staging to the next version. 

Image of five blue-green boxes that are placed horizontally which are pointing to the blue-green boxes on the other sidesSource: Medium 

Blue-Green Deployment helping your Drupal websites

Let us imagine that you constructed a website with the help of Drupal, now you are getting high traffic in it. Normally for developing, updating and testing a website (without risking the live integrity), you follow these steps:

Development: The development process starts with developers working on new features, bug fixes, theming and configuration in the local environment. It makes it possible to easily roll back to the previous stage of development.
Testing: Typically this environment is not available for client viewing and it is intended for testing developmental work against a lateral host. 

Staging: This stage is used for presenting the changes to the client for approval. QA (quality assurance) and UAT (user acceptance testing) are most often carried out on the staging stage. 

Production: This is the live site on the web available visitors. It contains new features that have been proven safe to go live. 

As you can see that this process can be long and time-consuming, maintaining and constructing site can be irritating therefore blue-green deployment rescues you at times like these. 

It would provide near to zero downtime and would present easy rollbacks capabilities. The fundamental idea behind blue/green deployment is to shift traffic between two identical environments that running differently in different applications. 

 Image of a blue and green square in two different images. The first one shows request in the blue box and the second pictures show the sameSource: NewGenapps

Some of the implementations for Your Drupal Website 

Blue-Green Deployment for Drupal websites with Docker 

Drupal Deployments are hard. The user has to make sure that that the code is deployed, composer dependencies are pulled, schema updates are pulled, scheme updates are performed and all the caches are cleared. 

All with keeping the website up and responsive to the users. But if anything goes wrong and you wish to rollback? Do you stop the deployment? Well, no blue-green deployment is the answer to it. 

Docker makes it easy to build, shift and run applications. On the EC2 instance, there are always two raised docker containers of “blue” and “green”, and ngnix works as a reverse proxy on the same instance. The user can build a Drupal site that is running parallelly in the “blue” and “green” environment and serve both from MySQL database. we install Apache, PHP, and Drupal in baseimage-docker.

 Image of a square box that says nginxconnected to blue-green boxes. These boxes are connected to MySQL boxSource: Nulab

Drupal with Blue-Green Deployment in AWS Beanstalk 

Within the help of ECS, the user can create task definitions, which are very similar to a docker-compose.yml file. 

A task definition is a collection of the container, each of which has a name, the Docker image runs, and have the option to override the image’s entry point and command. The container definition is also where the user can define environment variables, port mappings, volumes to mount, memory and CPU allocation, and whether or not the specific container should be considered essential, which is how ECS knows whether the task is healthy or needs to be restarted.

The Amazon web service solution allows the user to quickly and easily manage the deployment and scalability of web platforms. The deployment helps in configuring a high-availability environment that seamlessly runs a Drupal website. Running a DB instance that is external to Elastic beanstalk decouples the database from the lifecycle of the environment, and lets the user connect to the same database from multiple environments, swap out one database from another and perform a blue-green deployment without affecting the database.

The below image shows how green-blue deployment work in AWS environment. 

An image divided into two halves where both have a cloud at the top connected to a security group which in turn is connected to the EC2 security group. Source: CloudNative

Some of the best practices for smooth release 

Now that we understand how blue-green deployment works, let’s cover some of the best practices that are related to it:

Load Balancing

Load balancing helps you to automatically set a new server without depending on any other mechanism, without depending on the DNS mechanism. The DNS record will always point to the Load Balancer and the user would only modify the servers behind it. This way they can be absolutely sure that all traffic comes to the new production environment instead of the old one.

Rolling Update

To avoid downtime the user can execute rolling update which means instead of switching from all blue server to all green server in a single cut-off you are eligible to work with an integrated environment. This indicates that rather than switching from all blue servers to all green servers in a single cut-off, the user can control with an integrated environment

Monitoring the environment 

Monitoring the productive as well as the non-productive environment is important. Since the same environment can play both as production and as non-production, all you would need is to toggle the alerting between the two states. 


The user can script as many actions as possible in the witch process, instead of doing a manual set of actions. This brings huge benefits. The process becomes quicker, easier, safer and enables self-service.

Deployment in cloud

If your servers run in the cloud, there is an interesting variation of the Blue-Green method in which instead of going back and forth between two static environments, you can just create the next environment from scratch.

This process is also valuable for avoiding the danger of servers becoming snowflakes, which are servers that have a unique configuration set that isn’t documented anywhere.  Once these snowflakes get erased for some reason, you have no easy way to properly recreate them. Whatever may be the choice it is important to keep the newest test and release technology to ensure that the release is smooth.


Deployments are one of the most important parts of the software development lifecycle, therefore all the activities involved should thoroughly be researched and tested to ensure that they are a perfect fit for your system architecture and business. 

At OpenSense Labs, we have a pool of Drupal developers and experts that work on technologies that use these tools and services. Contact us now at [email protected], our experts would guide you with the queries and questions that are related to this topic. 

Mar 14 2019
Mar 14

About a year ago, I only just learned about the principles of IndieWeb, which in a way is a bit of a shame. Fast forward to now, and I'm proud to announce the first stable release for Drupal 8. Together with this milestone, I also pushed a new version of Indigenous so that both are aligned feature wise.

It's been a great journey so far, and while there's still a lot to do for both projects, the stability and feature set warrants a stable tag. It has changed the way I interact with (social) media day to day now since the last half year, both in reading and posting, being in full control of every aspect. It's great, everyone should try it!

What's next?

I've been thinking the last few weeks to raise funding, but after much consideration, I'm not going forward on that path. Even though my public GitHub profile lists over 1300 contributions the last year (about 3.5 per day), which somehow is simply crazy, I still have more than enough spirit and motivation to keep on going. Just a little slower from now on, since many features for both projects are not mission critical - even though they are awesome. Of course, I won't mind if someone would suddenly feel the urge to sponsor me.

Slowing down now you think, that can't be true ? Right. As already announced a few weeks ago, the next focus will be writing an Activitypub module for Drupal so you can communicate with your site on the Fediverse. I'm currently using Bridgy Fed for this, but, in the IndieWeb spirit, it's time to bring this home!

But first, time to make sure I don't mess up my tryouts of the Moonlight sonata. No commits until after March 31st - I promise :)

Say hello to the first stable release of the #IndieWeb module for #Drupal 8!

Mar 14 2019
Mar 14

We’re back with an overview of the top Drupal blog posts from last month. Have a read and get yourself up to speed on the most recent goings-on within the Drupal community!

The 15 Things Your AEM Team Says Drupal Can't Do, But Can

The first post that caught our attention was Third & Grove’s list of 15 misconceptions about Drupal when compared with Adobe Experience Manager (AEM). With this blog post, the team at Third & Grove want to shed some light on the real differences between the two content management solutions and help people make a more informed decision.

A lot of the assumptions about Drupal’s shortcomings with regards to AEM are outdated and hence more up-to-date information was needed for an honest comparison. With the recent developments in Drupal, such as the Layout API and the new admin UI that’s on the horizon, Drupal now offers a much better experience for developers and content editors alike.

Read more

A Security Checklist for Drupal 8 Sites with Private Data

Even though Drupal has the reputation of an extremely secure CMS out-of-the-box (hence also its widespread adoption in government sites), some websites built in Drupal need some additional security precautions. This is especially true for sites that contain sensitive private information. 

With this security checklist provided by Lullabot’s Matthew Thift, you’ll always have a point of reference to check if each security measure has been adequately followed in every step of the project. 

Read more

Announcing the New

Next on our list, we have another blog post by Lullabot, this one being an announcement of the new look of their website,, written by Mike Herchel. The previous version of the site was one of the first decoupled Drupal sites built with ReactJS, but a decoupled architecture was deemed too complex a solution for Lullabot's current needs, and so they decided to replatform the site. 

The new and improved is thus a return to a more traditional Drupal architecture. This makes it easier for developers to join the project while offering a better experience for content editors through the Layout Builder module.

Read more

Find out more in a podcast by Lullabot

Testing your Drupal code base for deprecated code usage with PHPStan

The starting point for the next post on our list was this blog post by the same author, Matt Glaman, about writing cleaner code with phpstan-drupal, a Drupal extension for PHPStan. The discussion in the comments section was what spurred this second blog post by Matt, which details how to test your Drupal code base for deprecations with the help of this extension. 

The goal of discovering deprecations is not just optimizing code, but also ensuring the compatibility with Drupal’s dependencies, namely Symfony and PHPUnit. This is one of the key responsibilities of the Drupal 9 group led by Gábor Hojtsy and Lee Rowlands; a tool that automates the tracking of deprecated code is thus exactly what they’ve needed.

Read more 

Drupal Pitch Deck at 60+ case studies

The following post is a sort of continuation, or rather, an update to Paul Johnson’s call for case studies. In this first post, he provided more information on the Promote Drupal initiative, the Pitch Deck project in particular, complete with examples of case study slides, and called on the community to contribute to the project with our own case studies.

This follow-up post details the progress of the Pitch Deck project: how many case study slides were submitted up until that point and what the next steps are. Even though this is an ongoing project, it’s never too late to get involved - anyone wishing to do so can and should contact Paul Johnson.

Read more

Optimizing site performance by "lazy loading" images

Next up, we have a post by Dries on how to greatly optimize site performance with the use of “lazy loading” images. Since all the images on a page are usually loaded simultaneously, this can be very detrimental to the site’s performance. A small tweak such as opting for lazy loading images can greatly reduce the time needed for the page to render.

How this works is by generating lightweight placeholder images which are as small as possible and devoid of any unnecessary headers and/or comments. These placeholder images are then embedded directly into the HTML and replaced with real images when they become visible to the user scrolling on the page.

Read more

Related blog post by Dries

Headless CMS: REST vs JSON:API vs GraphQL

Another post that we wanted to highlight was again written by Dries; this one is a comparison of different headless architectures. It is a very comprehensive post in which he compares three web services implementations - REST, JSON:API and GraphQL. The first part is a more general, CMS-agnostic comparison, while the second focuses on Drupal-specific implementation details.

The three different headless options are compared by the qualities that are most relevant for developers. These are: request efficiency, API exploration and schema documentation, operational simplicity, and writing data. According to the analysis in this blog post, the most viable headless solution for Drupal 8 core is JSON:API. As such, JSON:API is planned on being included in Drupal 8.7.

Read more

My 2019 Aaron Winborn Award Nomination

Finally, we have a post taken from Adam Bergstein’s aka n3rdstein’s blog. In this post, Adam reveals his 2 nominations for the Aaron Winborn Award - Nikhil Despande and Kendra Skeene, 2 instrumental members of the Digital Services in State of Georgia

Nikhil and Kendra are both avid advocates for open source and Drupal in particular. They were the driving force behind Ask GeorgiaGov that has a major two-fold benefit: the needs of Georgia’s citizens are better served, while Drupal profits from innovation in the form of an integration of the conversational interface Alexa. As such, they are truly outstanding members of the community and more than deserve the nomination for such an award.

Read more

These were the Drupal-related blog posts from last month that intrigued our team the most. If you’ve read any you found particularly interesting that we’ve missed, let us know and we’ll be happy to check it out. We’ll be back next month with another overview of the most interesting Drupal content - stay tuned!

Mar 14 2019
Mar 14

by Elliot Christenson on March 13, 2019 - 11:56pm

We're continuing our popular "Support Wizard Help Desk" at Drupalcon 2019! Book some time with myDropWizard for some FREE help with your Drupal site!

You're a first time Drupalcon attendee? You're a veteran Drupaler? Either way, you made part of your Drupalcon mission to fix a lingering issue - or at least to be pointed in the right direction!

We're here to help!

We spend our days helping Drupalers just like you every day with their support needs, so we thought "Let's bring that myDropWizard Support Face-to-Face with Drupalers: FOR FREE!"

So, drop by Booth #811 or (better yet!) schedule with us below!

Where we'll be and when

  • Our booth: We again sponsored DrupalCon this year and will have a booth in the exhibit hall! We're in booth #811!
  • Everywhere! Just like you we want to get around the convention to see everyone and everything. Stop us and say "hello!"

Schedule a one-on-one meeting

Again, we'll be happy to discuss your current challenges (or successes!) anywhere at Drupalcon, but if you want to be double extra sure that you'll be able to chat with us, schedule a one-on-one meeting with us!

We like to keep things simple, so just drop us an email to schedule a meeting with either Elliot or David:

[email protected].

Can't wait to see you there!

We're super friendly, non-imposing people who love Drupal and the Drupal community. :-) We all look forward to hearing how your organization is using Drupal and how we can help! Have a great week in Seattle!

Mar 14 2019
Mar 14

Are you concerned about web accessibility issues that might be hidden within your pages?

We recently gathered input from the Promet accessibility team concerning digital accessibility issues that are most often in need of remediation, and we came up with a Top 12 List of web accessibility mistakes and oversights. They pertain to:

1.  Alt text
2.  Color contrast
3.  Forms
4.  Headings
5.  iFrames
6.  Keyboard accessibility
7.  Landmark roles
8.  Links
9.  Lists
10. Semantic markup
11. Tables
12. File attachments

1. Alt Text

An image might be worth a thousand words, but if someone can’t see the image, then what? So, what’s up with the images on your site? Make sure that they are not missing: 

  • The alt attribute and descriptive text,
  • Enough description in the alt attribute, or 
  • A null alt attribute (alt="") indicating that the image is decorative and thus has no meaning.

If the image is a chart, alternative text that briefly describes it might not be enough. Complicated charts and graphs will require extra effort. The use of the longdesc attribute can be used if the narrative of your content doesn’t already include the information communicated by the image. 

2. Color Contrast

This one can be problematic if you’re heavily invested in your branding. If a color contrast checker reveals that your branding colors don’t create sufficient contrast, there are minor fixes you can employ to achieve accessibility. The two issues we see most often are insufficient color contrast:

  • Between text and background colors and 
  • Between text and UI components (i.e. button) or background image(s).

This type of problem can be headed off at the pass with a well-planned design and teaching your content authors how to incorporate accessibility into the creation of their colored charts and graphs.

3. Forms

Forms perform different duties. You have the search box on every page. That’s a form. That “Sign up for our Newsletter” on your homepage is a form. And, let’s not forget “Contact Us.” That’s three forms and we haven’t gotten to the comment forms, e-commerce forms, or event sign up forms. So, you can see, accessible forms require considerable attention.  

Now, add in the long list of issues we see to understand why your forms might be your most vulnerable objects on the page.

  • Form fields found with missing labels.
  • Form labels found with "for" attribute not matching another element’s ID.
  • Select element’s option doesn't have value available.
  • Select element doesn't have initially-selected option.
  • If this selection list contains groups of related options, they should be grouped with optgroup.
  • Checkboxes/Radio Buttons should be contained within a fieldset.
  • Fieldsets must contain a legend element.
  • Form is missing a required submit button.
  • Button elements missing value and/or content.

These are fixable offenses. For example, if your button elements are missing value and/or content, this is what that means.

<input type=”submit” />

<input type=”submit” value=”Submit Form” />

As you can see, the fix is simple. However, the tricky part can be gaining access to the site in such a way that the solution can be applied. If you’re using a third-party plug-in or a content management system, you might not have access to the code that generates your forms. 

4. Headings

Headings in HTML are defined via the <H1>, <H2>, <H3>, etc. elements. 
So often content is chunked in an article by using sub-headers styled with <strong> versus <H2>, for instance. This is not considered accessible. 

When Promet Source audits website pages, we often find:

Heading tags without content, and 
Heading structure that is not logically nested.

What does logically nested mean? Let’s take a look.

<h1>About Us</h1>
<h4>Our History</h4>
<h6>Our Future</h6>

<h1>About Us</h1>
<h2>Our History</h2>
<h2>Our Future</h2>

This example makes it look like the content is the problem and it might be. However, this kind of issue can creep up in the presentation of page objects that reside outside the main content. 

5. iFrames

iFrames are used to display content on your web page from an external source. In this scenario, you need to think about two things: the iFrame on your page and the external content source, or third-party.

Start with ensuring your iFrame has a title, as shown in the sample code below. Then, ensure that the external content is accessible, which might not be easy if you don’t have an agreement with the source to provide accessible content. Remember, just because it came from someone else, that doesn't mean you are responsible.

<iframe src=”/images/maine-beach-home.png” width=”...” height=”...” />

<iframe title=”Maine beach home” src=”/images/maine-beach-home.png” width=”...” height=”...” />

6. Keyboard Accessibility

You scroll the browser window to see what’s hidden below. You place your cursor on a link or in a form field using your touchpad or mouse. Swiping and screen taps have become actions we take for granted on mobile devices. What would you do if you couldn't click or tap?

The most common keyboard accessibility issues we see are:

Elements that are not keyboard accessible;
Elements that are not visible when it gets focus (e.g., show a dotted border); and 
Forms that cannot be navigated using the keyboard and other accessibility tools. (i.e. accordions).

Let’s consider the first issue. Helping a user navigate to non-link and non-form elements is often overlooked. If your page is divided into sections, allowing the user to tab through the sections can be helpful.

<div>Complementary content region</div>

<div tabindex=”0”>Complementary content region</div>

7. Landmark Roles

So far we’ve talked about aspects of web pages that you are likely aware. This next topic has to do with the W3C’s Accessible Rich Internet Applications Suite (ARIA), and the roles and attributes that you can assign to your HTML elements. 

The W3C says, “With WAI-ARIA, developers can make advanced Web applications accessible and usable to people with disabilities.” However, it can also create issues if you apply ARIA’s roles and attributes incorrectly. For instance:

  • Elements missing required landmark roles, and 
  • Landmark role "presentation" is applied improperly on an element because its child elements contain semantic meaning.

Let’s consider the application of roles and semantic meaning.

<div class=”promet-logo” role=”presentation”>
    <img src=”/images/promet-logo.png” />

<div class=”promet-logo”>
    <img src=”/images/promet-logo.png” />

Sometimes a role assignment makes things worse, not better.

8. Links

When it comes to accessible links, you have two perspectives to consider: code and content. Before we look at the coding issues for accessible hyperlinks, let’s consider content. 

Links such as “Click here” and “Read more” appear often on the internet, but they’re not accessible because they lack purpose. 

Imagine listening to assistive technology reading out the links on a page, “Read more. Read more. Read more.” Read more what? In order for the link to be purposeful it needs to indicate what you would be reading more about. For example: “Read More about Weather Patterns.”.

Regarding coding issues, we see five coding issues on a regular basis.

  • Anchor elements found with valid href attribute but no link content.
  • Anchor elements found with missing href attributes.
  • Broken links to 404 (page not found) pages (e.g., a link to versus
  • Back to top anchor link doesn't exist.
  • “Skip to main content” link is missing.

The ‘skip to main content’ link accommodates success criterion 2.4.1 Bypass blocks, enabling a user of the page to bypass listening to the menu and any other blocks of content that stand in the way of them hearing the main content. Below is some code that illustrates the problem.

     <main id=”main-content”></main>
     <a id=”skip-link”>Main Content</a>

    <a href=”main-content” id=”skip-link”>Skip to Main Content</a>
<main id=”main-content”></main>

9. Lists

f you are familiar with HTML, you might find it hard to believe that bulleted lists are, at times, not created using the <ul> and <li> elements. Just because a list visually appears as such, that doesn’t mean assistive technology will read as that way.

So, remember that:

  • List elements should be marked up as a navigation list, and 
  • Ordered/unordered/definition lists should include list items.

What do we mean by “should include list items?” See the example below.

     <div>Link 1</div>
     <div>Link 2</div>
     <div>Link 3</div>

     <li>Link 1</li>
     <li>Link 2</li>
     <li>Link 3</li>

10. Semantic Markup

Semantic markup has to do with meaning. If something is a paragraph, use <p>, not <span> or <div>, for instance. Other examples include <form>, <table>, and <article>. These HTML elements are descriptive and carry meaning. Semantic html matters.

We often see:

Duplicate ID attribute values found on pages, and
Semantic markup used for emphasis or special test (i.e. don’t use <font>).

Let’s take a look at the ID attribute that can be assigned to an HTML element. In this example, a web page has three unique forms and they each have the same ID. 

<form id=”search”>
<form id=”search”>
<form id=”search”>

<form id=”search-header”>
<form id=”search-content”>
<form id=”search-footer”>

The ease with which such fixes can be applied rely on how your website is created and if you have access to the code.

11. Tables

Tables are not as responsive as you will need them to be. So, if you don’t need to use a table, don’t. If you need to use a table, note that the following accessibility issues are often found.

  • Table is missing caption elements.
  • Table headers are missing the <th> element.
  • The relationship between <td> elements and their associated <th> elements is not defined.

The last example is easy for content authors to overlook as HTML editor buttons do not insert ID and header attributes. Notice how the data cell references the table header cell that is applicable.

    <td>Column 1 content</td>
<td>Column 2 content</td>
<td>Column 3 content</td>

        <th id=”col1” headers=”blank” scope=”col”>One</th>
<th id=”col2” headers=”blank” scope=”col”>Two</th>
<th id=”col3” headers=”blank” scope=”col”>Three</th>
    <td headers=”col1” scope=”row”>Column 1 content</td>
<td headers=”col2”>Column 2 content</td>
<td headers=”col3”>Column 3 content</td>

12. File Attachments

Accessibility is not just about the HTML page. PDFs are commonly uploaded to a page for purposes of download. They, and other files such as MS Word and Powerpoint files, are required to be accessible.

PDF accessibility requirements that we see most often pertain to the following issues:

  • Untagged content,
  • Missing alternative text for images, and
  • Incorrect reading order.

The process to fix non-web files varies, depending on the source document. 


As the above examples demonstrate, accessibility compliance calls for close attention to a wide range of details.

One of the most challenging aspects of making a site accessible tends to be of fixing the technology used to create it. If your site was created from individual HTML pages, you can edit the markup and fix many, if not all of your issues. If not, a site rebuild might be in order.

Before you build a new site, make sure that the content management system is designed to produce accessible pages and forms. It’s also essential that you audit your current pages to identify accessibility issues before they are migrated into the new site. 

Promet Source offers a path to achieving accessibility compliance for your websites, web applications and technical products. With flexible testing and remediation options, we can partner with you to ensure that you are adhering to WCAG 2.1 guidelines.  

Contact us today for a conversation on the level of training or support that best fits your needs.

Mar 14 2019
Mar 14

March 14, 2019

Often, during local Drupal development (or if we’re really unlucky, in production), we get the dreaded “Unable to send e-mail. Contact the site administrator if the problem persists.”

This can make it hard to figure out problems related to how emails are sent in a local environment.

Enter Mailhog

Mailhog is a dummy SMTP server with a web GUI, which means you view all outgoing messages with a Gmail-type interface.

It is a major pain to install, but we can automate the entire process with the magic of Docker.

Let’s see how it works, and discuss after. Follow along by installing Docker Desktop – no other dependencies are required – and installing a Drupal 8 starterkit:

git clone
cd starterkit-drupal8site

This will install the following Docker containers: a MySQL server with a starter database, a configured Drupal site, and Mailhog. You wil see something like this at the end of the output:

If all went well you can now access your site at:

=> Drupal:
=> Dummy email client:

Now, the magic

You might be seeing different port numbers instead of 32791 and 32790, so use your own instead of the example ports.

In my example, DRUPAL PORT is 32791 and MAILHOG PORT is 32790.

As you can see, all emails produced by Drupal are now visible on a cool GUI!

So how does it work?

A dedicated “Mailhog” docker container, using on the Mailhog Docker image is defined in our docker-compose.yml file. It exposes port 8025 which is mapped to a random unused port on the host computer (in the above example, 32790). Note that the 8025 port is for public GUI access, and port 1025 is the SMTP mailhog port as you can see in the Mailhog Dockerfile.

In the same docker-compose.yml, the “drupal” container (service) links to the “mail” service; this means that when you are inside the Drupal container, you can access Mailhog SMPT server “mail” and port 1025.

In the Starterkit’s Dockerfile, we download the SMTP modules, and in our configuration, we install SMTP (0, in this case, is the module’s weight).

Next, configuration: because this is for local development, we are leaving SMTP off in the exported configuration, because in production we don’t want SMTP to link to Mailhog. Then, in our overridden settings, we enable SMTP and set the server to “mail” and the port to 1025.

Now, you can debug sent emails in a very realistic way!

You can remove the starterkit environment by running:

docker-compose down -v

Please enable JavaScript to view the comments powered by Disqus.

Mar 13 2019
Mar 13

This blog has been re-posted and edited with permission from Dries Buytaert's blog.

Three stars will align and the Open Web will win.

Today, the world wide web celebrates its 30th birthday. In 1989, Sir Tim Berners-Lee invented the world wide web and changed the lives of millions of people around the globe, including mine.

Tim Berners-Lee sitting in front of a computer showing the first website

Tim Berners-Lee, inventor of the World Wide Web, in front of the early web.

Milestones like this get me thinking about the positive impact a free and Open Web has had on society. Without the web, billions of people would not have been able to connect with one another, be entertained, start businesses, exchange ideas, or even save lives. Open source communities like Drupal would not exist.

As optimistic as I am about the web's impact on society, there have been many recent events that have caused me to question the Open Web's future. Too much power has fallen into the hands of relatively few platform companies, resulting in widespread misinformation, privacy beaches, bullying, and more.

However, I'm optimistic that the Open Web has a chance to win in the future. I believe we'll see three important events happen in the next five years.

First, the day will come when regulators will implement a set of laws that govern the ownership and exchange of data online. It's already starting to happen with GDPR in the EU and various state data privacy laws taking shape in the US. These regulations will require platforms like Facebook to give users more control over their data, and when that finally happens, it will be a lot easier for users to move their data between services and for the Open Web to innovate on top of these data platforms.

Second, at some point, governments globally will disempower large platform companies. We can't leave it up to a handful of companies to judge what is false and true, or have them act as our censors. While I'm not recommending governments split up these companies, my hope is that they will institute some level of algorithmic oversight. This will offer an advantage to the Open Web and Open Source.

Third, I think we're on the verge of having a new set of building blocks that enable us to build a better, next-generation web. Thirty years into the web, our data architectures still use a client-server model; data is stored centrally on one computer, so to speak. The blockchain is turning that into a more decentralized web that operates on top of a distributed data layer and offers users control of their own data. Similar to building a traditional website, distributed applications (dApps) require file storage, payment systems, user data stores, etc. All of these components are being rebuilt on top of the blockchain. While we have a long way to go, it is only a matter of time before a tipping point is reached.

In the past, I've publicly asked the question: Can we save the Open Web? I believe we can. We can't win today, but we can keep innovating and get ready for these three events to unfold. The day will come!

With that motivation in mind, I want to wish a special happy birthday to the world wide web!

Mar 13 2019
Mar 13

by David Snopek on March 13, 2019 - 1:36pm

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 Views 6.x-3.x module to fix an Cross Site Scripting (XSS) vulnerability.

This module enables you to create customized lists of data.

The module doesn't sufficiently sanitize certain field types, leading to a Cross Site Scripting (XSS) vulnerability.

This vulnerability is mitigated by the fact that a view must display a field with the format "Full data (serialized)" and an attacker must have the ability to store malicious markup in that field.

See the security advisory for Drupal 7 for more information.

Note: There are two other security advisories that were published today for Views on Drupal 7, but they don't affect Drupal 6.

Here you can download the Drupal 6 patch or the full release.

Note: This only affects Views 6.x-3.x -- not 6.x-2.x.

If you have a Drupal 6 site using the Views 6.x-3.x module, 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

Mar 13 2019
Mar 13

By Natasha ChantoMarketing | March 13, 2019

By Natasha ChantoMarketing | March 13, 2019

DrupalCon 2019

We’re Going to Seattle!

We are a month away from flying out to Seattle for the one thing we have all been waiting for here at weKnow… DrupalCon 2019! Our team is beyond excited to be a part of this event once more as attendees and special conference guests.

Why are we going to DrupalCon?

Most of our WeGive efforts go towards coding for several projects weKnow maintain where we have several developers contributing a significant portion of their time to improving coding tools. Our three main contributors, Jesus Manuel Olivas, Omar Aguirre, and Andres Avila have dedicated their time to projects like the Drupal Console, which has now been downloaded more than 3 million times, helping hundreds of thousands developers code more efficiently. We also take the time to contribute to numerous modules and the Drupal core. This is why we are flying out to Seattle to share with other people and companies our work within the Drupal community.

What are some of the benefits of attending DrupalCon?

In this five day event, people from all around come for the training, conferences, social events and for the wealth of networking opportunities. It opens up your mind to a new world and business views and it allows you to learn about and from other people’s experiences with Drupal. This is the event where we go and soak up the inspiration. As developers, we learn from the strong and inspiring leaders that encourage us to think big and envision our future. It is a boundless source of motivation where they ignite your spark to continue improving your work and technology for the greater good. From the moment you step in, the positive vibe will enthrall you and, if you are a new attendee, you will for sure find support to take your first steps in Drupal. Find a space to bond and strengthen your relationship with colleagues, business partners and dive into the experience.

Our team at DrupalCon

This year, we are going to have our Head of Products, Jesus Manuel Olivas, as a speaker for two sessions. The first one will be in participation with Mario Hernandez and Mark Casias from Mediacurrent, and it is, Introduction to Decoupled Drupal with Gatsby and React  where people will understand and learn how to create a React-based Front End with Gatsby in combination with React. The second session is Building a Slack ChatBot where people will understand how to make interactions between computers and humans feel just like an interaction solely between humans. Andres and Omar are looking forward to attending DevOps and Front End sessions such as Drupal Blue/Green deployments with AWS ECS, Serverless, Well Actually…, Gatsby and Drupal, amongst others.

Through our time in Seattle, we will be uploading content and information on our social media sites to keep you updated. If you want to come with us through our journey, follow Jesus Manuel Olivas in twitter as @jmolivas and Andres Avila as @andresavila97. And if you are going to DrupalCon, see you in Seattle!


Drupalcon Seattle 2019

If you are looking to augment your team, execute your vision, automate your process or learn more about Drupal and our contributions, we invite you to get to know us better.

Mar 13 2019
Mar 13

By default, Drupal 8 has two methods for building the breadcrumb trail. For content, this method is based on the URL of the page, and for taxonomy terms this method is based on the vocabulary hierarchy.

The default construction of a breadcrumb

Let's explore in more detail the construction of the breadcrumb for content.

Let's take an example of a content page with the following URL:


The last part of the URL (webfactory-drupal) corresponds to the title of the page. Drupal will then inspect the rest of the URL and for each part look for if a content matches that URL.

So, Drupal will inspect this URL, to see if it matches existing content.


If so (let's imagine that a content whose title is Drupal Specialist has this URL), the title of the page is added to the breadcrumb trail.

Then, he inspects this URL, to see if it matches existing content.


If so (the content title is Freelance Drupal for example), the page title is added to the breadcrumb trail.

And finally Drupal inspects the last part of the URL, to see if it still matches existing content.


The page title (Services) is then added to the breadcrumb trail.

So for this example, if each part of the path corresponds to an existing content page, the breadcrumb trail generated for this URL will be the following.

Home > Services > Freelance Drupal > Drupal specialist > Web factory Drupal

It is thus possible to build a custom-made, relevant breadcrumb trail using this detection by parent path, either by using a manual alias for listing pages, pivot pages or landing pages, or by using the Pathauto module to automatically build a relevant alias for content to be automatically placed in a section of a site (typical example, news, events, services, etc.). 

Note that the generation of the last part of the breadcrumb trail, namely the title of the current page, Web factory Drupal in our example, is the responsibility of the theme. As a general rule, you will find an option in any correct theme that allows you to display or not the title of the current page in the breadcrumb trail. Or it can be done with a simple hook.

 * Implements hook_preprocess_HOOK().
function MY_THEME_preprocess_breadcrumb(&$variables) {
  $request = \Drupal::request();
  $route_match = \Drupal::routeMatch();
  $page_title = \Drupal::service('title_resolver')->getTitle($request, $route_match->getRouteObject());

  $variables['#cache']['contexts'][] = 'url';
  if (count($variables['breadcrumb']) <= 1) {
    $variables['breadcrumb'] = [];
  else {
    $breadcrumb_title = theme_get_setting('breadcrumb_title');
    if ($breadcrumb_title) {
      $variables['breadcrumb'][] = array(
        'text' => $page_title

The breadcrumb trail for the pages of taxonomy terms is built according to a different logic: according to the hierarchy of terms and this regardless of the alias used for the pages of terms.

These two methods of breadcrumb generation are the default methods included in Drupal Core. It is of course possible to modify this default behavior by means of contributed modules, such as Breadcrumb Menu for example which generates the breadcrumb depending on the position of the page in the main menu and which in the absence of the page in the menu switches to the default Drupal Core generation, or by means of a custom module.

Customize the breadcrumb trail with a module

Altering the construction of the breadcrumb is done by means of a service tagged with the breadcrumb_builder tag. For example, for example

  class: Drupal\my_module\MyModuleTermBreadcrumbBuilder
  arguments: ['@entity_type.manager', '@entity.repository', '@config.factory', '@path.validator', '@path.alias_manager']
  - { name: breadcrumb_builder, priority: 1010 }

The priority given to a service of this type makes it possible to order which rules to apply first, the highest priorities being those applied first.

The MyModuleTermBreadcrumbBuilder Class must implement two methods

  • The applies() method that will allow us to indicate when to apply this rule of construction of the breadcrumb
  • The build() method that will build the breadcrumb itself.

So if we want to add a parent to the breadcrumb trail of taxonomy terms pages, for example, our class will look like this.

 * Provides a custom taxonomy breadcrumb builder that uses the term hierarchy.
class MyModuleTermBreadcrumbBuilder implements BreadcrumbBuilderInterface {
  use StringTranslationTrait;

   * The entity type manager.
   * @var \Drupal\Core\Entity\EntityTypeManager
  protected $entityTypeManager;

   * The entity repository.
   * @var \Drupal\Core\Entity\EntityRepositoryInterface
  protected $entityRepository;

   * Drupal\Core\Config\ConfigFactoryInterface definition.
   * @var \Drupal\Core\Config\ConfigFactoryInterface
  protected  $configFactory;

   * The taxonomy storage.
   * @var \Drupal\Taxonomy\TermStorageInterface
  protected $termStorage;

   * The settings of my module taxonomy configuration.
   * @var \Drupal\Core\Config\Config
  protected $taxonomySettings;

   * The path validator service.
   * @var \\Drupal\Core\Path\PathValidatorInterface
  protected $pathValidator;

   * The alias manager.
   * @var \Drupal\Core\Path\AliasManagerInterface
  protected $aliasManager;

   * MyModuleTermBreadcrumbBuilder constructor.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   * @param \Drupal\Core\Path\PathValidatorInterface $path_validator
   * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository, ConfigFactoryInterface $config_factory, PathValidatorInterface $path_validator, AliasManagerInterface $alias_manager) {
    $this->entityTypeManager = $entity_type_manager;
    $this->entityRepository = $entity_repository;
    $this->configFactory = $config_factory;
    $this->pathValidator = $path_validator;
    $this->aliasManager = $alias_manager;
    $this->termStorage = $this->entityTypeManager->getStorage('taxonomy_term');
    $this->taxonomySettings = $this->configFactory->get('my_module.taxonomy_settings');

   * {@inheritdoc}
  public function applies(RouteMatchInterface $route_match) {
    return $route_match->getRouteName() == 'entity.taxonomy_term.canonical'
      && $route_match->getParameter('taxonomy_term') instanceof TermInterface;

   * {@inheritdoc}
  public function build(RouteMatchInterface $route_match) {
    $breadcrumb = new Breadcrumb();
    $breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));
    /** @var \Drupal\taxonomy\TermInterface $term */
    $term = $route_match->getParameter('taxonomy_term');
    $breadcrumb_parent = $this->taxonomySettings->get('vocabularies.' . $term->bundle() . '.breadcrumb_parent');
    if ($breadcrumb_parent) {
      $url = $this->pathValidator->getUrlIfValid($breadcrumb_parent);
      if ($this->pathValidator->isValid($breadcrumb_parent)) {
        $path = $this->aliasManager->getPathByAlias($breadcrumb_parent);
        if(preg_match('/node\/(\d+)/', $path, $matches)) {
          $node = Node::load($matches[1]);
          if ($node instanceof NodeInterface) {
            $node = $this->entityRepository->getTranslationFromContext($node);
            $breadcrumb->addLink(Link::createFromRoute($node->label(), 'entity.node.canonical', ['node' => $node->id()]));

    // Breadcrumb needs to have terms cacheable metadata as a cacheable
    // dependency even though it is not shown in the breadcrumb because e.g. its
    // parent might have changed.
    // @todo This overrides any other possible breadcrumb and is a pure
    //   hard-coded presumption. Make this behavior configurable per
    //   vocabulary or term.
    $parents = $this->termStorage->loadAllParents($term->id());
    // Remove current term being accessed.
    foreach (array_reverse($parents) as $term) {
      $term = $this->entityRepository->getTranslationFromContext($term);
      $breadcrumb->addLink(Link::createFromRoute($term->getName(), 'entity.taxonomy_term.canonical', ['taxonomy_term' => $term->id()]));

    // This breadcrumb builder is based on a route parameter, and hence it
    // depends on the 'route' cache context.

    return $breadcrumb;


This class largely follows the breadcrumb construction logic provided by Drupal Core, and only adds a parent to the breadcrumb built according to a configuration parameter. This same logic can also be applied to the breadcrumb trail of content pages, in case you want a view for example in the breadcrumb trail, or any other page that is not a content page.

In the end, customizing a breadcrumb trail can be done in many ways, as is often the case with Drupal, but I must admit that finally the default pattern responds to many use cases and is very often sufficient with a configuration zest at the level of generating aliases of the pages of a Drupal 8 project. Finally, we can also note the Custom Menu Breadcrumbs module which allows us to configure a main parent from a menu item for content of a certain type.

Mar 13 2019
Mar 13

The TWG coding standards committee is announcing an issue for final discussion. Feedback will be reviewed on March 20, 2019.

To help the initiative to update all deprecated code for Drupal 9 we need a standardized format for deprecation messages.

New issue for discussion:

  • Issue #3024461: Adopt consistent format for deprecation messages.
    Having a machine readable format for deprecation messages will allow us to develop tools on to keep track of the current status of deprecated code in Drupal core and contributed modules. This will help drive the initiative to update all deprecated code before the release of Drupal 9.

Interested in helping out?

You can get started quickly by helping us to update an issue summary or two or dive in and check out the full list of open proposals and see if there's anything you'd like to champion!

Mar 13 2019
Mar 13

The TWG coding standards committee is announcing an issue for final discussion. Feedback will be reviewed on March 20, 2019.

To help the initiative to update all deprecated code for Drupal 9 we need a standardized format for deprecation messages.

New issue for discussion:

  • Issue #3024461: Adopt consistent format for deprecation messages.
    Having a machine readable format for deprecation messages will allow us to develop tools on to keep track of the current status of deprecated code in Drupal core and contributed modules. This will help drive the initiative to update all deprecated code before the release of Drupal 9.

Interested in helping out?

You can get started quickly by helping us to update an issue summary or two or dive in and check out the full list of open proposals and see if there's anything you'd like to champion!

Mar 12 2019
Mar 12

Every year community members from across the globe meet in Orlando for Florida Drupal Camp. This year Adam, Ryan, and Jonathan from Hook 42 attended. It was a fantastic time to connect with people, to learn, and enjoy some warmer weather. Plus, alligators!

Ryan and Adam led a training on connecting Drupal 8 and Gatsby.JS. The training utilized a set of Docker images that help people build everything from end-to-end on their own system. Attendees used the Umami demo, installed JSON API, and configured Gatsby.JS to pull recipes from Drupal. It was well attended and there was a lot of collaboration in the room. Our team appreciated all of those that attended - especially as we worked through technical and wifi issues. 

Ryan and Adam also gave a talk on emerging technology related to Drupal. Some of the topics included, Hubspot, ElasticSearch, GraphQL, Gatsby.JS, and Pattern Lab. It’s important for community members to find and use the right tool for the right job. As Drupal community members, we must be mindful of how these complementary technologies can serve us. You can watch the recording of the session on Drupal TV.

Team Member Reflections


I look forward to this camp each year, and once again this year did not disappoint. Thank you to “the Mikes”, Kyle, and Jordana for volunteering again. The time spent with the community was uplifting and encouraging - even if it was a bit tiring giving both a training and a session. The time spent with my colleagues Jonathan and Ryan, having barbeque, and drinking craft beer with the community all brought a lot of energy. I was able to reconnect with many friends and I always treasure those opportunities. Also, Jonathan and I unintentionally packed the same hoodies and Drupal Camp Asheville shirts. Twinsies!

The session quality was outstanding! Most notably, there were some incredibly great non-technical, people-focused sessions provided by Jordana Fung and Qymana Botts. I strongly recommend seeing both. Thanks, as always, to the amazing Kevin Thull, all sessions are recorded and posted to Drupal TV.
At the end of camp, on the contribution day, I was able to work on the proof-of-concept integrating and Tugboat QA. The result of which is a new Tugboat QA contributed module based on a Backdrop CMS module port.


This wasn’t just my first time to Florida Camp, it was my first time in the state of Florida in general! What a great experience. I had a great time at the camp and really enjoyed speaking with a wide array of folks about decoupled Drupal and Gatsby.js, both through the training Adam and I conducted as well as hallway conversations. Brian Perry’s talk comparing various static site generators and their compatibility with Drupal proved really insightful. I was really excited about his demo of the Tome static site generator, which runs within Drupal itself.

Thanks a ton to the organizers - the camp was a lot of fun and I look forward to attending again next year!


My second time at Florida Drupal Camp was as good as, if not better, than my first. As a Drupal Camp organizer myself, I find Florida Drupal Camp to be inspiring. They manage to pull off being extremely well organized while maintaining a very casual air to the whole weekend. 

As an attendee, I had a unique (for me) experience this year. I went to Drupal Camp Florida without a computer and it was great! Without a laptop always in front of me I found myself more attentive to the session and more engaged in the camp in general. I enjoyed it so much that I will likely avoid taking my computer to future camps.

The sessions I attended were all wonderful and there are a few I’m still thinking about today. Here is a quick list, and my takeaways:

  • How to keep Drupal relevant in the Git-based and API-driven CMS era
    The Drupal island appears to be shrinking as the overall landscape for approaches to web development grows. It doesn’t hurt keeping an eye on the new ways to solve old problems.
  • How to Hire and Fire Your Employer
    Always a fan of these “being human” talks. In this one, April encouraged me to continuously evaluate my values as a person and how they match any given employer. “Life is too short to be miserable” is a powerful perspective to maintain.
  • An Introduction to Gulp
    I’ve been using Gulp and similar technologies for a number of years, but have almost always used someone else’s configuration. Tim makes it look easy to get started writing my own tasks, and I’m really looking forward to doing so on my next project.
  • The problem with Paragraphs, a return to rich fields!
    Maybe the only actual Drupal session I attended, it’s always great to see Hawkeye and get his perspective. In this session he opened my eyes to some serious problems with the Drupal community’s go to approach to solving complicated fields, the paragraphs module. By the end of the session, I was ready to start making custom rich/composite/compound fields for future projects.

Another top-notch Drupal Camp Florida in the bag. I’ll definitely be back next year, and if you’ve never been I highly recommend it.

Mar 12 2019
Mar 12

Simple XML sitemap 3.1 has been released

The third major version of simple_sitemap has been long in the making bringing a more reliable generation process, a significantly more versatile API and many new functionalities. The first minor ugrade of the 3.x branch comes with views support and human readable sitemaps.

Major new features in 3.1

Simple XML Sitemap views supportViews and views arguments support

Including view display URLs in the sitemap has been possible through adding these URLs as custom links in the UI (or via the API).

View variations created by view arguments however are tedious to include as one would have to include every version of the URL.

The integration of the simple_sitemap_views inside simple_sitemap 3.x makes it easily doable via the UI.

Thanks to @WalkingDexter for his tremendous work on this submodule!

Human-readable sitemaps with XSL stylesheets


Sitemap without XSL


XML sitemap with XSL stylesheet

This will not change how bots interact with the sitemaps, it will however make the sitemaps readable and sortable for humans. This can be helpful when debugging the sitemap content or using the sitemap to visually present content to users.

Other improvements

You can see the list of bug fixess and improvements on the module's release page.

Upgrade path

The module upgrades fine from any of the 2.x and 3.x versions.

To upgrade the module via composer, $ composer require 'drupal/simple_sitemap:^3.1' can be used. Afterwards, just visit /update.php, or run $ drush updb to update the module's storage.

For more information about the 3.x branch of the module, see this post. I invite you to watch this space for a more in-depth technical tutorial on how to programmatically create sitemap types. Also feel free to leave a comment below!

Mar 11 2019
Mar 11

It’s hard to imagine life without mobile devices. While a developer controls the display of the site and its structure, editors are the ones adding content to a site on a regular basis. One tool that developers can use with editors in mind is Responsive Preview.

Difficulties during content creation can range from complex interfaces to performance problems. Each of these problems can be multiplied when you add in responsive design.  

Responsive Preview is a module that provides you with a quick way to preview how the website's pages will appear with various screen dimensions.


Response Preview helps editors when they need to try out new layouts or add new content to preview the page. This means they can make sure everything works on the most commonly used devices before publishing on the live site. The module provides a quick approximation of how the page and the layout will look on any device.

How it works

From the development perspective, the module creates an iFrame with provided configs. This means it doesn't have to go through the trouble of getting all the frontend code and all the styles compiled and rendered in the backend to show a preview. Instead, we just load the iFrame which displays the frontend view.

The module provides a config entity “Preset” with the fields that describe “device” including  “width”, “height”, “rotation”, and more. On a node view page, there is a select with our options. Selecting an option opens an overlay with a preview of the current page.



width: width,

          height: height


This way we get a preview of everything we need. Simply create a controller and put a link to the source attribute of the iFrame.

Responsive Preview Module Screenshot


When creating a site, developers should think not only about end users but about editors who will need to work on the site daily. Drupal is a great solution for content management, but sometimes it lacks ease of use.

It’s not enough to only have a mobile, tablet, and desktop design anymore, as many devices fall in between those dimensions. Phones can be the same size as small tablets and the new iPad Pros have a larger screen than some laptops. Responsive Preview provides the flexibility to configure the module as an admin. This makes it easy to add new presets when new devices are released.

Got a project that needs editor-friendly responsive design? Get in touch with us today!

Mar 11 2019
Mar 11

Thank you for backing the Webform module's Open Collective

First off, I want to thank the backers of the Webform module's Open Collective. After my last blog post, Open email asking organizations to back the Webform module and Drupal-related Open Collectives, we have 14 backers and a current balance of $908.44 that needs to be spent.

I also received a comment and an email about the need for some process for paid support. It’s worth noting that the Drupal Association is exploring a paid support model for assisting with security releases. We should recognize that Drupal 8 was a major software change and it is one that is still changing the Drupal community. And while I am thinking about how the Drupal community is changing and how we can develop better support around the Webform module, one of my more immediate concerns is improving the Webform module's Open Collective, and brand is the first thing I want to address.

Improving the Webform module's Open Collective

There are some useful tips and guides for building and maintaining an Open Collective. I appreciate Pia Mancini’s statement that "A collective is not a sprint," which makes me feel comfortable taking time to build out the Webform module's Open Collective.

Defining and strengthening the Webform module's mission will help clarify to backers what they are supporting and getting from the Webform module. The product summary for the Webform module is…

The Webform module provides all the features expected from an enterprise proprietary form builder combined with the flexibility and openness of Drupal

Drupal directly completes with proprietary Content Management Systems and the Webform module is competing with 100's of proprietary form and survey builders. The Webform module is not included on any top form builder lists, even though in a feature comparison we are on par with most of these form builders, with the added benefit that Drupal and Webform is completely free for everyone to use. This is why with the launch of the Webform's Open Collective, I proposed using collected funds to improve the Webform module's marketing and brand.

Improving the Webform module's brand

The Drupal Association is actively working on promoting Drupal. At the same time, we as a community can also promote Drupal's contribute module ecosystem. There are some amazing contributed projects with equally amazing developers contributing and maintaining these projects. Besides writing quality open source software, it’s also essential to consider the big picture of an open source project. For example, the Webform module's project page's information architecture works to address every aspect of the Webform module from encouraging people to watch a video, try the Webform module, and explore documentation. The summation of a piece of software or project is visually represented by a logo.

A dedicated logo is missing from the Webform module's project and Open Collective landing pages.

I did not start this blog post with this direct ask for Webform logo because I feel there is much greater need and opportunity for the Drupal community. That said...

Better branding is missing from most Drupal contributed projects.

Improving all Drupal-related projects brand

Some Drupal projects have dedicated logos which help establish the project's brand.

  • website has the word TV inside the "Drupal" drop.
  • Acquia's Lightning distribution has a lightning bolt inside the "Drupal" drop.
  • Token module has very cool looking [T].
  • Rules module has an R flow diagram.
  • Paragraphs module has a right-pointing pilcrow.

All of the above project logos demonstrate how having a visual representation helps establish a project's brand.

In the spirit of the giving back to Drupal community…

Is it possible for us to collaborate and create a logo for the Webform module that also provides a universal logo kit which makes it possible for any Drupal contributed project to have a dedicated logo?

Providing a logo kit for Drupal contribute projects

When exploring the existing project logos in the Drupal community, I feel there are two key requirements for a reusable logo kit.

First, the logo should include a visual reference to Drupal. I like the concept of using the Drupal "drop" with some icon or text placed inside the drop.

Second, the logo kit is going to need to leverage a creative common and freely available icon library, which could include something like Seven theme's Libricons or Material Design's icon.

We can use Drupal media kit's logo page as a starting point for the final deliverables.

The Webform module's logo requirements and process

Right now, the simplest icon which could be used to represent a form builder is a checkbox, but I am open to other suggestions. The logo should also optionally include the 'Webform' project name. The Webform logo may also be used with the Webform UI as a callout.

Our entire process will be transparent with all materials freely available. As this project proceeds, we will publish blog posts encouraging community feedback.

Who should respond to this request for proposal

First and foremost, you need to want to give something back to Drupal and Open Source with the understanding that your contribution will be recognized, although you will most likely not to be fully financially compensated for work.

We have only $900 USD available for this project. It is not a lot and may be too little. It might make sense for us to do a two-phase approach with the Webform logo designed in phase 1 and the Drupal contributed project logo kit part of phase 2.

I know some people or organizations might do willing to do this work for free, but it is important that you are compensated in some way because…

It is not reasonable to assume that someone is going to doing something for free because they are contributing to open source.

Proposals could be very simple with a general statement of work and timeline. Our entire process is going to be transparently done using the issue queue. Proposals can be posted as comments to Issue #3026111: Create a logo and header for the Webform module. Also, feel free to ping on the Drupal Slack #webform channel if you have questions.

Submit a Webform logo proposal

Thanks again

I opened this blog post thanking the existing backers of the Webform because they are making it possible for the Webform module to have a logo. Building a reusable logo kit for all contributed projects most likely requires more funds. Having a Drupal contributed project logo kit will help us strengthen our community's visual brand and presentation.

Strengthen and supporting the Drupal community is a shared goal over every Drupal related Open Collective, whether it is providing testing environments, video recordings, cloud hosting, camps, or a powerful, flexible, and open source form builder.

Please consider backing the Webform module or any Drupal related Open Collective.

Support the Webform module

Almost done…

We just sent you an email. Please click the link in the email to confirm your subscription!

OKSubscriptions powered by Strikingly

Mar 11 2019
Mar 11

DrupalCon Seattle is about a month away, and we're putting the finishing touches on this year's plans. Drupal's biggest annual conference affords us the opportunity to support the project, share our expertise, and connect with our colleagues from far and wide. We love DrupalCon. Here's what we've got in store this year.

Our Booth & Swag

Come by the Chromatic booth, #516 in the exhibit hall, to pick up some free Chromatic swag. No kidding, our t-shirts are the softest/coolest and we've got an awesome new vintage design this year:

And we made some kick-ass stickers for this year's conference too:

Our Sessions

Introduction to Drupal 8 Migrations - Clare Ming

Migrations can be intimidating but with Migrate modules now in core, it’s easier than ever to upgrade or migrate legacy applications to Drupal 8. Let's demystify the process by taking a closer look at how to get started from the ground level.

In this session we’ll cover:

  • A brief overview of the Migrate APIs for importing content to Drupal 8, including Migrate Drupal's capabilities to move content from a Drupal source.
  • Understanding your migration pathway.
  • Getting your site ready for migrated content.
  • Sample migration scripts and configuration files for migrating nodes and field mapping.
  • Consideration of media entities, file attachments, and other dependencies.
  • Using Migrate Drupal UI and Migrate Tools for managing migrations.

For those new to Drupal, this session will introduce the basic concepts and framework for setting up your Drupal 8 migration path successfully.

Time: 04/10/2019 / 11:45 - 12:15
Room: 609 | Level 6

Configuration Management: A True Life Story - Nathan Dentzau

Long gone are the days of copying databases, creating a custom module, or creating features to push new functionality to your Drupal Website. Those days and arcane methods are a thing of the past with Drupal 8. Why or how you ask? Read on my friend, read on!

Managing configuration in Drupal 8 has become much easier with the introduction of configuration management. In this talk, we will review “good practices” Oomph and Chromatic have established for configuration management, what tools we use on all of our Drupal 8 projects and how to use them. We will also discuss how configuration management ties into a Continuous Integration pipeline using Github and Travis-CI.

We will discuss the following list of modules:

  • Configuration Manager
  • Configuration Split
  • Configuration Read-only mode
  • Configuration Installer

What you can expect to learn from this talk:

  • Automating configuration management in a Continuous Integration pipeline
  • How to export and import configuration in Drupal 8
  • How to manage configuration in version control
  • How to manage configuration for multiple environments
  • How to install a new instance of Drupal with a set of existing configuration

This talk is for all skill levels and aims to make everyone’s life easier through the magic of Drupal Configuration Management. We look forward to sharing our experience with you and answering any questions you may have.

Time: 04/10/2019 / 12:30 - 13:00
Room: 612 | Level 6

Ridding the world of bad websites. - Dave Look

"Ridding the world of bad websites." This is our compelling saga at Chromatic. We've spent years growing and evolving as a team and it has taken time for us to land on this phrase as our compelling saga. In this talk, we'll explore the idea of a compelling saga for an agency, what it is, and why it's important. This concept comes from a book titled "High Altitude Leadership" where the author explores leadership principles learned from mountaineering expeditions. We'll discover how these same leadership principles can be applied to our industry.

We will cover:

  • What a compelling saga is and why you should have one for your Agency.
  • How these change and evolve as your agency grows.
  • The cultural impact of all team members being able to articulate the compelling saga.
  • How buy-in or lack of can mean life or death of your agency.

Time: 04/10/2019 / 13:00 - 13:30
Room: 6C | Level 6

Preprocessing Paragraphs: A Beginner's Guide - Larry Walangitan

Paragraphs is a powerful and popular contributed module for creating dynamic pages in Drupal 8. Preprocessing allows us easily to create and alter render arrays to generate tailored markup for any paragraphs type.

In this session you will learn about:

Getting started with preprocessing paragraphs and structuring your preprocessing methods. Creating custom render arrays and overriding twig templates. Referencing nested entities and pulling data into paragraph twig templates. How to debug your preprocessing and twig files using contributed modules or composer packages without running out of memory.

You'll leave this session ready to preprocess paragraphs and have a plan of action to reference when debugging any issues. This session is perfect for site-builders or back/front-end devs that are new to preprocessing in Drupal 8 and Twig.

Time: 04/10/2019 / 16:00 - 16:30
Room: 608 | Level 6

If you're coming to the conference, we'd love to meet you. Come say "hello", grab some swag, and tell us how you use Drupal....oh, and if you're looking for a job, our booth is a great place to make an impression on us!


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