Upgrade Your Drupal Skills

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

See Advanced Courses NAH, I know Enough
Feb 08 2020
Feb 08

New year, new possibilities, as we say in Norway. Which is why I have relaunched my blog using Gatsby.js. I could write a blog post about that, but I am not going to do that today. There is a lot of tutorials on how to set up Gatsby with Drupal (one of my personal favorites is this one from Lullabot), and there is even an official page in the Gatsby.js documentation.

I could probably write many blog posts about different aspects I tweaked and looked at in the migration, but one field I feel is not often talked about is geography and performance.

With regards to servers, many Drupal sites (at least basic ones) are probably geographically limited by the actual server that is supposed to serve the web requests, and the location of this particular server. With a static site, made for example with Gatsby.js, you can deploy it to a Content Delivery Network (CDN) and have the same static html files on servers all around the world. This could mean that a website visitor from Tokyo to your static site could get a response from a server in Tokyo. The traditional Drupal site however might be on a server in Ireland, and then a visitor from Tokyo would quite often have to send their request all around the world to get responses.

This idea is not very new. In fact, there are several providers that let's you deploy your static site on their CDN for free (more or less). They will then serve your static HTML from different parts of the world, depending on the visitor. What a world to live in. But instead of comparing their service and the user experience of deploying, I decided to compare them by which ones were being performant from all parts of the world. A geographic performance cup if you like.

The competitors in the cup are:

  • Surge.sh
  • Zeit Now
  • Netlify
  • S3 with Cloudfront (a service from Amazon Web Services - AWS)

Instead of doing a very long analysis, let's just start with the results!

CDN ping

The fastest service is S3 with Cloudfront. S3 is a static file storage, and Cloudfront is the CDN service from Amazon.

In the same way I could write many things about my migration to Gatsby, I could also speculate and write many things about this result. Instead I want to just show some animated gifs about interesting aspects of the different geography results for the providers. I am going to do them in reverse order, best result last.

Fourth place: Surge.sh:

Surge.sh geography

Third place: Netlify:

Netlify geography

Then, slightly behind on second place, Zeit Now:

Zeit now geography

Lastly, the winner, here is AWS S3 with Cloudfront:

S3 with Cloudfront geography

Conclusions and reflections

The numbers are one thing, but let's talk a bit about their significance. The tests were performed from AWS datacenters, and the 2 services scoring highest is either an AWS service (S3/Cloudfront), or uses AWS for their service (Zeit Now). Meaning the actual numbers does not necessarily mean that Netlify is 144% slower than S3/Cloudfront. It also does not mean I think any of these services have been proven to be better or worse than others.

I think it means that now that we are able to serve static HTML pages for our blogs or websites in a somewhat dynamic way, we can make the performance more democratic and less unfair. I don't want to discriminate readers of my blog based on their location (or anything else for that matter). Performance matters, but performance also differs from different parts of the world.

I guess what I am trying to say is: Let's make the world a better place by thinking about everyone that lives there, no matter where they live. So I will finish this post with an animated gif about just that. The world.

Feb 01 2020
Feb 01

Working with custom datetime elements in Drupal can sometimes be a bit tricky when you need a very specific date format to render. Even trickier can be date ranges that span multiple days. Add on top of that, date ranges that span over 2 different months and you might have your work cut out for you.

I am currently working on theming a Drupal 8 site that will feature events and event dates in a prominent way. In this article, I will create a recipe for how I am coding this within a Twig template. The context here is a landing page view where we show a listing of events with a basic date - month, day, and year.

The format I want to achieve in the end is:

  • Multi-Day Event - e.g. Jan 29 - 31 2020
  • Multi-Day Event (spanning over 2 different months) e.g. Jan 29 - Feb 03 2020
  • One Day Event - e.g. Jan 29 2020

We'll be using Twig's date formatter so if you need a worldwide date format, i.e. non-American, it will be a case of just re-arranging when we code up our custom formats. For example:

format_date('custom', 'M d Y')

would be:

format_date('custom', 'd M Y')

Getting started

For this project, I am using Drupal 8, a few core modules, and one contrib module. This article assumes the following knowledge:

  • Installing Drupal modules with Composer
  • Setting up a local development environment (I use Docksal)
  • Using Xdebug in your IDE (I use PHPStorm)
  • Knowledge of writing Twig code
  • Knowledge of basic Drupal 8 site building

Core

  • Drupal core 8.7.11
  • Datetime
  • Datetime Range

Contrib

  • Twig Xdebug (Optional)

As you can see, we have Datetime as well as Datetime Range which allows us to have a field formatter for event dates that span over multiple days. Once you're up and running, get twig_xdebug module with composer:

composer require drupal/twig_xdebug

Now, enable the modules:

drush en datetime datetime_range twig_xdebug -y

Create an event content type with date field

The next step is to create an event content type, Events, with a date field using Date range as the type. We don't need to be concerned with the display settings here as we will be doing our formatting in our Twig template.

The image above shows the datetime range formatter in the Drupal 8 UI.The image above shows the datetime range formatter in the Drupal 8 UI.

Create a custom view mode / events view

The next step is to create a custom view mode for our events landing page. I'll call it "Event List." That custom view modes are now a part of D8 core is a nice plus here. Now create a basic view for the event content type and set the format to Content > Event List, whereby we use the new view mode just created. For the view, we can choose either a page or block display depending on the use case.

Create a custom Twig template

The next step is to create a few event nodes so we can load up our new events list landing page and start to debug. The first thing is to make sure you have Twig template debugging enabled in your local development environment. Since we want a custom template for theming, I look at the twig template suggestion debugging output and see this:


As you can see from the debug output above, we have a nice variety of template suggestions to choose from. I'll use node--events--event-list.html.twig which is specific to the content type, view, and view mode we are using.

Note that a huge advantage of theming views in this manner using view modes is that you can theme as if it were a regular node template. In that regard, I grab Classy's basic node.html.twig file and place it in my custom theme's templates folder using the custom name as above. Now run drush cr and re-check the Twig template output and ensure that the new template has taken effect.

Debug with Twig Xdebug

For debugging with Twig, I like to use Twig Xdebug as mentioned above, which piggybacks on top of Xdebug so you can debug right in your Twig template with one line of code, {{ breakpoint() }}.

When I start to debug, the output provides me with a wealth of information that we can leverage to create some custom date variables right within our twig template. (Note that you could also use standard Xdebug within a .theme or .module file via a preprocess function.)

$context["content"]["field_event_date"][0]["start_date"]["#attributes"]["datetime"] = 2020-02-19T12:00:00Z
The image above shows Twig Xdebug printing out variables in PHPStorm.The image above shows Twig Xdebug printing out variables in PHPStorm.

From the above debugging output, we have the date and time in what's known as UTC Time ISO-8601 Format. We'll be converting that later to a Unix timestamp with Twig so that in turn, we can create custom, nicely formatted dates.

Setting variables in Twig

