Upgrade Your Drupal Skills

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

See Advanced Courses NAH, I know Enough
Jul 20 2020
Jul 20

Most Drupal devs are familiar with hook_entity_access(and its cousins hook_ENTITY_TYPE_ID_access and hook_node_access). However, it is mostly used for serving “403: Access denied” to browsers.  And we use a separate hook, hook_form_alter to disable edit buttons on admin pages like content overview pages, node form edit and taxonomy form edit:

hook_form_alter vs. hook_entity_access

It would be more beneficial to use hook_entity_access to disable access to the buttons. Disabling view, edit or delete (where applicable) via hook_entity_access will handle the following all at once.

Advantages of using hook_entity_access

1. Serve 403 pages

As mentioned above, this is the typical use for hook_entity_acess. Users will be served 403 if access denied is returned by the hook.

2. All views listing page with entity operations

All views entity operations are already handled.  This is the most significant benefit, as you don’t have to hook_form_alter each of the listing pages in your site.  By default, it will respect hook_entity_access.

hook_entity_access defaultdefault entity operations in views

3. Core Node Form / Taxonomy Form (Any default entity form)

The entity form delete button respects hook_entity_access, as is shown by the following image that depicts the delete button in the Drupal node admin interface.

hook entity access

4. Tabs / Local Tasks

The default core edit/delete tabs also respect hook_entity_access, as is shown by the following image depicting the admin tabs available for editors.


5. $entity->access() checks

$entity->access(‘view|update|create|delete’) respects hook_entity_access. So in code, a deny in hook_entity_access ‘view’ operation will also result in a deny in $entity->access(‘view’).  

At the heart of what we have talked about above relies on this behavior.  All items above internally execute $entity->access() checks.

Caveats on using hook_entity_access:

1. Allow / Deny rules

If at least one module issues a deny, then it will result in access denial, even if your module provides an allow access (other modules should only set a neutral access so that it does not inadvertently deny access to the entity). 

At least one module must provide an allow access to an entity in order to provide access.  If all modules give a neutral response, then it will result in an access denial.

2. $entity->access also respects the node permissions page (for node entities) in conjunction with hook_entity_access()

In the Permissions (/admin/people/permissions) page, you can set whether a certain role has access to edit, delete (own/any) content type.  Internally, this also provides an access result allow when enabled, and the same Allow/Deny rules above apply.

This must be taken into consideration when combining hook_entity_access with permissions page.  So even if you issue a neutral access, you might wonder why something is still giving access.  This might be given through the permission pages.

3. Other operations

By default, Drupal core provides ‘view’, ‘update’, ‘delete’, ‘create’ access.  And you can further filter the access via operation type.  Internally, this translates to $entity->access($operation).  

Modules like content translation provide other entity operations apart from the basic ones above.  In particular, content_translation core provides a ‘translate’ operation. In your hook_entity_access.  You can then expect a value of ‘translate’ on $operation, when for example, rendering the translate button on the pages described above.

You can find hook_entity_operation[_alter] in order to define/alter entity operations.

Additionally, the other operations might intentionally depend on the ‘view’ operation, etc.  In particular, content_translation module also depends on the ‘view’ operation in showing the translate button.  Denying access on view operations will also deny access to the translate button.  So special conditions must be added for such instances.

caching based on theme and entity


4. Caching permissions

Be sure to set proper caching to AccessResult returned by hook_entity_access.  

In this example, $entity was added as a caching dependency to AccessResult and also the current theme used.

caching based on theme and entity

Looking for Drupal consultation and support for your complex website development?? Contact us today.

Jul 20 2020
Jul 20

Part 1 | Part 2

Emerging approaches to front-end development portend a very different world from the one we live in today with regard to handling and juggling components. After all, new best practices promulgated by the likes of JavaScript technologies like React are overturning our preconceived notions about components and our foregoing definitions. For instance, React now contains both declarative rendering of components through JSX and efficient document object model (DOM) diffing through the concept of Virtual DOMs. Despite all of this progress, however, content management systems (CMS) like Drupal and others have not kept pace with the rapid change in how components are realized in front-end ecosystems. Can they ever catch up?

Fabian Franz (Senior Technical Architect and Performance Lead at Tag1) presented a well-attended session entitled "Components everywhere: Bridging the gap between back end and front end" at DrupalCon Amsterdam 2019 that articulated his dream vision for shared components across back end and front end in Drupal's own native rendering. He recently rejoined Michael Meyers (Managing Director at Tag1), and me (Preston So, Editor in Chief at Tag1; Senior Director, Product Strategy at Oracle; and author of Decoupled Drupal in Practice) for a Tag1 Team Talks episode spotlighting some of the ways in which his thinking has evolved since then and what Drupal will need to do to enable a more robust component-driven rendering approach ready for the future. In this second installment of this two-part blog series, we examine what Drupal's next steps may need to be according to Fabian's vision in order to facilitate components everywhere.

Next steps for Web Components

Before proceeding, I recommend that readers interested in this topic check out the first installment of this blog series to gain all the background and context necessary to proceed. We ended the first installment of this two-part series with a discussion of how novel CSS paradigms are challenging long-held ideas about how to control components from the standpoint of their presentation. But there is also another key characteristic of components that we need to scrutinize: whether it is a layout or style component.

In Web Components, the distinction between layout and style components is realized in the Shadow DOM thanks to effectively scoped CSS. But unfortunately, Web Components are not declarative in that they are JavaScript-only and require you to load your component first through the Web Components API and then ensure that the browser can display said component correctly. According to Fabian, the ideal vision for Web Components is one in which the Shadow DOM can be leveraged declaratively and without any JavaScript needed whatsoever. Despite the fact that shims exist that can automatically traverse Shadow DOMs to find components (e.g. an <x-shadow-root> element), declarative Shadow DOMs are extremely challenging to implement, particularly when server-side rendering enters the picture.

Another recent project of interest to Fabian is Tome, a static site generator created by Sam Mortenson that integrates deeply with Drupal's render pipeline. According to Fabian's analysis, Sam succeeded in implementing a Shadow DOM analogue in Tome through classes, each of which approximated a Shadow DOM-like approach effectively enough to render an analogue to the component on the server. This got Fabian thinking. Because Web Components is still missing some crucial details, he admits that to implement a declarative Shadow DOM himself, he would leverage an abstraction for components (rather than Web Components) that would allow for a later distinction of React, Vue, or Twig as the renderer of that component. According to Fabian, the data flowing into a component is of far more importance than who is displaying or rendering it.

Taking inspiration from Inertia.js

Another project Fabian has taken inspiration from is Inertia.js, a JavaScript library that begins to approach Fabian's ideal goal of being able to write a single-page application without a single line of JavaScript. With bindings for Laravel and other server-side technologies, Inertia.js allows developers to write normal controllers as they are used to on the server side and set them up in such a way that they return data. As such, if only the data in a component changes, the templates will change on the client side, and the data can be fed to Vue or other frameworks for ingestion. Meanwhile, if the entire context of a component changes, Inertia.js will undertake a full server-side request.

Fabian believes that Inertia.js doesn't go far enough, because it focuses on the notion of individual pages rather than the highly granular page components in which Drupal trafficks. In Drupal, for instance, there are blocks and forms that occupy portions of the page but that each leverage their own complex APIs. Thanks to the Dynamic Page Cache module in Drupal 8 (also leveraged by Wim Leers' RefreshLess module), we can identify how similar a page is to a particular page layout and only update those page sections that have been modified.

Next steps for Drupal

Well after the conclusion of his talk, Fabian returned to his ideas and clarified for himself what would be required and what could be descoped from a "components everywhere" feature set. Many technologies he investigated since his DrupalCon Amsterdam session solve only one part of the problem he has outlined and provide robust approaches for those problem spaces. This led Fabian to recognize that the need to start simple is paramount. For instance, he confided in our recent Tag1 Team Talks episode, Drupal could theoretically learn significant new knowledge from Laravel's renderer and leverage their syntactic features for Drupal's own Components module, created by John Albin Wilkins.

After DrupalCon Amsterdam, there was considerable interest in "components everywhere" in Drupal, but Fabian also acknowledged that the level of interest from the community was much higher than that from core maintainers. Fabian next plans to look to the wider front-end community for next steps to move the proposed vision forward. And he planned to deliver a session at Frontend United in Minsk about those subsequent steps. Fabian still believes that his vision of completely decoupling the data is more difficult than something akin to Livewire where data definitions and data updates are both present within the same component.

Distinguishing interactive components

Drupal has a substantial opportunity to offer a means of registering components that have dynamic versus static data (that does not change unless a full-page request is executed). Similarly to how Dynamic Page Cache currently provides an initial skeleton that is then fleshed out with progressively more data to fill out the components in question, Drupal could define a means for components to indicate less need for rehydration than others. Moreover, Drupal could facilitate the creation of static pages without any JavaScript whatsoever for pages having only components that work with static data.

Because determining interactivity is something the front-end development world has not solved completely, Drupal could take the lead in allowing developers to resolve automatically what portions of pages need to be interactive or not. Fabian even envisions the possibility of a language in which we could declaratively assign interactivity to particular blocks on a page that are considered components. A scenario such as one in which a block should be more interactive due to a button lying therein that updates block content to the most recent version would be readily solvable under this approach. Giving the developer the ability to specify the level of interactivity of their components would not only lend greater power to defining cacheability but would also reduce the need to push the entire DOM tree to the page rather than only the portions that have changed.

Interactive components in other ecosystems

Other ecosystems indicate that this thinking is nothing new. After all, React's new hooks API attempts to approximate a typical page request, and Fabian argues that the core idea behind both GraphQL and React hooks is the ability to write code as if it were a traditional PHP application again. He believes that Drupal has significant opportunity at the moment to reenter the front-end landscape and reinvent the front-end developer experience in Drupal, thanks to the inspiration represented by ecosystems like Laravel, a frontrunner in front-end innovation when it comes to open-source successes.


Components are nothing new to front-end developers, but they have undergone such substantial evolution from a conceptual and technological standpoint over the last decade that they are virtually unrecognizable to traditional content management systems like Drupal that have retained a server-oriented approach to component management. When it comes to JavaScript, on the other hand, technologies like React have shown that the modern front-end developer experience must involve declarative rendering and Virtual DOM-driven diffing. Moreover, a shared sense of components across server and client are needed to enable universal JavaScript applications and to contend with a world in which data can be rendered in virtually any environment and by any system.

In this two-part blog series, we identified some of the ways in which next steps for Web Components and for Drupal could take inspiration from technologies like Laravel's Livewire and Inertia.js as well as React's JSX and the Shadow DOM. Fabian recommends anyone interested in component-driven front-end development in Drupal to join the #components channel in the Drupal Slack, where he will work to formulate a more formal proposal for review. In addition, Fabian recommends that developers take a look at BladeX and whether a similar x- prefix for Drupal components could be possible, such as <x-entity>. What would a simple alert or other Web Component look like in this context? It may still be early days for components everywhere in Drupal, but the initial steps are uniquely promising.

Special thanks to Fabian Franz and Michael Meyers for their feedback during the writing process.

Part 1 | Part 2

Photo by Raul Cacho Oses on Unsplash

Jul 20 2020
Jul 20

Last week I had the opportunity to attend PSEWEB 2020, Canada's annual digital marketing conference for colleges and universities.

While it would have been nice to attend sessions and meet attendees in person (the conference was originally supposed to take place on the McGill campus in Evolving Web's home city of Montreal), it's safe to say that the virtual version of the event was still a success.

PSEWEB streaming platform Screenshot of the PSEWEB virtual streaming platform, with the chat open in the right-hand column.

The streaming platform worked like a charm, the chat and live Q&A features added depth and dimension to each presentation, and the presenters nailed their sessions despite having to deliver them in front of a screen rather than a live audience.

As a newcomer to the Canadian higher ed space, I really enjoyed the friendly community vibe surrounding the event. Attendees and speakers alike seemed truly eager to share their experiences and help each other work through the industry's unique digital marketing challenges. The only downside was having to choose between two simultaneous sessions but that's always a dilemma IRL as well.

I've tried to pick out a few highlights among the presentations I did get to attend, but they represent just a fraction of the insights and knowledge that were shared over the two-day event.

Running Successful Large-Scale Campaigns

In her presentation "I've got 99 audiences and I need them to be one Breaking through the digital noise to reach your people", McGill University's digital strategy director Taylor Valee shared her insights on how to focus your marketing efforts when you're targeting a broad demographic.

Marketers, Vallee says, have a hard time defining specific audiences especially when it comes to things like large fundraising campaigns, which typically target a broad range of users.

Through the story of McGill24, the university's annual 24-hour fundraiser, Vallee shared a relatable tale of fundraising teams wanting to target everyone, and how communications and marketing departments can help focus those efforts by defining specific audience segments.

So how should you go about defining those audiences? The key, according to Vallee, is to know the numbers. In this case study, the McGill team looked through several years' worth of data and ended up pinpointing four key audiences to target. Then, they used a variety of tactics across multiple channels to reach those audiences where they were and speak to them in an authentic way, with a common goal of inspiring donations.

The question they would ask is a simple but crucial one: "What does this audience want to see, and how do they want to see it?".

The results were clear: audience segmentation pays off. The team's data-driven targeting strategy paved the way for the biggest day of donations in the history of the event.

Not Being Afraid to Start Over

McGill digital design manager Heidi Stroll's presentation focused on how the university redesigned its homepage in 2019... and then redesigned it again, that same year.

The redesign was a pilot project for the university: it was the first of its kind to be carried out collaboratively between multiple departments. The double redesign of 2019 was a lesson in collaboration and stakeholder management, and it also taught teams about the importance of truly understanding the purpose of their work.

The major takeaway: don't fall for the old sunk cost fallacy. If something isn't working, you need to take a step back, understand exactly why things aren't going as expected, and take those insights back to the drawing board.

Creating Content Strategies for Higher Ed

The University of British Columbia's digital marketing strategist, Houston White, gave a fantastic session detailing his experience building a content strategy for UBC. Looking back a year after kicking off the strategy, he shared his insights on what worked and what didn't.

For starters, the content team put together a brand wheel outlining crucial messaging components such as:

  • Their functional offering
  • Their emotional offering
  • Their brand story
  • Their frame of reference

This helped them define an overarching message for their marketing efforts as well as identify where they should be telling which stories. They then launched a cross-channel brand campaign whose goal was to bridge the gap between perceptions of the university and the reality of its brand story.

To do this, UBC focused on conveying a unified message but tweaking its delivery depending on the location of its audience. The university needed to take a different approach when targeting local prospective students, who were already aware of the university as an option for their studies, than for out-of-province audiences, for whom UBC was largely unknown. The results of this multifaceted campaign were extremely positive, with significant gains in brand awareness among prospective students in other provinces and a higher level of affinity with the UBC brand among British Columbia locals.

Understanding your users to build better experiences

Evolving Web co-founder Suzanne Dergacheva shared some secrets to building better experiences using techniques from UX research and content strategy. Featuring examples from two higher ed clients we worked with recently, Princeton and McGill, her session outlined various tactics that every higher ed marketer should have in their toolbox.

A slide from PSEWEB 2020 outlining why user experience is important for higher ed A slide from Suzanne Dergacheva's PSEWEB 2020 presentation highlighting the importance of user experience for higher education websites

Attendees were able to see how the Evolving Web team mapped out the steps prospective students typically follow when choosing a school, and learned how to translate those findings into a persuasive, cohesive website experience.

The session also outlined the components of a strong UX practice and explored how to interpret the results of user research. One of the main takeaways was the importance of creating a process around your UX practice and sharing resources and results across campus.

Figuring Out the Smartest Way to Spend a Media Budget

Adriann Kennedy, communications manager for University of Waterloo's faculty of mathematics, shared an inspiring and humorous! tale of trial and error in her presentation "Google can't fix everything (or, how we made the most of our ad fails)".

A common thread in many of the sessions I attended was front and centre here: you need to understand the numbers. Kennedy, who works mainly with mathematicians and prospective math students, shared how important data is when it comes to allocating money and resources to marketing and promotion.

Another important lesson learned is that small changes are better than no changes at all. If you're not 100% sure of the direction you're taking, make changes incrementally, then take a step back and measure the impact. Rinse and repeat until you've built a full campaign.

Finally, Kennedy reminded the audience that you're not alone in wanting to improve how you're promoting your story. Find your champions, whether they're students or faculty, and partner with them to tap into a wealth of authentic messaging that's sure to resonate with the people you want to reach.

Top 3 Takeaways

If I had to pick the three key messages I took away from PSEWEB, it'd be these:

  • Numbers are crucial, and not all pieces of data are created equal. Collecting, understanding, and utilizing the data at our disposal is a skill that every marketing team needs to focus on constantly improving.
  • Understanding your audience means more than just drafting a standard-issue persona. It also means digging deeper into users' wants, needs, behavioural quirks, and mental models in order to match their expectations in the experiences you deliver.
  • User-created content is extremely powerful, as long as you have well-defined guidelines and publication criteria in place.

Is Your School's Digital Presence Due for a Redesign?

In addition to speaking and hosting a workshop, our co-founder Suzanne represented Drupal at the conference on behalf of the Drupal Association. Drupal, an open-source CMS, sponsored PSEWEB 2020 as part of its Promote Drupal initiative, which aims to spread the word about Drupal to the wider community. You can learn more about Drupal by joining our free upcoming intro to Drupal webinar. If you're already familiar with the platform and would like to contribute, read about the Promote Drupal initiative.

If you didn't make it to PSEWEB 2020, here's hoping we'll see you there next year! In the meantime, if you need a hand creating high-quality online experiences for your students, prospects, alumni and staff, get in touch with Evolving Web. Our team of Drupal experts specializes in design and development for large institutions like universities and colleges, and we'd love to hear about your next big project.

Jul 19 2020
Jul 19

If Stanford University had been handing out Social Engineering degrees, Peta Hoyes would have graduated magna cum laude. Instead, she leveraged their Mechanical Engineering program as a launch pad for using technology and digital media to build practical solutions for extraordinary people. The one-time entrepreneur and current manager at Tag1 Consulting has finessed all aspects of the website development process for a diverse client list.

What drives her is making technology transparent and usable; creating highly efficient virtual teams; and furthering the mission of game-changing organizations using open source technology.

While managing Tag1's distributed team of unparalleled performance engineers from her home base in New York City, she likes to say that she optimizes the team who optimizes the machines.

Jul 18 2020
Jul 18

Nils Adermann, co-author of the Composer project, joins Mike Anello to talk about the past, present, and future of Composer. Ryan Price and Mike chat about the chat about the DrupalCon Global chat system and the future(?) of global Drupal virtual events.

URLs mentioned

DrupalEasy News

Audio transcript

We're using the machine-driven Amazon Transcribe service to provide an audio transcript of this episode.


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

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.

Jul 18 2020
Jul 18

If you use swiftmailer + simplenews, you may want to send html email with custom css.

To achieve that,you have to customise 2 twig templates.

The first template is the default template that is provided by swiftmailer: simplenews-newsletter-body.html.twig.

You can use this template to build your own email body with content you like to use. For example, in the template below, an hero image is inserted using table layout.

   <table aria-hidden="true" border="0" cellpadding="0" cellspacing="0" >
          <td class="align-center">
            <a href='[node:url]'><IMG class="hero" src="https://arrea-systems.com/format-html-email-simplenews-swifttmailer/path-to-image"/></a>
    <table role="presentation" border="0" cellpadding="0" cellspacing="0">  
             {{ build }}
             {% if not opt_out_hidden %}
              {% if format == 'html' %}
                <p class="footer"><a href="https://arrea-systems.com/format-html-email-simplenews-swifttmailer/[simplenews-subscriber:unsubscribe-url]">{{ unsubscribe_text }}</a>
              {% else %}
              -- {{ unsubscribe_text }} : [simplenews-subscriber:unsubscribe-url]
              {% endif %}
            {% endif %}

    {% if key == 'test' %}
        - - - {{ test_message }} - - -
    {% endif %}

You can rename the file following the naming convention for twig template and place it into you theme templates folder:

 * Copy this file in your theme directory to create a custom themed body.
 * Rename it to override it. Available templates:
 *   simplenews-newsletter-body--[newsletter_id].html.twig
 *   simplenews-newsletter-body--[view mode].html.twig
 *   simplenews-newsletter-body--[newsletter_id]--[view mode].html.twig

Once you have designed you email body you need to design the swiftmailer template with the required css style. to do that, create a file called swiftmailer--simplenews.html.twig into the same template folder as the previous file. You can build your html file with inserted css style following the sample structure below.

            /* insert your css style */
    <body class="body">
      <!-- content -->
      <table role="presentation" class="main">
          <td class="wrapper">
            <table role="presentation" border="0" cellpadding="0" cellspacing="0">
                  <div class="content">
                  /* content formated by  simplenews-newsletter-body */
                  {{ body }}
      <!-- footer -->
      <table class="footer">
            /* option footer */

With this technique you can design any type of email newsletter with rich content that adapt to desktop and mobile displays.

example template
Jul 17 2020
Jul 17

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

We are targeting to release Drupal 10 around June 2022. That is less than two years from today!

Why so fast, you ask?

Drupal 9's biggest dependency is Symfony 4, which has an end-of-life date in November 2023. This means that after November 2023, security bugs in Symfony 4 will not get fixed. Drupal has to adopt Symfony 5 (or later) and end-of-life Drupal 9 no later than November 2023.

For security purposes, all Drupal 9 users will need to upgrade to Drupal 10 by November 2023. We like to give site owners at least one year to upgrade from Drupal 9 to Drupal 10, therefore we are targeting Drupal 10 to be released in June 2022.

A timeline showing that Drupal 10 is targeted for June 2022 because Symfony 4 is end-of-life in November 2023.

Will the upgrade to Drupal 10 be easy?

Yes, it will be easy, and here is why.

New functionality for Drupal 10 is actually added to Drupal 9 releases. This means module developers can start adopting any new APIs right away. Along the way, we deprecate old functionality but keep backwards compatibility. Once we are ready to release Drupal 10, we remove all deprecated code. Removing deprecated code breaks backwards compatibility, but because module developers had a chance to stay up to date with API changes, the upgrade to Drupal 10 should be easy.

If that makes your head spin, think of it this way: Drupal 10 is identical to the last version of Drupal 9, with its deprecations removed. Because of that, there should be no last-minute, big or unexpected changes.

We used this approach for Drupal 9, and it was successful: 95 of the top 100 contributed modules were ready the day Drupal 9.0.0 was released. We know from Drupal 9 that this approach to upgrades works, and we'll continue to refine it going forward.

Jul 17 2020
Jul 17

Well, day 3 of DrupalCon Global delivered again. It's been a whirlwind 3 days full of good content and meeting lots of people new and old. Blake captured the general feeling of this 'con,

I was very skeptical of a virtual DrupalCon (especially as someone who didn't attend at all last year). Although I missed the first day, I'm really glad I had the time and opportunity to engage with the event. Seeing so many new faces presenting was also wonderful. DrupalCon Global was a great way to reconnect with folks in the community, and still be able to have dinner with my family in the evenings. Two thumbs up, would attend again.

Contribution Day

While sessions are over, don't forget that today, Friday, is the traditional contribution day. You'll need to sign up on the DrupalCon Global Contributions Room site, and it's open to everyone--no DrupalCon ticket required. There are many different kinds of groups that require a wide range of skills, with plenty of space for non-coders. If you're not sure how to get started, there is a page that explains how to take part in Mentored Contribution, which will walk you through the whole process.


We were definitely starting to feel some brain overload on the third day of so many sessions. There were some really good ones though on this last day of the session schedule. We also had 2 of our team, Amber Matz and Joe Shindelar, presenting on Thursday, so make sure to check those out when the videos come up.

Amber's session: Deep dive: state of Drupal (Link to slides with presenter notes)

Joe's session: Altering, extending, and enhancing Drupal (Link to session resources)

And here are the random notes from the sessions we attended yesterday.

The Olivero theme: Turning a wild idea into a core initiative

  • Drupal core ideas is a great place to find collaborators, and share ideas for potential projects
  • Documentation, identifying stakeholders, and having diverse skillsets on the team were key to the projects success.
  • Building a static POC on Netlify, and using Tugboat allowed folks to get involved and contribute earlier than if they had gone straight to a Drupal theme.
  • Drawing the line between must haves and nice to haves was important to maintain project momentum and contributors' mental health

Designing for Chaos: The design process behind Olivero

  • The main motivation for Olivero: to create a better first impression with Drupal
  • The team named the theme in honor of Rachel Olivero, who worked at the National Federation of the Blind, and who was committed to making tech accessible to all people
  • Validating the design: "The first draft of anything is shit"- Ernest Hemingway
  • The "flaw of averages" (if you want to design something for an individual human being, the average is completely useless) and how the designers worked to avoid it.
  • Spectrum analysis that was used to establish voice and tone (formal, bright, approachable, high contrast)
  • In order to be able to iterate more quickly defined a core set of stakeholders to help with initial designs before showing to the general community. This helped eliminate low hanging fruit issues (e.g. broken accessibility) that would have been blockers no matter what. This allowed the broader community to keep the discussion focused on bigger picture things.
  • Cool use of Invision app to allow stakeholders to rank things on a scale. They created an image with lines and good ---------------- bad and then people could leave their comments in Invision somewhere along the line. Since comments show as little red circles you could clearly see ranking. And discussions could take place in the comment threads.

(Philippa) As a non-tech person, what I liked about these both Olivero presentations was how they laid out the thought processes linking the idea to the core initiative, and how they advocated for the idea that led to the new default front-end theme for Drupal 9.

Intermission: Desk yoga with Gabrielle Rickman

Sooo good. While some people on the team opted for a breakfast intermission, others of us got a very nice break of stretches to do in your chair. Useful for any conference, but extra refreshing at an online event.

Driving today's CMS with tomorrow's artificial intelligence

  • What is artificial intelligence (AI), machine learning(ML)? ML is a subset of AI. ML is not smart enough to evolve itself.
  • Uses in business:
    • Advanced automated interaction with customers
    • Identifying patterns in behavior
  • Where can Drupal use this?
    • Content moderation
    • Analyze customer mood
    • SEO
    • Chatbots
    • Personalization
    • Visual search
  • How do you do this? Are you ready? Do you have a plan for this in your org?
  • APIs to use
    • Azure Cognitive Services API (multiple APIs: vision, speech, etc.)
    • Google Vision API (this is much bigger than the Azure Vision API)
    • Drupal modules exist for these APIs
  • Really neat to see examples of how this can be used for content management. Nice live demo and some really cool things you can help automate.

Open source belongs in school--Let's put it there!

A presentation by a teacher and his students, The Penguin Corps, about how they are using Open Source. Led by the students.

Software for a diverse community starts with a diverse team

Highly recommended. Really great session that addresses a lot of questions about diversity AND inclusion, and looks at how to create inclusive work agreements with clients and vendors.

MagMutual.com: On the JAMStack with Gatsby and Drupal 8

  • Decoupled architecture
    • volatility based decomposition of feature requirements
    • Drupal (CMS) / Gatsby (Website) / Serverless (AWS Deployment) / Bus. Logic (Lambda) / Apollo GraphQL (User Data) / ElasticSearch (Search) / Auth0 (User Identity)
    • Briefly walked through the features and benefits of each of these components
    • (notes for our potential future use: Drupal Elasticsearch AWS connector module, AWS lambda rate limiting, Gatsby searchkit plugin)
    • Serverless framework: not really used on live code, but helped with (by allowing folks to avoid using AWS console)
      • deployment
      • mocking
      • testing
      • logging
      • local development
      • project structure
    • Living with it - ongoing support
      • harder to debug integration points, more things to support, onboarding
      • Apollo GraphQL is a huge win (helps set up data structure schema, and force thinking about it), improved performance, adding new design assets is faster

Shift Left: Addressing Digital Inequity for the Black Community

Another highly recommended session. We'll be watching this again when the video goes up.

  • Designing tech for people without a detailed and rigorous study of people makes the kinds of tech designs that we see come at the expense of people of color and women (rough quote from Algorithms of Oppression)
  • Understanding the effects of systematic dehumanization of Black individuals
    • Sylvia Wynter (No Humans Involved)
    • Aime Cesaire (Discourse on Colonialism)
  • Hegemony's role determines which products are created, and which problems are prioritized
  • The continued exclusion of Black people from technical creation
    • Blackness as an afterthought (film)
    • Black input is consistently missing from product development (2.5% of employees at Google 2018, 3.3% of technical employees at Microsoft 2019)
    • Double Consciousness
  • The Digital Divide
    • Having less access to technical skill development enhances the divide, and makes being part of solving the problem through product creation more difficult
    • Beware software, PredPol algorithmic biases & flawed training data in machine learning systems leading to systemic injustices
  • How can we move forward?
    • Reframe perspectives (equitable and fair predictive algorithms)
    • Actually address the issues
    • Intentionally Carve Space - tokenism and quick fixes won't solve lack of equity

Hacking live! A realtime look at website security

  • Don't trust user input, even admin form input.
  • Use Form API. It provides XSS cleanup on output by default. (Drupalize.Me tutorials: Forms (Form API))
  • Avoid using the raw filter in Twig. (Twig auto-escapes strings and the raw filter removes that safety net.) (Drupalize.Me tutorials: Twig Filters and Functions)
  • XSS exploits can be stored both in cache and database. (Sanitize output that is coming from a cache.)
  • DDOS (Distributed Denial of Service). Hitting a page with a slow function at a large scale (relatively speaking) can take the site down.
    • Limit form submissions to prevent flooding.
    • Move slow functions to asynchronous queues.
  • Access Bypass
  • Use PHP CodeSniffer to Find Errors.
  • Module plug from the chat: Content-Security-Policy
  • Dries attended the session and he shared this link to his site: HTTP Headers Analyzer

Altering, extending, and enhancing Drupal

  • Check out Joe's resources
  • Don't hack core. (Alter and extend instead!)
  • Let others change your module, without hacking it. (This is super powerful!)
  • Ways to alter, extend Drupal:
    • Respond to an event (a user is logging in)
    • Drupal wants to a question (does anyone have a block they want to add to this list?)
    • Add code that adds new functionality
    • Make a change to existing functionality (change fields on a login form, for example)
  • Don't hack core. Instead use one of these systems.
    • hooks
    • plugins
    • services
    • events

Adapting your DE&I efforts to the reality of the crisis

Importance of creating safe spaces for people on your team to talk about their struggles and/or to get to know one another better. This could be through one-on-ones or regular online social events. (Physical distancing, not social distancing.)

Inclusive content strategy

"People want to be seen as equal participants and not afterthoughts."

  • (Philippa) LOVE that she called out hiring language that speaks to whether people are a good "culture fit" in businesses and organizations - because people shouldn't have to conform culturally - and how content that communicates aligned values is a great alternative.
  • Some of what inclusive content means:
    • Predictable structure, (like nesting and heading orders) for easy navigation
    • Color contrast/font/distinguishable links
    • Short sentences (9th grade reading level) and plain, jargon-free language
    • Bullets and number lists
    • Imagery with captions, subtitles, text alternatives (which also helps those with poor internet connections)
    • Closed or open captions - which also helps those whose first language isn't English
    • Minimizing or avoiding emoticons, which are hard for screen readers

We'll be posting a wrap-up of the overall DrupalCon experience for our team, including today's contribution day, some time next week. We hope you've had a great 'con and hope to see you at the contribution day. If you see anyone from our team, please feel free to say "Hi!".

Jul 16 2020
Jul 16

Baddy BreidertDuring DrupalCon Global, the members of the Drupal Community Working Group announced the winner of the 2020 Aaron Winborn Award, Baddý Breidert (baddysonja).  

The award is named after a long-time Drupal contributor who lost his battle with ALS in 2015. This award recognizes an individual who, like Aaron, demonstrates personal integrity, kindness, and an above-and-beyond commitment to the Drupal project and community. Previous winners of the award are Cathy Theys, Gabór Hojtsy, Nikki Stevens, Kevin Thull, and Leslie Glynn. Current CWG members, along with previous winners, selected the winner based on nominations submitted by Drupal community members.

Baddy has been a member of the Drupal community for over nine years, and is the co-founder of 1xINTERNET based in Germany, Iceland, and Spain. She has been a relentless force for good in the Drupal community as one of the co-organizers of Drupal Europe 2018, Northern Lights and Solstice DrupalCamps (Iceland), local and international Splash Awards, and as an extremely active member of the German Drupal community. She is also currently a member of the Drupal Association Board of Directors.  

Multiple people nominated Baddy for this award. Here are some of the things they said:

She has consistently and tirelessly worked for the good of Drupal across event organisation (Drupal Europe), in Drupal Agency life promoting Drupal to wider audiences and running an ethically grounded business (which contributes back in bucket loads).

She has been an amazing force in so many areas to even count. As a community organizer on crucial events like Drupal Europe to [foster] a contribution culture at her company. Then spreading the word about how that makes the best business sense. She cares so much for diversity and inclusion at her company and in the Drupal community as well.

This year, there were 22 individuals nominated for the award. In the coming weeks, the CWG will be contacting all nominees to let them know of their nomination and thank them for their continued work in the community.

In addition to the physical award shipped to Baddy, she was also provided with a free ticket to DrupalCon Global which she graciously donated to Surabhi Gokte. The physical award that was hand-crafted by Drupal community member Bo Shipley (simplyshipley).  

Nominations for the 2021 award will open in early 2021.

Jul 16 2020
Jul 16

The Notification Message module for Drupal 8 lets content editors quickly and easily publish configurable notifications. It can create site-wide notifications, conditional alerts, or other site messages — all using a consolidated UI that doesn’t require editors to stitch together functionality with complex combinations of core and contributed modules.

Have your organization’s hours of operation changed for the holiday? Is a specific product on backorder? Has a service area been affected by a storm system? No matter who needs to read it, what it needs to say, or when it needs to be automatically published and unpublished, Notification Message makes crafting messages to users simple.

The Nashville Public Library website with a prominent notification banner deployed with the Notification Message Drupal 8 module. Nashville Public Library uses the Notification Message module for Drupal 8 to deploy notification messaging specific to distinct audience segments in a bright, clear yellow banner.

I built the Notification Message module to help Nashville Public Library broadcast site-wide or contextual messages to their customers via time-boxed notification banners. Their previous system, built on Drupal 7, used separate content types for each variety of notification, and relied on configurations completed elsewhere in the site (blocks, contexts, scheduled or manual publishing) to function properly. Notification Message provides a clean, natural editorial experience and bakes in a lot of configuration options.


Notification Message un-clutters the content management experience and provides simple but powerful tools for editors. Notifications are:

  • Published and unpublished automatically within a specified date and time range
  • Built using custom entities to maintain separation from the standard content publishing experience
  • Linked in the Content Menu right out of the box to slide naturally into the content admin UI
  • Highly configurable via conditions to show up when, how and to who you want
  • Extensible far beyond basic site-wide banner messages using custom fields, custom templates and custom conditions
  • Complete with granular permissions for both administering custom notification message types and managing notification content

Quickstart Guide

Setting up Notification Message — and your first notification — is simple. First download the Notification Message module using the composer workflow: composer require drupal/notification_message

If you need help with composer, check out using composer to download contributed modules on Drupal.org. Once the Notification Message module is available in your project, you’re ready to get started.

  1. Enable Notification Message via drush en notification_message or directly from the Extend page at /admin/modules
  2. Navigate to the Content page at /admin/content, then to the new navigation item Notification message
  3. Click Add notification message, choose the Global type (for now) and complete the entity edit form, making sure to select the appropriate theme under Notification Conditions / Current Theme, and a date & time range that includes right now under Notification Options / Message Publish
  4. After saving your notification, head to the Block layout page at /admin/structure/block and place the Notification messages block (via the Place block button) in the appropriate region

Mission accomplished! Now you’ll see your global notification in the region you assigned as long as the current date & time are within the date range you indicated in the Message Publish section of the entity edit form. You can create new notification message types from the Notification Message types page at /admin/structure/notification-message-types that can respond to diverse conditions such as Page URL, node attributes and user attributes — or any other conditions defined by your site — and can include custom fields and custom display configurations.

The Human Rights Watch website featuring a takeover lightbox delivered via the Notifications Message module for Drupal 8. Human Rights Watch used a fielded and conditioned implementation of the Notifications Message module earlier in 2020 to deliver rich form content in a Lightbox takeover to drive a donation campaign.

Custom templates for your custom notification types can override or extend the included notification-message.html.twig and notification-messages.html.twig templates for a variety of presentations — from the standard site-wide notification banner to whatever you can imagine.

Jul 16 2020
Jul 16

Drupal 7 to Drupal 8/9 migration is something that should bring a great value to your business. Numerous Drupal 8 improvements and its fully revamped architecture impressed everyone when the 8th version was released.

Since then, Drupal 8 kept rapidly moving to better admin usability, performance, accessibility, third-party integration, multi-language, and other most modern web practices. The 9th version arrived as an even cleaner version, boasting instant upgrades from D8, equipped with modern libraries to make sites faster, and with plenty of ambitious plans for future innovation.

You might be already tempted with the idea to migrate from Drupal 7 to Drupal 8 or 9, but there is something stopping you. You ask yourself: how much time does it take and how much does it cost to migrate from Drupal 7 to Drupal 8/9?

This question should better be answered on a case-by-case basis, but we will do our best to give you the estimated time and cost of Drupal 7 to Drupal 8/9 migration in this post.

Getting ready for your Drupal 7 to Drupal 8/9 migration

Migration is always a great chance to refresh or revamp your website in many ways. To make sure the upgrade brings you the best value, as well as help the development team give you more precise estimates of Drupal 7 to Drupal 8/9 migration, you will need to do a little preparation.

Rethink your business goals: what new priorities have appeared and how would you like your website to reflect them? And, vice versa, what is no longer relevant and should be cleaned up? Talk to your admins and content editors: what functionality is missing and what could be improved in order to speed up their routine tasks?

Based on this, developers will help you review your website’s modules, configuration, UX design, and more. Something will “travel” to the next level, something will be replaced by more modern alternatives, something will be cleaned-up, and so on.

How much time does it take to upgrade from Drupal 7 to Drupal 8/9?

The simplest of brochure sites without custom modules and with just a couple of content types can be migrated from within 30 hours. However, as the site complexity grows, the migration process extends. For some websites, it can take a couple of months. The larger, the more complex, and the more custom-heavy your site is, the longer it will take to migrate. Let’s see how it works.

  • Initialization. The essence of every Drupal 7 to Drupal 8/9 migration is to move your website’s configuration and content to the newly created clean site instance. Content includes blog posts, images, files, and similar elements, while configuration is about your content types, fields, views, comment types, and so on. Developers analyze all this and decide on the migration specifics. They also prepare a fresh Drupal destination site, update your source site to the latest minor version, enable the necessary modules, etc.
  • Custom module rewriting. An important point is that your website’s custom logic in the form of custom modules will need to be rewritten according to the Drupal 8/9 standards (object-oriented programming, or OOP). This might take up a lot of the migration time.
  • Automated or manual migration process. Thanks to the migration pack of modules, it’s possible to automate many standard processes. However, in many cases, manual recreation of elements (e.g. views) is also needed. To import the website’s data in various formats (XML, CSV, RSS, etc.), developers will need to define the source and the destination. Some projects require complex field mapping, which influences the time. If you need to reorganize the content structure, the time also extends.
  • Validation. When the data has been migrated, developers carefully check if there are no errors and if the fields have been correctly filled with the data.
  • Website launch. When everything is thoroughly checked, developers deploy your new and shiny Drupal 8 or 9 website to live.

That said, the hours of your migration grow in these cases:

  • You have many custom modules.
  • Your website has a lot of content types and content.
  • Your content types need to be reorganized (split, consolidated, etc.)
  • Your content is multilingual.
  • There are custom fields on your site.
  • There is a need to recreate many views.
  • You need a website redesign.
  • And so on.

It should be noted that, even in the most complex projects, the time of Drupal 7 to Drupal 8/9 migration can always be reduced if you wish. To achieve this, you can hire a larger number of developers to perform the migration.

How much does it cost to upgrade from Drupal 7 to Drupal 8/9?

The cost of the Drupal 7 to Drupal 8/9 migration will depend upon the time and the hourly rate. The hourly rates may differ across companies. InternetDevels, together with our support team Drudesk that specializes in migrations, rate $30 per hour on average.

That said, if a simplest brochure site takes 30 hours to upgrade from Drupal 7 to Drupal 8 or 9, the cost starts with $900. This looks very lucrative, doesn’t it?

Upgrade from Drupal 7 to Drupal 8 or 9!

Show us your website to our Drupal migration and upgrade experts team to discover the exact time and cost of your Drupal 7 to Drupal 8/9 migration. Our high-efficiency approach will allow you to save a lot of hours and budget. There is also something totally free — our consultation and our attention. Contact us!

Jul 16 2020
Jul 16

COVID-19 and recognizing racism as a public health threat spotlights the importance of health communities of practice and their need to have high-quality, data-driven discussions. How do we do data-informed conversations well?  How do we expand them to include more health professionals and more community members outside what is recognized as the healthcare industry?  Both are very clearly needed now.

Thanks to a client giving us a shout out, Agaric realized recently we've done a lot of health communities over the years and would love to talk and learn with others.  We're hosting a "Birds of a Feather" (people interested in the same topic coming together) at DrupalCon Global today at 3:15 Eastern Time to talk about facilitating discussion among healthcare practitioners and researchers and the public, and anything along community or data-sharing lines. 

Environmental racism was forced into the national conversation by Flint, Michigan years ago and COVID-19 has made long-standing problems of racism in healthcare provision impossible to ignore.  The rebellion against police repression started in Minneapolis is itself a reaction to the public health issues caused by policing which were predictable, and Minneapolis resident D.A. Bullock, indeed, predicted it.

What's the next steps for healthcare workers and researchers?  For any person who cares about our communities?  How do we move conversations within health communities and with outside communities forward, and never fall back to not caring?  The stakes for both well-informed and broad-based discussion are clearer than ever.  We know pressure, policy, and practice are what make change; what is our role?

Please leave your comments even if you can't join us today!

Jul 16 2020
Jul 16

Acro Media is proud to be a part of Google Summer of Code 2020 for the first time in it’s 15 year history. 

What is Google Summer of Code (GSoC)?

“Google Summer of Code is a global program focused on introducing students to open source software development. Students work on a 3 month programming project with an open source organization during their break from university.” - About | Google Summer of Code

Why is Acro Media involved in GSoC?

Introducing students to open source software development and helping drive open source coding forward are key mandates of GSoC, which is something Acro Media can definitely get behind. 

Improved coding and talented new developers are only going to make the Open Source Community stronger.

Student developers like Vishal Chaudary gain valuable mentorship and insight through a 3-month internship. 

Vishal was chosen to take part in GSoC as a student developer working on the Drupal Commerce Fraud Project. The project aims to port the Commerce fraud module to Drupal 8/9 with candidate level release. This includes updating the current module with adding new features compatible with latest versions of Drupal. 

Vishal has been sharing his intern experience through a series of blog posts highlighting the things he has learned along the way. 

Here is a quick look at some of his highlights:

  • Week 1
    • Debugging and fixing for porting of Drupal 8 version
  • Week 2:
    • Added test for the feature to show cities previously having fraudulent orders
  • Week 3:
    • Added improvement in Features of the module
  • Week 4:
    • Addition of Reset fraud score functionality
  • Week 5:
    • Converting Rules entity form content type to config
  • Week 6:
    • Improving documentation for the module version 7.x and 8.x

Read more about Vishal’s GSoC journey here

Jul 16 2020
Jul 16

Enterprise-level businesses have very unique technical requirements that can prove to be complex due to the nature of their digital transformation requirements. For example:


Multilingual Digital Experiences

These businesses often need to communicate with a diverse global audience - needing to publish content and reach out with marketing messages personalized to each audience segment's language. Hence, the need to build a multilingual website.

Using the ideal technology to build your digital experiences you can enable your marketing team to create multilingual websites from the same Drupal CMS. Each language can be quickly translated and optimized for SEO at the same time.


Major enterprises have numerous domains or microsites dedicated to a particular audience or product. With Drupal you no longer need to spend extra to scale and grow your digital presence as the need arises. All those sites can be an interconnected web with seamless integrations from the same centralized CMS - sharing all best practices, security and UX features.

This is but the tip of iceberg when it come to building an engaging and open digital experience for an enterprise-grade business in today's digital world.

To gain more insight towards what it takes to transform such a project - you can download our ebook by filling out the form.

Jul 16 2020
Jul 16

Day 2 of DrupalCon Global was chock full of great presentations, and we also attended the 2 summits, Community and Performance & Scaling. Everyone has settled in to the platform and rhythm of the conference now, and it's been great catching up with friends and community colleagues.

As Amber says,

I'm enjoying DrupalCon Global more than I thought I would, to be honest. (Still bummed about missing a trip to Minneapolis!) But I'm learning a lot and reconnecting with what is going on with the project and in the community.

Here are our notes from day 2, which again, are not fully fleshed out, but highlight the things we found interesting or want to follow up on.


Drupal Initiatives Plenary

  • Great community initiatives to participate in. Quick overview of each one with some info about how to get involved.
  • Drupal Diversity and Inclusion (DDI) -
    • They have a booth in the Hopin Exhibit Hall if you want to learn more or chat with someone
    • Ideas for ways to take action
      • Read the Code of Conduct and understand it
      • Consider being an official CoC Contact
      • Speak up when you see a problem, prepare to disrupt harassment
      • Notice who is present; who's missing? Sponsor marginalized individuals
      • Management: Fix hiring, recruitment and pay gaps
      • Update your language

Single sign on across Drupal 8

  • Slides
  • A good walk through of the presenter's medium article on the same topic. Did a good job explaining the different components of a single sign on system, their role, and how to integrate Drupal at each point in the process.

Trans Drupal: Designing with transgender users in mind

  • Gender 101 and history
    • What is (personal) gender? The easiest answer is that it's whatever a person says theirs is
    • Social gender is a social organizing principle (e.g. men's and women's bathrooms)
  • All work is biased in some way - none of it is perfectly neutral
  • Words and images, be aware (find images on https://genderphotos.vice.com/ and https://getavataaars.com/)
  • Let people change their data, make sure it updates everywhere, and don't keep the old values (avoid deadnaming). Transition means a lot of different things and can happen at any time/over time. You want to get rid of old data completely so that it can't be resurfaced later.
  • Do you really need to track gender on your site? Why? If so, it's complicated to do.

Unit tests in Drupal: The road to test-driven development

  • Introduction to TDD
  • Live demo of the Red > Green > Refactor feedback loop using PHPUnit
  • Unit Test fundamentals & vocabulary

Dries Q&A

  • Make DX of Drupal better for devices with less power/RAM to increase adoption among students and others.
    • Any change we make to improve Drupal's DX/performance in this respect will both help lower end devices, but also benefit all sites. e.g. sidewalk curb cuts
  • Is there still a sizeable market for small businesses? Or are they moving to site-builder tools.
    • On the lower end of the market there are lot of competing technologies, and while Drupal can be used it's harder to convince people. vs. high end of the market there's less competition and more opportunity for Drupal to stand out.
  • Do you see online conferences becoming a permanent mix for the Drupal community going forward?
    • Dries: Likes that it lowers the travel barrier, and makes it more accessible to people
    • Dries: Misses seeing people in person, and misses human interaction. Which Dries believes is an important part of what has made Drupal successful.
    • Heather: DA is committed to in-person, and doesn't see the desire for that going away. But, is open to exploring how virtual events can supplement in-person ones.
  • What unexpected things, positive and negative, have you observed about yourself and the community as a result of the COVID pandemic
    • Good leadership is important in moments of crisis
    • Value of cooperation
  • How can we answer the criticism that Drupal is not popular and has a poor perception amongst developers in general
    • Drupal is so far ahead of the competition in a lot of ways that people just don't know about. e.g. caching and big pipe ... most devs have no idea about these things and their importance but benefit from them when they use Drupal. Also, Drupal is a model OSS community.
  • 3 biggest goals you have for the future of the product?
    • adoption, ease of use, low cost of maintenance
    • Increase adoption to a point it can be used as a wedge issue to promote the open web
    • See Drupal grow by making it easier to use, and lower the maintenance burden

Drupal.org panel

  • New Contributor Guide that aims to make it easier for contributors to on-board themselves and find things to work on
  • Lots of changes to packaging and stuff that happens behind that scenes that as an end user you probably don't care much about as long as it works but make a big difference for module maintainers and the security team
  • Issue Forks & Merge Requests - new tools for maintainers open for opt-in beta now, a Drupal.org implementation of something akin to GitHub pull requests. A bit improvement over the current .patch based workflow and will lower barrier to contributing to Drupal.org hosted projects. Mostly working on trying to iron out UI/UX issues before enabling it for all of contrib. And then core as well.
  • Future projects:
    • Federated login
    • Better telemetry
    • Upgrade Drupal 9
    • Packaging related to auto-updates initiative
    • Preparation to support the release of Drupal 10.

Drupal 9: New initiatives

A working session to discuss next steps for D9 initiatives. One major challenge for all initiatives is the need for people to help with project management and just general organizing of things. There was some talk about the proposed JavaScript menu component idea that was proposed in the Driesnote. Mostly recognizing that it requires better definition. Lots of agreement that keeping it limited in scope to something small and attainable is important. And, one of the primary goals is to create/demonstrate an on-ramp for JavaScript developers into the Drupal core community.

Looking to Drupal 10. Move everything to PHP8, and help/pressure upstream libraries to do the same. CKEditor is EOL, need to either update to new version or remove. jQuery related, it's probably time to convert to vanilla JS. Which also means removing jQuery UI, an maybe Backbone too? [meta] Release Drupal 10 in 2022

Easy out-of-the-box initiative needs a leader. And combines efforts from at least three other ongoing projects like Claro, and Olivero. Needs someone who can help with accessibility and focus on accessibility related issues within the initiative. Someone who cares about day-to-day users of Drupal and beginner experience.

Improving your onsite search

  • Making sure your Drupal site is optimized for both organic and onsite searching
  • Why onsite searching is important:
    • It presents your site as a reliable resource
    • It blocks out competitors, which may show up in a Google/Bing search
    • It increases a customer's satisfaction by validating the decision to be a customer.
  • How to make onsite searching a priority: Basically, you apply the same SEO/tagging/taxonomy/metadata/keyword principles that help optimize a site for organic searching.
  • Finally, you can use Google Analytics to learn what people using onsite search are looking for, and how they're phrasing those searches. This learning can be applied to future content creation.

Mind-blowing content planning in native Drupal

  • A great presentation from Lukas Fischer from Netnode about the nearly-released 1.0 version of the Content Planner module, a tool suite that helps plan editorial content calendars.
  • Lukas demoed how to download it, showed the module's flexible and configurable dashboard, (walking us through what types of views and widgets you could add), and made a strong case for why it should replace Google/Microsoft sheets and Trello (yup, that's us) for planning and managing content.

Drupal Security Team Q&A panel

  • Great info about what the Drupal Security Team does.
  • Highlight was Portland Drupal community member Sam Mortenson (https://twitter.com/mortensonsam) explaining how he, as a security researcher, finds bugs.

Sharing is caring: Don't hold your knowledge hostage

From squiggles to straight lines: Sketching discovery & UX

  • Marissa Epstein shared how she uses sketching in discovery and UX processes. In a world of perfectionism and over-engineering prototyping solutions, Marissa demonstrated how sketching is a great way to quickly flesh out ideas and get clients (and the whole team) on board and confident in the direction the site design is going.

Drupal Automatic Updates in action and in depth

  • This was my first time seeing a live demo of the Automatic Updates module. Really promising work here and there's a lot of work still to come in "Phase 2". This is one of the priorities for Drupal 10, as Dries explained in his "Driesnote", so expect some great progress on this front.


Community Summit

15-minute talks:

  • Events Organizer update - Baddy Breidert
    • Some history on this working group and where they are now, how to get involved.
  • Cultivating the Drupal Community Mindfully - Matthew Tift - mindfulness is not for solving problems, but to rethink our relationship to problems; how mindfulness can help our community based on our values and principles; cultivating an intentional community by being present
  • If you want to cry, watch Mario Hernandez's presentation, Why teaching someone else is the best way to learn.
    • And a meaningful way to both lift others up and contribute to the community
  • The ROI of a Dedicated Community Person - Anne Stefanyk
    • Having a dedicated community person makes it easier for the rest of the team to make impactful contributions with the "short" amount of time they get on a weekly basis to contribute to OSS. The community person on the team can help the rest of the team keep up with what's going on, and allow them to jump in and contribute without having to spend a tone of time figuring out what's happened since I was here last week.
  • Be a good boss: How to support your marginalized colleagues - Tara King
    • Cute animal pics for a hard topic.
    • This topic has real, material impact on people's lives; it's not about looking good.
    • Be kind isn't good enough. What does "kind" mean for different people?
    • Actions to take:
      • Reflect on yourself
      • Slow down (speed and spontaneity is not inclusive) - "Go fast and break things might work for software, but it's never good for people."
      • Make space (for processing experiences)
      • Ask (don't assume, just ask)
      • Practice (being uncomfortable)
      • Culture add, not culture fit
      • Educate yourself (use the Googles)
      • Increase pay equity and transparency

Performance & Scaling Summit

  • Mike Herchel - front-end performance audit
    • WebPageTest is a useful (low overhead) tool to get started testing your site.
    • Lighthouse is another useful tool for profiling your site.
    • Continuously profiling your site, and being aware of where the slow parts are is 80% of the battle.
  • Janna Malikova - load testing your Drupal website before it's too late
  • Shane Thomas - Decoupled Performance
    • Decrease your JS bundle size
    • pay attention to your images
    • make use of browser cache (progressive web app)
    • JSON:API Boost module
    • Optimize your API
      • Optimize GET requests using includes
      • Subrequests module
      • JSON:API Extras module
      • filters to explicitly filter out content
  • Michael Schmid - How to survive COVID-19 as a hosting provider

Let day 3 begin!

Day 2 was great and we're excited to dig into day 3, which is the last day of presentations. Don't forget that Friday is the community contribution day and everyone can participate. You don't need to be registered for DrupalCon to take part. So sign up for the DrupalCon Global Contributions Room to get involved and hang out with lots of great people.

Jul 16 2020
Jul 16

In early June, the long awaited version 9 of the Drupal CMS was released. Logically, this gave rise to a number of blog posts about the ease of migrating to 9 and what this release means for the open-source project. Revisit some of these in our overview for June!

Drupal 9.0.0 released

Despite the major disruptions of the past 6 months, the latest major version of Drupal, Drupal 9, was released on June 3. As is tradition, Drupal’s founder and project lead Dries Buytaert wrote a blog post for the occasion, providing some basic information about this release and thanking the community for another successful year - this time, especially all the people working on version 9.

The Drupal community is known for being very diverse and inclusive, with Dries leading by example. Contributors from all manner of cultural backgrounds have helped make Drupal 9 a reality, and this release brings the software even closer to its users, with an even greater focus on usability and accessibility. 

Read more

Drupal 9 is Here - Upgrading has Never Been So Easy

In the next post, Stella Power of Annertech highlights the unprecedentedly easy upgrade to Drupal 9. The post begins with a brief look into the history of Drupal version upgrades, which have evolved from a “the drop is always moving” mentality to one which prioritizes backwards compatibility, with biannual feature releases and planned deprecations.

As such, the groundbreaking thing about Drupal 9 is exactly this simplified upgrade path, especially for websites that have kept up to date with the latest versions of Drupal 8, for which the update is much smoother. Upgrading from Drupal 7 to 9 requires more effort, as it is essentially a complete overhaul, so Stella recommends also taking this opportunity to rethink and revamp your entire digital strategy. 

Read more

Migration, Security and More: We Answer Your Burning Questions about Drupal 9

We continue with another practical post on Drupal 9 in which Acquia’s Angela Byron and Gábor Hojtsy answer some of the most frequent questions developers and site owners may have concerning this release.

They include helpful information on migrating from Drupal 7 and its end-of-life, as well as the recommended tools for making the migration. In addition, they also cover the improvements to accessibility and security that come with Drupal 9.

The last few questions are particularly interesting as they pertain to the future of Drupal: what we can expect in terms of headless support and “no/low code” solutions, and more generally about Drupal’s position as the top enterprise CMS.

Read more

Multilingual Drupal - Part 2: Translation Management

This next post is a continuation of one that we included in last month’s recap. In it, Christophe Jossart of Amazee Labs takes a further look at Drupal’s multilingual capabilities, focusing on using the Translation Management Tool (TMGMT) module.

Christophe covers three different use cases: content moderation, paragraphs asymmetric translation, and some experiments to the UX/UI, also diving deeper into each of them, exploring things such as data loss and sending files via email to a translation service.

He concludes his blog post with a list of the TMGMT module’s features not covered more thoroughly already, and some possible next steps such as integration with different software.

Read more

Drupal 8 vs. Drupal 9: More Features for Content Editors

One of Drupal’s main future goals is simplifying the beginner experience and improving the user experience of both key stakeholder groups - developers and, in particular, marketers / editors. As Leigh Ryan of Evolving Web writes in her blog post, version 9 features a lot of functionality tailored to the latter user group.

Among other things, the Layout Builder is now in core and enables drag-and-drop page building. Drupal 9 features better media management and better content moderation workflows, as well as the new and even more accessible back-end theme Claro. Through all of this, Drupal 9 remains an API-first CMS, also staying mindful of the developer experience.

Read more

Caring for old software

Among discussions of updates, migrations and new features, another important piece of Drupal news from June came from the completely other side of the spectrum - namely, the announcement of extending Drupal 7’s end-of-life date, originally scheduled for 2021, for one year, until November 2022. 

In his accompanying blog post, Dries cited the impact of the pandemic on companies’ budgets as the primary reason for extending this deadline, since a lot of Drupal websites still run on version 7. This shows how Drupal really is all about its users, as it takes care to extend support for an old version right after releasing a brand new and updated one. 

Read more

Is it time to give Drupal another look?

Due to it being quite an old technology, Drupal has a somewhat negative connotation within the latest generations of software developers. Tim Lehnen, CTO for the Drupal Association, has recently written a great post for Stack Overflow in which he takes a look at the major changes the software has undergone in the past two decades and dispels some of the misconceptions associated with it. 

Among the most notable changes is Drupal’s new stance on backwards compatibility, taking a kind of middle ground between innovation and easy updates. Tim also points out that a major reason for the big changes in Drupal are a natural reflection of the changes to the very nature of content management, and discusses how Drupal is positioned in this new ecosystem.

Read more

How to Contribute to Open Source: The Ultimate Guide

We finish with a more general post about open source, namely, about contributing to open source projects. One of the individuals sharing their views and experiences is also the author of the previous blog post that we included, Tim Lehnen, from the Drupal community.

As the author of the article, Tatum Hunter of Built In, points out, one of the biggest pains of fledgling contributors is not knowing where and how to get started. 

It’s therefore important to do your research, get familiar with the structure and workflows of the project, while keeping in mind that something which seems insignificant to you may actually be viewed as a very valuable contribution to a more senior and predisposed community member.

Read more

We hope you enjoyed our recap and/or were able to find out more about the newly released Drupal 9. Learn more about how Agiledrop can aid with your Drupal development, or simply give us a shout out if you want to collaborate. Till next month!

Jul 16 2020
Jul 16

A short video showing how to use the newly released Component Blocks module.

Component blocks module lets you integrate your existing Pattern library / UI Patterns functionality with Layout Builder.

[embedded content] Photo of lee.rowlands

Posted by lee.rowlands
Senior Drupal Developer

Dated 16 July 2020

Jul 15 2020
Jul 15

DrupalCon Global kicked off of this week and the Drupalize.Me team was there to participate. The originally scheduled DrupalCon North America in Minneapolis was canceled earlier this year due to COVID-19 and the great team at the Drupal Association worked magic to create a new DrupalCon experience with DrupalCon Global, the first online DrupalCon.

Almost everyone on our team has attended in-person 'cons in the past, so it was interesting to feel the differences between in-person and online. Philippa has never gone to a 'con before, so it was awesome that she could experience DrupalCon for the first time. We've gathered all of our notes from day one, along with links to videos of sessions to check out if you are registered. (Note that the session videos will be available on YouTube for the entire community in September. In the meantime, you must be a registered attendee to access the recorded sessions on Vimeo.) We'll keep a daily commentary going all week.

The Hopin.to platform

DrupalCon is using Hopin.to to manage the conference. The live sessions are delivered here, along with the ability to chat with other attendees in chat rooms, as well as randomly meet others one-on-one through a networking feature. The exhibit hall is also managed here, and you can "visit" an exhibitors booth either by expressing interest so someone contacts you directly or by entering their chat room to talk with them and other visitors.

We found that the platform worked pretty well and it was pretty clear where things are. Besides being online of course, the big difference in sessions with this is that there is a chat room for each session so attendees can talk and ask questions during the presentation. This ended up feeling like both a plus and minus for many of us. On the one hand it was neat to see people engaging at the sessions and be able to "talk" while the session was in progress. This can really add to the session with interesting comments and conversations, and people helping each other out with questions. On the other hand seeing the back-channel chatter can be distracting or overwhelming, especially when there are large groups of attendees. You can close the chat window while you watch though, so if you find it annoying you can toggle that closed. There is a small button at the top of the chat window, between the timeline and the attendee count.

Hopin minimize chat window button

Joe sums up what many of us are feeling with the overall online experience so far.

"I'm quickly realizing how much I rely on the serendipity of in-person events to get to me to interact with others in the community, which is my favorite part of DrupalCon. But it's all primarily chat based, and a bit more opt-in than when someone walks up to you in the hall and says, "Hi Joe!". Being an active participant and not just a lurker is likely to be the hardest part of hopin for me."


One of the great things about an online conference is that it is much more accessible to many more people. It's also heartening to see the Drupal community highlighting diversity and inclusion. There is always so much work to do, and we were happy to see time scheduled in the event for 8:46 minutes of silence observed in honor of George Floyd and the Black Lives Matter movement. We hope this conversation continues and leads to lasting change in our community.

Another aspect of inclusion for online communities is the issue of time zones. Addi lives in Denmark, while the rest of our team live in several time zones in the United States. The main event is largely scheduled on American times, which meant that Addi missed a fair amount of live sessions and the first trivia night, being too late at night. That said, it's great to see that there are multiple trivia nights this year, with different days at different times so that everyone can participate. On the flip side, some of the initial sessions of the days are scheduled quite early in the morning for our folks who live on the U.S. west coast. There's really no way around time zones and live events, and it'll be interesting to see if there are more ideas that spring up after this 'con about how to create a more "live" experience for people who are not in the main targeted time zones.

Finding and scheduling sessions

You can find the schedule for all sessions both on Drupal.org and in the Hopin Reception area. Here is the schedule for Day 1. Don't forget that you can make your own schedule to follow by using the "My schedule" feature on Drupal.org or you can add sessions directly to your own calendar in Hopin. This can be a great way to cut down on the overwhelming list of sessions and it can help you figure out when you can watch live in your home schedule versus needing to go back to watch videos later once they get uploaded.

Session notes

Here are some somewhat random notes from sessions that we attended on Tuesday. We've also provided links to both the session page and the on-demand library video where possible (and we'll add the video links as they are put online).


There was a pasta intermission! Before the sessions started, Vincenzo De Naro Papa from Amazee.io showed us the authentic Italian way of cooking pasta. It was a fun way to make things feel homey and relaxed before things got kicked off, though a fair number of people were probably confused about whether they were at the right conference when they first entered the main stage area. :-)

How to improve psychological safety in your organization

  • (Addi) This session covered a lot of things that we do well, and some things that apply more to larger organizations than we are. It also introduced some new ideas for me to look into within Osio Labs: Personal user manuals and documenting the Andon cord process (how do you stop work to address problems?).

Driesnote (video - Dries' presentation begins at 15:48)

  • Details about Drupal 10: shorter release cycle (targeting June 2022), limited to ~5 official initiatives with a focus on improving the beginner/new user experience.
    • JS Menu component
    • Automated updates
    • New front-end theme (Olivero)
    • Easy out-of-the-box (complete Claro admin theme, Layout builder, and Media)
    • Drupal 10 readiness (dependency end-of-life timelines, e.g. Symfony 4)
  • Q&A session will happen on Wednesday instead of happening right after the talk.
  • (Joe) It's nice to see the hat tip to diversity and inclusion, and hopefully that continues to expand within the community and continues to result in real change. This year's speaker lineup is the most diverse, and it's great to see that.
  • (Addi) I really like the emphasis on DEI and that people have generally been very supportive of this stance in the chatrooms. Tim Lehnen's talk at the end of Dries' presentation was good to see.

Community & Belonging in the Time of Coronavirus

  • (Joe) Adjusting to remote work, remote community, changes how we engage and how we gain a sense of "belonging". For many people remote work/working from home is becoming the new normal, not just a temporary thing.

Drupalcon on the front lines of covid-19

  • (Philippa) Four panelists, working for widely different organizations, spoke about how, in recent months, they've used Drupal to help communities, governments, and organizations fight the effects of Covid-19. For example, Christina Costello, Web Developer, Redfin Solutions, LLC, spoke about her agency's work with the Rural Aspirations Project. They helped set up a Drupal 8 website for them using the Claro theme for admins, which delivered good content moderation functionality and gave them something they needed very quickly amidst the statewide shutdown of schools: a CMS offering a quick and efficient approval process for content editors. The result was that in a very short time, they were able to help connect rural communities in Portland, Maine with good, creative online learning opportunities for kids. For instance, the site connected a Portland, Maine-based comic strip artist with kids in rural areas, who learned how to draw what they were experiencing in quarantine in a comic strip. Cool!
  • (Amber) Interesting panel of speakers who talked about both client solutions and workplace issues they needed to solve at the onset of the crisis. Interesting mix of Drupal modules and solutions that helped us and our clients quickly deliver new types of content as well as remote workplace adjustments.

Decoupled Drupal in real life: JSON:API at scale

  • (Amber) Lessons learned, caching, and other strategies for scaling decoupled or progressively decoupled Drupal sites. Lots of good real-world lessons. Goes way beyond a basic demo of "turn on JSON:API".

Big systems, big problems: Lessons from 40 design systems

  • (Amber) Learned some helpful strategies for redesigning a site, including sketching out user flows. Also great information about setting content component priorities.

Social events


  • (Joe) Amber, Philippa and I had a team, and tried to have both a Google Meet and the Hopin session open at the same time, which made it feel like you where in loud bar with everyone talking over everyone else. It was kind of fun, and Fatima did a great job of being a lively host. But it's just not the same as Trivia in a pub. I'm glad that effort was put into keeping this tradition alive in some form though.
  • (Amber) It was fun to do a "happy hour" with co-workers during trivia. Definitely not the same as the in-person experience, but still fun in its own way.

What's next?

Well, that's our quick summary of day one as we gear up for day two. We'll be back tomorrow with our day two summary. Are you attending DrupalCon Global? What are your thoughts, tips, and highlights so far?

Jul 15 2020
Jul 15

In the previous article we provided a reference of available configuration options for migrate source plugins. In today’s article we are doing something similar for destination plugins. We will present a reference of available configuration options for migrate destination plugins provided by Drupal core and some contributed modules. Knowing which options are available might require some Drupal development knowledge. By providing this reference it should make the process of writing migrations easier.

List of configuration options for destination plugins

For each migrate destination plugin we will present: the module that provides it, the class that defines it, the class that the plugin extends, and any inherited options from the class hierarchy. For each plugin configuration option we will list its name, type, a description, and a note if it is optional.

DestinationBase (abstract class)

Module: Migrate (Drupal Core)
Class: Drupal\migrate\Plugin\migrate\destination\DestinationBase
Extends: Drupal\Core\Plugin\PluginBase

This abstract class is extended by many migrate destination plugins. This means that the provided configuration keys apply to any destination plugin extending it.

List of configuration keys:

  1. destination_module: An optional string value. Identifies the module handling the destination data. If not set, the Migrate API tries to read the value from the destination plugin definition.

Entity (abstract class)

Module: Migrate (Drupal Core) Plugin ID: entity:$entity_type See below.
Class: Drupal\migrate\Plugin\migrate\destination\Entity
Extends: Drupal\migrate\Plugin\migrate\destination\DestinationBase
Inherited configuration options: destination_module.
Related article: Drupal migrations reference: List of properties per content entity

This abstract class is extended by migrate destination plugins that want to import entities. It uses the MigrateEntity derivative to handle both content and configuration entities. The derivative sets the plugin ID to entity:$entity_type where $entity_type is the machine name of the entity. For example, entity:node and entity:node_type.

By default, content entities are handled by the EntityContentBase class while configuration entities use EntityConfigBase. Some entities like user (content) and node type (configuration) use specific classes for the import operation. The DefaultPluginManager::getDefinitions method triggers the search for classes that will override the default for a particular plugin ID. The override ultimately happens in the DerivativeDiscoveryDecorator::getDerivatives method.

In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys, which will be available to its derivatives:

  1. default_bundle: An optional string value. Gets the bundle for the row taking into account the default. If not present, the bundle entity key should be set in the process section for entities that can have more than one bundle. For example, the type property for nodes, the vid property for taxonomy terms, and the bundle property for media entities.


Module: Migrate (Drupal Core) Plugin ID: entity:$entity_type See below.
Class: Drupal\migrate\Plugin\migrate\destination\EntityContentBase
Extends: Drupal\migrate\Plugin\migrate\destination\Entity
Inherited configuration options: destination_module and default_bundle.

This class is used to handle import operations for all content entities, unless a specific class exists for the plugin ID being used. For example, nodes are handled by this class, but users leverage the EntityUser class. The MigrateEntity derivative sets the plugin ID to entity:$entity_type where $entity_type is the machine name of the content entity. For example, entity:node, entity:user, entity:taxonomy_term, entity:file, entity:media, entity:comment, entity:block_content, and entity:contact_message.

In addition to the keys provided in the parent class chain, this class provides the following configuration keys:

  1. translations: An optional boolean value. It indicates if the entity is translatable, defaults to FALSE. If set to TRUE, the corresponding langcode entity key will be added to the list of destination IDs that uniquely identifies each record. If the migration itself does not provide a value for the langcode property, the site’s default language is used.
  2. overwrite_properties: An optional array of string values. It is a list of properties or fields in the destination entity that will be overwritten if an entity with the same ID already exists. Any properties that are not listed will not be overwritten. Refer to the class documentation for an example.
  3. validate: An optional boolean value. It indicates whether an entity should be validated, defaults to FALSE. This was introduced in Drupal 8.8 and can be used to prevent invalid entities from being migrated. For example, a node with an empty title would fail validation. A required field that is not set by the migration will trigger a validation error, unless the field is configured to have a default value. Similarly, an integer field with minimum and maximum values will trigger an error if a value outside that range tries to be imported. Field API validations are triggered when this configuration option is set to TRUE.


Module: User (Drupal Core) Plugin ID: entity:user See below.
Class: Drupal\user\Plugin\migrate\destination\EntityUser
Extends: Drupal\migrate\Plugin\migrate\destination\EntityContentBase
Inherited configuration options: destination_module, default_bundle, translations, overwrite_properties, and validate.

This class provides a destination plugin for migrating user entities. It performs extra checks like preventing that the password for user 1 is overridden by the migration.

In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:

  1. md5_passwords: An optional boolean value. If set to TRUE, the pass (password) property of the user entity is assumed to contain an MD5 hash. The passwords will be salted and re-hashed before they are saved to the destination Drupal database.


Module: Migrate (Drupal Core) Plugin ID: entity_revision:$entity_type See below.
Class: Drupal\migrate\Plugin\migrate\destination\EntityRevision
Extends: Drupal\migrate\Plugin\migrate\destination\EntityContentBase
Inherited configuration options: destination_module, default_bundle, translations, overwrite_properties, and validate.

This class provides an entity revision destination plugin. Only revisionable entities, those that define a revision entity key, can use this destination plugin. It uses the MigrateEntityRevision derivative which sets the plugin ID to entity_revision:$entity_type where $entity_type is the machine name of the entity. For example, entity_revision:node whose revision key is vid and entity_revision:block_content whose revision key is revision_id.

Entity revisions can only be migrated after the entity to which they belong has been migrated. For example, revisions of a given node (entity_revision:node destination migration) can be migrated only after the current version of that node (entity:node destination migration) has been imported.


Module: Entity Reference Revisions module Plugin ID: entity_reference_revisions:$entity_type See below.
Class: Drupal\entity_reference_revisions\Plugin\migrate\destination\EntityReferenceRevisions
Extends: Drupal\migrate\Plugin\migrate\destination\EntityRevision
Inherited configuration options: destination_module, default_bundle, translations, overwrite_properties, and validate.
Related article: Introduction to paragraphs migrations in Drupal

This class provides an entity revision revision destination plugin. It uses the MigrateEntityReferenceRevisions derivative which sets the plugin ID to entity_reference_revisions:$entity_type where $entity_type is the machine name of the entity. For example, entity_reference_revisions:node and entity_reference_revisions:paragraph. For example, entity_reference_revisions:node whose revision key is vid and entity_reference_revisions:paragraph whose revision key is revision_id.

This is the destination plugin used for migrating Paragraphs. Entity reference fields are no longer supported to reference Paragraphs. Instead, entity entity reference revisions must be used. Therefore, this class is used for paragraphs migrations with the entity_reference_revisions:paragraph plugin ID. See this article for an example on how to migrate paragraphs.

In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:

  1. new_revisions: An optional boolean value. Flag to indicate if a new revision should be created instead of updating a previous default record. Only applicable when providing an entity id without a revision_id. Defaults to FALSE.


Module: Migrate (Drupal Core) Plugin ID: entity:$entity_id See below.
Class: Drupal\migrate\Plugin\migrate\destination\EntityConfigBase
Extends: Drupal\migrate\Plugin\migrate\destination\Entity
Inherited configuration options: destination_module and default_bundle.

This class is used to handle import operations for all configuration entities, unless a specific class exists for the plugin ID being used. For example, taxonomy vocabularies are handled by this class, but node types leverage the EntityNodeType class. The MigrateEntity derivative sets the plugin ID to entity:$entity_type where $entity_type is the machine name of the content entity. For example, entity:node_type, entity:user_role, entity:taxonomy_vocabulary, entity:block, entity:comment_type, entity:block_content_type, entity:contact_form, entity:date_format.

In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:

  1. translations: An optional boolean value. if TRUE, the destination will be associated with the langcode provided by the source plugin. Defaults to FALSE. For example: en for English, es for Spanish, and fr for French.


Module: Node (Drupal Core) Plugin ID: entity:node_type
Class: Drupal\node\Plugin\migrate\destination\EntityNodeType
Extends: Drupal\migrate\Plugin\migrate\destination\EntityConfigBase
Inherited configuration options: destination_module, default_bundle, and translations.

This class is used to import node types. It does not take extra configuration options. The plugin overrides the import method to attach the body field to the imported content type. This depends on the presence of certain destination properties in the imported row. That is, the following properties needs to be mapped in the process section of the migration:

  1. create_body: An optional boolean value. If TRUE, a body field will be added to the content type.
  2. create_body_label: An optional string value. If set and create_body is TRUE, the value for this destination property will be used as the label of the body field.


Module: Migrate (Drupal Core) Plugin ID: config
Class: Drupal\migrate\Plugin\migrate\destination\Config
Extends: Drupal\migrate\Plugin\migrate\destination\DestinationBase
Inherited configuration options: destination_module.

This class persists data to the configuration management system. In addition to the keys provided in the parent class chain, this class provides the following configuration keys:

  1. store null: An optional boolean value. If TRUE, when a property is NULL, the NULL value is stored. Otherwise, the default value is used. Defaults to FALSE. Note that there is a space character in the configuration name.
  2. translations: An optional boolean value. if TRUE, the destination will be associated with the langcode provided by the source plugin. Defaults to FALSE.

Additionally, the plugin expects certain destination properties in the imported row. That is, the following properties needs to be mapped in the process section of the migration:

  1. config_name: A string value. The machine name of the configuration. For example: node.settings, node.type.article, user.settings, system.site, and core.extension.
  2. langcode: An optional string value. The language code of the configuration. For example: en for English, es for Spanish, and fr for French.


Module: Migrate Plus Plugin ID: table
Class: Drupal\migrate_plus\Plugin\migrate\destination\Table
Extends: Drupal\migrate\Plugin\migrate\destination\DestinationBase
Inherited configuration options: destination_module.

This class allows you to write directly to a table not registered with Drupal Schema API. See this test for an example on how to use this plugin.

In addition to the keys provided in the parent class chain, this class provides the following configuration keys:

  1. database_key: An string value. Key for the database connection used for inserting records. See this documentation page for more information on database connection keys. We also covered the topic when explaining the SqlBase source plugin.
  2. table_name: An string value. Name of the table where records will be imported.
  3. batch_size: An optional integer value. Maximum number of rows to insert in one query. Defaults to 1.
  4. id_fields: An associative array value. Fields used to uniquely identify table rows. At least one field is required. See the class’s docblock for an example of the expected structure.
  5. fields: An optional associative array value. Mapping of column names to values set in the process section.

Available configuration for other migrate destination plugins

In Drupal core itself there are around 50 migrate destination plugins. And many more are made available by contributed modules. It would be impractical to document them all here. To get a list by yourself, load the plugin.manager.migrate.destination service and call its getDefinitions() method. This will return all migrate destination plugins provided by the modules that are currently enabled on the site. This Drush command would get the list:

# List of migrate destination plugin definitions. $ drush php:eval "print_r(\Drupal::service('plugin.manager.migrate.destination')->getDefinitions());" # List of migrate destination plugin ids. $ drush php:eval "print_r(array_keys(\Drupal::service('plugin.manager.migrate.destination')->getDefinitions()));"

To find out which configuration options are available for any destination plugin consider the following:

  • Find the class that defines the plugin and find out which configuration values are read. Some plugins even include the list in the docblock of the class. Search for a pattern similar to $this->configuration['option_name'] or $configuration['option_name']. The plugins can be found in the Drupal\module_name\Plugin\migrate\destination namespace. The class itself would be in a file under the /src/Plugin/migrate/destination/ directory of the module.
  • Look up in the class hierarchy. The destination plugin can use any configuration set directly in its definition class and any parent class. There might be multiple layers of inheritance.
  • Check if the plugin requires the presence of specific destination properties to be set in the process section. This is usually documented in the class’ docblock, but you can also look for code like $row->getDestinationProperty('property_name').

What did you learn in today’s article? Did you know that migrate destination plugins can inherit configuration keys from their class hierarchy? Were you aware that there are so many destination plugins? Other than the ones listed here, which destination plugins have you used? Please share your answers in the comments. Also, we would be grateful if you shared this article with your friends and colleagues.

Jul 14 2020
Jul 14

Mauricio Orozco from the SC Commission for Minority Affairs gave a talk about the state of Drupal within the SC State government. In recent years Drupal has grown from a tool used on a small number of projects to the platform of choice for all new agency sites. He spoke about the state’s initiative to move more to Drupal, South Carolina Interactive and their role in supporting government projects, which agencies are moving toward Drupal, and how this is benefiting residents of South Carolina.

[embedded content]

If you would like to join us please check out our up coming events on MeetUp for meeting times, locations, and remote connection information.

We frequently use these presentations to practice new presentations, try out heavily revised versions, and test out new ideas with a friendly audience. So if some of the content of these videos seems a bit rough please understand we are all learning all the time and we are open to constructive feedback. If you want to see a polished version checkout our group members’ talks at camps and cons.

If you are interested in giving a practice talk, leave me a comment here, contact me through Drupal.org, or find me on Drupal Slack. We’re excited to hear new voices and ideas. We want to support the community, and that means you.

Jul 14 2020
Jul 14

It's a lot easier to design an accessible website if you consider accessibility from the get-go, but we don't always have that luxury. You're far more likely to have an existing site on your hands, and, if you're reading this, you're probably wondering how to determine how accessible it is currently so you can get a better idea of what needs to be done.

Here's a simple guide to testing your Drupal site for accessibility. (Most of these apply to non-Drupal sites, too). We've divided it into 3 sections.

Jump to:

Manual Accessibility Assessments

Before you start jumping into automated testing solutions, go through your website manually to identify accessibility barriers. This is also a good way to develop your "accessibility reflexes".

Validate your code

For your website to be rendered correctly across devices and handled properly by assistive technologies, the underlying HTML and CSS need to comply with the latest web standards.

When it comes to your HTML, here are a few things to pay attention to:

  • Closing tags, perhaps the most common cause for invalid code
  • Attributes. The W3C recommends quoting all HTML attributes, even though it isn't technically a requirement.
  • Semantic markup. Don't put content in a <div\> when it should be in a <p\>

If you want a demonstration of the importance of semantics, open a screen reader and try reading these two pages:

You can use the W3C's markup validation service and CSS validation service to check your site's HTML and CSS markup.

Test your site's keyboard accessibility

The browser version of your website was likely designed first and foremost to accommodate users who navigate by clicking around with a mouse, but that doesn't account for everyone. Make sure to provide a comfortable experience for people browsing with their keyboard or with a screen reader. Here's what to look for:

  • Is there a "skip to content link" that lets users access the most important part of the page directly?
  • Is highlight focus enabled to provide visual feedback regarding where a user is on the page? Also make sure that all focusable elements are actually interactive.
  • Test any hoverable elements to make sure that the information revealed with a mouseover is also available to keyboard users.
  • Tab through each page to make sure that there aren't any dead ends or "traps".
  • Don't forget to test tabbing in both directions! Shift+Tab lets you tab backwards.
  • Pay attention to the flow. If a page's visual layout is in a different order than the DOM, the keyboard experience might be disjointed and confusing.

Test screen reader accessibility

Screen readers like VoiceOver (built into MacOS) and NVDA (Windows) let visually impaired users navigate through websites by reading out loud the contents of each page. A 2019 survey by WebAim found that 79.9% of screen reader users with a disability relied exclusively on sound to navigate.

The best way to make sure the screen reader experience on your site is up to par is to download a screen reader application, fire it up, and navigate through your site. Before you do that, you can go through the basics:

  • Do all images (except purely decorative ones that don't convey any information) have alt text?
  • Does link text make sense out of context? Hint: commonly used labels like "click here" are too ambiguous. Keep in mind that screen readers typically say "link" before reading a link's text (meaning that someone reading this page with a screen reader would have heard "link: NVDA" in the first sentence of the paragraph).
  • Make sure dynamic content changes (which occur without reloading the page, such as notifications or search result filtering) are "visible" to those who can't see them. If you're using Drupal, you can use the Drupal.announce() API, which uses ARIA live regions, to signal to screen readers that a dynamic content change should be announced.

This Web AIM article goes into detail about how you can use CSS to implement accessibility features for screen reader users.

Test colour contrast

Text should have a contrast ratio of at least 4.5:1 with the background to meet accessibility guidelines. There are many tools that can be used to test your site's contrast for accessibility. Here are a few:

  • Contrast-ratio.com lets you input a background colour and a text colour and outputs their contrast ratio.
  • Coolors.co's contrast checker does the same as the above, and provides additional information such as a quality score for small and large text (the smaller the text, the higher the contrast needs to be).
  • Kontrast is a Chrome extension that lets you check the contrast of any element on a page against WCAG requirements, among other useful features.

Make sure your content is usable and complete with CSS and JavaScript turned off

There are all sorts of reasons why users might have JavaScript disabled or are otherwise unable to access JS elements. This tweet from Jake Archibald offers a friendly reminder:

A tweet by Jake Archibald that reads "We don't have any non-JavaScript users" No, all your users are non-JS while they're downloading your JS.

In any case, noscript users do exist, and you should make sure they get a coherent experience on your website. To turn off JavaScript in your browser to start testing your site, use the option in the developer tools menu, or get the Toggle JavaScript extension for Chrome for one-click toggling.

Chris Ashton at Smashing Magazine wrote an in-depth article called I Used The Web For A Day With JavaScript Turned Off, and I highly recommend checking it out to understand how your noscript users experience the web.

Similarly, make sure that your website renders properly without CSS styling enabled. This is especially important given that people can use their own custom stylesheets in their browser; make sure to use plain and proper semantic HTML so that pages keep their logical structure regardless of style.

Use WAI-ARIA where appropriate

WAI-ARIA markup can be used in certain circumstances to improve accessibility. For example:

  • ARIA landmarks can make navigation easier for screen readers
  • Adding ARIA attributes to HTML forms can improve their accessibility
  • Aria live regions helps screen readers handle dynamic changes in content
  • The aria-hidden attribute can hide things from screen readers while maintaining them visually on screen

To get a better idea of what accessibility pitfalls can be solved with ARIA enhancements, check out this excellent blog post, which features videos of screen readers making use of various ARIA attributes.

The Mozilla Developer Network provides excellent guidance regarding ARIA screen reader implementation.

While most of the tools I've mentioned up to this point have a single precise function, there are also ways to check full web pages and sites for a variety of accessibility issues. Many of such tools exist, and they can save you a lot of time but they work best if you fully understand what they're telling you. Running an overall accessibility audit without any prior knowledge or preparation can lead to overwhelming results that are difficult to prioritize.

Here are two of my favourite accessibility testing tools that you can run directly in your browser.

Axe browser extension

Here's how to use axe to test a page's accessibility.

  1. Download and install axe for Chrome or Firefox
  2. Navigate to the page you want to inspect
  3. Open your browser's developer console.
    • Chrome: F12 (Windows), Cmd + Shift + I (Mac)
    • Firefox: Ctrl + Shift + K (Windows), Cmd + Option + K (Mac)
  4. Click on the axe tab, then click the Analyze button in the left-hand column

A screen capture of the axe browser extension in Firefox

Once the tool is finished analyzing the page, you'll see a list of issues (and if you don't, congratulations! But chances are there will be at least a couple of things to fix). Click on any issue for more information, including its level of impact on accessibility (low, medium, high) and what you can do to fix it. Use the Toggle Highlight button to pinpoint issues visually.

A screenshot of the axe browser extension showing where the Toggle Highlight button is located

Tota11y bookmarklet

This nifty tool aims to make accessibility testing more, well, accessible by providing easy-to-understand visualizations of accessibility issues and annotations on how they can be fixed. To try it out, scroll to the bottom of this page and drag the tota11y button onto your bookmarks bar.

To run the tool on any web page, just click the bookmarklet. This will toggle a button at the bottom-left corner of the page, which expands into a menu:

A screenshot of the tota11y bookmarklet's main menu

Choose what you want to focus on, and the tool will display any findings as well as show you where they are on the page, and what you can do to fix them.

A screenshot example of tota11y accessibility audit findings

Drupal Modules for Accessibility

Not only is Drupal WCAG-compliant out of the box, but you can expand even further upon its built-in accessibility features thanks to a variety of user-contributed modules.

  • Automatic Alternative Text uses AI - via the Azure Cognitive Services API - to generate alt text for your images

  • Block ARIA Landmark Roles lets you assign ARIA landmark roles to elements of the block class

  • Fluidproject UI Options lets your site's users customize their own accessibility settings, such as line spacing and text size, and saves their preferences via cookies
  • High Contrast (in beta) lets site users toggle between regular and high contrast modes

Here's a full list of accessibility-focused Drupal modules.

A list of Drupal modules for accessibility

Document the Process and Apply Newfound Knowledge to Your Next Project

As you go through the different steps involved in testing your site's accessibility, be sure to make notes on your findings and changes. This will help you internalize different accessibility notions that you should try to incorporate in your future web projects. Speaking of which, download our free accessibility ebook, or check out the rest of our accessibility series:

You might want to consider turning your notes into an accessibility policy for your organization, which you could even publish on your site as a statement of your commitment to inclusive web experiences.

Still aren't sure where to start testing? Want to brush up on your accessibility know-how? Need help crafting that accessibility policy? At Evolving Web, we make accessibility a top priority. Get in touch with us for personalized assistance.

Jul 14 2020
Jul 14

14 Jul

Nick Veenhof

Today, we are excited to announce that Dropsolid has joined as one of the exclusive partners that will offer Extended Support for Drupal 7 up until November 2025. This means you get at least 3 extra years of full security coverage. This Extended support program is in collaboration with the Drupal Association and Drupal Security Team, and will give you official support on your Drupal 7 site for a whole extra 3 years. This will give you all the time you need to take the right steps towards a new Digital Experience Platform on Drupal 9 and beyond.

Last year, we encouraged our clients to begin planning their migrations to Drupal 8. Not unsurprisingly, as we will need to say goodbye to our friend, Drupal 7, soon.

Drupal 7 was released on January 5, 2011. Drupal 8 was released on November 19, 2015 and the latest and shiniest release came out a couple days ago with Drupal 9 on June 3, 2020. Drupal 7 is almost 10 years old, and will be almost 12 years old when it comes time to say goodbye in November 2022.

New version or next level?

Moving from Drupal 7 to Drupal 8 or 9 could be a great opportunity to upgrade your digital platforms to the next level instead of merely to the next version. Drupal 9 is more than a CMS, it’s a DXP. Turning your website into a personalized digital experience is not something you do overnight. You need to be well prepared, start from a digital strategy with clear goals. Taking time for that preparation now, will pay off later.

Drupal Extended Support can be a solution if you need more time to finish your digital transformation strategy before upgrading.

A smooth upgrade path for every business on it’s own pace

Some businesses might have other priorities right now or might need more time to prepare the migration to Drupal 8 or 9. Businesses that are hit by COVID-19, or on the contrary, businesses that suddenly have decided to accelerate on their digital transformation and need more time to make a strategic action plan.

At Dropsolid we want to be a reliable partner for all companies using Drupal: big or small, in fast growing industries or in sectors that got hit hard by Corona. We want to provide all businesses with the best possible transition path to Drupal 9, so that business owners can focus on taking the right steps in their digital transformation whenever and however it is strategically the best time for their business.

All customers of Dropsolid using Dropsolid Experience Platform will automatically benefit from highly critical Drupal 7 updates, all other updates require signing up for our Extended Support program.

Want to move your Drupal 7 site to the Dropsolid Experience Cloud and get a bit more time to prepare your next phase?
Get in touch with us!

More information about this program of the Drupal Association can be found at https://www.drupal.org/security-team/d7es

Jul 14 2020
Jul 14
Jul 14, 2020 Drupal

During the development of Lucius we built quite a lot of features, that are embedded in the product (an open source Drupal distribution). But we figured some of these might come in handy for other Drupal site owners, outside of the OpenLucius Drupal install profile.

So this is the first release we did: "Simple Like Button", a very simple like button Drupal module that works in two steps:

  1. Install module
  2. Place block
  3. Done!


  • Instant feedback for end-user: count likes +1 or -1;
  • Adds names of users that liked the content;
  • It's compatible with all (custom) entities and bundles;
  • Compatible with all 'authenticated' roles, not with 'anonymous';
  • (non feature) Not compatible with Views at the moment.

Built with custom Drupal AJAX form

It's built with a custom AJAX Form, so we don't have to worry about building a custom AJAX route, a CSRF token and custom Javascripts to handle the user interactions.

While CSRF access checking looks like it can be easily integrated via module_name.routes.yml, ajax form was still more easy to implement.

Downside is that all forms can be cached, in high content site can lead up to unnecessary caching data.

And if you disagree on this approach, please let me know in the comments.

So anyway, if you are looking for a compact example of implementing an AJAX Form, check out the code of this module or the example in this blog.

Built with a Drupal custom entity

We used a Drupal entity for easy management of data:

  • Defining the data model and database table, easy installable.
  • CRUD: the Create, Read, Update and Delete queries are more easy if you work with Drupal entities.

So if you are looking for a compact example of implementing a custom entity, check out the code of this module.

And if you disagree on using a custom Drupal entity here, please let me know in the comments below.

Download the module

Check it out on Drupal.org.  Go to download page

Jul 14 2020
Jul 14

A well-performing website just doesn’t cut it these days. To stand out of competition, businesses are looking for high performance websites with lightning speed load times. You could potentially lose a big chunk of customers with every additional second your website takes to load. Today let’s learn about optimizing the frontend performance of your website with the Advanced CSS/JS aggregation module for Drupal 8.

To make Drupal sites run faster, it is essential to load CSS/JS files as quickly as possible for a page. One problem with Drupal core aggregate is that it is not good at determining which resource (CSS/JS) files go together. So, when you have different pages that require different resource (CSS/JS) files, usually Drupal core does it in a way where there is lot of extra information that are unnecessary on certain pages. The Drupal AdvAgg module comes with a plethora of features to help websites render faster. And the module also supports Drupal 9!

What does the Advanced CSS/JS Aggregation module do?

The Drupal AdvAgg module does a lot of different things to help speed up delivery and loading of resource files on your website. Advanced Aggregation combines multiple CSS files and creates fewer CSS files so that sites render faster. It caches aggregated files more efficiently. It also provides more effective methods of compression. Thus helping in offering users with more engaging user experiences.


Getting started with the Advanced CSS/JS Aggregation module


Installing the AdvAgg module for Drupal 8 is like installing any other contributed modules. I’m using the Composer to install since it automatically installs all of the necessary dependencies. Open the terminal, within the project enter the following command - 

      $ composer require 'drupal/advagg:^4.1'

Next, enable the AdvAgg module

Install- Adv-agg-module


Configuration tab:

This tab provides several configuration options that are discussed below.

Global Options

Advagg- Configuration


  1. Enable/Disable the Advagg module temporarily by checking/unchecking the Enable advanced aggregation checkbox.
  2. Use this option if you want to allow DNS prefetching for external CSS/JS, which tries to settle domain names for links before a user clicks on them. Enabling this can have unwanted effects on site. Keep this unchecked unless needed.
  3. In the Cache settings, we have options like development, low, normal, high caching of resource (CSS/JS) files. High caching stores more data while normal stores less data compared to high. Development caching stores very less data. I'm going with normal here.

Compression options

Compression options-in-AddAvg

This provides Gzip compression and Brotli compression which are the methods used for compressing CS/JS assets.

CSS Options/JS Options

  1. In order to avoid multiple CSS/JS files in one page, AdvAgg uses media queries to determine what files are needed on a page and combine them so that they load faster.
  2. Fix improperly set type – This option will fix the problem in syntax, when you are trying to reference CSS and JS files if there are any problem there
  3. If this option is checked, the external stylesheets on the same host are not converted into files.

CRON Options

  1. Here you can set the minimum amount of time between advagg_cron() runs. The default value for this is 1 day.
  2. Use this option to Delete aggregates that were modified more than the chosen time. The default value for this is 1 month.

Obscure Options

This tab does not contain any configuration options. You can flush the module cache or entire cache in the Operation tab.

Bundler Tab :

This splits your aggregated resource files into multiple bundles of small resource files. With bundler active checked, you have more bundles of small CSS files, it makes sure that it strips anything that's not being used in a given page. Even with the more http request for a resource file you can have overall boost in the performance because of fewer bytes transmission.

Bundler tab

This tab has CSS Bundling and the Javascript Bundling with the same configuration settings.
1. Target Number of CSS/JS Bundles Per Page: Specify the number of CSS/JS Bundles to be sent per page.
2. Grouping Logic: You can select the aggregation logic should go by file count of file size.

CDN Tab:


Content distribution network (CDN), is a distributed network of proxy servers that helps immensely in boosting website performance and load time. Website content can be distributed to servers closest to the site visitor which makes response and load times even faster.

  1. CDN to use - Choose between a network of server providers Google and Microsoft. 
  2.  Checking Use Minified resources would reduce the bandwidth needed because of the smaller file sizes.

CSS Minification tab:


This allows the removal of white spaces, comments, unwanted variable names etc. You can select between the Core minifier or the YUI Compressor, where YUI is better form of compression.

External Minification tab:

External Minification is used when you are using command line compression.

JavaScript Minification tab:


For JS minification select a minifier. Selecting a faster minifier is always better.

Old IE Compatibility tab:


Prevent more than 4095 CSS selectors in the aggregated CSS file - You can modify the value to avoid getting errors from IE Version below 10, where if your CSS has more than 4095 selector IE will not render the page properly.


Jul 14 2020
Jul 14


On April 24, 1985, the first five US universities gained a domain that had ".edu." in their URL: University of California, Berkeley, Carnegie Mellon University, Purdue University, Rice University, and University of California, Los Angeles. At first, this possibility was available to any educational institution in the world, but since 2001 only American universities can access these domains.

By May 2020, Educase has registered 7,537 sites that have ".edu." in their URL. Our article is a grain of sand in a desert, but we did not try to describe all the sites of American universities. Our goal as Drupal development professionals is to show that one of the most popular CMS is perfect for developing websites in the field of education or science.

We’re developing the Bibliography & Citation (or BibCite) project and helping others to get to know it, we are staying in touch with universities, libraries, and research centers, whose websites are created on the Drupal CMS. The project is a set of modules that allows keeping, outputting, exporting and importing bibliographic data. We want to help even more institutions. The project is irreplaceable for professionals working with data sources that are valuable for science and humanity.

Why Drupal is a perfect fit for websites for educational institutions

  • Drupal is an open-source system that is essential for this type of organization: open source provides a rather low price, security, flexibility for millions of students and teachers around the world. It is also an opportunity to move to distance education which is so important now.
  • A large community of Drupal developers and enthusiasts are always ready to advise or provide their services.
  • Thanks to multisite functionality, developers can build a “solar system” of sites around one core. Very often, an educational institution is a complex that includes schools, colleges, libraries, sports teams, etc., which can have their own websites. If these sites use the same modules, then you can have a common code base for them. 
  • Drupal website differs from its competitors in taxonomy. Taxonomy is functionality for creating categories of content that assemble website materials. With its help, it is easy to build a complex multifaceted structure, where the same material may refer to different categories.
  • You don’t have to be a developer to administer Drupal websites. The basic functionality can be obtained by putting several checkmarks on the menu. A Drupal theme provides a layout for a website, so you don't have to code it.
  • University websites are often served by the students themselves. PHP has a low entry threshold so that you can replace one student with another for some reason (if the student is graduating soon, for example).
  • Drupal allows you to create accounts for different categories of users with different access rights to functionality and data on the website. What teachers see is not available to students.
  • Drupal websites are adapted for mobile devices by default. It is important because mobile traffic has been prevailing over the desktop. How many students and teachers do you think have a mobile phone?
  • Drupal supports interface localization for over a hundred languages. This allows you to develop websites for educational institutions around the world.
  • You can set up marketing campaigns for email and social networks with this CMS.
  • Users of the website get collaboration tools. Students can work together on research or the FAQ section with the help of the “Book” module.

Now we'll tell you a little bit about each website. But before — a small side note. We wrote this article during the events that have affected everyone. Therefore, the websites are similar to each other with news about COVID-19, statements on racial discrimination, and mob violence. This was reflected in the UX/UI of the home pages, but, after a few months, news agenda and websites may change again. Based on the above, we will ignore such impending changes.

Jul 14 2020
Jul 14

Even though installing Google Tag Manager (GTM) adds a layer of complexity, it is far more flexible (and powerful) than Google Analytics (GA) alone:

  • GTM can be set up to track advanced analytics, like Scroll Depth, Link Clicks, & Video Playback information.
  • GTM makes it easy to install custom tracking, like LinkedIn Insights or Facebook Pixel, without developer help.
  • GTM makes it easier to track transaction data, like order amount, which is essential for ROI calculations for your ad campaigns.

While not difficult, it does take a little time and effort to complete. Below are the steps Volacci goes through to do a Google Tag Manager install on all our clients’ Drupal websites.


Except in very special cases, you do not want to have both the Google Analytics and Google Tag Manager modules (or embedded code snippets) enabled on your site at the same time -- it can skew your Analytics. We recommend coordinating the Google Tag Manager installation & configuration with disabling your Google Analytics module. Contact your developer if you have questions on how Google Analytics is currently installed on your website -- or if you have multiple GA codes deployed, which can complicate things further.

Google Account Sign Ups

While we offer top level instructions in this section, you may need to find additional resources on the exact steps for signing up for these accounts. Google tends to change things periodically, so it’s best to find their step by step instructions. We've included links to their current instructions in this section.

  1. If you don’t already have one, sign up for a free Google Account.
    This will include a gmail account. If your company already uses Gmail for email, then you can use that Google Account. You’ll use this account for all the sign ups that follow.
  2. Sign up for Google Analytics for your website. When you complete this process, you will have created a property for your website on the GA admin Tracking Info > Tracking Code page. There will be a tracking code there that looks something like this:

    We recommend opening a text editor and copying and pasting this tracking ID so you have it handy for your GTM set up. You’ll be using this text document again later, so leave it open.
  3. Create a Google Search Console (GSC) account for your website. This account will track organic (search) traffic to your website and can also be integrated into your Google Analytics (GA) account.
    For information on integrating GSC into your GA account, go here for their detailed instructions.
  4. Set up your website’s Google Tag Manager account.
    google tag manager add a new account dialog box
  5. Fill out the Account Name and Container name fields with your organization’s and website’s information, and select “Web” under Target platform.
  6. Click Create, agree to the terms of service and GDPR rules, and you should be presented with a pop up window containing two different code snippets. The top one will look like this:
    google tag manager snippet code example
  7. Highlight the GTM-XXXXXXX number as we have in the example above.
  8. Copy and paste that number into the same text editor you placed your Google Analytics tracking ID.
  9. Deploy Google Analytics using Google Tag Manager by following Google's instructions. NOTE: You’ll need the UA-XXXXXXX-1 number you pasted into your text document for this step.

Install The Google Tag Manager Module

You may need to get help from your developer with this process. Contact them should you have any questions or issues. Sending along a link to this page could help speed things up.

  1. Make a backup of your website. If something goes wrong, you’ll need to restore your website from a backup.
  2. Install the Google Tag Manager module available here: https://www.drupal.org/project/google_tag

    NOTE: Drupal module installation instructions can be found here: https://www.drupal.org/docs/extending-drupal/installing-modules

  3. Once the module is installed, make sure it’s enabled by going to the Extend page of your website: Click Manage > Extend or visit https://yourdrupalwebsite.com/admin/modules.
    Note: if you are using Drupal 7, you may need to consult the D7 specific instructions.
  4. In the search box, enter “google tag” to find the Google Tag Manager module.
    google tag manager drupal module enable
    • If the check box next to the module is checked, then the module has been enabled and is ready for configuration. Move on to Configure The Google Tag Manager Module.
    • If the check box next to the module is not checked, it will need to be enabled.

      If you have permissions to enable a module, you can select the check box next to the module, and click the Install button at the bottom of the page.

      NOTE: If you do not have permissions to enable the module, you’ll need to contact your web developer to enable it and give you the appropriate permissions to install and configure the GTM module.

Make sure you have that text document handy that contains the GTM container ID that was generated above.

  1. On your Drupal site, go to Manage > Configuration > System > Google Tag Manager or visit http://<www.yourdrupalwebsite.com>/admin/config/system/google-tag in your browser.
    This will take you to the Google Tag Manager containers page.
    drupal google tag manager container
  2. Click on the + Add container button. This will take you to the Add container page.

  3. Enter a relevant name in the Label field.
  4. In the Container ID field, enter the Container ID  (GTM-XXXXXXX) you copied from Google Tag Manager.
  5. Leave all other settings at their default.
  6. Click the Save button at the bottom of the page.

Testing Your Installation

We recommend testing to make sure your Google Tag Manager is properly installed and configured. Here at Volacci, we test in several different ways using the Chrome browser. If you use a different browser, some of these methods may not work.

  1. Go into the Google Tag Manager workspace for your website and follow Google's instructions for testing with Preview mode.
  2. Install Google Tag Assistant within your Chrome browser. 

    For additional information on how to use Google Tag Assistant for testing and troubleshooting your Google product installations, visit Google's support page

There you have it. You should be all set to gather Google Analytics data and make deployment of 3rd party scripts to your website much easier.

We always try to make sure our posts are as accurate and up to date as possible. If you find something is wrong, or you have a question, please feel free to contact us with any questions or feedback you might have.

And remember, Volacci stands ready to help you implement your Google Tag Manager and Google Analytics should you need us to.

Happy Drupaling!

Jul 13 2020
Jul 13

Drupal 9’s big splash in early June sparked a widespread realization that migration needed to move to front burner status in anticipation of a Nov. 2021 decommission date for Drupal 7 and 8. That sense of urgency has been temporarily tabled as the Drupal organization took the widespread uncertainty and upheaval of the global pandemic into account, and moved the end-of-life date for Drupal 7 and Drupal 8 out by one year to November 2022.

So now what?

How does this date extension change how site owners should be approaching migration? What’s in store for Drupal 9? And what else do we need to know right now? 

Subscribing to the Kenneth Blanchard conviction that, “None of us is as smart as all of us,” we reached out this week to some of Promet’s top experts for insights into these and other important issues.

Here’s what they had to say:

Drupal 9 Expert Panelists

Juan Garay, Project Manager, Scrum Master
Luc Bezier, Solutions Architect
Aaron Armstrong, Drupal Developer
John Ross Castano, Web and Support Developer

Q. Now that the Drupal Organization has extended for one year -- from Nov. 2021 to Nov. 2022 -- the decommission date for Drupal 7 and 8, is there a compelling reason to migrate now?

Juan: I wouldn’t suggest migrating to 9 now, as there are many contributed modules that are not available for Drupal 9 yet.

I would tho encourage anyone to migrate from Drupal 7 to 8 ASAP, as the improvements between Drupal 7 and Drupal 8 are far and many.

Also, migrating right now from Drupal 7 to Drupal 8 will make for a much smoother migration path to Drupal 9 in the future, as Drupal 8 to Drupal 9 migrations (content in particular), are meant to be considerably smoother than migrations from previous versions of Drupal.

Aaron: November 2, 2021 is still the date that we need to focus on as the effective end-of-life date for Drupal and 8. Drupal is dependent upon Symfony, and Symfony will no longer be supported after November 2021. Security patches are all that will remain available after that date. My recommendation for any website that’s still on Drupal 7 is to move forward now with a migration to Drupal 8, and then as Drupal 9 matures, build out a Drupal 9 migration timeline. 

Q. What do you view as the primary, overarching benefit of Drupal 8 and 9 over Drupal 7?

Juan: In Drupal 8 and Drupal 9, nearly the entire system uses the Drupal Entity API, which provides a much more robust and flexible framework for building custom solutions.

John Ross: Drupal 8 and 9 have improved over Drupal 7 by leaps in bounds in terms of deployments through Configuration Management (and content). Automatic deployment is a breeze between environments and has become very robust since Drupal 7. This is one of the biggest issues or dilemmas on our multi-environment development workflow when using Drupal 7. Drupal 7 heavily relies on Features and other similar modules, but cannot really provide a “one-size-fits-all” solution for an automatic deployment.

Aaron: The deployment and configuration export/import is the biggest benefit for Drupal 8 and 9. It saves hours upon hours of work, which previously was accomplished with Features. 

Also, there are a multitude of contributed modules in Drupal 7, which are now core modules in Drupal 8. Translations are a huge example. Drupal 8 comes ready, out of the box, for translations. Drupal 7, on the other hand, required loads of contributed modules and configurations to accomplish the same thing. 

Q. Drupal 9 has been described as akin to more of a “point release” from Drupal 8 than the Drupal 7 to Drupal 8 leap forward in features and functionality. So what is new or potentially game-changing about Drupal 9?

Luc: Drupal 9 is not a game changer, in the sense that Drupal 8 was. Drupal depends on Symfony, if you were to very quickly summarize, you could say that Drupal 9 is essentially a new version of Symfony under the hood. Drupal 9.0 has the same features Drupal 8.9, with a clean up of some functions that it was using. The aspect of Drupal 9 that is game changing is the fact that it is the first release for Drupal to be non-breaking. You don’t need to process a major migration to update, it is relatively easy to migrate from Drupal 8 to Drupal 9. 

Aaron: Drupal 9 solidifies some of the features in Drupal 8. As others have mentioned, it also is a very easy upgrade between Drupal 8 and 9. Up to this point, Drupal migrations have been time-consuming process. 

Q. Drupal 7 was released on Jan. 5, 2011, nearly 10 years ago. Can you comment on some of the most significant trends in UI/UX or within Drupal functionality that have emerged since that time?

Juan: Among the most significant developments is the ability to edit content inline, in real-time through the Drupal 8 Layout Builder interface

Luc: During the development of Drupal 8, I remember meeting Alex Pott (Drupal 8 core co-maintainer, and Drupal 8 configuration system co-maintainer). I worked with him on some changes to the configuration system. This system is for me the biggest improvement in the way we build and maintain large websites using Drupal 8 and above.

Aaron: The use of importing and exporting configuration yaml files is the most significant change from Drupal 7. The default back-end theme has improved greatly, along with the number of core modules in Drupal 8 and 9. 

Q. How have businesses and organizations changed in their use of and need for Drupal over the past decade?  

Luc: The complexity of websites have increased, and thanks to Drupal’s level of abstraction, we are also able to build more complex solutions. For example, it is common for large companies or administrations to have more than a dozen of websites now, and using Drupal with tools like Acquia Cloud Site Factory, one company can generate websites on demand.

Aaron: Drupal has always been an enterprise type CMS that works well with larger sites. I think it has continued to work in that space, while allowing for much more complex sites, deployments, and configuration sharing.

There also have been huge leaps ahead with the hosting provided by Acquia and Pantheon. 

Q. What do you view as the most significant Drupal evolutionary developments over the past decade?

Aaron: The possibility of headless Drupal is what first comes to mind, but the configuration management, as well as translations being part of core, are the biggest advancements in my opinion.

Luc: The past decade saw the emergence of static sites generators (Jekyll in Ruby, Hugo in Go). I find it very interesting as it is removing all the overhead of modern websites for performance and maintenance. Nothing will ever be faster than a plain HTML page. A module like Tome (by Samuel Mortenson) bridges the gap between Drupal and the static sites generator solutions, allowing Drupal to be automatically exported as plain HTML. This opens some interesting possibilities for Drupal.

Any other questions on Drupal? Drupal 9? The path to migration? Drupal is in our DNA at Promet Source and we are happy to help. Let us know what we can do for you!  Contact us today


Jul 13 2020
Jul 13

Defining a brand design system in Figma

For the past year at Kalamuna, we have, slowly but surely, been working on refreshing our brand. Over much discussion, internal and external collaboration with branding agency C42D, and iteration, we ended up with a guide that laid the groundwork for our new brand strategy and visual identity system. This guide, however useful, was quite limited as a PDF. While PDFs are sufficient for viewing elements in practice, we require greater control over the properties of elements to easily duplicate and modify them across different projects and use cases. So we decided to recreate and expand on it in Figma. Along the way, we visited old and new Figma concepts and features that apply not only to branding projects but design projects across the board. 

Although there is an ‘i’ in Figma, its philosophy is less individualized and more focused as a collaborative tool that has been called the “Google Docs” for designers.

Figma is a cloud-based tool available as a web app and a desktop app. Like Google Docs, you and your teammates can collaborate in real-time and leave and resolve comments as well, which is particularly useful for distributed teams like ours at Kalamuna. Figma also brings the “single source of truth” principle and version history from software design to UI/UX design. In other words, no more accidentally overwriting the work of your teammates or working on incorrect or outdated project files.

Eight design file icons with variable saved names, such as 'project.dsgn'An example of a file naming strategy many designers have used at one point or another to deal with multiple iterations of a file. 

For these reasons, Figma is the perfect tool for putting together a living document to define a growing and changing brand design system. 

We’ve broken down these Figma concepts and features into the following categories:

  1. Components
  2. Color and Text Styles
  3. Layout
  4. Prototyping

1. Creating Components

A Component in Figma can be thought of as a parent and every copy or instance, its child. The parent is called the master Component and changes to it are inherited by its children. This is very useful for commonly used elements like logos. 

Screenshots of creating a component in Figma using Kalamuna's logo as an example.An example of creating a Component with Kalamuna's horizontal logo. 

Instances of Kalamuna’s horizontal logo Component placed into a Kalamuna branding graphic example. Instances of Kalamuna’s horizontal logo Component throughout the guide.

A Component is even more useful when published to your Team Library. The Team Library is globally accessible throughout all projects and includes Components, Text, and Color Styles. It’s also easy to enable on any given project. This way, all branding projects can be consistent and reference the same logo and styles. Most organizations at one point in their existence are left negotiating between several different versions of their logo. Applying the single source of truth principle here saves us time searching through numerous files and folders for the right version of our logo and saves us from potentially costly errors like print or digital ad banners with outdated versions of our logo.

An example of publishing updates to the Team Library and enabling them in a new file in Figma.Here we are publishing our updated Kalamuna Brand Guidelines file to the Team Library and then enabling it in a new file so we can start using Kalamuna’s horizontal logo Component.

We repeated this process of creating Components and publishing to our Team Library for other icons tied to our brand like the heart icon that is part of our purpose statement, as well as the plus icon used for list item bullets. 

Examples of different Components like a pink heart, social media icons like LinkedIn and Instagram published to the Kalamuna Team Library.Examples of icon Components in our Kalamuna Brand Guidelines file published to the Team Library.

Our updated button definitions remain a work-in-progress, but storing all button states in one Component has helped us avoid maintaining several different Components – keeping our inventory tidy.

Examples of different button states, like press, hover, focus, stored in a single Component. Examples of different button states stored in a single Component. 

2. Color and Text Styles

Colors and typography are key to the values and personality of a brand’s expression. Color Styles and Text Styles allow us to apply color and typographic styles consistently. You can find styles in the text, fill, and stroke panels by clicking the button with the four dots in it. This brings up a popup of already defined styles and a plus sign to add more styles. 

Examples of Text Styles and Color Styles in the design panel of a text element with styles varying from headings to body text. Examples of Text Styles and Color Styles in the design panel of a text element.

We had some previously established type rules, like our fonts (as seen on this blog) and font sizes. We used these rules to define styles for our headings, paragraphs, and general text. Once defined, any type or color updates will be reflected in all elements that use this style, as with Components. We made tweaks to established line heights and spacing and instantly saw the project file update. 

Updating the size of a Text Style and seeing elements using that Text Style change automatically. Here we are updating the size of a Text Style and seeing elements using that Text Style change instantly. 

To make global updates to these styles, we need to republish to the Team Library.

3. Layout

As your guide or project grows, updating content while keeping the intended space between elements can become a chore. Maybe some paragraph copy needs to be changed or a list item removed, which results in all items below it needing to be manually shifted down or up. Luckily, Figma released their new Auto Layout feature back in December, which has saved us a lot of time by automating these tasks.

Elements with Auto Layout enabled dynamically resize themselves to fit their contents. There are options to specify direction, space around and in between nested items. For anyone familiar with CSS, it resembles CSS Grid Layout and Flexbox in these respects. It would be great to extend these similarities even further with greater control over how much space an item should occupy, for example, 25% or the remaining space, but that’s a whole other topic.

An example of an element with Auto Layout enabled. Typing extra content into this element automatically resizes it.Here we are typing extra content into an element with Auto Layout enabled and seeing it resize automatically.

Patterns of repeating elements benefit the most from this feature, like a list, or a grid of cards, or elements with defined padding like buttons.

An example of a row of images with Auto Layout enabled in Figma. Images can be easily moved using arrow keys as a result.In this example, we can easily move elements around with our arrow keys because Auto Layout is enabled.

4. Prototyping

After our first iteration in Figma we realized we didn’t have an effective way to navigate the guide outside of the default next and previous navigation built into Figma’s presentation mode. Our Director of Design & UX suggested adding a fixed menu, which was a great solution. With Figma’s prototype feature, we created a scrollable frame to list clickable text labels linked to each frame in the guide. This scrollable frame opens after clicking a custom hamburger menu Component found in the top corner of each frame.

A screenshot showing prototype connections between text labels and frames in Figma.Prototype connections between text labels and frames. The Kalamuna brand guide in prototype mode. Clicking the hamburger icon on the top right opens a scrollable menu and clicking the x icon closes it.Our guide menu in action. Clicking the hamburger menu icon opens the scrollable menu and clicking the x icon closes it.

We also prototyped primary and secondary color palette frames. As an agency that strongly values accessibility, we wanted to include information like color contrast ratios and rules for text sizes based on the WCAG 2.1 guidelines. But, we wanted to do so in a seamless way that wouldn't clutter the already compact color boxes. To solve this, we made this information appear by checking a box for more details.

A screenshot from the Kalamuna brand guide in Figma showing prototype connections between checkboxes and frames with accessibility information.Prototype connections between checkboxes and frames showing accessibility information. The color palette page of the Kalamuna brand guide in prototype mode. Clicking the checkbox shows and hides accessibility information.The color palette checkboxes in action. Clicking the checkbox shows and hides accessibility information. 

Wrapping up...

There’s always an ‘and’ in rebrand; it’s an ongoing process that doesn’t conclude with the creation of guidelines. A guide is really just the beginning. We see our brand guide as a living document that will continue to grow and improve along with the tools we used to build it, and of course evolve with Kalamuna itself. When creating your own guide, we hope you make use of Components, Color Styles, Text Styles, Auto Layout, and prototypes to make your rebranding journey as streamlined as possible.

Jul 13 2020
Jul 13

The Drupal community plays an important role for those who use the Drupal framework on a daily basis. Developers, project managers, designers, marketing managers, end-users, everyone that work with Drupal can benefit from an event like this in a big way. Growing the network is a valuable factor, and at these large events it is possible to share and collaborate about your open source knowledge. It is so inspiring and empowering for everyone involved, and it does not matter if you are new to Drupal or if you have decade of experiences in your bag, everyone leaves the event like this inspired and looking forward to the next DrupalCamp and the next DrupalCon.

Highlight of this year DrupalCon Global

This DrupalCon is different from what we are used to. There will be no in-person parties or surprise bumping-into old Drupal friends, but to focus on the positive the event is packed with great sessions. We are looking at a week of 100 sessions including industry and topical mini summits, interesting sessons from professionals, presentations from sponsors, on demand video library and lots of other content to keep us entertained this week!

We at 1xINTERNET are very happy that our CEO and Co-Founder Baddy Sonja will take part in two summits at this DrupalCon Global. Baddy will be taking part in the Government Summit on Tuesday 14th of July at 18:00 UTC organised by Becca Goodman and Jess Dearie . Baddy will talk about how the City of Reykjavik changed from building websites to building culture and framework for digital development, and why it's important to have a good content strategy.

On Wednesday 15th at 14:00 UTC she will take part in the Community Summit where she will give an Events Organizer update. Directly after her session at the Community Summit she will participate in the Public Q&A with the Drupal Association staff and board together with Dries, Adam Goodman (chairman of the board), Heather Rocker (Executive Director of the DA) and Tim Lehnen (CTO of the DA). This session is interesting for everyone who would like to know more about the Drupal Association and how it is supporting the project. Since November last year, Baddy is the Treasurer of the board of the Drupal Association and will give an update on the financials as well as other activities of the Drupal Association. You will also find Baddy both in the Event organiser group booth and the Drupal Association booth during exhibition hours. Please stop by and say hi to her ( Baddy loves that:).

Jul 13 2020
Jul 13

Creating components using the Paragraphs module offers incredible flexibility in building pages based on Drupal. One of the common restrictions is the issue of reusing the same paragraphs in very similar components. If the only thing that limits you is the set and layout of fields, the Paragraph View Mode module will help you.

The very first lines of the module's code were created as a dedicated module for one of the projects we implemented. I quickly noticed, however, how such a functionality could be useful in the whole Paragraphs module ecosystem. Currently, the module has a stable 1.4 version and is covered by the Security Advisory Policy.


The first version of the module was released in July 2019. Since then, I have been actively following the list of issues, implementing patches and new functionalities. The last patches were introduced to the developer version in July 2020.

Module's popularity

According to the statistical data published on the module's page: https://www.drupal.org/project/paragraph_view_mode, it is currently used by about 450 websites, which translates into approximately 10 uses per week.

Module's creators

The first draft of the module was created in order to address the needs of a current project. After its initial release on the drupal.org website, I introduced some additional improvements and new functionalities. The community also helped, e.g. with making the module compatible with Drupal 9.
Currently, I am the only person who worked directly on the module's code. The module itself is supervised by two maintainers who respond to all issues as quickly as possible.

What is the module used for? 

Paragraph View Mode is a sub-module for the Paragraphs module. Its advantages will be appreciated by both, developers and people responsible for editing content on a website. It may be necessary when:

  • you are building a website from many components, and some of them are very similar, e.g. they use a similar set of fields;
  • you want to minimise the number of components with regards to the administration;
  • you think about streamlining the frontend part;
  • you want to ensure better organisation of templates with regards to the UI and directly within the code;
  • you want to avoid using many complex field-based modifiers, e.g. lists.

As you can see, this module can offer several useful functions, and all this goes hand in hand with the simplicity of this solution in accordance with the so-called "Drupal Way".


You can download the module from the https://www.drupal.org/project/paragraph_view_mode webpage or via composer:

composer require drupal/paragraph_view_mode

After the installation, go to editing the selected paragraph type, the default path is usually:
In the "Paragraph View Mode" drop-down section, select the option “Enable Paragraph view mode field on this paragraph type" and then save the form.


The module will automatically create a "Paragraph view mode" field with a configuration widget (available in the manage form display tab).
The widget's configuration consists of two fields. The first field is the selection of available display modes. The module automatically receives a list of only those that are unblocked on the current paragraph type, while you can decide which of them you want to display on the list of options in the form.

The second field is used to define the default value of the field in the absence of its value (e.g. for a newly created paragraph).


With the module configured in this way, you can dynamically switch the display modes directly in the page adding/editing form.


Plans for the future

The basic functionality of the module is already completed, and it is hard to come up with new functionalities. Recently, however, I created a new issue https://www.drupal.org/project/paragraph_view_mode/issues/3150153, in which I plan (with a little help from the community) to develop the functionality of linking the field value with the display mode of the form and its dynamic substitution. I also intend to continue supporting Drupal 9 and future versions.


The Paragraph View Mode module, despite its low complexity, offers a lot regarding the efficiency, convenience and – above all – flexibility of the editors' work. In addition, it allows the Drupal developers or the person responsible for the website to reduce the amount of work needed to organise and maintain the components on the website, thus reducing the overall cost of maintaining the website.

Jul 13 2020
Jul 13

In a previous article we explained the syntax used to write Drupal migration. We also provided references of subfields and content entities' properties including those provided by the Commerce module. This time we are going to list the configuration options of many migrate source plugins. For example, when importing from a JSON file you need to specify which data fetcher and parser to use. In the case of CSV migrations, the source plugin configuration changes depending on the presence of a headers row. Finding out which options are available might require some Drupal development knowledge. To make the process easier, in today’s article we are presenting a reference of available configuration options for migrate source plugins provided by Drupal core and some contributed modules.

List of configuration options for source plugins

For each migrate source plugin we will present: the module that provides it, the class that defines it, the class that the plugin extends, and any inherited options from the class hierarchy. For each plugin configuration option we will list its name, type, a description, and a note if it is optional.

SourcePluginBase (abstract class)

Module: Migrate (Drupal Core)
Class: Drupal\migrate\Plugin\migrate\source\SourcePluginBase
Extends: Drupal\Core\Plugin\PluginBase

This abstract class is extended by most migrate source plugins. This means that the provided configuration keys apply to any source plugin extending it.

List of configuration keys:

  1. skip_count: An optional boolean value. If set, do not attempt to count the source. This includes status and import operations.
  2. cache_counts: An optional boolean value. If set, cache the source count. This saves time calculating the number of available records in the source when a count operation is requested.
  3. cache_key: An optional string value. Uniquely named cache key used for cache_counts.
  4. track_changes: An optional boolean value. If set, the Migrate API will keep a hash of the source rows to determine whether the incoming data has changed. If the hash is different the record is re-imported.
  5. high_water_property: An optional array value. If set, only content with a higher value will be imported. The value is usually a timestamp or serial ID indicating what was the last imported record. This key is configured as an associate array. The name key indicates the column in the source that will be used for the comparison. The alias key is optional and if set it serves as a table alias for the column name.
  6. source_module: An optional string value. Identifies the system providing the data the source plugin will read. If not set, the Migrate API tries to read the value from the source plugin annotation. The source plugin itself determines how the value is used. For example, Migrate Drupal's source plugins expect source_module to be the name of a module that must be installed and enabled in the source database.

The high_water_property and track_changes are mutually exclusive. They are both designed to conditionally import new or updated records from the source. Hence, only one can be configured per migration definition file.

SqlBase (abstract class)

Module: Migrate (Drupal Core)
Class: Drupal\migrate\Plugin\migrate\source\SqlBase
Extends: Drupal\migrate\Plugin\migrate\source\SourcePluginBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, and source_module.

This abstract class is extended by migrate source plugins whose data may be fetched via a database connection. This means that the provided configuration keys apply to any source plugin extending it.

In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:

  1. key: An optional string value. The database key name. Defaults to 'migrate'.
  2. target: An optional string value. The database target name. Defaults to 'default'.
  3. database_state_key: An optional string value. Name of the state key which contains an array with database connection information. The Migrate API will consult the States API using the provided key. The returned value should be an associative array with at least two keys: key and target to determine which database connection to use. A third key database can also be included containing database connection information as seen in the snippet below.
  4. batch_size: An optional integer value. Number of records to fetch from the database during each batch. If omitted, all records are fetched in a single query.
  5. ignore_map: An optional boolean value. Source data is joined to the map table by default to improve performance. If set to TRUE, the map table will not be joined. Using expressions in the query may result in column aliases in the JOIN clause which would be invalid SQL. If you run into this, set ignore_map to TRUE.

To explain how these configuration keys are used, consider the following database connections:

<?php $databases['default']['default'] = [ 'database' => 'drupal-8-or-9-database-name', 'username' => 'drupal-8-or-9-database-username', 'password' => 'drupal-8-or-9-database-password', 'host' => 'drupal-8-or-9-database-server', 'port' => '3306', 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', 'driver' => 'mysql', ]; $databases['migrate']['default'] = [ 'database' => 'drupal-6-or-7-database-name', 'username' => 'drupal-6-or-7-database-username', 'password' => 'drupal-6-or-7-database-password', 'host' => 'drupal-6-or-7-database-server', 'port' => '3306', 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', 'driver' => 'mysql', ];

This snippet can be added to settings.php or settings.local.php. The $databases array is a nested array of at least three levels. The first level defines the database keys: default and migrate in our example. The second level defines the database targets: default in both cases. The third level is an array with connection details for each key/target combination. This documentation page contains more information about database configuration.

Based on the specified configuration values, this is how the Migrate API determines which database connection to use:

  • If the source plugin configuration contains database_state_key, its value is taken as the name of a States API key that specifies an array with the database configuration.
  • Otherwise, if the source plugin configuration contains key, the database configuration with that name is used.
  • Otherwise, load a fallback state key from the States API. The value that it tries to read is the global state key: migrate.fallback_state_key.
  • Otherwise, the database connection named migrate is used by default.
  • If all of the above steps fail, a RequirementsException is thrown.

Note that all values configuration keys are optional. If none is set, the plugin will default to use the connection specified under $databases['migrate']['default']. At least, set the key configuration even if the value is migrate. This would make it explicit which connection is being used.

DrupalSqlBase (abstract class)

Module: Migrate Drupal (Drupal Core)
Class: Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase
Extends: Drupal\migrate\Plugin\migrate\source\SqlBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, source_module, key, target, database_state_key, batch_size, and ignore_map.

This abstract class provides general purpose helper methods that are commonly needed when writing source plugins that use a Drupal database as a source. For example, check if the given module exists and read Drupal configuration variables. Check the linked class documentation for more available methods.

In addition to the keys provided in the parent class chain, this abstract class provides the following configuration key:

  1. constants: An optional array value used to add module dependencies. The value is an associative array with two possible elements. The first uses the entity_type key to add a dependency on the module that provides the specified entity type. The second uses the module key to directly add a dependency on the specified module. In both cases, the DependencyTrait is used for setting the dependencies.

Warning: A plugin extending this abstract class might want to use this configuration key in the source definition to set module dependencies. If so, the expected keys might clash with other source constants used in the process pipeline. Arrays keys in PHP are case sensitive. Using uppercase in custom source constants might avoid this clash, but it is preferred to use a different name to avoid confusion.

This abstract class is extended by dozens of core classes that provide an upgrade path from Drupal 6 and 7. It is also used by the Commerce Migrate module to read product types, product display types, and shipping flat rates from a Commerce 1 database. The same module follows a similar approach to read data from an Ubercart database. The Paragraphs module also extends it to add and implement Configurable Plugin interface so it can import field collection types and paragraphs types from Drupal 7.


Module: Migrate Drupal (Drupal Core). Plugin ID: d8_config
Class: Drupal\migrate_drupal\Plugin\migrate\source\d8\Config
Extends: Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, source_module, key, target, database_state_key, batch_size, ignore_map, and constants.

This plugin allows reading configuration values from a Drupal 8 site by reading its config table.

In addition to the keys provided in the parent class chain, this plugin does not define extra configuration keys. And example configuration for this plugin would be:

source: plugin: d8_config key: migrate skip_count: true

In this case we are setting the key property from SqlBase to use the migrate default database connection. The skip_count from SourcePluginBase indicates that there is no need to count how many records exist in the source database before executing migration operations like importing them.

This plugin is presented to show that Drupal core already offers a way to migrate data from Drupal 8. Remember that there are dozens of other plugins extending DrupalSqlBase. It would be impractical to list them all here. See this API page for a list of all of them.


Module: Migrate Source CSV. Plugin ID: csv
Class: Drupal\migrate_source_csv\Plugin\migrate\source\CSV
Extends: Drupal\migrate\Plugin\migrate\source\SourcePluginBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, and source_module.

This plugin allows reading data from a CSV file. We used this plugin in the CSV migration example of the 31 days of migration series.

In addition to the keys provided in the parent class chain, this plugin provides the following configuration keys:

  1. path: A string value. It contains the path to the CSV file. Starting with the 8.x-3.x branch, stream wrappers are supported. The original article contains more details on specifying the location of the CSV file.
  2. ids: An array of string values. The column names listed are used to uniquely identify each record.
  3. header_offset: An optional integer value. The index of record to be used as the CSV header and the thereby each record's field name. It defaults to zero (0) because the index is zero-based. For CSV files with no header row the value should be set to null.
  4. fields: An optional associative array value. It contains a nested array of names and labels to use instead of a header row. If set, it will overwrite the column names obtained from header_offset.
  5. delimiter: An optional string value. It contains a one character column delimiter. It defaults to a comma (,). For example, if your file uses tabs as delimiter, you set this configuration to \t.
  6. enclosure: An optional string value. It contains one character used to enclose the column values. Defaults to double quotation marks (").
  7. escape: An optional string value. It contains one character used for character escaping in the column values. It defaults to a backslash (\).

Important: The configuration options changed significantly between the 8.x-3.x and 8.x-2.x branches. Refer to this change record for a reference of how to configure the plugin for the 8.x-2.x.

For reference, below is the source plugin configuration used in the CSV migration example:

source: plugin: csv path: modules/custom/ud_migrations/ud_migrations_csv_source/sources/udm_photos.csv ids: [photo_id] header_offset: null fields: - name: photo_id label: 'Photo ID' - name: photo_url label: 'Photo URL'


Module: Migrate Spreadsheet. Plugin ID: spreadsheet
Class: Drupal\migrate_spreadsheet\Plugin\migrate\source\Spreadsheet
Extends: Drupal\migrate\Plugin\migrate\source\SourcePluginBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, and source_module.

This plugin allows reading data from Microsoft Excel and LibreOffice Calc files. It requires the PhpOffice/PhpSpreadsheet library and many PHP extensions including ext-zip. Check this page for a full list of dependencies. We used this plugin in the spreadsheet migration examples of the 31 days of migration series.

In addition to the keys provided in the parent class chain, this plugin provides the following configuration keys:

  1. file: A string value. It stores the path to the document to process. You can use a relative path from the Drupal root, an absolute path, or stream wrappers.
  2. worksheet: A string value. It contains the name of the one worksheet to process.
  3. header_row: An optional integer value. This number indicates which row contains the headers. Contrary to CSV migrations, the row number is not zero-based. So, set this value to 1 if headers are on the first row, 2 if they are on the second, and so on.
  4. origin: An optional string value. It defaults to A2. It indicates which non-header cell contains the first value you want to import. It assumes a grid layout and you only need to indicate the position of the top-left cell value.
  5. columns: An optional array value. It is the list of columns you want to make available for the migration. In case of files with a header row, use those header values in this list. Otherwise, use the default title for columns: A, B, C, etc. If this setting is missing, the plugin will return all columns. This is not ideal, especially for very large files containing more columns than needed for the migration.
  6. row_index_column: An optional string value. This is a special column that contains the row number for each record. This can be used as a unique identifier for the records in case your dataset does not provide a suitable value. Exposing this special column in the migration is up to you. If so, you can come up with any name as long as it does not conflict with header row names set in the columns configuration. Important: this is an autogenerated column, not any of the columns that comes with your dataset.
  7. keys: An optional associative array value. If not set, it defaults to the value of row_index_column. It contains the "columns" that uniquely identify each record. The keys are column names as defined in the data_rows key. The values is an array with a single member with key 'type' and value a column type such as 'integer'. For files with a header row, you can use the values set in the columns configuration. Otherwise, use default column titles like A, B, C, etc. In both cases, you can use the row_index_column column if it was set.

Note that nowhere in the plugin configuration you specify the file type. The same setup applies for both Microsoft Excel and LibreOffice Calc files. The library will take care of detecting and validating the proper type.

For reference, below is the source plugin configuration used in the LibreOffice Calc migration example:

source: plugin: spreadsheet file: modules/custom/ud_migrations/ud_migrations_sheets_sources/sources/udm_book_paragraph.ods worksheet: 'UD Example Sheet' header_row: 1 origin: A2 columns: - book_id - book_title - 'Book author' row_index_column: 'Document Row Index' keys: book_id: type: string

SourcePluginExtension (abstract class)

Module: Migrate Plus
Class: Drupal\migrate_plus\Plugin\migrate\source\SourcePluginExtension
Extends: Drupal\migrate\Plugin\migrate\source\SourcePluginBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, and source_module.

This abstract class provides extra configuration keys. It is extended by the URL plugin (explained later) and by source plugins provided by other modules like Feeds Migrate.

In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:

  1. fields: An associative array value. Each element represents a field that will be made available to the migration. The following options can be set:
  2. name: A string value. This is how the field is going to be referenced in the migration. The name itself can be arbitrary. If it contains spaces, you need to put double quotation marks (") around it when referring to it in the migration.
  3. label: An optional string value. This is a description used when presenting details about the migration. For example, in the user interface provided by the Migrate Tools module. When defined, you do not use the label to refer to the field. Keep using the name.
  4. selector: A string value. This is another XPath-like string to find the field to import. The value must be relative to the location specified by the item_selector configuration. In the example, the fields are direct children of the records to migrate. Therefore, only the property name is specified (e.g., unique_id). If you had nested objects or arrays, you would use a slash (/) character to go deeper in the hierarchy. This will be demonstrated in the image and paragraph migrations.
  5. ids: An associative array value. It contains the "columns" that uniquely identify each record. The keys are column names as defined in the data_rows key. The values is an array with a single member with key 'type' and value a column type such as 'integer'.

See the code snippet for the Url plugin in the next section for an example of how these configuration options are used.

Url (used for JSON, XML, SOAP, and Google Sheets migrations)

Module: Migrate Plus. Plugin ID: url
Class: Drupal\migrate_plus\Plugin\migrate\source\Url
Extends: Drupal\migrate_plus\Plugin\migrate\source\SourcePluginExtension
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, source_module, fields, and ids.

This plugin allows reading data from URLs. Using data parser plugins it is possible to fetch data from JSON, XML, SOAP, and Google Sheets. Note that this source plugin uses other plugins provided by Migrate Plus that might require extra configuration keys in addition to the ones explicitly defined in the plugin class. Those will also be listed.

In addition to the keys provided in the parent class chain, this plugin provides the following configuration keys:

  1. urls: An array of string values. It contains the source URLs to retrieve. If the file data fetcher plugin is used, the location can be a relative path from the Drupal root, an absolute path, a fully-qualified URL, or a stream wrapper. See this article for details on location of the JSON file. If the HTTP data fetcher plugin is used, the value can use any protocol supported by curl. See this article for more details on importing remote JSON files.
  2. data_parser_plugin: A string value. It indicates which data parser plugin to use. Possible values provided by the Migrate Plus module are json, xml, simple_xml, and soap. If the Migrate Google Sheets module is installed, it is possible to set the value to google_sheets. Review the relevant articles in the 31 days of migration series to know more about how each of them are used.

The data parser plugins provide the following configuration keys:

  1. item_selector: A string value. It indicates where in the source file lies the array of records to be migrated. Its value is an XPath-like string used to traverse the file hierarchy. Note that a slash (/) is used to separate each level in the hierarchy.
  2. data_fetcher_plugin: A string value. It indicates which data parser plugin to use. Possible values provided by the Migrate Plus module are file and http.

The HTTP data fetcher plugins provide the following configuration keys:

  1. headers: An associative array value. The key/value pairs represent HTTP headers to be sent when the request is made.
  2. authentication: An associative array value. One of the elements in the array should be the plugin key which indicates the authentication plugin to use. Possible values provided by the Migrate Plus module are basic, digest, and oauth2. Other elements in the array will depend on the selected authentication plugin.

The basic and digest authentication plugins provide the following configuration keys:

  1. username: A string value.
  2. password: A string value.

The OAuth2 authentication plugin requires the sainsburys/guzzle-oauth2-plugin composer package to work. It provides the following configuration keys:

  1. base_uri: A string value.
  2. grant_type: A string value. Possible values are authorization_code, client_credentials, urn:ietf:params:oauth:grant-type:jwt-bearer, password, and refresh_token. Each of these might require extra configuration values.

The client credentials grant type requires the following configuration keys:

  1. token_url: A string value.
  2. client_id: A string value.
  3. client_secret: A string value.

For configuration keys required by other grant types, refer to the classes that implement them. Read this article on adding HTTP request headers and authentication parameters for example configurations.

There are many combinations possible to configure this plugin. In the 31 days of migration series there are many example configurations. For reference, below is the source plugin configuration used in the local JSON node migration example:

source: plugin: url data_fetcher_plugin: file data_parser_plugin: json urls: - modules/custom/ud_migrations/ud_migrations_json_source/sources/udm_data.json item_selector: /data/udm_people fields: - name: src_unique_id label: 'Unique ID' selector: unique_id - name: src_name label: 'Name' selector: name - name: src_photo_file label: 'Photo ID' selector: photo_file - name: src_book_ref label: 'Book paragraph ID' selector: book_ref ids: src_unique_id: type: integer


Module: Migrate (Drupal Core). Plugin ID: embedded_data
Class: Drupal\migrate\Plugin\migrate\source\EmbeddedDataSource
Extends: Drupal\migrate\Plugin\migrate\source\SourcePluginBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, and source_module.

This plugin allows the definition of data to be imported right inside the migration definition file. We used this plugin in many of the examples of the 31 days of migration series. It is also used in many core tests for the Migrate API itself.

In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:

  1. data_rows: An array of all the records to be migrated. Each record might contain an arbitrary number of key-value pairs representing "columns" of data to be imported.
  2. ids: An associative array. It contains the "columns" that uniquely identify each record. The keys are column names as defined in the data_rows key. The values is an array with a single member with key 'type' and value a column type such as 'integer'.

Many examples of 31 days of migration series use this plugin. You can get the example modules from this repository. For reference, below is the source plugin configuration used in the first migration example:

source: plugin: embedded_data data_rows: - unique_id: 1 creative_title: 'The versatility of Drupal fields' engaging_content: 'Fields are Drupal''s atomic data storage mechanism...' - unique_id: 2 creative_title: 'What is a view in Drupal? How do they work?' engaging_content: 'In Drupal, a view is a listing of information. It can a list of nodes, users, comments, taxonomy terms, files, etc...' ids: unique_id: type: integer

This plugin can also be used to create default content when the data is known in advance. We often present Drupal site building workshops. To save time, we use this plugin to create nodes which are later used when explaining how to create Views. Check this repository for an example of this. Note that it uses a different directory structure to store the migrations as explained in this blog post.


Module: Migrate Drupal (Drupal Core). Plugin ID: content_entity
Class: Drupal\migrate_drupal\Plugin\migrate\source\ContentEntity
Extends: Drupal\migrate\Plugin\migrate\source\SourcePluginBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, and source_module.

This plugin returns content entities from a Drupal 8 or 9 installation. It uses the Entity API to get the data to migrate. If the source entity type has custom field storage fields or computed fields, this class will need to be extended and the new class will need to load/calculate the values for those fields.

In addition to the keys provided in the parent class chain, this plugin provides the following configuration key:

  1. entity_type: A string value. The entity type ID of the entities being migrated. This is calculated dynamically by the deriver so it is only needed if the deriver is not utilized, i.e., a custom source plugin.
  2. bundle: An optionals string value. If set and the entity type is bundleable, only return entities of this bundle.
  3. include_translations: An optional boolean value. If set, entity translations are included in the returned data. It defaults to TRUE.

For reference, this is how this plugin is configured to get all nodes of type article in their default language only:

source: plugin: content_entity:node bundle: article include_translations: false

Note: this plugin was brought into core in this issue copied from the Drupal 8 migration (source) module. The latter can be used if the source database does not use the default connection.


Module: Migrate Plus. Plugin ID: table
Class: Drupal\migrate_plus\Plugin\migrate\source\Table
Extends: Drupal\migrate\Plugin\migrate\source\SqlBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, source_module, key, target, database_state_key, batch_size, and ignore_map.

This plugin allows reading data from a single database table. It uses one of the database connections for the site as defined by the options. See this test for an example on how to use this plugin.

In addition to the keys provided in the parent class chain, this plugin provides the following configuration key:

  1. table_name: An string value. The table to read values from.
  2. id_fields: An associative array value. IDMap compatible array of fields that uniquely identify each record.
  3. fields: An array value. The elements are fields ("columns") present on the source table.

EmptySource (migrate module)

Module: Migrate (Drupal Core). Plugin ID: empty
Class: Drupal\migrate\Plugin\migrate\source\EmptySource
Extends: Drupal\migrate\Plugin\migrate\source\SourcePluginBase
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, and source_module.

This plugin returns an empty row by default. It can be used as a placeholder to defer setting the source plugin to a deriver. An example of this can be seen in the migrations for Drupal 6 and Drupal 7 entity reference translations. In both cases, the source plugin will be determined by the EntityReferenceTranslationDeriver.

In addition to the keys provided in the parent class chain, this plugin does not define extra configuration keys. If the plugin is used with source constants, a single row containing the constant values will be returned. For example:

source: plugin: empty constants: entity_type: node field_name: body

The plugin will return a single row containing 'entity_type' and 'field_name' elements, with values of 'node' and 'body', respectively. This is not very useful. For the most part, the plugin is used to defer the definition to a deriver as mentioned before.

EmptySource (migrate_drupal module)

Module: Migrate Drupal (Drupal Core). Plugin ID: md_empty
Class: Drupal\migrate_drupal\Plugin\migrate\source\EmptySource
Extends: Drupal\migrate\Plugin\migrate\source\EmptySource
Inherited configuration options: skip_count, cache_counts, cache_key, track_changes, high_water_property, and source_module.

By default, this plugin returns an empty row with Drupal specific config dependencies. If the plugin is used with source constants, a single row containing the constant values will be returned. These can be seen in the user_picture_field.yml and d6_upload_field.yml migrations.

In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:

  1. constants: An optional array value used to add module dependencies. The value is an associative array with one possible element. An entity_type key is used to add a dependency on the module that provides the specified entity type.

Available configuration for other migrate source plugins

In Drupal core itself there are more than 100 migrate source plugins, most of which come from the Migrate Drupal module. And many more are made available by contributed modules. It would be impractical to document them all here. To get a list by yourself, load the plugin.manager.migrate.source service and call its getFieldStorageDefinitions() method. This will return all migrate source plugins provided by the modules that are currently enabled on the site. This Drush command would get the list:

# List of migrate source plugin definitions. $ drush php:eval "print_r(\Drupal::service('plugin.manager.migrate.source')->getDefinitions());" # List of migrate source plugin ids. $ drush php:eval "print_r(array_keys(\Drupal::service('plugin.manager.migrate.source')->getDefinitions()));"

To find out which configuration options are available for any source plugin consider the following:

  • Find the class that defines the plugin and find out which configuration values are read. Some plugins even include the list in the docblock of the class. Search for a pattern similar to $this->configuration['option_name'] or $configuration['option_name']. The plugins can be found in the Drupal\module_name\Plugin\migrate\source namespace. The class itself would be in a file under the /src/Plugin/migrate/source/ directory of the module.
  • Look up in the class hierarchy. The source plugin can use any configuration set directly in its definition class and any parent class. There might be multiple layers of inheritance.
  • Check if the plugin offers some extension mechanism that would allow it to use other types of plugins. For example, the data fetcher, data parses, and authentication plugins provided by Migrate Plus. The Url migrate source plugin does this.

What did you learn in today’s article? Did you know that migrate source plugins can inherit configuration keys from their class hierarchy? Were you aware that there are so many source plugins? Other than the ones listed here, which source plugins have you used? Please share your answers in the comments. Also, we would be grateful if you shared this article with your friends and colleagues.

Jul 12 2020
Jul 12
Composer 2-alpha2 performance results graph

One of the primary goals of the upcoming Composer 2.0 release is decreasing the memory footprint and increasing the performance of common commands. I decided to test out the performance of the second alpha release of Composer 2.0 to see how much real-world change users can expect to see. 

tl;dr: Composer 2.0 will be much faster. Users can expect to see up to a 2x gain in speed in composer create-project commands, up to a 10x gain in composer require commands, and a over a 2x gain in composer update commands. 

I have Composer installed both on Mac OS X as well as automatically via the DDEV web containers that I use for teaching and client work on a day-to-day basis. I ran four tests for three different composer commands (create-project, require, and update) - 2 tests on Mac OS X (Composer 1.10.8 and 2.0-alpha2) and 2 tests in the DDEV web container (Composer 1.10.8 and 2.0-alpha2).

The Composer team has made it super-easy to test out Composer 2.0 using:

composer self-update --preview

To return back to your original version:

composer self-update --rollback

Test methodology

  • To mitigate any caching effects, each test was run 3 times consecutively.
  • All tests were run on a 13" 2018 MacBook Pro with 16GB RAM, SSD, running Mac OS X Catalina (10.15.5).
  • DDEV tests were run with: version 1.14.2, NFS, project type of "Drupal 9", and Docker for Mac 

The results

The graph above displays the average of each test's three runs. The composer require command (using Composer 2.0-alpha2) is slightly faster in the DDEV web container than Mac OS X - this is a surprising result, and one that I can't explain.

composer create-project drupal/recommended-project

  • Mac OS X Composer 1.10.8: 40.4, 12.9, 11.7 seconds
  • Mac OS X Composer 2.0-alpha2: 9.0, 10.8, 10.1 seconds
  • DDEV Composer 1.10.8: 116.9, 81.4, 92.0 seconds
  • DDEV Composer 2.0-alpha2: 66.8, 63.3, 52.8 seconds

composer require drupal/pathauto:1.7.0

  • Mac OS X Composer 1.10.8: 63.2, 45.5, 19.8 seconds
  • Mac OS X Composer 2.0-alpha2: 5.3, 3.2, 3.7 seconds
  • DDEV Composer 1.10.8: 79.9, 56.7, 29.8 seconds
  • DDEV Composer 2.0-alpha2: 3.3, 2.8, 3.0 seconds

composer update drupal/pathauto --with-dependencies

  • Mac OS X Composer 1.10.8: 36.8, 28.5, 41.4 seconds
  • Mac OS X Composer 2.0-alpha2: 14.6, 13.2, 12.8 seconds
  • DDEV Composer 1.10.8: 51.1, 24.7, 44.8 seconds
  • DDEV Composer 2.0-alpha2: 16.1, 16.0, 15.6 seconds

More information

For additional details about the upcoming Composer 2.0 release, see this slideshow by Nils Adermann (co-creator of Composer) and this article on PHP.Watch for additional details.


Jul 12 2020
Jul 12
Composer 2-alpha2 performance results graph

One of the primary goals of the upcoming Composer 2.0 release is decreasing the memory footprint and increasing the performance of common commands. I decided to test out the performance of the second alpha release of Composer 2.0 to see how much real-world change users can expect to see. 

tl;dr: Composer 2.0 will be much faster and use much less memory. Users can expect to see up to a 2x gain in speed in composer create-project commands, up to a 10x gain in composer require commands, and a over a 2x gain in composer update commands. On the memory side of things, the results are even more dramatic, but come with the important caveat that as more dependencies are added to a project, the results may not be large.

I have Composer installed both on Mac OS X as well as automatically via the DDEV web containers that I use for teaching and client work on a day-to-day basis. I ran four tests for three different composer commands (create-project, require, and update) - 2 tests on Mac OS X (Composer 1.10.8 and 2.0-alpha2) and 2 tests in the DDEV web container (Composer 1.10.8 and 2.0-alpha2).

The Composer team has made it super-easy to test out Composer 2.0 using:

composer self-update --preview

To return back to your original version:

composer self-update --rollback

Test methodology

  • To mitigate any caching effects, each test was run 3 times consecutively.
  • All tests were run on a 13" 2018 MacBook Pro with 16GB RAM, SSD, running Mac OS X Catalina (10.15.5).
  • DDEV tests were run with: version 1.14.2, NFS, project type of "Drupal 9", and Docker for Mac 

Time results

The graph above displays the average time of each test's three runs. The composer require command (using Composer 2.0-alpha2) is slightly faster in the DDEV web container than Mac OS X - this is a surprising result, and one that I can't explain.

composer create-project drupal/recommended-project

  • Mac OS X Composer 1.10.8: 40.4, 12.9, 11.7 seconds
  • Mac OS X Composer 2.0-alpha2: 9.0, 10.8, 10.1 seconds
  • DDEV Composer 1.10.8: 116.9, 81.4, 92.0 seconds
  • DDEV Composer 2.0-alpha2: 66.8, 63.3, 52.8 seconds

composer require drupal/pathauto:1.7.0

  • Mac OS X Composer 1.10.8: 63.2, 45.5, 19.8 seconds
  • Mac OS X Composer 2.0-alpha2: 5.3, 3.2, 3.7 seconds
  • DDEV Composer 1.10.8: 79.9, 56.7, 29.8 seconds
  • DDEV Composer 2.0-alpha2: 3.3, 2.8, 3.0 seconds

composer update drupal/pathauto --with-dependencies

  • Mac OS X Composer 1.10.8: 36.8, 28.5, 41.4 seconds
  • Mac OS X Composer 2.0-alpha2: 14.6, 13.2, 12.8 seconds
  • DDEV Composer 1.10.8: 51.1, 24.7, 44.8 seconds
  • DDEV Composer 2.0-alpha2: 16.1, 16.0, 15.6 seconds

Peak memory results

Composer 2.0-alpha2 memory comparison graph

The graph above displays the peak memory usage (MiB) of each test. Clearly, the results are dramatic, but also highly dependent on the number of dependencies in the project as well as the specificity of the version constraints for each dependency. 

Results for each of the three runs for each case were nearly identical. Differences between the Mac OS X memory usage and the DDEV memory usage is (probably) due to differences in the operating system as well as the maintenance version of PHP. 

The create-project test (I'm assuming) uses less memory than both the require and update tests due to the fact that drupal/recommended-project uses exact versions of dependencies, so there is much less work for Composer to do in figuring out exactly which version of each dependency to use.

composer create-project drupal/recommended-project

  • Mac OS X Composer 1.10.8: 204 MiB
  • Mac OS X Composer 2.0-alpha2: 13 MiB
  • DDEV Composer 1.10.8: 200 MiB
  • DDEV Composer 2.0-alpha2: 7 MiB

composer require drupal/pathauto:1.7.0

  • Mac OS X Composer 1.10.8: 1477 MiB
  • Mac OS X Composer 2.0-alpha2: 29 MiB
  • DDEV Composer 1.10.8: 1472 MiB
  • DDEV Composer 2.0-alpha2: 24 MiB

composer update drupal/pathauto --with-dependencies

  • Mac OS X Composer 1.10.8: 1290 MiB
  • Mac OS X Composer 2.0-alpha2: 20 MiB
  • DDEV Composer 1.10.8: 1285 MiB
  • DDEV Composer 2.0-alpha2: 15 MiB

More information

For additional details about the upcoming Composer 2.0 release, see this slideshow by Nils Adermann (co-creator of Composer) and this article on PHP.Watch for additional details. You may also want to check out DrupalEasy Podcast 235 featuring an interview with Nils.


Jul 12 2020
Jul 12

Unlike the previous years; DrupalCon 2020 will be virtual due to the outbreak of Coronavirus and resulting restrictions on travelers. The annual festival open digital experience conference will be going global thanks to open source solutions developed by the innovative Drupal community.

What is DrupalCon?

DrupalCon is a conference designed to bring people together to share thought leadership around open source and ambitious digital experiences, provide professional development opportunities to enhance your career and your organization, foster a feeling of community, and invigorate Drupal project momentum.  

The event is a mission-centric program of the Drupal Association, the non-profit organization dedicated to accelerating the Drupal software project, fostering the community, and supporting its growth. 

  • Where: Everywhere. Online.
  • When: July 14 - 17 2020

Why you should join DrupalCon Global?

DrupalCon is for marketers seeking to create truly immersive digital experiences, for developers who want to build the best of the web, and for business owners who want to get ahead of their competition.

If you’re a developer, project manager, designer, work for a digital agency or consulting firm, or a Drupal end-user you can learn the latest technology and grow your Drupal skills and deliver more value to your organization by attending DrupalCon Global. Build a stronger network in the Drupal Community. Collaborate and share your open source knowledge with others. Find opportunities to contribute to the Drupal project.

DrupalCon is for everyone with a passion to create through technology. Here are a few highlights to look forward to:

Mini Summits are an opportunity to network with and learn from peers in your field who share the same interests, issues, and challenges. 

In lieu of the traditional full-day summits, DrupalCon Global will feature mini summits focused on highlights and innovations and will be integrated into the main conference program. You will have the opportunity as marketers and developers to learn industry-specific insights in the following key sectors that rely on Drupal technology: 

Drupalers focused on higher-ed can also enjoy a dedicated summit for library-related digital projects.

For those interested in building API-driven Drupal backed sites and applications to learn preferred practices, planning, and implementation advice, and see case studies from existing sites, you can benefit from networking with fellow Drupalers in the Decoupled summit.

Boost your support and ongoing maintenance efforts with the latest insights during the Performance and Scaling summit which will enable you to prevent slow page loads and disastrous outages; learn the latest tools and techniques across the full stack to create fast, scalable Drupal applications.

2. Sessions

From enabling marketers to creating inclusive strategies and digital brands to lessons on how to implement Decoupled Drupal in real-life - DrupalCon Global will have access to nearly 100 sessions and experts about how to build the best of the web, relating to the following topics:

  • Being Human, Contributions, & Community
  • Drupal 9 
  • Content & Digital Marketing
  • Development & Coding
  • DevOps & Infrastructure
  • Leadership, Management, & Business
  • Site Building
  • User Experience, Accessibility, & Design
  • What's Next in Drupal and Open Source 

3. Drupal 9

The Drupal community has accomplished amazing things with the release of Drupal 9. It is the easiest major version upgrade in a decade, extending the pattern of continuous innovation from Drupal 8, with dramatically easier tools for end-users.

At DrupalCon Global you'll find all the Drupal 9 content you need:

  • Sessions about getting ready for the upgrade, whether you're on Drupal 7 or Drupal 8
  • Instruction from expert speakers about using Composer to manage your site
  • Programming about next-generation features like the new administrative UI and the upcoming Olivero default theme
  • Tips and best practices for making your custom code Drupal 9 ready

4. Future Road Map

To kickoff proceedings, the Drupal project founder; Dries Buytaert, will give his traditional Driesnote which celebrates recent successes and details the vision for where Drupal is going next to kickoff the proceedings of this year's DrupalCon.

To better accommodate the global community, the event start and end timing of the scheduled programming will be expanded each day and offering specific moments of live networking and togetherness for regional communities throughout the event. Both for the sake of DrupalCon's speakers and staff, this won't be a 24/7 event, but because much of the content will be available to ticket-holders on demand, you'll have the freedom to participate at the time you choose.

Click here to view the full schedule details. 

Don't miss out on the biggest DrupalCon yet - you never know; you just might find exactly what your business or Drupal project is looking for to take things to the next level!

Book your DrupalCon ticket today!

Jul 11 2020
Jul 11

The Drupal::entityQuery method has been a staple for Drupal developers since the early days of Drupal 8. But without a dedicated drupal.org Documentation page, it can be difficult for new developers to get a really good handle on. 

I've been using the QueryInterface API documentation for a few years now as my go-to source for help with using entityQuery, but a couple of weeks ago I stumbled on a feature of entityQuery that made me wonder what else, if anything, I was missing.

This blog post is meant to provide those new to entityQuery with some commonly used examples, as well as a request for those experienced with entityQuery to let us know what else is possible.

The basics

entityQuery allows developers to query Drupal entities and fields in a SQL-like way. A Drupal site's tables and fields are never a 1-to-1 match for the site's entities and fields - entityQuery allows us to query the database as if they were 1-to-1. 

Much like you could write some SQL that returns all rows of table1 where field1 is 14, using entityQuery you can ask Drupal to return all entities of type "basic page" where the value of field_some_field is 14. 

Developers can write an entityQuery using the following method to return the QueryInterface:

$query = \Drupal::entityQuery(string $entity_type_id);

Example 1: Simple node entity queries 

This first example returns all nodes of type page where the value of field_some_field (an integer field) is 14.

$query = \Drupal::entityQuery('node')
  ->condition('type', 'page')
  ->condition('field_some_field', 14);
$results = $query->execute();

This example shows that an entityQuery is built up by adding various conditions, sorts, ranges, and other qualifiers. Note that the $query methods are all chainable - each one returns the $query, so we can add multiple conditions per line. 

For conditions, the default operator is "=", so in both of the conditions shown above, the EntityQuery is looking for type=page and field_some_field=14. If we wanted to find all basic page nodes where field_some_field > 14, then the entityQuery would look like this:

$query = \Drupal::entityQuery('node')
  ->condition('type', 'page')
  ->condition('field_some_field', 14 '>');
$results = $query->execute();

Sorts and ranges can also be easily added:

$query = \Drupal::entityQuery('node')
  ->condition('type', 'page')
  ->condition('field_some_field', 14 '>')
  ->sort('nid', ASC)
  ->range(0, 10);
$results = $query->execute();

Finally, we can save ourselves some typing by calling execute() directly on the $query:

$results = \Drupal::entityQuery('node')
  ->condition('type', 'page')
  ->condition('field_some_field', 14 '>')
  ->sort('nid', ASC)
  ->range(0, 10)

The execute() method returns an array of IDs for the entities found. For node entities, this is the node ID. If this was an entityQuery of users, then the ID would be user ID.

Example 2: Condition groups

While the first example covers many real-world use cases, another pattern that is often seen is that of condition group. Consider the use case where we want to find all users whose account was created either before the year 2010 or since January 1, 2020.

In this case, we can create an oConditionGroup as part of the entityQuery, as well as adding additional conditions, sorts, and ranges:

$query = \Drupal::entityQuery('user');
$group = $query
  ->condition('created', '1262304000', '<')     // Jan 1, 2010
  ->condition('created', '1577836800', '>');    // Jan 1, 2020
$results = $query->condition($group)
  ->condition('status', 1)
  ->sort('created', DESC)

Example 3: Reaching into reference fields

My latest entityQuery() discovery is the fact that it can be used to query field values of referenced entities. This means that if you have two node entities:


  • Node ID
  • Name
  • Date
  • Location (reference field)


  • Node ID
  • Name
  • Address
  • Venue type - List (text) field

Then you can use entityQuery to return all event nodes whose location's "venue type" is a particular value.

$results = \Drupal::entityQuery('node')
  ->condition('type', 'event')
  ->condition('field_location.entity:node.field_venue_type', 'boat')

Note: I recently wrote about this in a quicktip as well.

Example 4: Show me the SQL

During DrupalCamp Asheville I presented a short mostly-unplanned session on this topic during the unconference. Thanks to Hussain Abbas, Kristen Pol, and others I learned how easy it was to see the SQL that entityQuery actually uses to return the list of entity IDs - it's really quite easy. For example, to output the SQL from the previous example, use:

$query = \Drupal::entityQuery('node')
  ->condition('type', 'event')
  ->condition('field_location.entity:node.field_tag.entity:taxonomy_term', 'sailboat')

Resulting in:

SELECT base_table.vid AS vid, base_table.nid AS nid
node base_table
INNER JOIN node_field_data node_field_data ON node_field_data.nid = base_table.nid
INNER JOIN node__field_location node__field_location ON node__field_location.entity_id = base_table.nid
LEFT OUTER JOIN node node ON node.nid = node__field_location.field_location_target_id
INNER JOIN node__field_venue_type node__field_venue_type ON node__field_venue_type.entity_id = node.nid
WHERE (node_field_data.type = 'event') AND (node__field_venue_type.field_venue_type_value = 'boat')

Example 5: How deep can we go?

Let's go back to example 3 - is it possible to create a condition that queries a field value of an entity that is referenced by and entity that is referenced by the entity you are querying on?

Consider the use case where we want to find all events whose location has a term whose name is "sailboat". Turns out that it is:

$results = \Drupal::entityQuery('node')
  ->condition('type', 'event')
  ->condition('field_location.entity:node.field_tags.entity:taxonomy_term.name', 'sailboat')


It is important to understand that the entityQuery will only return entities that the user has access to - access control is performed by default. If you want to disable access control, then add the following to the query:


Did I miss anything? What else can be done with entityQuery? Feel free to leave a comment and let me know.

Jul 11 2020
Jul 11

Jess Snyder joins Mike Anello to talk about how Drupal and nonprofit organizations - topics include the unique needs of nonprofits, the challenges they have with Drupal 8+, and how nonprofit folks organize and support each other. Also, Kaleem Clarkson returns to the podcast to provide an update on the Drupal Event Organizers Group.

URLs mentioned

DrupalEasy News


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.

Jul 10 2020
Jul 10

External Media module for Drupal 8 and 9 is a successor of the File Chooser Field module that was bulit for Drupal 7. The same functionality was implemented for Wordpress too. The module provides custom form element.

The new form element would allow you to add external services such as Google Drive, Dropbox, Box, OneDrive, AWS, Unsplash, Instagram, Pixabay, Pexels and other services, in addition to regular file choose field. 

Jul 10 2020
Jul 10

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

I remember the first gathering of Drupal contributors back in 2005. At the time, there were less than 50 people in attendance. In the 15 years since that first gathering, DrupalCon has become the heartbeat of the Drupal community. With each new DrupalCon, we introduce new people to our community, demonstrate the best that Drupal has to offer, and reconnect with our Drupal family.

Next week's DrupalCon Global is going to be no different.

Because of COVID-19, it is the first DrupalCon that will be 100% virtual. But as much as we may miss seeing each other in person, the switch to virtual has opened opportunities to bring in speakers and attendees who never would have been able to attend otherwise.

There are a few moments I'm particularly excited about:

  • Mitchell Baker, CEO of the Mozilla, is joining us to talk about the future of the Open Web, and the importance of Open Source software.
  • Jacqueline Gibson, Digital Equity Advocate and Software Engineer from Microsoft, will be talking about Digital Inequity for the Black community – a topic I believe is deeply important for our community and the world.
  • Leaders of current Drupal strategic initiatives will be presenting their progress and their calls for action to keep Drupal the leading CMS on the web.
  • And of course, I'll be giving my plenary presentation to celebrate the community's accomplishment in releasing Drupal 9, and to talk about Drupal's future.

Beyond the sessions, I look forward to the human element of the conference. The side conversations and reunions with old friends make attending DrupalCon so much more powerful than simply watching the recordings after the fact. I hope to see you at DrupalCon Global next week!


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