Now that we have debugging info, we can set some variables right in Twig like this:


 {# Define event start / end dates. #}
    {% set event_start_date = content.field_event_date.0.start_date["#attributes"]["datetime"] %}
    {% set event_end_date = content.field_event_date.0.end_date["#attributes"]["datetime"] %}

Now we will do some comparisons to check if the event is a single day, muti-day, or a muti-day event that takes place in two different months.

First we will check for a single day event by comparing the start and end day.


{% if event_start_date | date('U') | format_date('custom', 'd') == event_end_date | date('U') | format_date('custom', 'd') %}

From the above code, we are doing a few things. First, we convert the UTC ISO formatted date into a Unix timestamp and then from there, we leverage a custom format to compare the event start and end day using Twig's comparison operator, ==.

If this is true, then we write the twig code as:


{# Check for and render a single day date. #}
  {{ event_start_date | date('U') | format_date('custom', 'M d Y') }}

... which will render like this Feb 29 2020. Next, we will add some logic if the event is muti-day and takes place within the same month:


{# If the start date month and end date month match. #}
{% elseif event_start_date | date('U') | format_date('custom', 'M') == event_end_date | date('U') | format_date('custom', 'M') %}
  {{ event_start_date | date('U') | format_date('custom', 'M d - ') }}
  {{ event_end_date | date('U') | format_date('custom', 'd Y') }}

For the above code, we once again use a comparison operator to check if the month start and end date is the same. If so, then the date renders within here as Jan 12 - 16 2020. Finally, if the event takes place within two different months, we add the end date month to our custom date formatter:


{# If the start date month and end date month DO NOT match. #}
    {% elseif event_start_date | date('U') | format_date('custom', 'M') != event_end_date | date('U') | format_date('custom', 'M') %}
      {{ event_start_date | date('U') | format_date('custom', 'M d - ') }}
      {{ event_end_date | date('U') | format_date('custom', 'M d Y') }}

This will render as Jan 29 - Feb 03 2020. And there you have it, nicely formatted custom event dates all within a Twig template.

The image above shows the finished event listingThe image above shows the finished event listing

Summary

I should note that Twig's custom date formats draw from PHP datetime so when you see something like format_date('custom', 'M d Y'), those time formats might seem familiar. Coding up dates in Twig in this manner was a great learning experiment for me. As with all things Drupal, there are so many different ways to achieve the same end result so I am sure there are no doubt other ways to do this. In fact, probably the Date and time UI within Drupal would probably suffice in most cases as you can create custom date formats in there as well. In the end, this was a great learning experience for me.

Resouces

Jan 30 2020
Jan 30

Recently, we were asked if we could integrate some small, one-page websites into an existing Drupal website. This would not only make it easier to manage those different websites and their content, but also reduce the hosting and maintenance costs.

In this article, I will discuss how we tackled this problem, improved the content management experience and implemented this using the best Drupal practices.

First, some background information: America’s Promise is an organization that launches many national campaigns that focus on improving the lives and futures of America’s youth. Besides their main website (www.americaspromise.org), they also had separate websites and domain names for some of these campaigns, e.g. www.everyschoolhealthy.org.

We came up with a Drupal solution where they could easily configure and manage their campaigns. Next to having the convenience of managing all these campaigns from one admin panel, they could also reference content items easily from their main website or other campaigns by tagging the content with specific taxonomy terms (keywords).

We created a new content type “Campaign” with many custom paragraph types as the building blocks for creating a new campaign. We wanted this to be as easy as possible for the content editors, but also give enough freedom where every campaign can have their own branding, by selecting a font color, background image/color/video.

Below are some of the paragraph types we created:

  • Hero
  • Column Layout
  • WYSIWYG
  • Latest News
  • Newsletter Signup
  • Twitter Feed
  • Video Popup
  • Community Partners
  • Latest Resources
  • Grantee Spotlight
  • Statistics Map
  • Partner Spotlight
  • Media Mentions

These paragraphs offer lots of flexibility to create unique and interactive campaigns. By drag and drop, these paragraphs can be ordered however you’d like.

Below is a screenshot of some of these paragraph types in action, and how easy they can be configured on the backend.

Every School Healthy paragraphs

Below you can see how the “Hero” paragraph looks like in the admin panel. The editor enters a tagline, chooses a font color, uploads a logo, an optional background image or video, and a background overlay color with optional opacity.

Campaign Builder Hero Backend

As you can see in the above screenshot, this is a very basic paragraph type, but it shows the flexibility in customizing the building blocks for the campaign. We also created more complex paragraph types that required quite some custom development.

One of the more complicated paragraph types we created is a statistics map. America’s Promise uses national and state statistics to educate and strengthen its campaign causes.

Campaign Builder Statistics Map

The data for this map comes from a Google Sheet. All necessary settings can be configured in the backend system. Users can then view these state statistics by hovering over the map or see even more details by clicking on an individual state.

Campaign Builder Statistics Map Backend

Some other interesting paragraph types we created are:

  • Twitter Feed, where the editors can specify a certain #hashtag and the tweets will display in a nice masonry layout
  • Newsletter Signup, editors can select what newsletter campaign the user signs up for
  • Latest News/Resources, editors can select the taxonomy term they want to use to filter the content on

Time to dive into some of the more technical approaches we took. The campaign builder we developed for America’s Promise depends on several Drupal contrib modules:

  • paragraphs
  • bg_image_formatter
  • color_field
  • video
  • masonry (used for the Twitter Feed)

Font color and background image/color/video don’t need any custom code, those can be accomplished using the above modules and configuring the correct CSS selectors on the paragraph display:

Campaign Builder Hero Display

In our custom campaign builder module, we have several custom Entities, Controllers, Services, Forms, REST resources and many twig template files. Still, the module mainly consists of custom field formatters and custom theme functions.

Example: the “Latest News” paragraph only has one field where the editor can select a taxonomy term. With a custom field formatter, we will display this field as a rendered view instead. We pass the selected term as an argument to the Latest News view, execute the view and display it with a custom #theme function.

Conclusion

By leveraging the strength of paragraphs, other contrib modules and some custom code, we were able to create a reusable and intuitive campaign builder. Where the ease of content management was a priority without limiting the design or branding of each campaign.

Several campaigns that are currently live and built with our campaign builder:

Could your organization benefit from having your own custom campaign builder and want to see more? Contact us for a demo.

Jan 23 2020
Jan 23
Allan Chappell

Allan Chappell

Senior Support Lead

Allan brings technological know-how and grounds it with some simple country living. His interests include DevOps, animal husbandry (raising rabbits and chickens), hiking, and automated testing.

January 23, 2020

In the Drupal support world, working on Drupal 7 sites is a necessity. But switching between Drupal 7 and Drupal 8 development can be jarring, if only for the coding style.

Fortunately, I’ve got a solution that makes working in Drupal 7 more like working in Drupal 8. Use this three-part approach to have fun with Drupal 7 development:

  • Apply Xautoload to keep your PHP skills fresh, modern, and compatible with all frameworks and make your code more reusable and maintainable between projects.
  • Use the Drupal Libraries API to use third-party libraries.
  • Use the Composer template to push the boundaries of your programming design patterns.

Applying Xautoload

Xautoload is simply a module that enables PSR-0/4 autoloading. Using Xautoload is as simple as downloading and enabling it. You can then start using use and namespace statements to write object-oriented programming (OOP) code.

For example:

xautoload.info

name = Xautoload Example
description = Example of using Xautoload to build a page
core = 7.x package = Midcamp Fun

dependencies[] = xautoload:xautoload

xautoload_example.module

 'xautoload_example_page_render',
    'access callback' => TRUE,
  );
  return $items;
}

function xautoload_example_page_render() {
  $obj = new SimpleObject();
  return $obj->render();
}

src/SimpleObject.php

 "

Hello World

", ); } }

Enabling and running this code causes the URL /xautoload_example to spit out “Hello World”.

You’re now ready to add in your own OOP!

Using third-party libraries

Natively, Drupal 7 has a hard time autoloading third-party library files. But there are contributed modules (like Guzzle) out there that wrap third-party libraries. These modules wrap object-oriented libraries to provide a functional interface. Now that you have Xautoload in your repertoire, you can use its functionality to autoload libraries as well.

I’m going to show you how to use the Drupal Libraries API module with Xautoload to load a third-party library. You can find examples of all the different ways you can add a library in xautoload.api.php. I’ll demonstrate an easy example by using the php-loremipsum library:

1. Download your library and store it in sites/all/libraries. I named the folder php-loremipsum.

2. Add a function implementing hook_libraries_info to your module by pulling in the namespace from Composer. This way, you don’t need to set up all the namespace rules that the library might contain.

function xautoload_example_libraries_info() {
  return array(
    'php-loremipsum' => array(
      'name' => 'PHP Lorem Ipsum',
      'xautoload' => function ($adapter) {
        $adapter->composerJson('composer.json');
      }
    )
  );
}

3. Change the page render function to use the php-loremipsum library to build content.

use joshtronic\LoremIpsum;
function xautoload_example_page_render() {
  $library = libraries_load('php-loremipsum');
  if ($library['loaded'] === FALSE) {
    throw new \Exception("php-loremipsum didn't load!");
  }
  $lipsum = new LoremIpsum();
  return array(
    '#markup' => $lipsum->paragraph('p'),
  );
}

Note that I needed  to tell the Libraries API to load the library, but I then have access to all the namespaces within the library. Keep in mind that the dependencies of some libraries are immense. You’ll very likely need to use Composer from within the library and commit it when you first start out. In such cases, you might need to make sure to include the Composer autoload.php file.

Another tip:  Abstract your libraries_load() functionality out in such a way that if the class you want already exists, you don’t call libraries_load() again. Doing so removes libraries as a hard dependency from your module and enables you to use Composer to load the library later on with no more work on your part. For example:

function xautoload_example_load_library() {
  if (!class_exists('\joshtronic\LoremIpsum', TRUE)) {
    if (!module_exists('libraries')) {
      throw new \Exception('Include php-loremipsum via composer or enable libraries.');
    }
    $library = libraries_load('php-loremipsum');
    if ($library['loaded'] === FALSE) {
      throw new \Exception("php-loremipsum didn't load!");
    }
  }
}

And with that, you’ve conquered the challenge of using third-party libraries!

Setting up a new site with Composer

Speaking of Composer, you can use it to simplify the setup of a new Drupal 7 site. Just follow the instructions in the Readme for the Composer Template for Drupal Project. From the command line, run the following:

composer create-project drupal-composer/drupal-project:7.x-dev  --no-interaction

This code gives you a basic site with a source repository (a repo that doesn’t commit contributed modules and libraries) to push up to your Git provider. (Note that migrating an existing site to Composer involves a few additional considerations and steps, so I won’t get into that now.)

If you’re generating a Pantheon site, check out the Pantheon-specific Drupal 7 Composer project. But wait: The instructions there advise you to use Terminus to create your site, and that approach attempts to do everything for you—including setting up the actual site. Instead, you can simply use composer create-project  to test your site in something like Lando. Make sure to run composer install if you copy down a repo.

From there, you need to enable the Composer Autoload module , which is automatically required in the composer.json you pulled in earlier. Then, add all your modules to the require portion of the file or use composer require drupal/module_name just as you would in Drupal 8.

You now have full access to all the  Packagist libraries and can use them in your modules. To use the previous example, you could remove php-loremipsum from sites/all/libraries, and instead run composer require joshtronic/php-loremipsum. The code would then run the same as before.

From here on out, it’s up to your imagination. Code and implement with ease, using OOP design patterns and reusable code. You just might find that this new world of possibilities for integrating new technologies with your existing Drupal 7 sites increases your productivity as well.

Making the web a better place to teach, learn, and advocate starts here...

When you subscribe to our newsletter!

Jan 23 2020
Jan 23

Drupal’s massive and passionate community has long been the envy of the open-source world. The many thousands of active contributors to Drupal are its strength, and one of the key reasons Drupal continues to be a force while others have stumbled.

With the release of Drupal 9 rapidly approaching, the support of the community is more important than ever. Here’s your chance to make the first release of Drupal 9 even better!

The annual Drupal Global Contribution Weekend, where Drupal User Group Meetups all over the world volunteer Drupal development time and make open-source contributions, is this weekend.

Anyone can take part in this initiative either from the comfort of their own home or at a contribution event near them. It is a great way to meet new people, learn about Drupal, and be part of something bigger. 

Check this Drupal map to see if there is a group meeting near you.

If you are planning to attend Southwestern Ontario’s contribution Meetup event in London, Canada on January 25th, (still time to RSVP) read on to get some helpful pre-event recommendations. 

Drupal 8 license plate

Pre-Attendance Checklist

Here are five things you can do ahead of time so that you are prepared for a quick start - especially if you have not contributed to Drupal core before: 

  1. Create a user account on Drupal.org if you do not have one
  2. Install Git on your laptop* (Yes, you will need a laptop)
  3. Make sure your laptop has a local development environment* (more on this later)
  4. Set up Drupal*
  5. Have some knowledge of how to create and apply patches using git*

Do as many of these steps beforehand as you can. If you need help with one or more, someone can help you on the day. 

*Not mandatory if you plan to contribute to documentation or marketing issues on Drupal.org, instead of code.

Resources For Beginners

Some other things we recommend beginners do ahead of time is to get familiar with the following resources:

  • Search the Drupal 8 Issue Queue. A list of issues tagged as ‘novice’ can be found here.  
  • Read guidelines on how to make a good issue.
  • Chat with the Drupal community using Slack and speak to core maintainers directly in the #contribute channel.
  • Join the slack channel for #Global-contribution-weekend
  • Read Echidna’s How to Contribute to Drupal blog series 

Local Development Environment

To have a successful contribution weekend you will need a solid local development environment and to install the latest development branch of Drupal. You can use any local environment you are comfortable with and in my opinion, either Pantheon, XAMPP, or the Acquia Dev desktop, would have what you need.

  • Pantheon sandbox is easy to setup. You can work with it either in SFTP or Git mode if you don't want to set up a server on your computer. 
  • XAMPP is a simple, lightweight Apache distribution that works well to create a local web server for testing and deployment purposes.
  • The Acquia dev desktop local comes with almost all tools you would ever need - Apache, PHP, mySQL and drush - and it installs Drupal in one click so you can get going, faster.

At the Southwestern Ontario event, we will have available a limited number of older machines ready and set up, specifically for guests to use for writing and testing patches, etc. 

Social

Finally, let people know you participated on your social media by using the hashtags #ContributionWeekend #Drupal, and tag the Drupal Users Group that organized the event you attended. 

For Southwestern Ontario's event, use @LondonDUG and hashtag #WRDUG, download and post this badge. 

London Ontario building with loon

Digital Echidna is a proud sponsor of the Southwestern Ontario Global Drupal Contribution Event 2020. 

--

 

Jan 15 2020
Jan 15

When migrating content with the Drupal 8 migrate module, the creation and updating of new entities may fire lots of custom module hooks. This may or may not be desired; if you have found yourself here, it probably interferes with the source data in a problematic way, or unnecessarily slows down the migration process.

The cleanest way I found to stop specific hooks for specific migrations, is to add a dummy/meta field to the migration and check for its value in the hook.

Include a dummy field in the migration

In the process section of the migration, add a field with a name that will not interfere with any field name of the target entity:

  1. # This is the field that will provide a custom hook

  2. # with the information about the migration.

  3. _migration:

  4. - plugin: default_value

  5. default_value: 'blog_categories'

This is an example migration with CSV as source and taxonomy terms as target:

  1. id: blog_categories

  2. label: 'Blog category migration'

  3. migration_group: default

  4. source:

  5. plugin: csv

  6. path: 'public://migrations/blog_categories.csv'

  7. delimiter: ','

  8. enclosure: '"'

  9. header_row_count: 1

  10. ids: [tid]

  11. process:

  12. name: name

  13. # This is the field that will provide a custom hook

  14. # with the information about the migration.

  15. _migration:

  16. - plugin: default_value

  17. default_value: 'blog_categories'

  18. destination:

  19. plugin: entity:taxonomy_term

  20. default_bundle: blog_categories

  21. migration_dependencies:

  22. required: {}

  23. optional: {}

Check for the value in an entity hook

  1. /**

  2.  * Implements hook_entity_update().

  3.  */

  4. function my_module_entity_update(Drupal\Core\Entity\EntityInterface $entity) {

  5. if (isset($entity->_migration) && $entity->_migration === 'blog_categories') {
  6. return;

  7. }

  8. // Some undesired custom hook logic.

  9. }

In this case the hook will never fire for this specific migration, but may fire for other migrations. Skipping the second condition will make sure the hook will never fire for migrations where the _migration dummy field is defined.

Jan 03 2020
Jan 03

That’s nice, now why are you telling me this?

In you role as a project- or site owner you might not be aware of the implications the “End of Life” announcement has if your site is running on Drupal 7 right now. There are two things you should be aware of:

1. Active development of Drupal 7 stops on the EOL date.

This does certainly not mean that your site will come to a grinding halt on that day, but it does mean that Drupal’s strong points will start to fade going forward. The Drupal Association will no longer provide security releases for Drupal 7, no further development on the core framework will be done and development on the Drupal 7 version of most contributed modules will stop.

Security, flexibility and scalability are often reasons why Drupal was chosen for a project and this clearly has an impact. I knowingly say ”impact” because the robustness of the Drupal project prevents a full stop of support even after the EOL date. A number of partners will be selected to provide paid security support for several years and there will always be members of the community who are prepared to do some work on unsupported contributed modules.

2. Upgrading means migrating.

Upgrading your site from Drupal 7 to Drupal 8 means that you have to also migrate all content that is present in your site. The theme that is used to display the content on the site will also have to be re-developed. This only holds true for this specific upgrade and not for later upgrades from Drupal 8 to Drupal 9 for instance, more on that later... The massive structural changes of the inner workings of Drupal are the cause of this, highly inconvenient but certainly necessary to keep Drupal the modern framework we all need it to be.

Performing a migration and re-developing the theme mean that this needs to be discussed and planned well in advance. Depending on the size of your site the time needed may vary, but to wait until the EOL date arrives is obviously not a good idea.

I see, so what should I do?

The sensible thing to do is to start thinking about what steps are necessary to perform an upgrade to Drupal 8. Drupal 8 was released in November 2015, so it has been in production use for over 4 years now. It is a very stable and mature piece of software with a wide adoption worldwide.

As mentioned earlier, “under-the-hood” Drupal 8 changed significantly compared to Drupal 7. Upgrading therefore provides a chance to perform structural and visual changes to your site that you have in mind anyway. It doesn’t make sense to make big changes to your Drupal 7 site when you know that it’s official life will come to an end in 2021. If you now start to plan for incorporating these changes into the Drupal 8 version of the site, you still have plenty of time to thoroughly discuss these changes and efficiently spend your budget when the time comes to actually perform the upgrade.

The same goes for migrating your content. The upgrade provides an opportunity to think about what content you want to keep and how you can put it to it’s best use!

Drupal 9 will be released in 2020, do I have to do all this again? Should I postpone?

Drupal 9 will be released on June 3rd 2020. Since that is less than half a year away, it might seem better to wait a bit and move from Drupal 7 to Drupal 9 directly. That’s where the big “under-the-hood” structural changes in Drupal 8 come in, upgrading from Drupal 8 to later versions will be extremely easy and not require a full migration! This makes the move from Drupal 7 to 8 an exception, once you are on Drupal 8 upgrading can more or less be done with the click of a button!

So migrating to Drupal 8 first makes a lot of sense because you can start incorporating changes into your site directly, without having to wait for a move away from Drupal 7. This way you benefit from being on the new version of Drupal right away and are future proof from that moment on.

Ok let’s do this, how do we perform the migration?

There are 3 parts relevant to the migration from Drupal 7 to Drupal 8: upgrading code, rebuilding the theme and migrating content. To perform a successful migration we first need to understand where you want to go, so we first discuss what the Drupal 8 site will look like before we do anything else. We have extensive project management experience in house that will lead to a clearly defined product to deliver.

Once we know where we are going, it is time to look at the Drupal 7 site we are coming from. For projects we have not built ourselves this usually means we perform an assessment that tells us how the site is built and what we can expect from its content. The assessment’s outcome tells us how much work the migration will entail and forms the basis for an estimated budget and time needed to complete the project.

Do you want us to help you migrate your Drupal website? Contact us for an introductory meeting and get started right away!

Jan 01 2020
Jan 01

The Problem

Replacing files uploaded to your Drupal site can be very frustrating. In most cases, when an editor wants to replace a document, they want to keep the exact same filename and filepath and just overwrite the contents of the file. This is important in cases where the file is linked to elsewhere throughout the website or on other websites outside of the editors control. If you use the media module to manage documents on your site, you’ll quickly discover that it’s not possible to upload a replacement file for a document and keep the same filename.

Why is this? The core file field allows you to remove and upload a replacement file. But when you upload a replacement file with the same filename, Drupal appends a number to the end of it, like _0, _1, etc. This is because the old file is not actually removed from the filesystem immediately. Drupal will mark it as a temporary file and it will be removed during a cron run sometime in the future (* see exception to this below). Drupal won’t overwrite that file with the new one, so it appends a number to the end to make it unique. Drupal also does this to support revisions properly. If the file field is attached to an entity that has revisions enabled, then Drupal keeps that old file around because previous revisions may require it.

* Actually, as of Drupal 8.4, old unused files are never deleted unless you have a specific config override set that enables this cleanup.

Existing Contrib Solutions

There is a 4 year old Drupal core issue where the community has tried to resolve this problem. Probably the most popular solution has been to use the Media Entity Download module. It works by creating a special route for each media entity that will directly return the file associated with that entity as a download. So if you had a document media entity with ID 59, editors can create links to /media/59/download and Drupal will serve the file directly from that path. This solves the problem because it hides the actual file system path from visitors. It doesn’t matter what that path is or how many numbers Drupal has appended to the end of replacement files, the visitor never sees it and you’ll never have broken links.

The main problem I have with Media Entity Download is that it gets Drupal involved in serving up the files which are normally not handled by Drupal at all. After all, the files are just sitting there in the public filesystem. The web server (apache, nginx) typically serves them to visitors and leaves Drupal out of it. With this module, every time a file is requested, Drupal is bootstrapped and a PHP process is tied up until the download completes to the visitor. This is a bit scary if you get a large surge of traffic with many users requesting large downloads.

The New Solution

I just completed work on the Media Entity File Replace module to provide another solution to this problem. This module is intended for site builders that are using the Media module to manage documents on their site. It works by adding a replacement file widget to the media edit form for media types that use a file source (Image, Document, etc). You can control which specific media types it’s enabled for by visiting the form display configuration and showing/hiding it. When replacement files are selected and the form is saved, the file is first uploaded to temporary storage and then copied over the existing file. The filepath and filename are kept in tact. Just the contents of the file and the metadata describing the file are updated - which is what editors want most of the time.

Edit form for a document media entity showing the "replace file" form widget

Note that the module still supports the previous behavior of NOT overwriting the original file. Editors just need to uncheck the “Keep original filename” checkbox and the replacement file will be uploaded and the media entity updated to reference it.

This module should fill a functionality gap in document management in Drupal - I hope others find it useful!

Dec 12 2019
Dec 12

Maybe it is your first website. Maybe you've been here before, but you're starting afresh. You're full of enthusiasm. In your dreams, your website looks like a flashy cruise liner - huge, and with every amenity money can buy. However, your budget stretches to a dinghy with an outboard motor. So how can you rationalise your aspirations within your financial constraints?

You don't have to be a paragon of fiscal rectitude, but you do need to prioritise, and think a little cleverly about how you can approach the project.

Lego boats

Taking the boat analogy a little further, both the cruise ship and the dinghy can arguably meet your needs. Both will keep you out of the water. Both will get you from A to B. Both have the potential for memorable holidays. Sure, the cruise ship has a roof, but you could elect not to go boating in the rain, so the question is: do you need a roof?

Making your website fit your budget is all about prioritisation, and the realisation that not every available feature is actually necessary, or often even a good idea.

Time, cost and quality. These three things go into your project. You don't want to compromise on quality, because that will cause you problems in the future. You don't want to rush it too much because that will lead to mistakes. Your budget is limited, so the only thing that can be a variable is the scope of the project.

An On-going Development Relationship

This is where things get interesting. A website is not just for launch day: it is for the duration of its life. And over that lifetime, we would expect it to see new content, new features, new sections, upgrades, design changes... Users expect to see change when they return to your site, and this empowers you, the site-owner, to embrace the process of change over a longer time. Rather than trying to build a huge monolithic project on day one, why not stagger your build over a longer time, and use it to bring new features to your users as they are ready?

Take, for example, a house. When you buy a house, it is generally considered a poor idea to immediately demolish part of it and build extensions. It takes time to digest, time to experiment, time to learn what elements you like and which you really can't live with. Equally, you need to learn how your needs have changed in your new house and how they are different to your imagined needs before moving in. You'll also want to think about how your house works within its environment - where does the sun come in? are there any problematic times of year?

So too with websites. Just as you'll figure out your needs over time, it pays to keep an eye on what is happening and changing in your industry and the internet at large since you decided to invest in a site.

Start Small, Extend and Prioritize

So, with websites. As you start to use your site you will have ideas and wants and needs. If you have started small, with a view to extending your site, these ideas can be embraced and your site will grow with you as your experience and that of your users illustrates what the needs really are. Change can now be embraced, nurtured and turned into features that both you and your users really love.

The irony is, that in most traditional projects, everyone is asked to do most of the planning, thinking and budgeting at the very outset - which is the point where everyone concerned has the least knowledge about the project, its constraints (both known and hidden) and its goals. This is essentially gambling and is fraught with the danger of failure.

Project knowledge increases over time

An Example Timeline

To illustrate a staged approach to development, here's a timeline for a simple web project.

Day One - Install Drupal and build our first content type: the basic page. We've identified half a dozen pages of content that will describe who we are and what we do. We'll include a FAQ page to releive pressure from staff and some downloadable documents to reduce printing costs. We'll also install Webform to get a contact form on the site. We'll use the core menu system for navigation. We get metatags and Google Analytics to keep on top of our SEO. We'll set up a solid, responsive theme, but will intentionally keep the design very simple so that we can embellish it later. 

Pre-launch - We set up the site on a specialist, tuned, managed Drupal hosting platform and are ready to go.

Launch Day - We go live with a great looking, dependable, flexible, and fast, responsive site. The site is saving us time and money, increasing our visibility and working for us - from the start.

Two months in - We decide that we want a blog, in order to entice visitors and to establish ourselves as thought leaders in our industry. So we add a content type and a views listing (blog listing landing page), and some additional design and styling to make the blog articles look pretty.

Four months in - The blog is going well and we're getting readership traction. We would like to get further traction and extend our reach into social media. We build in share and follow buttons and Twitter cards to drive traffic. We add a block of latest blog articles to the home page.

Six months in - We decide to integrate Mailchimp to let people sign up to our new newsletter, in order to increase our reach and better communicate with our prospective customers. We get a newsletter signup block on the home page and all blog pages. We add some more design flair to our blocks to make them really sing.

Eight months in - We decide to open up a dialog with our readers, adding comments, and of course, spam protection!

Twelve months in -  We launch a range of beautiful products sold through a fully featured, integrated e-commerce solution from our site.

Who knows where we'll go next?

This is an example, but it could be your project. By starting with the bare minimum and extending the site over time, the site owners and developers have full knowledge of the project at all times and importantly, full knowledge of what they like and don't like. Each item of functionality is discrete and self-contained, allowing proper testing and proper scheduling of deployments.

The benefits of such an approach include:

  • Spread the cost of your site build over a longer time for less financial impact
  • Smaller chunks of work allow for defined, short-term goals and milestones
  • Each new feature is the most important feature to the site-owners, right now, so they get what they want quickly
  • Users enjoy a fresh site with each visit
  • The site can react to changing business needs
  • The entire team builds up project knowledge with every new feature, reducing potential for problems and on-boarding overhead, which all means a more efficient build process
  • Better bang for your buck because only the most important items are built and only these items are styled. You never end up styling something that is never used, and equally, you never end up with an un-styled feature because you ran out of budget.

Consider this approach if you:

  • are getting your first site built
  • have limited budget, but grand aspirations
  • are rebuilding your site from the ground up
  • don't have a lot of time to spend writing lots of content or answering endless questions from your developers
  • think your requirements may change, or are at all unsure what they are

When you're ready, we're ready.

If you want to discuss Annertech helping you build an award-winning website, please feel free to contact us by phone on 01 524 0312, by email at [email protected], or using our contact form.

Dec 06 2019
Dec 06

You may have read our previous articles about how to plan for Drupal 6 or Drupal 7 End-of-Life. The important thing to know is that the Drupal 8 End-of-Life is nothing like those. In fact, “End of Life” is completely the wrong idea. Instead, it’s more like one of those spa treatments where you get a full body scrub to get rid of the dead skin cells. You walk out feeling rejuvenated and refreshed. 

Drupal 9 — Same as Drupal 8, But Without The Old Stuff

Drupal release timeline

In each new minor version of Drupal 8 there are some new features, and some old code is marked as “deprecated” (that just means that it’s time to stop using this, because it’s going to go away some day). After nine minor versions over almost five years, there’s now an accumulation of deprecated code. This deprecated code is like those dead skin cells that you go to the spa to get rid of.  So Drupal 9.0 will be the same as Drupal 8.9, just without the deprecated code. The two might even be released at the same time. 

Then, in Drupal 9.1, we see the cycle starting again: some new features, and some old code is marked as deprecated.

Don’t Rely on Deprecated Code

In the graphic above, you’ll notice that 8.9 does not have any more deprecated code than 8.8. That means that once a website is upgraded to 8.8, we can then start the process of ensuring that the site isn’t using any deprecated code. 

If you are an Advomatic client, we’ll create a ticket in your queue to clean out all uses of deprecated code. In fact, if you’ve done a project with us recently, we’ve already started doing this as part of the Q/A process in our two-week sprints. 

A Window of Almost Two Years for This Cleanup

Drupal timeline by quarters

This is the timeline for the next several versions of Drupal.  We’ve got about 2 years to make this change — more than enough time. 

Alternating Minor Versions

We handle all the technical stuff for you. But the purpose of the website is not for us to have a technical toy to play with, it’s to advance the mission of your non-profit. So we want to devote most of our time and effort towards your web strategy. While we could upgrade your website to the newest version every six months, it’s not the best use of your money or time. So we alternate versions. That means that your Drupal 8 website is either always on an even minor version, or an odd minor version. 

We’ll likely continue that pattern as we cross the threshold into Drupal 9. That means that this process could be delayed by 6 months from what you see here.

Flipping the Switch

Once we’ve cleaned up all the deprecated code, then we’re ready to upgrade the site to Drupal 9.  Remember: this is nothing like past major upgrades in Drupal. Instead it’s just like the minor upgrades from Drupal 8.6 → 8.7 → 8.8 etc.

Conclusion

The key takeaway is that this whole process should be almost seamless. We’ll create a few tickets in the queue to prep for the upgrade, and then for the upgrade itself.  But the majority of our time will still be spent on advancing your mission. Over the years to come the website content and its presentation will be able to continually evolve, all without a costly major upgrade. 

Thanks to Amanda Luker for the charts!

Nov 18 2019
Nov 18

In 1992, there was a little known new thing called the world wide web. By 1995, it was a "thing". Now, what exactly do those quotes do to the word "thing"? And what does this have to do with "entities"?  Cue my favorite programming joke.

Q: What are the two hardest problems in computer programming?

A: Naming things, garbage collection, and off-by-one calculations.

All of that joke is true, but it's the first problem that is the point of this blog post. Because "entity" is just a fancy word for "thing", i.e. coders have the same problem naming some "things" as everyone else does.

What is an Entity?

Just as in our vernacular usage, an "entity" is a "thing with something extra", and it's the "extra" that makes it an entity. To make it more concrete: lots of things can be entities, and in CiviCRM, all contacts, contributions, and events are entities. It's not to hard to think of a contact as a "thing", but in fact, a lot more things in CiviCRM are entities: even such abstract notions as relationships, memberships, and participants to an event. You might get carried away and guess that everything is an entity, and it's a reasonable guess, but not quite. For example, an option in a list of options is usually not an entity. You might also be getting confused at this stage about whether a specific contact is an entity or whether "Individuals" is an entity: the answer is that we use "Entity type" for "Individual", whereas a specific contact is an "entity" (of type "Individual").

Who Cares?

And here's why you should care, even if you're not a programmer. In CiviCRM, entities are a core part of the codebase, and that means that what you can do with one entity, you can often do with other entities. So understanding what is an entity, and what you can do with any entity, makes you a better user of CiviCRM.

Again, what is an entity?

If you look up the definition of entity on Wikipedia, there's a good chance you will be no further ahead than I was after reading it. Because "entities" aren't a specific thing, they are an abstraction. Just like our vernacular use of "thing", a thing becomse a "thing" when it acquires special properties, and those special properties allow us to treat them with a very useful level of abstraction that doesn't need to worry about other details. And now you know why parents often haven't a clue what their children are talking about.

For example, when the web became a "thing", we no longer had to explain what it was, it was a self-explanatory word. Analogously, an entity is a "thing" with certain properties that allows us write code about it without knowing the specifics of the entity - the entity is self-explanatory enough that we can handle it in an abstract manner.

Again, why should I care?

The best I can do is to provide some examples. Here are three that illustrate the power of the entity in civicrm.

1. Custom Fields

You probably know that you can add custom fields to contacts via the web interface in CiviCRM. But that same code works for any entity. So you can add custom fields to things like Relationships, or Recurring Contributions, or ... a surprising number of things you might not even be able to imagine uses for. Go ahead and look at the form where you add a new custom fieldset, and you'll see a long list of things that you can apply it to: those are CiviCRM's entities.

2. CSV entity importer 

Eileen's excellent extension allows you to import data into your civicrm for anything that is an entity. So for your highly customized CiviCRM for which you had to add all kinds of custom fields, you can import that content from your old CRM without even writing any custom code. My example of this, and why I'm such a big fan of this extension, was when our clients needed to import recurring contribution data from their old CRM.

3. The API and browser

CiviCRM has an API that leverages the properties of underlying entities. That means if your site has some kind of custom entity, it's automatically exposed via the API and the API browser, even if you didn't know about it, and even though that code was written before you invented your entity.

3. CiviCRM Entity in Drupal

The Drupal module "CiviCRM Entity" exposes CiviCRM's entities as Drupal entities. Drupal has it's own concept of entity, and it's compatible in concept to a CiviCRM entity. So this module provides some magic glue function allowing all of CiviCRM's entities to also be Drupal entities. And that means you get (for example), Drupal Views of any CiviCRM entity.

But we're still stuck with the hardest problems, including naming things. And off-by-one calculations.

Filed under

Nov 12 2019
Nov 12

Why this is a problem

Allowing any user to user to upload files directly to your website introduces the risk of accepting virus infected files into your filesystem. The risk is much higher for anonymous (not logged in) users because they might be malicious users, but for business reasons it often makes sense to allow anonymous users to submit files. Further processing of infected files, like forwarding a submitted resumé to colleagues or external parties, allows the virus to spread. This could cause significant trouble and hurt SEO as well as your reputation as a dependable business partner.

Scan those files!

Scanning files that are uploaded by anonymous users to a site is something that is often overlooked. Fortunately this a problem that can be easily fixed! The most common way to solve this is by installing a virusscanner in your webhosting environment and let it scan each file that is uploaded. There are various options out there, but we use the open source virusscanner ClamAV to get the job done. In order to be able to scan uploads in your Drupal site there are 2 things you need to do:

1. Install the ClamAV binary file in your hosting environment

With high service managed hosting providers like Acquia or Pantheon this has often already been done for you. If you are hosting on a VPS or dedicated server you will have to install the binary yourself, see this guide for some help with that.

2. Install and configure the ClamAV Drupal module

Instructions are on the project page. Don’t forget to clear the cache of your Drupal installation after after you complet the install, most settings will not take effect until you do. After installation and configuration, you can verify the module is working correctly by trying to upload a fake virus to your website. For this purpose ClamAV is EICAR compliant, meaning you can upload the harmless EICAR anti-virus test file that will then be detected as a real virus if the installation works correctly.

Enjoy your hassle-free solution

This setup now allows for each file that is uploaded to your Drupal website to be scanned for viruses. An infected file will not be accepted into the filesystem and an entry into the site’s log is made so you can keep track of infected upload attempts.

Scanning uploaded files this way provides you with an extra layer of security in your website, protecting your organisation, SEO results and business reputation without site visitors even noticing…

Oct 15 2019
Oct 15

What a UX designer thinks will be quite different from what a mechanical engineer thinks, which will be worlds away from what an artist thinks.

For example,

  • I am a trained civil engineer. As an engineer, design is in providing the minimal technical solution that fits the brief.
  • I often work in the role of a (web) site architect, where design is in accurately modelling business data to provide efficient and scaleable solutions.
  • I was never great at graphic design as my photoshop-fu is weak, but I always understood that as a graphic designer, design is in creating beautiful interfaces for people to interact with.

As a developer, which takes up most of my daily work, I take website designs created by others and implement these into real, usable, functional software. I'm going to talk about things I have seen on real projects, with real clients and perfectly competent teams, where the design actually hindered the build process.

Building The Foundations, Out of TNT

Design can easily make or break a project, and graphic design is easily the most impactful of all design processes. From this point on, any references to 'design' will refer to web design, the graphical design of a web site, such as is often delivered as a Photoshop file (.psd) for implementation by developers.

I have seen great projects with great project teams really struggle because a design, whilst beautiful, was very difficult to implement. Conversely, a design that facilitates ease of implementation can make the project a joy to work on, and will result in a happy client and success all round. Site owners love something that they can 'sign off' on, and more often than not, the first thing that is signed off is the design, which can become a Bible against which the entire project is measured. It is little wonder that design can have such wide-ranging implications.

Deep Impact

There are many ways in which design can impact upon a project.

It's a safe assumption that a website will be built upon a content management system (CMS) - in Annertech's case, we use Drupal. The CMS will have a way of doing things, and the design can work with it, or the design can hinder it.

Nowadays, every site should be a responsive site. But does your design naturally lend itself to being responsive? This does not mean that as a designer you should create separate designs for multiple screen-sizes, but rather that a given design should naturally adjust and flow for different devices. In fact, having a separate design for mobile and tablet-sized screens to desktop can actually hinder development because of inconsistencies of design elements across Photoshop files. Without a solid understanding of how devices interact with and render a page, how page elements float and stack and expand and contract, you run the risk of a design that requires undue effort to force onto a small screen, resulting in a sub-optimal end product. When designing adaptive layouts, content order really matters too. The natural order and flow of DOM elements (if you are not a developer, read: "things on the page") should not have to be adjusted based upon screen width. To do so adds unnecessary complexity and will again probably impact upon performance - how quick your site is rendered on a screen for users.

An Artful Work of Fantasy

Sometimes a design will show visual effects that CSS simply will not produce. Whilst often these effects can be created with enough Javascript and imagery, often the trade-offs (maintainability, performance, page weight) are not worth the gain. Mobile performance, especially, can fall victim here.

A Font is Worth 1000 Pictures

Any designer worth their salt will tell you that font choice is hugely important. This is undeniably true. But the following things are often forgotten when choosing fonts:

  • A font can add considerably to page weight, depending on how many weights/styles you include.
  • On large and complex pages the Flash of Unstyled Text (the screen showing default fonts before the correct ones get to load) when using javascript-based font-replacement techniques can by very jarring. It can also be rather slow to go away on older browsers/machines.
  • Fonts can be expensive, and clients do not always want to pay for them. The smart money says: find out what the font budget is before you do your design. For example, a Photoshop design showing Proxima Nova (€615.99) will never look like a site built using Arial. This will cause untold friction between developer, designer and client over the build process.
  • Not all fonts are created equal. Some fonts might look lovely on a crisp MacBook Pro with retina display, but make sure you look at them on Windows, with a shoddy old 17" monitor. Often that is quite a different experience.

50 Shades of Grey

Great design is all about subtlety and attention to detail. However, this should not deliver a licence for the inclusion of unnecessary detail.

For example, a consistent and concise colour palette is a thing of beauty. However, more than a dozen shades of grey, many indistinguishable from one-another to the lay user, is merely an expensive waste. Again, try out the design on a low-budget monitor: can you tell the difference between #ffffff and #f4f4f4? If not, you probably don't need that level of subtlety and should simplify your design. Yeah, that's right: shots fired in the Needless-Shades-of-Grey wars.

To put it another way, consistency of design elements is a really powerful tool in a web designer's arsenal. Consistently presented elements, re-used in a logical manner, can endlessly simplify CSS, speed up site builds and improve performance. Clearly this is a desirable outcome!

An Appeal for Sanity

Speaking as a developer, this is my plea to designers everywhere to think about how your design can be implemented. Every addition to the design will have an impact on the build and probably on the end user. Is it necessary? Will it enhance or hinder? The ideal is design in the browser, so that you can mock up interactions, see how DOM elements (again, "things on the page") react to changes in screen width and look at what CSS can achieve and what it can't. This is not about asking the designer to do development, but rather to ensure that the agreed-upon design can be practically implemented.

Shucks, as a designer, you might even ask the developer "hey, any problems implementing this before I ask for sign-off from the client?".

Website owners: It's Up to You

Prospective site owners: people who would like to get a Drupal site built. This appeal I direct to you: "Do not accept the artful work of fancy."

There are two possible scenarios stemming from an impractical design.

  1. If you get the design before contracting a development team, the price will be higher than otherwise, as the design makes it more difficult.
  2. If the design is late and the developers have already begun, the project will be late as the effort required will be far greater than originally estimated.

Rather, ask for a design that works with your choice of CMS. One that facilitates responsiveness. A design that is not unnecessarily complicated. These are often the most beautifully simple, accessible designs. Everybody wins.

Love Your Developers

This final plea is one directly related to Photoshop. It is an amazing tool, and one that facilitates wonderful-looking sites. However, I open PSDs with dread. But it does not have to be that way. Herewith, a couple of tips to make the dev in your life happy:

  1. Name your layers. Names like 'Layer 35 Copy' make developers sad. We who are not conversant with the mysteries of Photoshop really find semantically named layers useful! (such as "Sidebar block, heading")
  2. Apply your layer effects. Unless one actually possesses a copy of Photoshop, one cannot see layer effects. Gimp and Preview won't parse them. Be nice to your devs and apply the effects to the layers that require them so that when we slice up a layer, we get the colour you intend and not a pale imitation.

Conclusion

Modern websites are really complex, and it takes a team of dedicated, skilled people to create them. The designer is often the first onto the green field site, and is arguably the person with the most far-reaching power. I suspect that many designers simply do not realise the depth and breadth of their power.

I think that in an absolute ideal, a designer would work alongside the developers, rather than rather than handing over "signed off designs", to create a site that is a harmonious thing of beauty.

Let's work together.

* No sites were harmed in the writing of this blog post
** Whilst all examples come from real life, names have been changed to protect the guilty parties
*** We'd love some cake, if you're sharing

If you want to discuss Annertech helping you build an award-winning website, please feel free to contact us by phone on 01 524 0312, by email at [email protected], or using our contact form.

Sep 18 2019
Sep 18

As we noted in Mastering Drupal 8 Multilingual: Post 2 of 3, installing the Multilingual modules, enabling content translation and setting the configuration translation is really all you need to do in order to translate your site.  

However, the translation experience does leave a few things still to be resolved:

  • Views will show duplicate results for translations.
  • It is difficult to know what language the site is in on the admin side.
  • Interface translations can affect content edit forms to the point where it is nearly impossible to know which field you are editing.

Views translation duplicates

Out-of-the-box, any view (including the Admin Content view) will show what appears to be duplicate results for multilingual translated content. In reality, the duplicate content being registered by the view is the translated version of the node. If you are browsing the Admin Content view in English, clicking on any of the links to the node will take you to the English version, but it can be confusing to editors.

A simple solution to this is to enable the Translation Language filter and set the language to 'Interface translation selected for page.’ This will tell your views to only display the translations for the language the site is currently set to. 

When using this filter, you’ll also want to ensure that the Rendering Language is set also to be ‘Interface language selected for page’ so that the translations are displayed in the current language. 

Setting both the language filter and rendering language to the currently selected language, for all views that have translated results, will remove the duplicate results for translations and ensure that the correct content is always shown in the correct language.

It can also be helpful to add a language column to editorial views that have translated content. Displaying the language of the translation lets editors see the language of the node they are going to be editing—which can be very handy if there are languages on the site which editors are unfamiliar with. 

Current admin language

Another common issue for editors is not knowing which language is active when navigating the admin side of the site. When using Drupal provided languages the admin side of the site will often be partially translated, but the amount of admin interface translation depends on the language and the part of the site you are in.

For example, an editor starts in English and goes to the Admin Content view and clicks Add Node. They add a node, then click the Translation tab to create a Spanish version. They do the translation, save the node and see the node displayed in Spanish. Now, they want to add a link to the node in the main menu. 

They go to the main menu UI and often don’t realize that the active language is still Spanish. In the screenshot below, the only default indicator to let the editor know they are still in Spanish are a couple of admin toolbar links in Spanish and /es in the URL. 

This is because the interface translation for Spanish has not been done for the bulk of the menu UI. Even when creating the menu link, there are only a few description text strings, the Enabled checkbox and the Save button in Spanish. A sharp editor will catch that, but someone less familiar with the menu UI could easily miss these indicators. 

In our example, after adding their menu link, the editor clicks Save and then goes back to view the site. They see that there is now an English link to their new node on the Spanish translation because they unknowingly added the English link in the menu UI while the admin side was still in the Spanish language.

Providing an easy visual method for editors to detect the current language in the admin theme can be done by adding a bit of JS and CSS via a custom module or your custom admin theme. If adding via a custom module, you’ll want to be sure to add the library loading the JS and CSS files to admin pages only. 

The first thing to do is to detect the current language of the site. This can be done by reading the lang attribute of the tag. You’ll also want to fetch the current url using window.location.href. Set them both as variables.

Once the variables are defined, a simple if/else statement will create the visual tag. Since we’re creating a tag for the current language, we might as well add a link back to the default language with the tag.

Lastly, some path detection can be used to add a confirm message on edit forms when the user clicks to go back to the default language letting them know unsaved translation changes will be lost. A bit of CSS will fix the tag to the bottom of the screen.

Translated field labels on edit forms

The goal of a multilingual site is to provide translated content. However, having translated content on the admin side is not always a desirable thing—especially if your editors are not multilingual!

The screenshot below is part of the node edit form for a booklet node being translated to Spanish. Because Spanish is a Drupal-provided language, much of the admin interface is translated automatically when the language is added. Fields that have their labels translated for the end user in configuration translation will also show that translated field label to the editor.

An editor who is very familiar with the booklet node form, or one who remembers their two years of high school Spanish, may be able to puzzle out what the bottom two fields are, but what about a new editor who only ever learned some German?

Field groups are the best choice when it comes to making edit forms easier to understand, and can help give editors a clear picture of what they are editing. By grouping fields together and arranging them in the order in which they appear on the rendered node, the editing experience becomes more intuitive and tied to the content. This is helpful for both English editing and translations. 

Field groups are particularly key for translation. Field groups come with names shown only to the editor. By using a field group even for just single fields on a content type and naming the group just slightly different then the field it contains, the fields themselves can have translated labels for the end-user but the editor can still see the non-translated Field group label.

Sep 13 2019
Sep 13

Wanna know my rules when I am writing templates in PatternLab for Drupal view modes such as teasers, cards, search results, etc? Read on, my friend...

BEM Classes for Streamlined Classes

Classes used in the card view mode should be prefixed with card__ not node__

  • We need to make sure that CSS for cards does not leak out into other components
  • We need to make sure we have as little selector specificity as possible - so we have .card__content instead of .card .node__content in our CSS.

Card Variations

If you want to have slight variations for cards, please add that as an option in the classes array. Examples of this might be for a card for a specific content type, or a card when there is no image present, or a card that has the image on the left/right.


{% set classes = [ 
  "card", content_type ? 
  "card--" ~ content_type, image ? 
  "card--has-image" : "card--no-image", 
  alignment ? "card--" ~ alignment, ] 
%} 

This will print:

We can then apply overrides using these variations. For example, if the date field on a event is bold but but on a blog is not, we can have code like so:

.card__date { 
  color: $c-grey--darkest; 
} 

.card--event .card__date { 
  font-weight: $fw--bold; 
} 

Avoid Twig Blocks

Try not to use Twig blocks in view modes - {% block image %} If we use Twig blocks, then in the Drupal template anything can be put in the {% block %} to override it. If we change the order of things in the {% block %} in PL, this will have no effect in Drupal, since the Drupal version will be overriding it.

For example, the Drupal template could have something like this:

{% block image %} 
  {{ content.field_date }} 
{% endblock %} 

Avoid Drupal Templates

Try to avoid having templates based on specific content types for view modes. This is usually necessary for Full view mode, but for Teaser, Card, etc let's try to keep them more generic.

If you need to use a content-type template, that is fine; but it should be the exception, not the rule.

In general, since each content type Card should be similar, then each content type should be able to use the same node--card.html.twig template file.

Avoid {% if not page %}

{% if not page %} Should not be needed in view modes. A Card or Teaser will never be a full page. For the same reason, we can usualy leave this out in the content type full view mode templates, since the full view mode will always be a page.

Do Not Hardcode Heading Levels

Unless you know that the Card view mode is never going to have a h2 item above it, do not set h2 or h3 etc as the heading element.

We do not want to have a HTML structure like this:


  

Views Card Block Title

Card Title

Card Title

Card Title

Instead, we would like this:


  

Views Card Block Title

Card Title

Card Title

Card Title

In general, view modes will take a h2, so let's place that as our default.

{% set card_title_element = card_title_element|default('h2) %}

<{{ card_title_element }}>{{ card_tite }}

Then, in our Drupal template, we can set the element depending on whether it has a parent h2 or not; for example, if it is in a 'Related Content' building block and that building block has a title such as:

 

We can do so in the Drupal template with a variation of this:

{% if node._referringItem.parent.parent.entity.field_p_rc_title.value %} 
  {% set teaser_title_element = 'h3' %} 
{% endif %} 

If the above returns as false, our default h2 from the PL pattern will kick in.

Use Prefixes for Variables

Let's use prefixes for variables, using {{ card_content }} instead of {{ content }}. This will help avoid global variables being used by accident in our components (unless we want them to, such as the image_alt variable from data.json). The {{ content }} if used, will not necessarily print the content of your component when that component is used outside of its own context: for example, if you print a card in a views list in a sample page.

Variables for Specific Content Types

If there's a variable for a specific content type, such as the location field for an event card, we can just wrap that in an {% if %} statement, like so:

{% if content_type == 'event' %}
  {% if event_location %}

    {{ card_location}}

  {% endif %} 
{% endif %} 

Then that variable will not print in any other content type's template.

Share (please)

Filed Under:

  1. Drupal
  2. Frontend Development
  3. PatternLab
  4. Web Design
  5. Design in Browser
  6. Drupal Planet
Sep 10 2019
Sep 10

Just like the poem says, “Little drop makes the mighty Ocean,” all contributions matter in the growth of the Drupal global community. 

A diverse community results in great things. To ensure the longevity of Drupal digital experiences and the adoption of this open-source technology, Drupal itself must be ready for a global audience. 

Contributors are Drupal's most valuable asset, and are the sole force behind improvements to the platform and the community itself. There are so many ways to contribute to Drupal. One way non-native English speakers like me can contribute to Drupal, is simply by volunteering time translating Drupal’s user interface text. 

Why does translation matter?

Drupal, by default, assumes modules and themes are written in English. This assumption of English as a default language creates a common ground and standard for sharing with the Drupal community. 

Modules and themes must be translated from English to other languages. To translate Drupal is to translate from English, the pieces of text (or set of “strings” in programming terminology) that are visible in buttons, menus, field captions, messages, and so on. 

At present in Drupal, there are 100 languages with about 115 translation groups. According to the translation status of Drupal 8, only Ukranian, French, and German are considered 100 per cent (with 9,353 strings) translated.

Malayalam is one of the languages in which I am fluent and it is a language spoken by 36 million people in Kerala, a southern state in India. Malayalam has incomplete versions of the text in core. Parts of the interface will still show up in English, while other parts need corrections and improvements of the language. 

When I started contributing to this particular translation project, it was immediately noticed and embraced by others in the online community. First, I was a Translation Self Moderator and Translation Content Moderator, then made Translation Community Manager. 

Translating Drupal means opening doors for talented developers everywhere to embrace the Drupal open-source platform. 

Whenever I do translation I feel like I’m solving a puzzle. When I get a chance to contribute to my mother tongue and home community, it is always a happy and prideful moment. I feel connected to a place very far away from where I live now, in Canada. 

I often think of Julia Carney's immortal lines (from her poem, Little Things), "Little drops of water,/Little grains of sand,/Make the mighty ocean/And the pleasant land./So the little minutes,/Humble though they be,/Make the mighty ages/Of eternity". Meaning, if things are done well and effectively on a regular basis, even if it’s only for a short while each day, it adds up to something substantial.

Interested? You too can join the Language Team from the Drupal Translation page and help out in the language of your choice by suggesting translations that will be later approved by team members with Content Moderator role. Strings can have multiple suggestions at a time, and even translated strings can receive further suggestions to help fine-tune translations. There is also something in it more than the greater good or feeling of a job well done -- issue contributors get credits on drupal.org. 

I want to thank both Steve Bayer (SteveBayerIN) and colleague M Parker (mparker17), for helping me get started.  

ഈ ലേഖനം വായിച്ചതിന് നന്ദി ! :-)

Read other blogs in this series, How To Contribute to Drupal

--

Did you enjoy this article? Get more just like it by signing up to receive Digital Echidna’s free e-newsletter, delivered to your inbox every month. Subscribe today.

Aug 15 2019
Aug 15

Once, the Drupal community had Mollom, and everything was good. It was a web service that would let you use an API to scan comments and other user-submitted content and it would let your site know whether it thought it was spam, or not, so it could safely publish the content. Or not. It was created by our very own Dries Buytaert and obviously had a Drupal module. It was the service of choice for Drupal sites struggling with comment spam. Unfortunately, Mollom no longer exists. But there is an alternative, from the WordPress world: Akismet.

Akismet is very similar to Mollom. It too is a web service that lets you use an API to judge if some submitted content is spam. The name is derived from the Turkish word kismet, which means fate or destiny. The A simply stands for automatic (or Automattic, the company behind both WordPress and Akismet). It was created for WordPress, and like Mollom was once for Drupal, it is the service of choice for WordPress sites. However, nothing is keeping any other software from making use of it, so when you download the Akismet module, you can use it with your Drupal site as well. Incidentally, the module is actually based on the code of the Mollom module.

There is no stable release of the module, currently. In fact, there is no release at all, not even an alpha release. Except for development releases, that is. This means that for now it might not be an option for you to deploy the module. Hopefully, this changes soon, although the last commit is over a year ago at the time of writing. A mitigating circumstance, though, is that Drupal.org itself seems to be using this module as well, albeit in the Drupal 7 version (this article will be discussing the D8 version).

Adding Akismet to your Drupal site

How to add the module will depend on your workflow. Either download a development release, or - when you use a composer-based workflow - add the module like so:

$ composer require drupal/akismet:^1.0@dev

Then, enable the module through the Extend admin screen (/admin/modules).

Basic configuration

In order to configure the module, you will first need an Akismet API key. To get this, register at https://akismet.com. If you have a wordpress.com account (which you might have from either wordpress.com itself, or e.g. because you also have Gravatar) you can sign in with it.

Once you've obtained an API key, you can go to /admin/config/content/akismet/settings to configure Akismet.

The choice what to do when Akismet is not available is probably dependent on how busy your site is. If it is very busy, and you do not get tons of spam, you probably want to accept all submissions. If you get a lot of spam and not very many actual contributions, you might want to block everything. If you both have a high traffic site and get a lot of spam, good luck. Of course, you can always look at a second line of defense, like the Honeypot module

The second two settings - Show a link to the privacy policy and Enable testing mode - seem to be left-overs from the Mollom module, because neither of them seem to do anything. I created issues for both the privacy policy and the testing mode.

While Mollom had a requirement to either show a link to its terms of use on protected forms, or have your own terms of use that made it clear you make use of the Mollom service, Akismet doesn't seem to have such a requirement. (Of course, it is a good idea to add something about your use of Akismet in your terms of use or your privacy policy).

Testing with Akismet is possible to either pass "viagra-test-123" as the body of the message, or "[email protected]" as the email address; these will always result in a spam classification. This seems to trigger the "unsure" scenario, eventhough that doesn't actually fully work, currently (see further). Forcing a ham (the opposite of spam - I didn't make this up) response is a bit trickier, because it would involve setting some parameters to the web service you do not have control over from the outside. Especially the testing mode might be a nice feature request for the Akismet module. Ideally, the module would work similar to the Mollom module, where you could simply send in a comment with "ham", "unsure" and "spam" to test. As said, I created an issue to flesh out this functionality.

The advanced configuration hides settings to control whether to only log errors and warnings, or all Akismet messages, and a timeout for contacting the Akismet server. Especially in the beginning you might want to log all messages to monitor whether things are working as they should. 

Configuring which forms to protect

When having finished the basic configuration for the module, it is time to configure the forms you want to protect. This happens on the path /admin/config/content/akismet. Here, click the "Add form" button to start configuring a form.

When clicking the button, the module will ask you which form you wish to configure. Out of the box, the module will offer to protect node, comment user and contact forms. A hook is offered to add additional forms, although either a module will need to implement the hook itself, or it will have to be done for it. Here, I'm choosing to just protect the comment form, as I am suffering from quite a lot of comment spam. Once you've chosen a form, it will show the form fields you might want to pass to the Akismet web server for analysis.

You'll basically want to select anything that is directly controlled by the user. The obvious candidate is the body, but also the subject, user name, email address, website and hostname will contain clues whether something is spam or not.

Next, you get to select what happens when Akismet decides content is or might be spam. Akismet may report back that it is sure something is spam. If it says something is spam, but does not pass back this certainty flag, the Drupal module says Akismet is "unsure", which is actually a term that can be traced back to the Mollom roots of this module. You may tell the module it should then retain the submission for manual moderation, although this doesn't seem to work correctly, at the moment. I created an issue in the issue queue for that. What I'm seeing happening is that the post is discarded, just like when Akismet is sure.

Click Create Protected Akismet Form to save the protection configuration. You're now ready to catch some spam. You can look at the watchdog log (/admin/reports/dblog) to see the module reporting on what it is doing. Akismet itself also has a nice dashboard with some graphs showing you how much ham and spam it detected on your site.

Reporting spam to Akismet

Sometimes, Akismet might wrongly accept some piece of content that is actually spam. Or, when the moderation queue mechanism actually works properly, you probably want to let Akismet know that yes, something is in fact spam (you might also want to let Akismet know it didn't correctly identify spam, i.e. report false positives. This is a feature of the web service, but is currently not in the module; another feature request, it seems. I've submitted one in the issue queue).

The module comes with action plugins for comments and nodes that let you unpublish the content and report it as spam to Akismet at the same time. You can add it to your comment views by changing their configuration at /admin/structure/views/view/comment (you will need the Views UI module enabled to be able to configure views). Unfortunately, it seems that also with this functionality there is an issue, the action doesn't actually unpublish. A patch is available in the linked issue and of course the workaround is to first use the Akismet action, and then use the standard unpublish action.

Find the configure link for the Comment operations form. Click the link and, in the modal that opens, find the list of checkboxes for the available actions. Enable Report to Akismet and unpublish and save the configuration. Repeat for the Unapproved comments display. This will mean you will now have the action available in the actions dropdown on the comments overviews at /admin/content/comment.

Adding this to a node view will be similar, although chances are that when you have end users submitting nodes, you likely also have some dedicated views for your specific use case, such as Forum posts.

Issues created as a result of this blog post

Please note that I did not intend to "set anyone to work" with creating these. I simply wanted to record some findings and ideas from writing up this blog post.

Aug 12 2019
Aug 12

Drupal already comes with 100 languages to choose from, and you can also add custom languages. This means that you can translate content into any language you can think of with no limitations.

To add a language, go to Configuration > Languages and click Add Language.  If you choose one of the default languages from the select list, Drupal will automatically fetch the most up-to-date interface translation files. These interface translation files automatically provide translations for a large part of the administration interface when viewed in that language.

Note: You will often see errors or PHP warnings when installing default languages. This is due to the difficulty of keeping 100 languages updated with all the changes between Drupal versions and compatibility with the vast sphere of contributed modules. Do not worry, the language will still work perfectly for content, configuration, and custom string translations.

If you choose to add a custom language (at the very bottom of the language list) you will be prompted to choose a language code and language name as well as the language direction you wish to use. It is very important that you use an approved language code. Approved language codes can be found in the Commerce Guys Address repository.

Using approved language codes will prevent fatal errors with Views and other possible bugs. The list of approved codes may not contain the specific code you want to use for the language prefix—often seen in the URL when viewing the site in a different language–but the prefixes can customized to display whatever you want to the end-user.

Once you add a language to the site, the Drupal language switcher block will become available to your list of blocks. Place this via block layout (or your own preferred method) to allow users to change the site language. The page header is a typical location.

After you've added all of the languages you need for the site, click on the 'Detect and selection tab' in the languages interface. The settings here will let Drupal know how to tell which language to display. Each method has pros and cons, depending on your site and user base. We prefer the URL method. Using this method will add the language prefix of the user-selected language to the URL and will keep the site in that language until a different language is selected or the prefix is manually removed from the URL.  

Configuring the URL method will allow you to choose the prefix you wish to use for each installed language. Using a custom prefix along with the language name you set means that you can use approved codes (as mentioned above) without being culturally insensitive to your users.

For example, on a recent project requiring Hmong translations, we did not have a pre-existing prefix. On the backend, we used the pre-existing Vietnamese prefix but rewrote it to display "hm" instead of "vi" (recognizing that these are two different languages). 

Language names can also be translated in the Languages interface. 

Aug 08 2019
Aug 08

Once the decision is made to build a multilingual site, it is time to start planning. Since multilingual impacts so many areas–project management, design, development, and content creation—the sooner you start planning, the better.

Some questions to ask:

  1. What languages are going to be used?
  2. Do you need to design for any right-to-left languages?
  3. Is the entire site going to be translated, or just certain sections or content types?
  4. Where are the translations coming from? Will they be provided by a service, by the client?

Right-to-left languages may provide an obvious design and layout challenge, but also remember that many languages use more words or much longer words than English. Leave some extra white space in the design of translated elements to account for this.

It will also be beneficial for site builders, developers and project managers to team up early to define any non-content translations needed. Non-content translations include things like Views filters, field labels, and text set in Twig templates or modules that cannot be accessed by site editors. These translations will have to be provided by the client and then added by developers.

Developing a spreadsheet or list of non-content translations, and providing that to the client or translation service early in the project, will allow site builders and developers to add translations to the site as they become available. Try to make sure, however, that these translations are finalized before adding them because each change to base language configuration or interface text is compounded on a multilingual site. The amount of work for each change is multiplied by the number of languages that change needs to be translated into.

Aug 05 2019
Aug 05

When deploying changes to a Drupal environment, you should be running database updates (e.g. drush updb, or through update.php) first, and only then import new configuration (which itself is supposedly the result of running the same update hooks on a development environment). The reason for this is that update hooks may want to update configuration, which will fail if that configuration is already structured in the new format (you can't do without updates either; update hooks don't just deal with configuration, but may also need to change the database schema and do associated data migrations). So, there really is no discussion; updates first, config import second. But sometimes, you need some configuration to be available before executing an update hook.

For example, you may want to configure a pathauto pattern, and then generate all aliases for the affected content. Or, you need to do some content restructuring, for which you need to add a new field, and then migrate data from an old field into the new field (bonus tip: you should be using post update hooks for such changes). So, that's a catch-22, right?

Well, no. The answer is actually pretty simple, at least in principle: make sure you import that particular configuration you need within your update hook.

For importing some configuration from your configuration sync directory, you can add this function to your module's .install file:

/**
 * Synchronize a configuration entity.
 * 
 * Don't use this to create a new field, use 
 * my_custom_module_create_field_from_sync().
 *
 * @param string $id
 *   The config ID.
 *
 * @see https://blt.readthedocs.io/en/9.x/readme/configuration-management/#using-update-hooks-to-importing-individual-config-files
 */
function my_custom_module_read_config_from_sync($id) {
  // Statically cache storage objects.
  static $fileStorage, $activeStorage;

  if (empty($fileStorage)) {
    global $config_directories;
    $fileStorage = new FileStorage($config_directories[CONFIG_SYNC_DIRECTORY]);
  }
  if (empty($activeStorage)) {
    $activeStorage = \Drupal::service('config.storage');
  }

  $config_data = $fileStorage->read($id);
  $activeStorage->write($id, $config_data);
}

Use it like this:

my_custom_module_read_config_from_sync('pathauto.pattern.landing_page_url_alias');

As you might have seen in the docblock above that function, it is not actually suitable for creating fields. This is because just importing the configuration will not create the field storage in the database. When you need to create a field, use the following code:

/**
 * Creates a field from configuration in the sync directory.
 *
 * For fields the method used in kankernl_custom_read_config_from_sync() does
 * not work properly.
 *
 * @param string $entityTypeId
 *   The ID of the entity type the field should be created for.
 * @param string[] $bundles
 *   An array of IDs of the bundles the field should be added to.
 * @param string $field
 *   The name of the field to add.
 *
 * @throws \Drupal\Core\Entity\EntityStorageException
 */
function my_custom_module_create_field_from_sync($entityTypeId, array $bundles, $field) {
  // Statically cache storage objects.
  static $fileStorage;

  // Create the file storage to read from.
  if (empty($fileStorage)) {
    global $config_directories;
    $fileStorage = new FileStorage($config_directories[CONFIG_SYNC_DIRECTORY]);
  }

  /** @var \Drupal\Core\Entity\EntityStorageInterface $fieldConfigStorage */
  $fieldStorage = \Drupal::service('entity_type.manager')
    ->getStorage('field_storage_config');

  // If the storage does not yet exit, create it first.
  if (empty($fieldStorage->load("$entityTypeId.$field"))) {
    $fieldStorage
      ->createFromStorageRecord($fileStorage->read("field.storage.$entityTypeId.$field"))
      ->save();
  }

  /** @var \Drupal\Core\Entity\EntityStorageInterface $fieldConfigStorage */
  $fieldConfigStorage = \Drupal::service('entity_type.manager')
    ->getStorage('field_config');

  // Create the field instances.
  foreach ($bundles as $bundleId) {
    $config = $fieldConfigStorage->load("$entityTypeId.$bundleId.$field");
    if (empty($config)) {
      $fieldConfigStorage->create($fileStorage->read("field.field.$entityTypeId.$bundleId.$field"))
        ->save();
    }
  }
}

And, once again, a usage example:

my_custom_module_create_field_from_sync('node', ['basic_page', 'article'], 'field_category');

The function will check whether the field already exists, so it is safe to run again, or to run it for a field that already exists on another bundle of the same entity type.

Note that when using post update hooks, it will be important to create a single hook implementation that applies all required actions for what should be considered a single change, because there are no guarantees about the order of post update hooks. So that would for example constitute:

  1. Create a new field.
  2. Migrate data from the old field to the new field.
  3. Remove the old field.

Hopefully, this helps someone get out of that catch 22. Whatever you do, don't run your config import before your database updates.

Jul 30 2019
Jul 30

Testing integrations with external systems can sometimes prove tricky. Services like Acquia Lift & Content Hub need to make connections back to your server in order to pull content. Testing this requires that your environment be publicly accessible, which often precludes testing on your local development environment.

Enter ngrok

As mentioned in Acquia’s documentation, ngrok can be used to facilitate local development with Content Hub. Once you install ngrok on your development environment, you’ll be able to use the ngrok client to connect and create an instant, secure URL to your local development environment that will allow traffic to connect from the public internet. This can be used for integrations such as Content Hub for testing, or even for allowing someone remote to view in-progress work on your local environment from anywhere in the world without the need for a screen share. You can also send this URL to mobile devices like your phone or tablet and test your local development work easily on other devices.

After starting the client, you’ll be provided the public URL you can plug into your integration for testing. You’ll also see a console where you can observe incoming connections.

Resources

Jul 29 2019
Jul 29

In the coming weeks, you can expect a series of changes going into the development pipeline to support the CiviCRM-Drupal 8 integration. Individually, these will seem unrelated and disjoint - they may not explicitly reference “D8”. I wanted to spend a moment to discuss the concept which ties them together: the clean install process, which will make Civi-D8 an equal member of the Civi CMS club and a good base for continued development and maintenance.

This work on D8 stabilization has been made possible by the generous funders of the Civi-D8 Official Release MIH. If you’d like to see more topics addressed, please consider contributing to the MIH.

What do you mean by "clean" install process?

A "clean" install process is a set of steps for building a site in which CiviCRM comes in a direct fashion from source-code with a bare minimum of intermediate steps.

To see this concept in action, we can compare CiviCRM's integrations with Drupal 7 and Joomla:

  • CiviCRM-D7 is amenable to a (comparatively) clean install process. There are three Github projects (“civicrm-core”, “civicrm-packages”, and “civicrm-drupal”) which correspond directly to folders in the web-site. If you copy these projects to the right locations, then you have an (almost) valid source-tree.

  • CiviCRM-Joomla is not amenable to a clean install process. You might think it's similar -- it uses a comparable list of three projects (“civicrm-core”, “civicrm-packages”, “civicrm-joomla”). The problem is that “civicrm-joomla” does not correspond to a singular folder -- the install process requires a diasporadic distribution of files. The install script which handles this is tuned to work from the “civicrm-X.Y.Z-joomla.zip” file, and producing that file requires a tool called ”distmaker”. “distmaker” is fairly heavy - it requires more upfront configuration, is brittle about your git status, runs slower, and produces 200+mb worth of zipfiles. In short, building a CiviCRM-Joomla site from clean source is more difficult.

Why does a "clean" process matter?

It's easier to develop and maintain software when the build is clean and intuitive. Specifically:

  • It's easier to climb the ladder of engagement from user/administrator to contributor/developer.

  • It's easier to lend a hand - when someone submits a proposed patch, it's easier to try it out and leave a friendly review.

  • It's easier to setup automated QA processes for evaluating proposals and upcoming releases.

  • It's easier to setup sites for RC testing, issue triage, pre-release demos, and so on.

  • It's easier to pre-deploy a bugfix that hasn't been officially released yet.

Anecdotally, more experts with stronger collaborations have grown-up and stayed around in the Civi-D7 and Civi-WP realms than the Civi-Joomla realm. And that does not feel like a coincidence: as a developer who watches the queue, I'm generally intimidated by a Civi-Joomla patch -- even if it looks simple -- purely on account of the difficult workflow. I believe that a reasonably clean/intuitive build process is prerequisite to a healthy application and ecosystem.

Moreover, a clean build of Civi-D8 is important for Civi's future. Civi-D7 cannot be the reference platform forever - if we expect Civi-D8 to take that mantle, then it needs to be on good footing.

What kind of changes should we expect?

From a civicrm.org infrastructure perspective: Expect automatic setup of D8 test/demo sites - in the same fashion as D7, WordPress, and Backdrop. This means PR testing for "civicrm-drupal-8". For bug triage, it means normalized and current test builds. For release-planning and QA, the test matrices will provide test-coverage for D8 (similar to the other CMS integration tests). These services are blocked on the need for a clean process.

From a site-builder perspective: Expect the recommended template for `composer.json` to be revised. This should improve support for backports and extended security releases. Early adopters may eventually want to update their `composer.json` after this settles down; however, the details are not set in stone yet.

From a developer perspective: Expect the process for setting up `git` repos to become simpler. Instead of using the bespoke `gitify`, you'll be able to use the more common `composer install --prefer-source`.

From a code perspective: Expect changes to code/use-cases which (directly or indirectly) require auto-generated files. For example, when initializing Civi's database, the current Civi-D8 installer relies on “.mysql” files (which have been pre-generated via ”distmaker”); we can replace this with newer function calls which don't require pre-generated files -- and therefore don't depend on ”distmaker” or “setup.sh”.

Filed under

Jul 23 2019
Jul 23

Here at Phase2, we’re excited to participate in the premiere Drupal government event, Drupal GovCon, held at the National Institutes of Health campus in Bethesda, Maryland where we'll once again be a platinum sponsor.

We hope you will join us for one of North America’s largest Drupal camps, this week.  

You can find Phase2 at our sponsor booth and all over the session schedule:

Why Migrate To Drupal 8 Now

With Drupal 9’s release impending, there has been a resurgence of chatter around Drupal 6/7 migration. If your government organization is still on Drupal 6 or 7 you will won’t want to miss this session. You can read more about the subject here from our on-site presenters, Tobby Hagler, Director of Engineering, and Felicia Haynes, Vice President of Accounts.

Measuring What Matters: Using Analytics To Inform Content Strategy

Content Strategy is the backbone to any successful digital experience. It’s also rarely considered an analytical process, but it should be! Catch our session to learn more, and in the meantime, read about the top 3 content strategy tips for government ahead of Jason Hamrick’s session.

Accessible Design: Empathy In A World With No Average

Our Accessibility expert, Catharine McNally, has a special treat for her session’s attendees: she’ll be hosting some interactive empathy building exercises, to showcase the impact of accessible design for citizens. This is a unique opportunity for anyone involved in the design, content, and UX of their organization’s/agency’s digital experience.

Personalization & Government: The Odd Couple or The Perfect Match?

Personalization has become the new standard, across industries, for improving customer experience, but how can personalization be leveraged in government? Join our CEO, Jeff Walpole, and Vice President of Business Development, Ben Coit,  to explore use cases and how governments can continue thinking about the next generation of citizen experiences.

Jul 23 2019
Jul 23

A common architectural model in Drupal is for one entity to reference another. For example, when using the Paragraphs module to build structured modular content, imagine that you have a paragraph type that references another paragraph type. The use case for this might be to build something like a grid of cards, an image gallery, or a carousel. The parent or "referencing paragraph" points to another paragraph type that contains an image, text, and title. Thus, the referencing paragraph is a container of multiple, similar sets of child entities that can be re-purposed in different manners depending on a setting in the referencing paragraph.

Use case

With this type of referenced entity paradigm, one can create a custom theme hook according to a setting in the referencing paragraph such as a select list with a set of "style options." In this way, we can theme with custom templates, HTML, and CSS depending on the style selection.

Getting started

The diagram below outlines our design pattern. In this, we see that the referencing paragraph has a select list, "Choose a Style" to select how the referenced entities will appear. The we see a visualization of "Cards" as one possible option.

This diagram outlines our architectural modelThis diagram outlines our architectural model

Essentially you would create a regular paragraph type with an image and a textarea, "Image & Text." Then, create another paragraph type, "Image & Text Reference" that points to Image & Text. This is visualized below.

The Paragraphs UI showing the relationship between the referencing and referenced paragraphsThe Paragraphs UI showing the relationship between the referencing and referenced paragraphs

Once that's all setup, add content and ensure that your local Drupal environment is setup for theming and development. I like to use Docksal for my local setup which makes it easy to get up and running with Xdebug. In addition, you'll want Twig debugging enabled in your local settings files. See the resources section below for more information.

Debugging with Twig & Xdebug

Now that we've added some content, we can start to debug. Inspecting the elements in Chrome, we see that our theme hook is named paragraph.






From the above information, we can leverage template_preprocess_paragraph for further debugging using Xdebug. In the case of creating a custom theme hook, we can use the Drupal 8 API's function hook_theme_suggestions_HOOK_alter where 'HOOK" is the discovered theme hook above; "paragraph." In this way, we can use theme_suggestions_paragraph_alter.

Using Paragraph's API function, getParentEntity(), we can run Xdebug in the referenced paragraph bundle and evaluate the expression, $paragraph->getParentEntity(). This "reaches" up to any values you'd like to retrieve from the referencing paragraph bundle and can make them available in the referenced paragraph bundle.

Xdebug in action showing getParentEntity() evaluatedXdebug in action showing getParentEntity() evaluated

From the above, we see the value that's been set on our select list, "Choose a Style." Now we can leverage that as we like in our referenced paragraph theme hook.

 if ($bundle === 'image_text') {
 // We evaluate the expression in Xdebug.
 // And from that, we set a variable and derive the value. ($host_value).
 $host_value = $paragraph->getParentEntity()->field_style->value;
 $suggestions[] = 'paragraph__' . $paragraph->bundle() . '__' . $view_mode . '__' . $host_value;
 $suggestions[] = 'paragraph__' . $paragraph->bundle() . '__' . $host_value;
    }

New theme suggestions

Once again, viewing Twig debug, we now have awesome new theme suggestions available.




Note the presence of:

   * paragraph--image-text--gallery.html.twig
   * paragraph--image-text--default--gallery.html.twig

These two new theme suggestions derive from the $host_value we had set in theme hook definition and creation.

Summary

This is really just the tip of the iceberg of what can be accomplished using getParentEntity() within paragraphs but it should come in really handy.

I'd also add that I've recently become a huge fan of Xdebug in combination with PHPStorm and it massively speeds up development and debugging. I used to use Kint, but no more, it was just too slow. It's really worth the time and effort to get up and running with Xdebug.

In addition, I started learning to use Adobe XD for the architectural diagram above. XD is an awesome free tool from Adobe that's very similar to the Sketch app.

Resources

Jul 20 2019
Jul 20

For starters, over 200 Drupal 8 sites already run CiviCRM!  This post is based on my own research and conversations with those involved, and is intended to be informative and encouraging.  As you may know, CiviCRM works with no less than four CMS at the moment, including three versions of Drupal, two 'officially'.   Understandably with Drupal 7 end-of-support scheduled for Nov 2021, there has been recent discussion amongst those using or considering Drupal about which to use for your website.

  • Many Drupal shops already support and recommend Drupal 8 with CiviCRM
  • Preferred installation techniques for Drupal 8 have coalesced around the use of the Composer tool
  • Tutorials and how-tos for installation by leading experts are available

Let's back up a step...what is different about Drupal 8?  Well, Drupal 7 to Drupal 8 represents a major leap and upgrade.  Whereas Drupal 8 to 9 (and beyond) should be significantly less laborious, according to the Drupal head honcho.  The investment to jump to Drupal 8 will be offset by easier Drupal updates planned in the future.  Compatibility with CiviCRM should be similarly less laborious to maintain.

The Make it Happen fundraising campaign for Drupal 8 & Civi is currently halfway there.  But what's it for?

  • Improvements to the CiviCRM core installer for use with Composer and a clean build process
  • Funding the CiviCRM Core Team, who are already carefully considering and coordinating the sustainable architecture they will implement
  • An officially supported Drupal 8 release listed for download
  • Future maintenance

But what about other Drupal integration modules we know and love, such as Webform CiviCRM and CiviCRM Entity?  Again, great question...

  • Efforts to port these modules to Drupal 8 are already well underway, and nearing completion!
  • These modules have little to no dependency on the Drupal 8 & core CiviCRM Make it Happen effort
  • There are issue queues and sponsors for Entity and Webform. Code and financial contributions are welcome

Ok but "What do I do?" you may ask.  First off, that's a deeply individual question, depending on what your website already does and what you need it to do with CiviCRM.  But regardless it's a good idea to start this conversation right now.  Here's some food for thought:

  • Discuss with your CiviCRM consulting partner that supports Drupal.  If you are a consultant, consider a proactive chat with your clients
  • You don't need to wait for an official release, you can get started today building Drupal 8 with Civi using these tips and installation guides
  • Get involved technically and financially by supporting individual module efforts and/or the Make it Happen
  • Talk to others, ask their opinion, and get them involved.  You can find support on CiviCRM's Stack Exchange or the 'dev' and 'drupal' channels of Civi's MatterMost chat
  • You might consider another CMS for your new website that already has official CiviCRM support.  WordPress and Joomla! come to mind of course.  But it's worth mentioning Backdrop specifically in this category, due to it being a Drupal offshoot with a supposedly clean upgrade path from Drupal 7
  • Or you could wait a little bit longer...and see what happens.  Drupal 7 isn't going away at end of 2021, it's just no longer officially supported.  Third-party providers are already gearing up for long term support of Drupal 7 into 2022 and beyond.  So if you've built a behemoth with Drupal 7, you may be able to keep it active for quite some time

Hope this helps people get their heads wrapped around what's going on...comments welcome!

Filed under

Jun 27 2019
Jun 27

Dreditor is a browser extension that provides handy buttons for working with issues on drupal.org in a consistent way. The Safari extension is no longer being distributed, but you can build it yourself and install it as a custom extension. It does not require a developer certificate.

Jun 20 2019
Jun 20

We’ve been starting many of our projects using Acquia’s Lightning distribution. This gives a good, consistent starting point for and helps speed development through early adoption of features that are still-in-the-works for Drupal 8. Like other distributions, Lightning bundles Drupal Core with a set of contributed modules and pre-defined configuration.

While Lightning is a great base to start from, sometimes you want to deviate from the path it provides. Say for example you want to use a Paragraphs based system for page components, your client has a fairly complex custom publishing workflow, and you also have different constraints for managing roles. Out-of-the-box, Acquia Lightning has a number of features you may find yourself in conflict with. Things like Lightning Layout provide a landing page content type that may not fit the needs for the site. Lightning Roles has a fairly hard-coded set of assumptions for role generation. And while it is a good solution for many sites, Lightning Workflow may not always be the right fit.

You may find yourself tempted to uninstall these modules and delete the configuration they brought to the party, but things are not always that simple. Because of the inter-relationships and dependencies involved, simply uninstalling these modules may not be possible. Usually, all looks fine, then when it comes time for a deployment things fall apart quickly.

This is where sub-profiles can save the day. By creating a sub-profile of Acquia Lightning you can tweak Lightning’s out-of-the-box behavior and include or exclude modules to fit your needs. Sub-profiles inherit all of the code and configuration from the base profile they extend. This gives the developer the ability to take an install profile like Acquia Lightning and tweak it to fit her project’s needs. Creating a sub-profile can be as easy as defining it via a *.info.yml file.

In our example above, you may create a sub-profile like this:

name: 'example_profile'
type: profile
description: 'Lightning sub-profile'
core: '8.x'
type: profile
base profile: lightning
themes:
  - mytheme
  - seven
install:
  - paragraphs
  - lightning_media
  - lightning_media_audio
  - lightning_media_video
exclude:
  - lightning_roles
  - lightning_page
  - lightning_layout
  - lightning_landing_page

This profile includes dependencies we’re going to want, like Paragraphs – and excludes the things we want to manage ourselves. This helps ensure that when it comes time for deployment, you should get what you expect. You can create a sub-profile yourself by adding a directory and info.yml file in the “profiles” directory, or if you have Drupal Console and you’re using Acquia Lightning, you can follow Acquia’s instructions. This Drupal Console command in Lightning will walk you through a wizard to pick and choose modules you’d like to exclude.

Once you’ve created your new sub-profile, you can update your existing site to use this profile. First, edit your settings.php and update the ‘install_profile’ settings.

$settings['install_profile'] = 'example_profile';

Then, use Drush to make the profile active.

drush cset core.extension module.example_profile 0

Once your profile is active and in-use, you can export your configuration and continue development.

Jun 18 2019
Jun 18

While many things stayed the same as previous years, such as the camp location and month it is held, this year was a first for many small changes.

Programming
The first big change was programming. Unlike previous years, where there was 1 day of training, and two full days of sessions and tracks (like you would have at a DrupalCon), this year’s schedule had one day of training, and only one day of traditional sessions.

The third day of the conference was dedicated to “unconferencing,” where those attending decided as a group what topics to discuss, and everyone participated in round table discussions for the day. The feedback was extremely positive for the new schedule, so it seems likely to stick.

The @TCDrupal unconference is underway! pic.twitter.com/WqaQsNL2rk

— Twin Cities Drupal (@TCDrupal) June 8, 2019

Welcome Party
The second big change was adding a new social event, the Welcoming Party. While the first night of camp has traditionally included a party for sponsors and speakers, this year it was opened up to ALL camp attendees. One of the core values of TCDC has always been inclusiveness, and this small change just made a lot of sense.

Community Sponsors
The third big change related to sponsors. There were still a number of great organizations who stepped up to help sponsor the conference, but this year included a dedicated push to encourage more “community sponsors.” The conference was still a very affordable $50/person, but during registration, there was ask to those who used Drupal professionally to give more, if they could afford to.

And people really came through! While there had been some individual sponsors in the past, 2019 had more community sponsors than ever before. 34 people joined in, and helped keep the conference both affordable to all, and in the black.

Jun 14 2019
Jun 14

Once upon a time, the authoring experience (AX) in Drupal left much to be desired. Content editors using Drupal 6 or Drupal 7 glanced longingly across at WordPress editing screens wistfully hoping for some of that ease of use. The flexibility of Drupal from a content management standpoint was never in doubt, but we all just wished the edit screen looked so much better and behaved in a manner we were accustomed to when using other modern digital products and services. Well, finally the wait is over!

Welcome to the new Drupal authoring experience!

Let's focus on three main areas of the Drupal authoring experience which have made Drupal 8 a game-changer for digital marketing professionals.

1. Gutenberg Editor

It's nice...it is really nice! Below is a screenshot of the new Gutenberg editor experience available in Drupal 8.

Gutenberg Drupal Editor

It is intuitive and simple to use. To add text to your page, just start typing. To add a different component, such as an image or YouTube video, simply click the plus sign to add a new block then select the block type and away you go. All of the block options are displayed to the right of the editing pane, so you can focus on creating content but still have the flexibility to configure it how you wish. 

2. Layout Builder

Custom landing pages can now be created lightning fast in Drupal 8 with the new Layout Builder module in Drupal Core. It allows content creators to decide which layout they want to use and allows them to drag and drop content from one section to another. You are able to set up default layouts so, for example, all your case study pages have the same consistent look and feel but should you wish you override individual case study pages (i.e. change the CTA from appearing in the sidebar to appearing after the content) you can do that in just a few straightforward clicks. Below is a screenshot of what the layout builder looks like in Drupal.

Layout Builder in Drupal 8

You can see that it's easy to add sections and blocks to make up any design you want to fit the content you are creating. Now the power of Drupal's back end is mirrored in its flexibility in the front end.

3. Media

Adding different media types in Drupal is now taken care of thanks to the long-awaited Drupal Media Initiative. Adding images or video from your local machine, remote hosting service, or the newly built media library is all handled via one easy-to-use modal window. Below is a screenshot of what it looks like when selecting a couple of images from your media library to insert in your page.

Drupal 8 Media Initiative

Additionally, you also have the ability to contextually place media via the Gutenberg editor so if you want to just drag and drop an image from your computer to a specific place in your page's content you can do so in five seconds and then carry on creating.

In Summary

No more calls to developers or the in-house Drupal expert to do the types of content creation tasks commonplace in today's digital marketing landscape. The new author experience available in Drupal is excellent and allows your subject matter experts to create and publish what they want and when they want without roadblocks. Drupal's editing capabilities have caught up with its unrivaled technical capabilities to present a CMS which continues to deliver best-in-class ambitious digital experiences.

For a tour around what Drupal has to offer you and your organization contact one of the Drupal experts at Thinkbean.

Jun 12 2019
Jun 12

Glitzy websites are all the rage these days. Everybody seems to be looking for easy ways to create multimedia-rich pages with ease. Yet there is a big downside to the current trend of page builders -- if you're not careful, you might end up making your long term content management far harder than it should be.

WordPress 5 made its Gutenberg "Block editor" the standard for all WordPress sites going forward. Drupal 8.7 added a new "Layout Builder" in its core, adding sophisticated layout capabilities. Both of these are playing catchup to Software-as-a-Service (SaaS) offerings like Squarespace and Weebly -- and a whole bunch of 3rd party modules and plugins that have been filling the gap so far.

The goal for all of these is to make it easy to interleave text with photography, video, galleries, and animations using something approaching a drag-and-drop interface. Yet how they go about doing this varies drastically under the hood. In broad strokes, you can group all of these layout builders into one of 3 categories:

Broad categories of layout builders

  Field-Oriented Repeating Templates Embedded Layouts Module or Plugin

Drupal "Layout Builder"

Drupal Panels, Panelizer

Display Suite

Custom themes, page-type templates

Drupal "Paragraphs"

Field Collections

Entity References/Inline Entity Form

Commerce Variations

WordPress Gutenberg

Drupal Entity Embed

Vast majority of WP layout plugins

Where items are stored Individual fields are in individual database tables/columns `Multiple entities are linked together to build up a page Everything is dropped into a huge text field Best for Managing huge numbers of similar items Keeping content and presentation separate, to allow re-skinning down the road, while still making rich authoring relatively easy Very easy authoring Drawbacks Slightly less flexible -- harder to change up the sequence of rich elements Not as organized as field-based layouts, harder to extract, search, and aggregate information Very poor at reusing information on other pages, inconsistent look across the site, hard to update overall look and feel, finicky to use and get "just right", often has accessibility issues

That's the summary. Now let's take a look under the hood...

How do layout builders store their data, and why should I care?

Which is the best tool -- Excel or Word? Entirely depends on the job you're trying to do, of course. Yet these layout builders are as different as Word and Excel -- some are excellent at creating long documents with lots of variation, while others are far better at preserving data so you can show it in a chart, do math, and more. You wouldn't pick Excel to write an essay, for example, and you shouldn't pick Word to track your finances.

If you are creating a rich landing page for a campaign, a layout builder that takes the Embedded approach can get you there quickly. Lots of support for drag-and-drop, lots of ways to quickly get a result. You can build 5 more while you're at it -- but now try to compare things across 50 of these one-off pages -- now suddenly not having a template and simple fields to fill in makes the job much harder. You create pages for a bunch of products, and then you go to create a product comparison chart, and you're building that table by hand, cut-and-paste.

Or say for example you are a research institution, publishing research papers from dozens of contributors. You can make a nice landing page for each paper, with sections for the author's biography, the category, methodology, supporting organizations, and various other items -- but if you don't put each of these in its own field, it gets a lot trickier to build a nice search interface that will help your visitors find what they are looking for.

What is Content Management?

There are plenty of definitions of Content Management out there, mostly by vendors looking to sell you on a specific system, or pedantic descriptions of how big companies (Enterprises) need all this sophisticated stuff. While we are a vendor trying to sell you on something, let's take a moment to clear away all the B.S.

Website Content Management is about creating, maintaining, curating, and cultivating on your website for the entire life of the website. The problem with this focus on Layout Builders is that all the focus is on that very first step -- Creating. It ignores the rest of the lifecycle of your content.

At Freelock, we believe the longer you keep good content on your website, the more valuable it becomes. And keeping old content maintained and relatively fresh is a big part of that job. A Content Management System can help you keep your old content fresh -- keeping it looking consistent with rest of your site, bringing in new traffic, guiding people down your sales funnel to become customers, providing reputation and longevity that assure your customers you're not just another fly-by-night operation.

Embedding all of your rich content into one-off pages hampers this very process, especially when you want to change the look-and-feel of your website -- or find, re-use, or change the overall experience of your oldest content. Let's drill down into these different types of builders to see how they compare, for the longer term.

Field Oriented Layout Builders -- the Excel approach

Drupal Layout Builder Adding a custom block to a page using Layout Builder

Drupal excels at information architecture, and so the layout builder Drupal chose to include in its core supports this way of thinking about content. With the ability to easily create fields on different content types, and aggregate content using the powerful "Views" module, Drupal is all about information reusability.

There are dozens of different kinds of fields out there, and an even larger number of ways to use each one. For example, if you add a date field for an event, you can show it on a list of upcoming (or past) events automatically. You can show it on a calendar view. You can show it in a list, or a set of cards.

Add a geolocation field, and now you can show it on a map -- and you can filter that for upcoming events near me. Add a price and now you can create a "facet" that lets you see items between certain price ranges. All of this power builds on all of the other kinds of information stored in fields, and makes it easy to manage hundreds, thousands of similar items.

The new Drupal Layout Builder lets you easily create a template for showing each of these fields in a particular spot on the page, create multiple columns, drag-and-drop items around. In addition, you can create one-off blocks to highlight certain items, and reuse that on other items -- change up the layout entirely on a single item, if you wish.

Managing field layouts in the future

Down the road, if a product is no longer a special snowflake, hit a button and it reverts to the same layout as all the rest of your products -- the layout is stored in "just" another field on the item.

If you want to show a Google Map or a thumbnail linked to a file, you would have a field for the location to show and another field for the media. Then when you place the location field on the layout template, you would pick the "map" renderer to show a map for the field, and when you want to show the downloadable file, you could specify the size to generate the thumbnail and place it where you want it -- and it will look consistent across all the items in your site.

Want to change your design? Swap out the Google Map renderer for OpenStreetmaps, and all of the maps on your site use the new service immediately. Change the thumbnail size for the document, and move it to the left sidebar, and it's done across your site.

Embedded Layouts - the Word approach

Gutenberg in action Gutenberg editor in action

The new WordPress Gutenberg editor is the poster child for the opposite way of creating rich layouts. Instead of having a field for each kind of data, you start with a blank page and a collection of blocks you can drop into it.

Honestly, I like using Gutenberg -- once you figure out the basics, it's mostly fun to use. Its killer feature is management of "Reusable Blocks" -- create a chunk of boilerplate, save it as a reusable block, and then you can reuse it on any other Gutenberg page. You can keep it in your page as a "reusable block" or you can convert it to a regular block and edit it.

You can create entire templates this way.

This... this is awesome for creating proposals! Or reports, or anything you need to do once, and don't care much about how it will look in 5 years.

It's very rapid for creating pages, and if you are constantly editing some key landing pages, Gutenberg seems like a fine way to go.

However, for content that's going to stick around for years, especially through a site redesign, it's going to be a bit of a nightmare. And right from the start it stops being useful for a huge number of scenarios modern sites are trying to support.

Very little design control

One thing a CMS attempts to do is make your site look consistent. One challenge with Gutenberg and other approaches that largely dump styles as well as content into a big text area is that it makes it much easier to violate your site's design, leading to ugly, confusing, jarring sites. Having spent several years as a professional writer, seeing garish colors and inconsistent fonts and font sizes makes me shudder. I don't want to have to think about what it looks like -- I just want to write it and trust the designer to make it look good.

Useful data is embedded, hard to reuse

I see blocks for "Product Comparisons" for Gutenberg. Wow, drop these in and you get some boxes where you can enter stuff -- cool!

But... you have to enter that stuff. And it already exists, on the product pages. Wait a second -- I thought this was supposed to make my job easier? And... hey, I have a new product that just varies in two of these areas. Which page did I put that product comparison on?

Managing changes in the future

Back to the earlier scenarios, now I want to switch from Google Maps to OpenStreetmap. To make this change, I need to do a search and replace -- find every map on my site, and generate a new widget from the new map provider. Lots of manual work. Maybe I can find or create a script, but even so, it feels a little brittle -- if I chose a different map style on one page, I might not find that one. And change my document thumbnail to move it to the other side of the page and shrink the thumbnail? Geez, I have dozens of those to do now.

This is the big "mistake" of embedded layouts -- managing content down the road.

And this is not new to Gutenberg -- the vast majority of page builders for WordPress essentially work the same way, embedding "short codes" into the body, and the only way to find them is search.

This is part of why I've heard many shops say you just need to start over and redo your website from scratch every few years.

If you've kept your content separate from the design, that is entirely not true -- having to rebuild your site is entirely the result of having your design too entwined with your content.

Repeating Templates -- a Hybrid

Nested Paragraphs Nested Paragraphs

In between these two extremes, there is a third way. The best current example of this approach is the Paragraphs module for Drupal.

Compared to field-based layouts, you can easily make pages with a bunch of varied layouts, changing the layout as desired, one row at a time. If you do this very much with a field-based layout, you end up with a bunch of blocks hanging out that can clutter other parts of your CMS, and you end up constantly tweaking the design to get a result that looks good.

Compared to Embedded layouts, your content is still entirely separate from the design, making it easy to re-skin down the road. And you can still use fields that can be extracted and compared/searched/reused, although doing that effectively takes a fair amount of upfront planning.

We typically create a set of paragraph types, such as:

  • Plain text
  • Pull quote
  • Image and text (image to the left or right)
  • Photo Gallery
  • Large media (video or image)
  • Columns, cards
  • Tab set, Accordion set
  • Slide carousel
  • Embed a view

When creating your content, you can add these in any order you like. We can provide particular classes for color variations, locked down to your brand's style guide.

The design remains very tightly controlled. Data is not necessarily easily reused -- but you can have a section of Paragraphs on content that still uses fields for all of the data management scenarios you like.

Because everything is templated, a re-skin of the site can make changes to one of these templates and it instantly applies everywhere it is used.

So which layout type should I use?

Should you use Excel or Word? Well, of course, you should use both, if you need them. There are very compelling reasons to use fields -- they are essential to Content Management, and many, many ways they make your work much easier. But there are times when dashing out a quick document, or web page, is needed right now.

By making Gutenberg its default editor, WordPress has gone entirely to the right side of that table -- they are trying to focus on being a good page builder, potentially at the expense of content management. Do you need content management? Depends on how much content you have to manage! If you're only talking about having a nice brochure site, and a steady stream of blog or news posts, this is all fine. But the more sophisticated your needs, the more you're starting to go against the grain. You can add fields to WordPress, and create views of content -- but this involves either creating some code or finding plugins that will help you do this -- many of which are not free/open source (a discussion for another post).

With Drupal, on the other hand, you can choose all three. You can even have all 3 on the same website! We are already using Gutenberg in Drupal on some sites, and we're using Paragraphs almost everywhere. Meanwhile we are very impressed with the new Layout Builder, and find it just the thing for making attractive layouts for certain types of content. You can have your Word, and your Excel too!

Jun 11 2019
Jun 11

Every once in a while you have those special pages that require a little extra something. Some special functionality, just for that page. It could be custom styling for a marketing landing page, or a third party form integration using JavaScript. Whatever the use case, you need to somehow sustainably manage JavaScript or CSS for those pages.

Our client has some of these special pages. These are pages that live outside of the standard workflow and component library and require their own JS and CSS to pull them together.  Content authors want to be able to manage these bits of JavaScript and CSS on a page-by-page basis. Ideally, these pages would go through the standard development and QA workflow before code makes it out to production. Or perhaps you need to work in the opposite direction, giving the content team the ability to create in Production, but then capture and pull them back into the development pipeline in future deployments?

This is where Drupal 8’s Configuration Entities become interesting. To tackle this problem, we created a custom config entity to capture these code “snippets”. This entity gives you the ability to enter JavaScript or CSS into a text area or to paste in the URL to an externally hosted resource. It then gives you a few choices on how to handle the resulting Snippet. Is this JavaScript, or CSS? Do you want to scope the JavaScript to the Footer or the Header? Should we wrap the JavaScript in a Drupal Behavior?

Once the developer makes her selections and hits submit, the system looks at the submitted configuration and if it’s not an external resource, it writes a file to the filesystem of the Drupal site.

Now that you’ve created your library of Snippets, you can then make use of them on your content. From either your Content Type, Paragraph, or other Content Entity – simply create a new reference field. Choose “Other”, then on the next page scroll through the entity type list till you get to the configuration section and select JSnippet. Your content creators will then have access to the Snippets when creating content.

By providing our own custom Field Formatter for Entity Reference fields, we’re then able to alter how that snippet is rendered on the final page. During the rendering process, when the Snippet reference field is rendered, the custom field formatter loads the referenced configuration entity and uses its data and our dynamically generated library info to attach the relevant JavaScript or CSS library to the render array. During final rendering, this will result in the JavaScript or CSS library being added to the page, within its proper scope.

Because these snippets are configuration entities, they can be captured and exported with the site’s configuration. This allows them to be versioned and deployed through your standard deployment process. When the deployed configuration is integrated, the library is built up and any JS or CSS is written to the file system.

Want to try it out? Head on over to Drupal.org and download the JSnippet module. If you have any questions or run into any issues just let us know in the issue queue.

May 29 2019
May 29

Search Engine Optimization (SEO) might not be the first thing you think of when designing a new website, but building an optimized framework from the start will help you drive traffic to your site and keep it there.

With our Drupal SEO checklist in hand, you can build an excellent website that draws customers in as soon as you launch. To give you a quick summary before we go into detail, here’s a bullet list of what to check before the launch day.

  • Check that all web pages have unique titles using the Page Title module

  • Check if your XML Sitemap and Google News Sitemap are configured properly

  • Check if the Redirect module is enabled and configured

  • Check if the Global Redirect module is enabled and configured

  • Check that .htaccess redirects to your site

  • Check that your homepage title includes a descriptive headline, logo, and primary image

  • Check if your meta tags are filled with descriptive information

  • Check that OG tags are filled correctly and with descriptive information

  • Check if your site's information displays well when shared on social

  • Check if your path alias patterns are meaningful

  • Check if Google Analytics is enabled and configured

  • Check if Site Verification is enabled and configured

  • Check if the Search 404 module is enabled and configured

On-Site SEO 2023

Identify all the pest practices you need to implement in order to ensure that your website is optimized for search engines!

Drupal SEO: 13 Things That Will Improve Your Site's Ranking

1. Check that all web pages have unique titles

Titles are the first element that any user will see --whether they come directly to your site, find it on a search engine, or see it shared on social media. Not only do good page titles help customers who are already on your site, but they help with social sharing, and picking your site out of search engine results.

All of your pages should be easily identifiable to the end user. Not only should they have unique titles, but they should also have meaningful titles. Having multiple pages with the same titles (like “Get in touch”, “Contact us” and “Make a booking”) will simply confuse your end users and search engine crawlers.

From an SEO perspective, page titles are among the most important types of data you can fill, because they help search engines understand what each of your web pages is about.

Writing good titles is extremely important, and having keywords in your title that match a user's search greatly improves the chances of them clicking on your page. Moz suggests the following format for title tag design: Primary Keyword - Secondary Keyword | Brand Name.

You can set up unique page titles much easier if you install the Drupal Page Title module.

2. Check if XML Sitemap and Google News Sitemap are configured properly

The XML Sitemap module for Drupal creates a robot-friendly map of your site that Google and other search engines can crawl to categorize your website. You should configure XML Sitemap early in your site build for the best effect, but you can also alter the settings later on at admin/config/search/XML if needed.

You can view your sitemap from http://yoursite.com/sitemap.xml (just replace “yoursite.com” with your domain).

Google News Sitemap offers a similar but different service that creates a Google-specific map for ranking under their “News” section and appears as news items on their main SERP pages. These two modules work nicely side by side to make your site easy for search engines to crawl and index.

Source:Drupal.org
Please note that if your site contains accelerated mobile pages (AMPs), there is no need to create sitemaps for them. The rel=amphtml link is enough for Google to pick up on AMP versions, which means you can easily gain traffic from Top Stories carousels and mobile searches.

3. Check if the Redirect module is enabled and configured

Redirect is a handy module for making sure users always make it to your site. It uses case-insensitive matching to help catch broken links with redirects and tracks how often users are hitting those redirects.

You can use redirects to capture any broken links, set up promotional links, or simply grab typos users are entering when trying to access your site.

Source: webwash.net

4. Check if the Global Redirect module is enabled and configured

If you’re using Drupal 8 you can skip this one because the functionality has been rolled into the Redirect module. Otherwise, install Global Redirect to work in tandem with Redirect to catch any broken links.

Global Redirect will test all links with and without a trailing slash, ensure links are case-insensitive, and if a link is truly broken, it will return a user to your home page rather than a 404 page which decreases the position of your site in SERPs.

Source: webwash.net

5. Check that .htaccess redirects to your site

Some users attempting to visit your site will navigate to www.yoursite.com, while others will simply type yoursite.com. By setting up your site to handle either request using an .htaccess redirect, you can be sure you won’t miss any visitors.

6. Check that the homepage title includes a descriptive headline, logo, and primary image

Design a homepage title that contains a descriptive headline as well as a slogan, to represent who you are as a business. This is usually the first impression you give off to visitors the moment they land on your site or catch your entry on a search engine.

This is a good opportunity to load your website up with SEO-friendly keywords, but don’t go overboard and sacrifice your image for it - keyword stuffing may not only decrease the trust index of your site but also its conversion rates.

7. Ensure that your meta tags are filled with descriptive information

SEO-optimized meta tags remain to be one of the top on-page ranking factors. You can think of these as expanded page headers --short-form descriptions of your website that give users and search engines a clearer idea of what to expect out of a webpage.

Make sure to install the Metatag module on your site to have an easy, user-friendly interface for updating metadata. With the module installed you can easily populate metadata with keywords, page descriptions, and more.

The Metatag module will also give you extra control over how your site appears when shared on Twitter or Facebook.

8. Check that OG tags are filled correctly and with descriptive information.

OG tags are meta tags specifically designed to ensure your site communicates nicely with Facebook. By setting these tags correctly you will be able to control exactly how your site appears on Facebook, including what images and what taglines are used.

 

9. Check if your site information displays well when shared on Facebook and Twitter

After configuring the Metatag module and OG tags, pop over to Facebook and make sure that your site shares the way you would like it to. It’s important to test this out now before users start sharing your site.

Similarly, try tweeting a couple of your pages to see how well your Twitter Cards come through. If you don’t want to show your site to your audience until you are sure it’s set up correctly, you can check Twitter Cards using the Card Validator.

For more information on configuring Twitter cards, check out these user guides by Twitter.

10. Check if your path alias patterns are meaningful

By default, Drupal will set your URLs to node/123 - while this works great for the database backend, it doesn’t work well for your end users or search engines.

You can use the Pathauto module to create rules and patterns for your URLs that will significantly cut down on your maintenance times and simplify your site navigation.

11. Check if Google Analytics is enabled and configured

While having Google Analytics configured won’t improve your SEO, it will give you all the data you need to understand where your users are coming from and how they behave once they hit your site.

Installing the Google Analytics module makes setting up and configuring Google Analytics a breeze.

12. Check if Site Verification is enabled and configured

Having your site verified will make it easier for search engine crawlers to reward you with a higher rank, and for Google to allow you to access private search data. With site verification, you will receive better data and better search engine rankings in just a few minutes.

The Site Verification module makes it easy to prove to search engines that your site is truly your own.

13. Check if the Search 404 module is enabled and configured

The Search 404 module is a saving grace for reducing your bounce rate and SERP rankings, as well as for improving your overall user experience. Instead of your users finding an ‘Error: Page not Found” in place of the content they were hoping for, they will be offered a search of your site based on the URL string.

For example, if www.yoursite.com/great-SEO-tips doesn’t exist, use this module will automatically search your site for “Great SEO tips” and show visitors the results.

While SEO may seem like a tricky subject to wrap your head around, the basics are easy with the right modules and guidance, and Drupal is a great content management system for building search engine-optimized websites.


If you liked our SEO checklist, then check out the other educational materials that we at Vardot have designed to help you build a top-quality website. If you’re looking for even more ways to improve your site’s SEO, have a look at SEO articles on our blog --or better yet, get in touch with our team!

May 24 2019
May 24

Time is always of the essence. From a consumer perspective, you want to know when events take place, when something’s open or closed, how long a meeting or activity will last. And, from a development perspective, you want to be able to create a date field that’s intuitive for the users, but doesn’t involve a lot of custom work.

There’s a default functionality in Drupal 8 that, while functional, is cumbersome. So I recently developed a module called Smart Date that will make things a lot easier for site developers -- and provide that functionality that editors want.

I initially identified the need back when I was working on a client site that required me to enter some sample content. We’ve all used calendar software -- whether it’s a Google or Outlook calendar, or even what you have on your phone.

In this instance, with Drupal, I needed to enter the year, month, and date. I also had to enter a start hour, start minute, and define whether it was AM or PM. And then do it all over again for the end time, meaning 12 fields to fill out for each instance. As a user, we have an expectation and assumption that entries would autopopulate end times -- but you know what they say about assumptions.

I wanted Drupal to have that same ease of use. To achieve that, I made a date widget that adds a concept of duration. Like your calendar application, it can assume a default duration, so as soon as you enter the start, it can populate the end for you.

As a site builder you can choose this default duration, so if you want it to be one hour (like Google and Apple’s calendars) if can do that out of the box. If you’re building a recruiting site that should default to 15-minute intervals, that’s up to you.

You can even restrict what intervals are available. In the default setup, editor has the convenience of choosing from a default duration or making a custom range if they need something that isn’t listed. But suppose you’re organizing a conference where the sessions will all be 45 or 90 minutes in length. As a site builder, Smart Date allows you to enforce these constraints.

Another request we’ve had from clients is the ability to designate events as “all day”. Again, something we’ve all become used to in our calendar applications. And a perfectly valid use case in how we need to register events on the sites we build. But up until now, we’ve had to custom build a solution as a customization, again and again. Smart Date gives your editors this ease-of-use with the click of a button – again unless the needs of your solution dictate that as a site builder, you need to take that option away (which you can).

Another request we get again and again – and have had to build custom – is to make the display of time and date ranges more intelligent. For example, if you were formatting a date range by hand, if the start and the end were on the same date, you wouldn’t write the date on both, you’d only write it once. Smart Date has this kind of intelligence built in. It’s a little more complex to set up, but hopefully, the presets will work for a wide range of use cases, and in time we’d like to see translations available on localize.drupal.org so a wide variety of cultures can get their preferred date and time formats available on install.

One last major aspect of Smart Date is performance. At Digital Echidna, we know that the speed of a site is a critical component of the overall experience, not to mention SEO. We test our sites at various points during development to ensure they’ll meet the appetite by web visitors for a site that not only looks great and is easy to use, but loads quickly so they get done what they need, and go back to surfing for funny cat videos.

In a recent mid-development site performance audit, I realized that the slowest page identified was an events archive, even though it held almost no content. When I looked at the query Drupal had constructed based on the view configuration, I realized the core date fields were storing values as strings, and at query, every row had to convert multiple values into date formats in order to make the required comparisons. I’ve since spoken to a number of other developers within the Drupal community, who have had to build workarounds so that date and time stored in Drupal can be accessed in a way that meets web visitors’ ever-increasing expectations for fast page loads.

MySQL has its own DATETIME field especially to provide fast queries for storing and accessing this type of data, but the Drupal core team chose not to use it but a solution that depends on this wouldn’t be portable to other database engines, which is understandable. For Smart Date, I chose to store the values as timestamps, which have some limitations in their ability to store values in the far future or distant past, but more than meet the need for what we see as a typical use case, storing coming or recent events.

The beauty of this approach is that we could use functionality built into Drupal 8 for date and time functionality (handling of date and time widgets, with validation, etc) and its built-in capabilities for storing and retrieving timestamps (which are still used for node creation and revision dates, for example) and only write the code that is necessary to translate between the two.

It’s a testament to the object-oriented infrastructure of Drupal 8 that we could build this solution using different parts of what’s already in Drupal 8 core, and focus our efforts on adding code where it really adds value.

The module has already started to get feature requests, so I expect we’ll see its capabilities continue to grow, as other developers submit patches to “scratch their own itch”. That pooling of community effort is another key strength for Drupal, as we can all benefit from the work we do individually to make things better.

We hope that Smart Date will make Drupal sites better solutions: for site builders, for the editors that use them, and for the visitors who come to consume the content. All by making it easy for Drupal to work like the calendar application we’ve all become accustomed to using, from technology giants like Google, Apple, and Microsoft.

At Digital Echidna, we’re committed to improving that experience across the board with our products, so that when someone who is not as familiar with Drupal is entering content, it’s going to be a positive, intuitive, and enjoyable experience. When we discover a new, better, or more intuitive way to do things, we add that to our baseline development toolbox to ensure that all of our customers can benefit from that improved experience.

We often take for granted how much back-end work goes into creating what appears to be a simple bit of online functionality. But these things take time -- and with Smart Date, I’m hoping that this module will provide a better experience that lets people spend less time developing and frees up more time to focus on creating innovative, customer-focused solutions.

May 14 2019
May 14

Published: May 14, 2019

I was playing around with the SpeechRecognition API last night and thought, "wouldn't it be cool if we could use voice to administer a website?". Then, I put together this tiny proof of concept module for use with Drupal.

Speak Speak

Here's a short video of it in action.

Ok, that looks pretty cool. Show me the code.

window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; 
const recognition = new SpeechRecognition(); 

recognition.interimResults = true; 
recognition.addEventListener('result', e => { 
  transcript = Array.from(e.results).map(result => result[0]).map(result => result.transcript).join(''); 
  const statement = e.results[0][0].transcript; 
  console.log(statement); 
  if (statement === "voice admin new page") { 
    window.location.href = "/node/add/page"; 
  } else if (statement === "voice admin new article") { 
      window.location.href = "/node/add/article"; 
    } else if (statement === "voice admin log out") { 
      window.location.href = "/user/logout"; 
    } else if (statement === "voice admin go home") { 
      window.location.href = "/en"; 
    } 
  }); 

// When we stop talking, start the process again, so it'll record when we start 
// talking again. recognition.addEventListener('end', recognition.start); recognition.start(); 

WTF? That code is crap. You have hard-coded what you want the site do to. That's not going to work for all sites, only for your specific use case.

Yep, that's true at the moment. Like I say, it's just a proof-of-concept. We'd need to create a settings page for users to decide if they want it to be available or not. And we'd have to create a better parsing system that listens for "voice admin" and then starts recording. Then we'd need to make sure that it patches together the fragments of speech after this to construct the action that you want to perform. Following that, it would be really cool if on the settings page users could type in commands and responses that SpeechRecognition will listen for and then perform.

I think all this is very possible, and probably not too much work. It would be great to see more progress on this.

If you'd like to create a pull request, the code is available on GitHub.

Share (please)

Filed Under:

  1. Drupal Planet
  2. Drupal
  3. Accessibility
  4. Frontend Development
May 13 2019
May 13

Considering all the complications and expense with upgrading to Drupal 8, a natural reaction might be to not bother at all. Why not move your site to WordPress, for example? There are, however, more than a few important reasons to consider staying with Drupal.

Drupal 8 is so much better

We’ve talked about how the rearchitected Drupal 8 made version upgrades difficult. But you can’t do that without also talking about much was gained in Drupal 8.

  • More in Core – Views, Media, WYSIWYG, Layout Builder and more
  • Improved Editorial Experience – CKEditor, drag and drop, inline editing
  • Improved Media Management – including new Media library tools
  • Accessibility improvements
  • HTML 5
  • Mobile first and responsive
  • Data integrations – API-first platform with RESTful services and JSON:API in core
  • Configuration Management – easier and faster for developers
  • Improved multilingual support for over 100 languages
  • Security and performance improvements

Future updates are so much easier

Even though the Drupal 7 to 8 process can be long and cumbersome, the future is bright! Drupal 8 was designed for ease of version upgrades. It relies on a new release cycle and semantic versioning for more predictable update schedule. Minor releases come out every 6 months (e.g. 8.6 to 8.7) allowing every site owner to keep their site up to date.

Even better, each minor release contains new and sought-after features, meaning you don't have to wait years between release cycles. Patches and bug fixes get released as needed, until the next stable release of Drupal comes out. Updating to Drupal 9.0 won’t be any different than updating from 8.6 to 8.7!

Even now, every Drupal 8 module is being tested for compatibility with Drupal 9, and the great news is that many of them are already there. As long as you’re keeping your Drupal 8 site up to date, the next full version upgrade should be a piece of cake.

Drupal is ready for the future

Thanks to Drupal’s API first initiative, Drupal 8 (and beyond) is positioned as a powerful platform that makes it easy to integrate with other systems. This includes the increasingly common need for tight integration with existing applications and tools, plus the ability to use and display your content any where you like.

Drupal can now be easily used to power mobile applications, digital signage, voice controlled skills, the Internet of Things (IoT) or as an API that other applications can communicate with directly. The world is quickly moving in this direction, and Drupal 8 is ready for it now.

Familiar with the software

In addition to gaining all the features mentioned prior, it’s worth putting in a plug for the advantage of familiarity. As much as things have changed, there is still a core experience that you will find the same. Content types still power how your content gets entered, Views still drive your database queries, Users can still be managed through powerful Roles and Permissions. Blocks are still a key element of building out your pages.

If you’ve built up years of experience and know-how working with Drupal 7, why throw that all away? Get to know the new features which will improve your site experience, while taking advantage of all that historical knowledge.

And most importantly, the community that makes Drupal so great is still here. That means all the help and knowledge sharing you found on Drupal.org, the online tutorials and articles throughout the web, the agencies and developers who worked with you before, and conferences and meet-ups dedicated to Drupal–we’re all here to help you move to Drupal 8!

May 07 2019
May 07

If your organisation uses CiviCRM with Drupal, and would like to do in the future, we need your help!

 

Over the past few years lots of amazing work has been done on the unofficial Drupal 8 CiviCRM release.
The CiviCRM core team have looked at this and are now in a position to complete the work to make this an official CiviCRM release. This means they will make changes so

  • CiviCRM can easily be installed with Drupal 8
  • They will ensure CiviCRM works with Views in Drupal 8
  • Going forward future CiviCRM releases will be tested with Drupal 8

 

What about Drupal 9? Isn't that being released soon?

Both Drupal 7 and 8 are officially supported until November 2021. But the move from Drupal 8 to Drupal 9 will not be the same as previous Drupal major updates. It will be much easier to migrate existing sites between Drupal 8 to 9. For more information see https://dri.es/drupal-7-8-and-9.

The CiviCRM core team has looked at this and the code changes required to ensure CiviCRM works with Drupal 9 should be minimal.

So very importantly this Make It Happen work is also preparation for Drupal 9.

 

If your organisation uses CiviCRM with Drupal then please contribute to this Make It Happen.

Filed under

Apr 30 2019
Apr 30

In 2018, the state of California passed the California Consumer Privacy Act, or CCPA, as a consumer-rights focused bill to protect user privacy. Similar to the GDPR, the new law would require businesses to be upfront about what data they are collecting, who they are sharing it with, and allow consumers to request their data be deleted.

This changes the equation significantly for US-based organizations. You may be fairly certain your site’s visitors are US-based, but what about the state they live in? What if they are from California? Similar to other laws originating in California, the mere presence of a law like this begins to affect how all the states treat issues of privacy.

As recent as April 2019, lawmakers were pushing several news bills to reign in some of those protections, on behalf of employers and businesses who found the new law too broad. The tech industry is somewhat discouragingly behind a lot of the lobbying as well. The original law was set to take effect by 2020, but some of the details are still being debated.

It seems certain, however, that some form of the law will be implemented soon. And much like the EU and GDPR, the first step as site owners will be more transparency on data collection, and making it easy for users to opt-out, or request their personal information be deleted. Listing your privacy policy is also a requirement.

The CCPA doesn’t appear to apply to everyone, however. It is targeted towards businesses with annual gross revenues over $25 million, and/or companies whose annual revenue primarily comes from selling users personal information. And unlike the GDPR, it is more of an “opt-out” law than “opt-in.” Websites don’t have to ask before applying a cookie, and businesses don’t have to ask before selling personal information. They do, however, need to offer an easy method to opt-out.

Apr 19 2019
Apr 19

What we learned from our fellow Drupalists

Lisa MirabileMassachusetts Digital ServicePublished in

5 min read

Apr 19, 2019

On April 7th, our team packed up our bags and headed off to Seattle for one of the bigger can’t miss learning events of the year, DrupalCon.

“Whether you’re C-level, a developer, a content strategist, or a marketer — there’s something for you at DrupalCon.” -https://events.drupal.org/

As you may have read in one of our more recent posts, we had a lot of sessions that we couldn’t wait to attend! We were very excited to find new ideas that we could bring back to improve our services for constituents or the agencies we work with to make digital interactions with government fast, easy, and wicked awesome. DrupalCon surpassed our already high expectations.

At the Government Summit, we were excited to speak with other state employees who are interested in sharing knowledge, including collaborating on open-source projects. We wanted to see how other states are working on problems we’ve tried to solve and to learn from their solutions to improve constituents’ digital interactions with government.

One of the best outcomes of the Government Summit was an amazing “birds of a feather” (BOF) talk later in the week. North Carolina’s Digital Services Director Billy Hylton led the charge for digital teams across state governments to choose a concrete next step toward collaboration. At the BOF, more than a dozen Massachusetts, North Carolina, Georgia, Texas, and Arizona digital team members discussed, debated, and chose a content type (“event”) to explore. Even better, we left with a meeting date to discuss specific next steps on what collaborating together could do for our constituents.

The learning experience did not stop at the GovSummit. Together, our team members attended dozens of sessions. For example, I attended a session called “Stanford and FFW — Defaulting to Open” since we are starting to explore what open-sourcing will look like for Mass.gov. The Stanford team’s main takeaway was the tremendous value they’ve found in building with and contributing to Drupal. Quirky fact: their team discovered during user testing among high-school students that “FAQ” is completely mysterious to younger people: they expect the much more straightforward “Questions” or “Help.”

Another session I really enjoyed was called “Pattern Lab: The Definitive How-to.” It was exciting to hear that Pattern Lab, a tool for creating design systems, has officially merged its two separate cores into a single one that supports all existing rendering engines. This means simplifying the technical foundation to allow more focus on extending Pattern Lab in new and useful ways (and less just keeping it up and running). We used Pattern Lab to build Mayflower, the design system created for the Commonwealth of Massachusetts and implemented first on Mass.gov. We are now looking at the best ways to offer the benefits of Mayflower — user-centeredness, accessibility, and consistent look and feel — to more Commonwealth digital properties. Some team members had a chance to talk later to Evan Lovely, the speaker and one of the maintainers of Pattern Lab, and were excited by the possibility of further collaboration to implement Mayflower in more places.

There were a variety of other informative topics. Here are some that my peers and I enjoyed, just to name a few:

Our exhibit hall booth at DrupalCon 2019Talking to fellow Drupalists at our booth

On Thursday we started bright and early to unfurl our Massachusetts Digital Service banner and prepare to greet fellow Drupalists at our booth! We couldn’t have done it without our designer, who put all of our signs together for our first time exhibiting at DrupalCon (Thanks Eva!)

It was remarkable to be able to talk with so many bright minds in one day. Our one-on-one conversations took us on several deep dives into the work other organizations are doing to improve their digital assets. Meeting so many brilliant Drupalists made us all the more excited to share some opportunities we currently have to work with them, such as the ITS74 contract to work with us as a vendor, or our job opening for a technical architect.

We left our table briefly to attend Mass.gov: A Guide to Data-Informed Content Optimization, where team members Julia Gutierrez and Nathan James shared how government agencies in Massachusetts are now making data-driven content decisions. Watch their presentation to learn:

  1. How we define wicked awesome content
  2. How we translate indicators into actionable metrics
  3. The technology stack we use to empower content authors

To cap it off, Mass.gov, with partners Last Call Media and Mediacurrent, won Best Theme for our custom admin theme at the first-ever Global Splash awards (established to “recognize the best Drupal projects on the web”)! An admin theme is the look and feel that users see when they log in. The success of Mass.gov rests in the hands of all of its 600+ authors and editors. We’ve known from the start of the project that making it easy and efficient to add or edit content in Mass.gov was key to the ultimate goal: a site that serves constituents as well as possible. To accomplish this, we decided to create a custom admin theme, launched in May 2018.

A before-and-after view of our admin theme

Our goal was not just a nicer looker and feel (though it is that!), but a more usable experience. For example, we wanted authors to see help text before filling out a field, so we brought it up above the input box. And we wanted to help them keep their place when navigating complicated page types with multiple levels of nested information, so we added vertical lines to tie together items at each level.

Last Call Media founder Kelly Albrecht crosses the stage to accept the Splash award for Best Theme on behalf of the Mass.gov Team.All the Splash award winners!

It was a truly enriching experience to attend DrupalCon and learn from the work of other great minds. Our team has already started brainstorming how we can improve our products and services for our partner agencies and constituents. Come back to our blog weekly to check out updates on how we are putting our DrupalCon lessons to use for the Commonwealth of Massachusetts!

Interested in a career in civic tech? Find job openings at Digital Service.
Follow us on Twitter | Collaborate with us on GitHub | Visit our site

Apr 16 2019
Apr 16

Last week Drupalcon North America was held in Seattle, where Dries opened the conference with the traditional "Driesnote". In the presentation, Dries talked about automated updates for Drupal, a thing I am very passionate about myself. He then went on to say:

I hope that in Drupalcon Amsterdam...in six months… I will be able to stand on stage and actually give some sort of demo. That would be my goal. So obviously… I would need your help with that… but that would be fantastic.

This triggered a thought: with the tools we have today, and as composer support is fairly decent, we can actually demo this somewhat utopic goal now. Which is why I made a video of just that. So without further ado: here is the demo!

[embedded content]

Automatic updates and the future

This demo demonstrates tools that are available now. Instead of only focusing on those tools (and promoting violinist.io), I want to expand on the subject of automated updates in Drupal, and its future.

Like for Dries, automatic updates is an important issue to me. Not only because I promote running automated composer updates with violinist.io, but because having these features will make Drupal more viable for hobbyists and beginners. Which in turn is something that can help us reach more users, and increase our diversity. Consequently, having automated updates is important for the “non-professional” group of Drupal users.

In the presentation, Dries also points out some important positive effects of having automated updates. First, it will help securing your site (or your client's site) when time-critical security updates are released. Second, it will make it easier for organizations and agencies to maintain websites. This means that having automated updates is important for the “professional” group of Drupal users as well.

This brings us to the next segment, which mostly applies to agencies and organizations using Drupal professionally. Two issues are often raised about having automated updates. First, that moving and/or overwriting the files of your codebase is a security risk. Second, that updating files on your live server can be a no-go. Maybe you have a version control system in place. Or perhaps you have a continuous integration/deployment pipeline. Or, you have setups that deploy their codebase to multiple front-servers. The two issues are valid concerns, but usually they are less of a concern to "non-professional" users. This implies that having automated updates is important for the “professional” AND “non-professional”, but the preferred implementation for these two groups might conflict.

In my personal opinion, we can support both. Let me explain how.

My suggestion is that we can have a system in place that is pluggable in all parts. This means that the "non-professional" can use plugins that are useful for updating via the file system, and hopefully set-and-forget the automatic updates for their site. It also means that the "professional", the one with the pipeline and version control, could have entirely different plugins for updates. To get back to the video above, a pre-flight check (which is how we determine if we can update) can mean checking for pull requests for the available update, and checking that the tests pass. The plugin for updating could simply merge the pull request, since automated deploys are run for the master branch. Now, different teams have different requirements, but this means that you could use a Pantheon or Platform.sh plugin for automated updates. Or, maybe you have a custom plugin for your team that you use across projects.

I believe this feature can help automation for "professional" teams of all sizes, and make the very same system usable for "non-professionals" that want to set-and-forget. This is also why I believe having automated updates in core, is in no way in conflict with doing automated updates like in the video above. It will only complement the toolbox we currently have!

If you want to read more about the Automatic Updates initiative, there is more info here. It is an exciting future, and we can all help out in making the future more user-friendly and secure. I know I will!

Apr 12 2019
Apr 12

For us, the Paragraphs module is the holy grail of structured content creation.

With Paragraphs it is relatively uncomplicated to define prefabricated content elements that define the structure of the corresponding content. These can then simply be placed in the desired content by editors.

This allows editors to create clearly structured content without a lot of effort and to fall back on recurring content structures. The editors simply select the desired element from the list of available content elements, fill in the corresponding fields and the content is output in the specified structure. This is extremely helpful when creating more complicated page layouts where you want to use the same structures over and over again.

Is there a better way?

We have asked ourselves and our clients' editors how to further simplify and improve the input using Paragraphs, or what might interfere with the editorial process when using Paragraphs.

It has often been mentioned here that it is quite annoying to have to drag the content elements to the desired position after adding them. This is especially cumbersome for content with many content elements. It would be much better to be able to insert the element right at the corresponding position.

Fortunately, there is the Paragraphs Features module from the Thunder Core team. This module extends Paragraphs by inserting a button between each content element to open the modal dialog for adding more elements. 

Using these buttons, editors can insert the elements in the correct position as desired and do not have to move them first.

 

Beautiful. But is there an even better way?

Editors always add the same elements to certain content. The question arose whether these content elements could not be inserted preferentially, i.e. without first having to open the dialog.

In addition, some editors were disturbed by the large number of buttons: after each single content element a button for adding further elements appears. *sigh*

So we thought about how to make the buttons less annoying. 

Buttons you don't see don't interfere. Accordingly, with our new module Paragraphs Editor Enhancements, we have simply hidden the buttons. 

With some applications and tools (e.g. Apple Mail or Slack) the buttons for certain actions only become visible when you point the mouse over a certain area. Exactly this function has also been implemented for the buttons: only when you point the mouse over an existing content element, the buttons for adding become visible above and below the element.

In addition, the most important content elements should also be able to be inserted directly with a click. 

So we had to add two new buttons for the most important content elements to the button to open the dialog.

Editors are no longer disturbed by the large number of buttons and can simultaneously insert the most important content elements with just one click.

Great! But can you make it even much better?

Another often mentioned improvement suggestion concerned the dialog for adding content elements themselves.

If you have many elements to choose from, the dialog quickly becomes confusing. In addition, editors often find it difficult to find the right elements. On the basis of the title of a content element one cannot always immediately conclude on the actual purpose of the element and cannot imagine how the element is represented in the content.

With Paragraphs Editor Enhancements we have completely redesigned the dialog. We've added the ability to filter the list of content elements so editors can quickly find the desired elements through the title and description of the element.

In addition, the representation of the elements in the dialog has been revised. Each element shows the title and the description as well as an image (if uploaded in the element's configuration).
As an alternative to displaying the elements as tiles, you can also display the elements as a list.

As a bonus, you can create categories for content elements and assign the individual elements to one or more categories. 

This gives editors a faster and better overview of the available content elements and allows them to find the desired element more quickly and easily.

Whew. Do you have any more?

We wouldn't be undpaul if that was all.

Some time ago, one of our clients was faced with the problem of having to add the same elements in the same order over and over again. 

As a simple example, one can imagine this as follows: an introductory text followed by an image, then a two-column text and finally a text with an image.

For the editors, this meant that the corresponding content elements had to be inserted in the correct order for each individual content item. 

Wouldn't it be great if you could add the desired elements with just one click, so that the editorial staff could concentrate on entering the actual content?

The solution to this problem was the Paragraphs Sets module.

Paragraphs Sets are used to define groups of content elements. These groups can be added to the content just like the usual elements.

This saves editorial members the hassle of searching out and inserting individual elements and allows them to start entering the corresponding content directly.

Of course, Paragraphs Editor Enhancements and Paragraphs Sets also work together. The element groups of Paragraphs Sets are displayed in a separate category in the dialog and can also be found using the filter function. 

Pages

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web