Upgrade Your Drupal Skills

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

See Advanced Courses NAH, I know Enough
May 03 2021
May 03

By Hansa Pandit

CSS frameworks are very popular these days. They give us a head start without having to write a lot of CSS. There is this new shiny thing that's gaining a lot of attention these days, TailwindCSS. Recently, I got a chance to try my hands on it and I am going to share a high-level overview about TailwindCSS that may help you to get started with it quickly.

What is TailwindCSS?

TailwindCSS is a utility-first CSS framework, which provides you with low-level utility classes to build your custom websites.

I will try to explain how to get into using TailwindCSS based on my personal experience. If you want to use TailwindCSS on your next project, this will be a quick guide for you, which I wish I had when I started working with TailwindCSS, it could have saved me a lot of internet-digging time.

Why use TailwindCSS and not the good old framework, which you are already familiar with?

Every website is unique and it should have its unique styles.

What I like the most about the TailwindCSS, is that it does not give me multiple CSS properties under one class name , so I can use its classes without having to override the other stuff, which most of the other frameworks fail to do, they give you pre-styled components that force you to override the styles.

TailwindCSS comes with a lot of low-level utility classes that you just have to add into your HTML element, to style your website. By low-level, I mean that TailwindCSS goes to the very basics and provides the classes that will not affect any other CSS property.

For instance, TailwindCSS has a class called “container”, the basic use of this class should only be to control the width of the block on various breakpoints, regardless of any other property. and YES, that's exactly what this class does in the TailwindCSS. So that way you do not have to override anything.

Let's see how the most basic example of HTML and CSS with the TailwindCSS classes will look like.

<form class="w-full">

  <fieldset class="p-8 w-full mx-auto">



<button class="bg-black inline-block p-8 font-semibold text-white uppercase">


Below is how the above CSS will be rendered in DOM

.uppercase {
  text-transform: uppercase ;

.text-white {
  color: #fff ;

.p-8 {
  padding: 2rem ;

.font-semibold {
  font-weight: 600 ;

.inline-block {
  display: inline block ;

.bg-black {
  background-color: #000 ;

.w-full {
    width: 100% ;

.mx-auto {
  margin-left: auto ;
  margin-right: auto ;

The class names that you see in the above examples are the utility classes that come with the TailwindCSS, all you have to do is add the classes inside your HTML element and you are DONE! 

This could look very tempting and appealing at first but then you start to realize there could be some problems with this approach, few of them are:

  • The DOM looks very crowded, this is the first thing that bothered me when I started with the TailwindCSS.
  • This lacks the semantic approach.
  • For every similar element, you have to add the same bunch of classes, which is not something you would really want to do.

Apart from the above, I personally would not like the user to have a look at all the styling in the DOM itself. 

But as I mentioned, that was the most basic example and we do have tricks to fix the above problems.

Inherit the TailwindCSS way!

TailwindCSS provides us with a very cool feature to inherit its own classes using the @apply directive.

@apply is the magic word here, you can create any class name of your own choice, and within that class name, you can inherit the TailwindCSS classes. I will show you, how you can achieve that.

Below is an HTML element with the class names of my own choice.

<button class="button button--primary">

And this is how your CSS will look for the above HTML.

.button {

  @apply inline-block p-8 font-semibold uppercase ; // These are the classes that come with the TailwindCSS.


.button--primary {

   @apply bg-black text-white ;


This is how the above CSS will render

.button {

    display: inline block ;

    padding: 2rem ;

    font-weight: 600 ;

    text-transform: uppercase ;


.button--primary {

    background-color: # 000 ;

    color: #fff ;


So you see, now all the button elements will have the same CSS properties, without making the DOM look too busy.

Looks better, right?

Likewise, if you want all your section titles to be the same, you can simply inherit the TailwindCSS classes, like below

.section-title {

   @apply text-title font-semibold uppercase font-semibold text-2xl text-brand-black mb-5 leading-tight ;


In the above code examples, I have used a naming convention that makes much more sense and still it inherits all the CSS classes that come with the TailwindCSS. So practically, I did not have to add any new CSS property or override any existing CSS. Also, if you take a closer look, you'll find that TailwindCSS has a class for almost everything.

That's very cool, right?

So now, there is one very obvious question, what if you do not want the values ​​or colors that come with the TailwindCSS. Will you have to override the CSS? Or will you have to write your own CSS?

Answers to these questions take me to the part which happens to be one of my favorites about the TailwindCSS.

One file to rule them all - tailwind.config.js

This is the file where you can customize your entire theme, be it the theme colors or the font-family or the breakpoints, or anything that you want. 

Sounds interesting, right?

For instance, what if you do not want the width or the max-width values ​​to be in rem unit (that comes with TailwindCSS), rather you want them to be in percentage.

Any thoughts?

All you have to do is go to your tailwind.config.js file and just customize it. 


Let's take a ride.

// File tailwind.config.js

module.exports = {

 theme: {

   extend: {

     colors: {

       'brand-black': '# 1b1b1b',

       'light-gray': '# e4e4e8',

       'gray': '# A6A6A6',

       'text-gray': '# CCC',

       'navy': '# 060B2B',

       'theme-blue': '# 4553ad'


     maxWidth: {

       '1/4': '25% ',

       '2/5': '40% ',

       '1/2': '50% ',

       '3/4': '75% ',

       '4/5': '80% ',

       '9/10': '90% ',


     fontFamily: {

       'display': 'roc-grotesque, sans-serif',


     fontSize: {

       'title': '1.75rem',

       '4.5xl': '2.5rem',

       '5.7xl': '3.75rem',


     boxShadow: {

       'form': '0px 1px 7px rgba (23, 25, 40, 0.13549)',

       'dropdown': '0px 4px 5px # 1b1b1b'


     screens: {

       'mobile': {'max': '767px'},

       'tablet': {'min': '768px'},

       'desktopScreens': {'min': '1024px'},

       'wide': {'min': '1280px'},

       'belowRetina': {'max': '1920px'},

       'retina': {'min': '1921px'},





In the above code, I have customized my theme colors, max-width property, font-family, font-sizes, box-shadow, and breakpoints.

Now, let's take a look at how these values ​​can be used in CSS.

.banner-title {

  @apply max-w-9/10 ; // This will apply max-width: 90% as we defined in tailwind.config.js


In the above CSS, max-w is the TailwindCSS class for max-width and 9/10 is my customized value for 90%.

In the DOM, it will render as:

.banner-title {

    max-width: 90% ;


Similarly, let's see one more example, this time for color.

.button - primary {

    @apply bg-brand-black text-white ; // brand-black is the color that I customized in my tailwind.config.js


and the next code example is how it will be rendered

.button - primary {

    background: # 1b1b1b ;

    color: #fff ;


This color that you defined in tailwind.config.js can be used with any property where you can apply colors. So if you want the text color to be brand-black then you will simply write:

.button - primary   {

   @apply bg-light-gray text-brand-black;   // light-gray is another color that we defined. 


Which, in the DOM, will render as

.button - primary { 

   background: # e4e4e8 ; 

   color: # 1b1b1b ; 


That was quick and easy, right?

I really enjoyed using TailwindCSS, it's simple, light, highly customizable, and so easy. I hope this post could give you all that you needed to know for building your project using the TailwindCSS.

For installation and checking out the more utility classes, you can follow the official documentation.

Good luck! :)

Written by Hansa PanditHansa Pandit
Frontend Engineer at Ramsalt Lab

Aug 20 2020
Aug 20

In our 4 part series on "Faster Drupal", we have so far published three different articles on: 

  1. Faster Drupal: Part 1: Caching
  2. Faster Drupal: Part 2: Aggregation, CDN and Image Optimization
  3. Faster Drupal: Part 3: Theming

If you haven't already read those parts, go ahead and check them out! Now let's get to our beloved CSS/JS stuff!

Faster Drupal - Part 4: CSS/JS Tips

We’ve come to find this amazing blog post by Charlie Gerard, The first three items are from her blog post, I added the TL;DR version that we need for this guide but it's worth checking:

CSS: Avoid modifying layout wherever possible: Changes to some CSS properties will require the whole layout to be updated. For example, properties like width, height, top, left (also referred to as “geometric properties”), require the layout to be calculated and the render tree to be updated.

CSS: The descendant selector can be expensive: in an example like this: #nav a The browser is going to assess all the links on the page before settling to the ones actually inside our #nav section. A more performant way to do this would be to add a specific selector of .navigation-link on each  inside our #nav element. CSS: Browser reads selectors from right to left, so less selector the better

  • CSS: Some CSS properties are more expensive than others. What this means is that they take longer to paint.
    Some of these expensive properties include:
    1. border-radius
    2. box-shadow
    3. filter
    4. :nth-child
    5. position: fixed
  • Check to see if you are overriding your CSS selectors, there are IDE tools for that
  • Avoid duplicated CSS selectors, in large scale websites I’m pretty sure you can find a lot of them
  • Avoid !important declaration
  • Avoid DOM manipulation in javascript. If you really have toi do that (and often we do) keep the DOM updates to the bare minimum
  • The Drupal core will call attached behaviors when the DOM (the object representation of the HTML) is fully loaded and on each AJAX response altering the DOM.
  • Conditionally load assets where necessary! You have some JS or CSS only being used for certain nodes/content-types/pages? Load those files for those necessary pages only
  • Consider component-based themes that handle assets per component such as bootstrap_storybook
  • Use one of the methods below to defer parsing for external JavaScript files:
    1. Use the async attribute
    2. Use the defer attribute
  • Append the script to the DOM in JavaScript during the onload event
  • Make sure your scripts are placed at the bottom of the page (ideally at the end of the body) unless you really need it to be in the head..
  • Be sure to deliver the lightest possible font format. And also note the order of fonts loading is important as well. The preferred order of web font formats are as follows:
    1. EOT
    2. WOFF2
    3. WOFF
    4. TTF
    5. SVG
  • Try vanilla JS instead of jQuery: I mean we all love jQuery and it has saved us a lot of time and headache in the past, however nowadays you might not need jQuery for most of day-to-day operations.
    That said.. Sometimes you gotta do what you gotta do, but even then: do yourself a favour and use the latest jQuery available, not the default which comes with Drupal core to get the most updated library.
    • In Drupal 8 you can go one step further: Since D8 jQuery is not automatically loaded in the frontend so you can remove the jquery dependency from your theme's libraries and just use Vanilla JS!
  • Consider making a CSS/Image sprite out of your icons, especially if your users are still heavily using HTTP1.1.
    On the other hand if most of your traffic si via HTTP2 the number of your requests to the server are not really an issue (but don't go crazy)!

Are we done with this list? Never! We would like to continuously improve it.

We would also love to have your comments and suggestions!

Written by Sohail LajevardiSohail Lajevardi
Developer at Ramsalt Lab

Jul 22 2020
Jul 22

This post will save you some headaches when upgrading Drupal core from 8.7 to 8.9 addressing some common challenges.


Drupal 9.0.0 has been released simultaneously with Drupal 8.9.0. Drupal 8.9 is a long-term support version that will be supported until November 2021. Versions of Drupal 8 prior to 8.8.x are end-of-life and do not receive security coverage. Upgrading an existing site that’s not yet running on the latest core 8.8 or 8.9 can be challenging due to some new changes in Drupal core.



If your site version is below 8.7 make sure you upgrade to 8.7 first because the process would be a lot smoother if you are on Drupal 8.7


Upgrading from Drupal 8.7 or 8.8 to 8.9

  1. Make sure you have Pathauto 1.6 or greater. You can run: composer require drupal/pathauto:^1.6

  2. Remove/replace old dev packages composer remove --dev webflo/drupal-core-require-dev The webflo/drupal-core-require-dev provides the require-dev dependencies of drupal/core as a standalone package.

  3. Remove the deprecated drupal-scaffold composer remove drupal-composer/drupal-scaffold Drupal-composer scaffold provides a composer plugin for placing scaffold files (like index.php, update.php, …) from the drupal/core project into their desired location inside the web root. The purpose of scaffolding files is to allow Drupal sites to be fully managed by Composer, and still allow individual asset files to be placed in arbitrary locations.

  4. Remove Drupal core strict composer remove webflo/drupal-core-strict Drupal-core-strict is a virtual package, that causes you to get exactly the versions of Drupal core's dependencies as they are specified in Drupal core's composer.lock file

  5. Add drupal/core-dev composer require --dev drupal/core-dev:^8.8

  6. Prepare your composer.json for the new scaffold plugin. Make sure you have the following block in the extra section of your composer.json.

"drupal-scaffold": {

"locations": {

"web-root": "web/"



7. Run composer require drupal/core-recommended:^8.8 drupal/core:^8.8 drupal/core-composer-scaffold:^8.8 --update-with-dependencies

"drupal/core:^8.8" is added because the composer may not be able to resolve the dependency tree. The drupal/core-recommended is the new recommended project template for Drupal 8 projects. Once the above command is successful, you can run composer remove drupal/core to remove the package.

8. drush updatedb -y

9. drush cex -y


Update settings.php

Check settings.php files for the $config_directories variable and replace it with $settings['config_sync_directory'] = '../config/sites/default';

if you see an error like the one below after running composer command:

Installation failed, reverting ./composer.json to its original content. [RuntimeException] Could not delete /.../web/sites/default/default.services.yml:

You can resolve this with: chmod +w web/sites/default and run the composer command again.


Strange errors

If everything goes well and you see the site breaking on some pages like /admin/modules or any other page with this error in the log

Drupal\Core\Extension\Exception\UnknownExtensionException: The module does not exist or is not installed. in Drupal\Core\Extension\ExtensionList->getExtensionInfo() (line 346 of /app/web/core/lib/Drupal/Core/Extension/ExtensionList.php).

You can resolve that by running drush ev "\Drupal::configFactory()->getEditable('core.extension')->set('profile', 'standard')->save();" locally. This command enables the standard profile.


Note that you will need to run the same command on production before you can import configurations.


Do you have other tips or have questions, don’t hesitate to contact Fred.

Fred AgbemenyaWritten by Fred Agbemenya
Developer at Ramsalt Lab


Nov 22 2019
Nov 22

This article was originally posted on Thunder.org and is reposted here with the permission from Community Manager Julia Pradel. 

Not everyone has the necessary resources to engage their own design team. Our Certified Thunder Integrator (CTI) Ramsalt has recognized this need and developed a generic theme that will be available to other Thunder users as an open-source product.

The idea for the theme emerged a few years ago: “We wanted to develop a generic design which newspapers could easily customize to their individual needs” explains Ramsalt’s CEO Yngve Bergheim. “We had a starter kit in mind which could either be used as is, or easily tweaked by a designer.”

The first task was to gather all of the requirements for a design. We arranged focus groups with digital editors from several newspapers to understand their needs. “We also drew upon our own pool of experience,” says tech lead Stephan Zeidler. Ramsalt has made numerous magazines and newspapers since 2011. The analytic process ended up in a 51 pages design requirement specification and corresponding wireframes.

[embedded content]Example of Longform/featured articles

Art director Evgeny Pugachev led the design process while Stephan Zeidler was tech lead. The CTI Ramsalt Lab has offices in several countries among them Sweden, Norway, the Netherlands and Russia, and the Thunder development is directed from the German office in Berlin. According to Stephan, the greatest challenge with the theme’s development was ensuring that everything would be reusable - and at the same also be customizable. Stephan, therefore, relied on a component-based approach: “It is certainly significantly more complicated and takes longer at the beginning of the project but the risk of regressions is much reduced”.

Simple to adjust

The component-based approach also enables Stephan to capture updates from the numerous Drupal modules. “Since we use our own HTML templates rather than the standard Drupal templates, adjustments are much simpler than they would otherwise be.” Another advantage in his view is the lean markup which makes the site significantly quicker and also delivers plus points in terms of SEO aspects. The theme has also been put to the test and further optimized in order to achieve the best possible results in Google’s Pagespeed. It was a project by itself and led to the publication of a series of articles on Planet Drupal, under the heading The ultimate guide for faster Drupal.

The theme was conceptualized over a period of six months with two designers, challenged with the help of several customers and continuously developed along the way - and it is still a work in progress. The three-person development team working with Stephan, also wants to examine whether Drupal’s Color Module can be integrated and how the design could also be used as a demo theme by other CTIs.


Get the new design now!

For company chief, Yngve Bergheim, there is no question about whether the Ramsalt design will be made available to Thunder users: “Anyone that wants to try out the new design can drop us an email on [email protected]. - We want to use the theme as a showcase for publishers evaluating Thunder. Publishers already have the best technology in place in the Thunder distro, the best and biggest community. What is lacking now is a good looking design on the bodywork that fits the top-notch “Porsche” engineering we have in Thunder”, says Bergheim.


The design is aimed to be released as an open-source module on drupal.org as soon as the integration with Thunder works seamlessly. There is still some work left: “The design currently makes many assumptions, like how the menu and various article variants look, that there is a search bar or that authors are shown with their names, pictures and even job titles” explains Stephan. The fields for these points did not exist in a standard Thunder. “And that is also a good thing, Thunder should remain as generic as possible” stresses Stephan. This does, however, pose him and his team the question of how the theme can, together with its Thunder installation, show its full effectiveness out of the box. Which is our goal, to have the theme in the Thunder distro eventually.

Aug 01 2019
Aug 01

Written by Sven Berg Ryen, Leader of the GDPR audit team at Ramsalt Lab

EU Cookie Compliance, one of the top 100 Drupal modules, is a Drupal module that offers a cookie consent banner with various features, making it more convenient for your site to become GDPR compliant. GDPR is the new data privacy regulation that came into effect on 25 May 2018 and it sets out to bolster the rights citizens of the EU have over their data which is held by companies. Ramsalt Lab is currently supporting the module development as part of our GDPR audit services.

According to GDPR, if you have any traffic from EU citizens on your site, you need to ask for consent before you, or third party scripts, process any of their personal data.

This is all very well, you can ask for consent first, and then only use the visitor’s private data if they consent, but under GDPR you’re required to do so only when the visitor is an EU or EEC citizen. That still leaves billions residents outside of the EU where privacy laws may not require consent (one could argue whether this is good or bad) for storing cookies that identify individuals. Wouldn’t it be nice if you can comply with EU regulations and at the same time not pester those outside of the area where GDPR is enforced?

Luckily, EU Cookie Compliance has a feature to the rescue. It can first check whether the user resides in the countries that GDPR affects, and then display the banner accordingly, only when applicable.

So the technical parts

To achieve this, you need an additional addon; either the Smart IP or geoIP modules - or the geoIP PHP library. It may be easiest to use the module route, since adding the PHP library may not be feasible on your hosted server or cloud solution.

We will here use Smart IP, since that’s the only module that the Drupal 8 version of EU Cookie Compliance supports. There is now also a beta version of GeoIP available for Drupal 8, so at some point, EU Cookie Compliance may support GeoIP also in the 8.x module version. You can follow this issue for the progress.

The option to show the banner only to EU countries can be found near the bottom of the module settings page. A notification can be seen when the Smart IP module is not enabled.

EU Countries configuration section when no geolocation utility has been selected.

Enabling and setting up the Smart IP module

Install and enable the Smart IP module, using your preferred technique (such as composer/drush or direct download from drupal.org). In Drupal 8, you also have to enable a Smart IP data source module.

The Drupal 8 module gives you to the following geolocation lookup options:

  • Free and licensed geolocation files from ip2location.com (signup required to get access to the free version). For the purposes of this module, you only need the DB1 database, with coverage of countries. Attribution is required when you use the free database.
  • Geolocation service from ipinfodb. A free API is available. You are however limited to 2 requests per second, and will be blacklisted if you exceed that limit. Also, the service limits you to lookup requests from one server IP only, which may not be ideal if you’re planning to test the service from your localhost. Note that the module utilizes the ip-city endpoint, and not the faster ip-country one. Sign up to get an API key.
  • MaxMind GeoIP2. A free database is available, updated on the first Tuesday of each month. No signup is required to use the free version, though attribution is required.
  • MaxMind GeoIP2 Precision API service offering lookup at the country level at $0.0001 per request. A free trial is available.

Some fallback options are available, and will be accessible if the headers exist in the web page query when you open the configuration page (which means they may not be available on your localhost, but could be available on your server).

  • Cloudflare headers
  • The mod_geoip module in Apache
  • Nginx headers

The Drupal 7 version of Smart IP offers all of the above and in addition some legacy lookup services.

We will be using the Smart IP MaxMind GeoIP2 binary database, because it has a free version of the database that will automatically be updated once a month on cron run. In other words, you need to enable the smart_ip_maxmind_geoip2_bin_db submodule (part of smart_ip).

Configuring Smart IP for GDPR

After having enabled the required modules, head over to /admin/config/people/smart_ip.

Select the “Use MaxMind GeoIP2 binary database” option to see the configuration for the service. Choose the Lite database version, the Country level edition and make sure that Yes is chosen under Automatic updates.

Further down, in the second pane, configure your settings to allow geolocation lookup for all desired user roles. Then, since I guess you care about privacy, either opt to not save the user’s geolocation on account creation, or enable the feature to prevent storing location details from GDPR countries.

Scroll all the way to the bottom and press “Save configuration”. If you get an error at this point, you need to set a private file path in settings.php.

Smart IP configuration section with recommended configuration highlighted.

After having configured Smart IP, you need to head over to MaxMind’s website and download the GeoLite2 Country file in DB format. Then, expand the archive, grab just the file labeled “GeoLite2-Country.mmdb” and drop it into “[PATH_TO_PRIVATE_FOLDER]/smart_ip”. After you add this file manually once, the Smart IP module will take care of the automatic monthly updates.

Note: In Drupal 7, the GeoLite 2 country database is downloaded automatically when configuring the module, so there’s no need for a manual download.

Configuring EU Cookie Compliance

Next, head back to the settings for EU Cookie Compliance at admin/config/system/eu-cookie-compliance and enable the “Only display banner in EU countries” option. If your site uses any caching at all, you’ll want to enable the Javascript based option.

EU Cookie Compliance configuration section for limiting the display of the banner to only show up in EU countries.

After enabling this feature, you will need to rebuild Drupal cache, in order for Drupal to pick up the new path that is used to determine if the user is in the EU.


Note: If you’re on an EU Cookie Compliance version prior to 8.x-1.7, you need the patch from this EU Cookie Compliance issue in order for the debug feature in Smart IP to work. The Drupal 7 version of EU Cookie Compliance doesn’t have this problem (though you should always make sure that your version is up-to-date to get the latest bug fixes and features).

This feature involves a few moving parts, so to ensure everything has been set up correctly, there’s a handy debug feature in Smart IP that can be used. This way, you can check that you are indeed displaying the banner only to European countries where GDPR legislation apply. The easiest way to check if the settings are correct is to temporarily set up debugging in Smart IP for the Anonymous user and open an Incognito window. This way you can ensure that no existing cookies are giving false assurance that the feature is working.

Try using a value such as (which at the time of this article is one of the IPs for the drupal.org server, situated in the US). Notice that no banner is shown when you debug smart IP with this value.

Try (the IP for the server where drupalnorge.no is hosted, which is in Norway) and the banner should appear.

Section of Smart IP configuration showing an IP number has been configured for debugging purposes.

After testing is completed, remember to disable debugging for the anonymous user by clearing the value on the Smart IP configuration page.


A little work is required to set up EU Cookie Compliance to display the GDPR cookie banner only to countries and territories where the law requires one. Resulting from this, you will hopefully have happier users.

If you need help setting up your GDPR cookie banner, or have questions about how your site can become GDPR compliant, you can always get in touch with us at Ramsalt Lab through our contact page.

Written by Sven Berg Ryen
Developer and Leader of the GDPR audit team at Ramsalt Lab

Sven Berg Ryen

Jun 28 2019
Jun 28

Next step in our journey after Part 1 Caching and Part 2: Aggregation of our ultimate guide to Drupal performance is all about Drupal theming.


Faster Drupal - Part 3: Drupal Theming

  • Automate optimizing of CSS, JS & Images. The thing is, it really depends on the node packages that you use on your theme level and how you can take advantage of it, for instance, there are many (I MEAN MANY WITH ALL CAPS) packages that can help you achieve that using a build system such as gulp, grunt or the new favorite webpack.

  • Avoid using unnecessary bootstrap packages as much as possible. Usually, Starterkit themes load bootstrap packages one by one, why not remove the ones you don’t need? WHY? JUST TELL ME WHY?

  • Is your theme using fontAwesome or any other kind of font out of box? But you are using SVG icons from your design file! Well… why not just remove the built-in icon font from your theme then?

  • Fonts are nice, And it seems our designers usually like to use 12 billions of them in a single page, but you should never listen to your designer (Or should you?) Always remember to load fewer fonts and fewer font weights as much as possible.

  • While we are on the fonts topic:
    Control font performance with font-display - Resource

  • Are you the type that invents the wheel each time yourself? Then don’t use a base theme that comes with a lot of good stuff! we usually don't use half of those goodies. Create a new base theme off of Drupal core's "stable" theme and go with the bare minimum. Or use a proper Starterkit, strip off the unnecessary parts, get your own Starterkit and get rid of all the Drupal themes excessive wrappers and classes.
    On this note, it’s a good practice to get your DOM size less than 1500 nodes (recommended from Google Page Speed)
    For Drupal 7 also maybe just consider Fences module if nothing else works for you

  • Reduce the scope and complexity of style calculations

  • Prioritizing Your Resources with link rel='preload' and yes you can use for scripts as well - Resource

  • When we were kids (Back in Windows XP era) you’d read everywhere that do not use inline styles for your HTML files, but now you should use inline-styling to avoid render blocking CSS files. All the CSS Styles loaded from external files is considered render blocking. Why You asked?
    In order for the browser to display your web page and use the styles you specified in the external CSS files, it has to load them first. This means that your web page won't be displayed until these files are loaded. In order to speed up the loading of your website, you can inline the parts from the external CSS files which are needed to render the above the fold content. After loading the page you can instruct the browser to load the rest of the CSS files via JS - There are many tools that you can use to achieve this but this one explains good enough and works: https://www.sitelocity.com/critical-path-css-generator
    Also, check penthouse as well, Can be set up easily as a task runner task!
    https://www.npmjs.com/package/penthouse - includes CSS for critical path above the fold in the HTML head.
    By the way, there’s a Drupal module for that (but we didn’t test it,  do so at your own risk)
    Our very own Sven played around with both penthouse and critical and let me just quote him in our slack chat here:

    critical is a wrapper for penthouse with the main advantage that it delivers critical css for several breakpoints in one file. 
    Note: To generate critical css, `link_css` module must be enabled, and you can not be using deter css loading in AdvAgg, otherwise you get an empty file. (Needs testing)
    Critical_css module on Drupal
  • Now that you have the critical CSS, the proper tool to load the rest of your CSS: https://github.com/filamentgroup/loadCSS

  • Remove unused CSS, there are tools inside the IDEs that can help you with that, you should search this part yourself since it depends on your weapon of choice for coding, also there are node packages that you can set up but I’d still go with the IDE approach and do it manually, just to be safe.

  • Use video tag instead of gif images (Yup, it loads faster)

  • Avoid using document.write, specifically for scripts injection - Resource

  • Images must not be delivered larger than they are actually displayed to avoid loading unnecessary data. Resizing images on the browser side to reduce their rendering size is not recommended.


Faster Drupal - Part 4: CSS/JS Tips


Written by Sohail LajevardiSohail Lajevardi 
Developer at Ramsalt Lab 

Jun 21 2019
Jun 21

Written by Sven Berg Ryen, Leader of the GDPR audit team at Ramsalt Lab

EU Cookie Compliance, one of the top 100 Drupal modules, is a Drupal module that offers a cookie consent banner with various features, making it more convenient for your site to become GDPR compliant. GDPR is the new data privacy regulation that came into effect on 25 May 2018 and it sets out to bolster the rights citizens of the EU have over their data which is held by companies. Ramsalt Lab is currently supporting and maintaining the module as part of our GDPR audit services.

Does your site have traffic from EU? Then you need to ask for consent

According to GDPR, if you have any traffic from EU citizens on your site, you need to ask for consent before you, or third-party scripts, process any of their personal data.

One recurring GDPR feature request we’ve seen over the past few years has been to allow granularity in the cookie compliance consent, so that the user could accept or decline various cookie categories. This feature has now been added to the recently released versions 8.x-1.6 and 7.x-1.29. You can find the new consent method on the module settings page. To enable this feature, select “Opt-in with categories” as the consent method.

In this blog post, you can learn how to configure the EU Cookie Compliance banner to use GDPR categories, as well as how to use the categories in your code to track the user only when they give consent.

The different GDPR consent methods that the EU Cookie Compliance supports.

GDPR consent banner configuration

Choosing this consent method reveals an expanded set of fields named “Cookie Categories” that you can find beneath the “Consent method” options. Here you can set up your cookie categories and configure how the banner behaves. Let’s first look at the categories:

Field for GDPR cookie categories showing configuration where 4 categories are entered

Categories are entered using the following pattern: “key|label|description”. The description is optional. The above setup will result in the following EU Cookie Compliance consent banner:

The resulting GDPR cookie banner, with the categories

This will result in a fairly large GDPR consent banner. Note that the banner appearance in EU Cookie Compliance is based on a Drupal theme template, so you could always create a theme specific template and for example place the descriptions on the same line as the title, or perhaps have the descriptions appear on hover if space is a concern. By default, the banner has two buttons when you use the category consent method: “Save preferences” and “Accept all cookies”.

Below the text field for cookie consent categories are some additional options. The first option, which is on by default allows you to replace the “Agree” button with the two “Save preferences” and “Accept all cookies” buttons. In addition to labeling the buttons, you can also choose to make the first option compulsory by choosing “Tick the first checkbox and mark it read-only”. You can also choose to “Tick all category checkboxes by default” to make it more convenient for the user to opt-in to cookie usage under GDPR.

Screenshot showing the configuration options for the cookie banner with categories.

Limit scripts and white-list cookies per category

When you're using this consent method, you can prefix the white-listed cookies and scripts you want to run only when the user has given consent. Simply prefixing the field entries with the category key will do the trick. For example:

To limit scripts based on category

If the category key is advertising: "advertising:path/to/the/script.js"

To white liste cookies based on category

If the category key is functional: "functional:cookie-name"

Note that only when consent is given for a category, will the prefixed cookie be white-listed.

Code usage

In order to let your site and javascript comply with the cookie preferences set by the visitor, you may have to write some custom code. Although EU Cookie Compliance has some options to whitelist cookies and block scripts, not all scripts are added to the page source using the standard Drupal methods and can be altered through f.ex hook_js_alter in Drupal 7 (which is what the module attempts to do).

EU Cookie Compliance has for years had a method you can call to check if the user has agreed to store cookies and processing their personal data:


This function will return true when consent is given, and false when the user has declined processing of their data.

With the newly introduced categories, you can call the same function with a parameter:


Where ‘category’ is one of the category keys that you have defined on the EU Cookie Compliance module settings page, for example:

if (Drupal.eu_cookie_compliance.hasAgreed('performance')) {
  // Load scripts that deal with performance.


Many high profile sites allow visitors to choose among categories when the visitors give consent to the processing of private data through cookies in their browser. Now your site can do offer the same granularity if you use a recent version of the EU Cookie Compliance module.

If you need help setting up your GDPR cookie banner, or have questions about how your site can become GDPR compliant, you can always get in touch with us at Ramsalt Lab through our contact page.

Written by Sven Berg Ryen
Developer and Leader of the GDPR audit team at Ramsalt Lab

Sven Berg Ryen

May 20 2019
May 20

We are on our journey to master the Drupal performance, after having our previous Part 1: Caching published a couple of weeks ago, we've been lucky enough to get into Issue 386 of TheWeeklyDrop newsletter, Planet Drupal, and got much love and good feedback on Twitter.

If you haven't already read the first part of the series, the ultimate guide for faster Drupal: Part 1 Caching, please feel free to read that article too.

Note: You don't necessarily have to do all of these, some items listed here are replaceable with each other as well, so proceed with caution!

Faster Drupal - Part 2: Aggregation and CDN

  • The one and the only holy grail: Advanced CSS/JS Aggregation
    On every Drupal optimization post you’d read you have to setup and configure AdvAgg module, but you gotta do what you gotta do!
    AdvAgg features and core benefits are listed on the module page completely, so go ahead and read them all, configure it the way that works best for you and move on
    Advanced CSS/JS Aggregation Drupal module

    Note: If you have Mod Pagespeed you might not need AdvAgg module, make sure that you don't overlap your own work

    But that’s not all, if you are on Drupal 7, you should consider checking Speedy module as well, in some areas, this might work a bit better so make sure to check it out as well
    Speedy module

  • For good JavaScript minification in Drupal, you can use modules such as minify but we’d like to recommend minifyJS instead, they listed the differences and benefits on their module page so check it out
    Drupal MinifyJS module

  • CDNize the whole project, as much as you can! You may use CDN module too

  • Move JavaScript to the footer if necessary, some JS files need to be rendered in the head based on the use case and what does the JS do! Also in Drupal 8, it’s quite easy to append your necessary library (Read it JS files) in the footer in twig template files

  • Consider if you can make your own scripts defer/async (a new challenge when it comes to Drupal js aggregation)

Okay, this round was much easier thanks to AdvAgg module for taking care of half of the things we need to do for us! Note that on the frontend side you can Uglify, Minify and make sure everything that you code, will become compressed, whether it’s CSS, JS or even images or SVG files! Now let's get to it, Image optimization. 

Image optimization

  • Drupal 8: Use the Responsive Image module wherever possible and create the appropriate styles. It uses the tag which is what we really want

  • One might say we have one too many image optimization modules in Drupal, which is a good thing! For that we tested some, experienced with some of them and here’s what we suggest: Use blazy and lazyload_images (Drupal 8 that uses IntersectionObserver instead of scrolling events), Also consider: lazyloader and image_lazy_loader when using the picture module for responsive images in Drupal 7. There is also a lazy loading option that works well

  • Image optimization: for main images/icons used in the design (Yes you can optimize SVG files as well), also the best tool for that is not in Drupal, try ImageOptim desktop app, Also there’s an API-based service available with a Drupal 7 module, take a look here, might worth setting/selling this up to clients

    Also in the same context, we can use ReSmush.it which is free (But should donate some beer to them)
    Drupal 7 Module, Drupal 8 Module

  • Image formats like JPEG 2000, JPEG XR, and WebP often provide better compression than PNG or JPEG, which means faster downloads and less data consumption. There's a really good module that help you serve WebP, it's called, you guessed it; WebP.

  • Serve WebP images with your web server with the MOD PageSpeed by Google for Apache and Nginx.
    Or conditionally serving WebP images with Nginx.

Bonus tip: Even favicons should be optimized. Sometimes people ignore the weight of a favicon file. You shouldn’t! 


For the next week, we will be covering subjects regarding Drupal database/web server tweaks & improvements, stay tuned.

Written by Sohail LajevardiSohail Lajevardi
Developer at Ramsalt Lab

Apr 24 2019
Apr 24

At the Lab section of our name: "Ramsalt Lab" we tried to put Drupal on steroids to test and see how much can we get out of Drupal performance wise and we will now publish a series of blog posts that together make a coherent How-to guide on Drupal performance.

Experience, general web performance and Drupal optimization articles

For gathering all the data in this document, we did some heavy research. We have studied a lot of general website performance, Drupal optimization articles and we have done a lot of tests and put in the organization's over 100 years of total Drupal experience into play. A highlight that we would like to point out is this great presentation in DrupalCon 2018 Nashville that you can download its pdf and take a look for yourself.

Chapters in the "Faster Drupal" blog series

As a starting point, note that it’s a much easier bet to start with a Drupal 8 installation instead of Drupal 7 since you can get much better results built-in. But in many cases, the current project is already on Drupal 7, so we try to cover both cases. Some of the items are, to say the least, “Obvious” but this list is supposed to be as coherent as possible. For most of this, we consider you have full access to your server and can set up the things listed here, so based on that, let’s kick things off with Caching. Then for the second blog article, we will look into asset distribution, CDN, compression, and aggregation. Thirdly we’ll be taking a look at one of the greatest enemies of performance: Images! Fourth step we will cover some techniques for Database/Web Server Tweaks & Improvements and lastly some general tips and HowTo’s for optimizing theming in Drupal.

Improving Caching in Drupal:

  1. Use Redis: Integration of Drupal with the Redis key-value store. It provides cache, lock, and path optional backends
    Redis Drupal module
    Not happy with Redis for some unknown reason? Try Memcache
    For a simple drupal installation, we can take advantage of these two modules:
    Drupal Memcache + Drupal Memcache Storage modules


  2. Use Varnish Cache: If you want to improve the performance of your website without using Varnish is like trying to cook without a pan! Varnish is an advanced and very fast reverse-proxy system. In the common configurations Varnish will handle all caches regarding anonymous page-views, and sometimes even static files and pages for logged in users via per-role-caches and ESI (Edge Side Includes) for your site.
    Varnish Drupal module (not required for caching, but essential for cache purging).
    But hey I’m on shared hosting and don’t have access to any fancy Varnish HTTP cache thingy? Well then use Boost module
    Drupal Boost module


  3. Take advantage of PHP Cache (APC): With APC caching your PHP script executions can run more efficiently, by cutting down on dynamic PHP executions.

  4. Let’s all agree we all love CloudFlare: CloudFlare is a FREE reverse proxy, firewall, and global content delivery network and can be implemented without installing any server software or hardware. At least based on Cloudflare module’s page, on average, CloudFlare-powered websites load 30% faster, uses 60% less bandwidth, and process 65% fewer requests. CloudFlare-powered websites are protected from many forms of malicious activity including comment spam, email harvesting, SQL injection, cross-site scripting, and DDoS (denial of service) attacks.
    Drupal CloudFlare module


  5. The Purge (Not the movie): So by now you cached the hell out of your website and now you just want to change something on your website? The purge module facilitates cleaning external caching systems, reverse proxies and CDNs as content actually changes. This allows external caching layers to keep unchanged content cached infinitely, making content delivery more efficient, resilient and better guarded against traffic spikes.
    Drupal Purge module


  6. Did you know you can cache your views? In Drupal 7 Enable “Views Caching” in each Views manually and in Drupal 8 there’s a module that helps a lot with that.
    Drupal Views Advanced Cache module


  7. Using Panels? Enable Panels caching in each Panel

  8. Drupal 8: Do you like BigPipe in Drupal 8 core? How about some sessionLess BigPiping? (No pun intended)
    Sessionless BigPipe module


  9. Use views with minimum pagination navigation to save some SQL time (just first, previous, next, last links instead of (1,2,3,4,5…). In Drupal 7 you also need to use:
    Views Litepager module


  10. A long cache lifetime can speed up repeat visits to your page, Serve static assets with an efficient cache policy
    Read more on Google developers


  11. Drupal 7: People need to login to your website and you still would like some caching? AuthCache to the rescue
    Authenticated User Page Caching module


  12. Drupal 7: You like Drupal 8 core cache tags and cache max-age? But maybe for Drupal 7?
    Drupal 8 Cache Backport module


  13. Drupal 7: Need different caching per block? Fear not
    BlockCache Alter module


  14. Drupal 7: Already setup Memcache and Redis? Add some Entity Caching
    Entity Cache module


  15. Drupal 7: Render Cache is also quite powerful but has some issues on the cache clearing level, so use with caution.
    Render Cache Drupal module


  16. Consider using Google QuickLink Library if possible. Enables faster subsequent page-loads by prefetching in-viewport links during idle time at the cost of increased page loads for the client.
    Google QuickLink Drupal module

Okay, that was a long list of things to consider/do for just caching, but hey we are here to make something extra performative.

In the next upcoming part that will be published in about a week, we will focus on Drupal Aggregation / CDN / Compression

Written by Sohail Lajevardi
Developer at Ramsalt Lab

Sep 19 2018
Sep 19

Expo just got nominated for the Swedish design award. Before Expo was nominated for two publishing awards, best magazine and best magazine website. The winners will be announced 7th of November 2018 in Stocholm where Ramsalt will be present. While we we wait, we have decided to share with you the secrets behind building Expo.se on Drupal. 

Expo screenshotShort about the client 

Expo is a Swedish anti-racist magazine started in 1995 by Stieg Larsson, also known as the author of the Millennium series books, where the inspiration comes from Expo. Expo magazine is issued by the non-profit Expo Foundation. The magazine contains investigative journalism focused on nationalist, racist, anti-democratic, anti-semitic, and far-right movements and organisations. The people responsible for Expo make no connections with specific organisations or political parties, but work together with individuals and organisations that share Expo's platform. The magazine is headquartered in Stockholm.

Why Drupal was chosen?

Drupal was chosen for many reasons and out-ranked other solutions because it fulfilled many of the requirements from Expo. The strong capabilities for large amount of data, content-authoring options and the high level of community support were a few key elements where Drupal perfectly met the needs. Additionally, Drupal provided reliable content management and moderation features, as well as an editor and user-focused interface. Especially when it came to the wiki functions.

Other reasons include

  • Feature flexibility
  • Scalability
  • No licensing fees
  • Maintainability

Goals, requirements and outcome

Previous site pain points
Multiple Subsites
The previous version of the site was spread over a number of subsites/subdomains which the client was eager to unify into one categorised Drupal site.
Complex, custom database structure & content editing
The database of the previous site was overly complex and custom built which made the site very hard to maintain. On top of that the content editing forms were very long and confusing.

Non-responsive theme
Expo has a huge readership but without a mobile friendly version of the site the full potential of their reach was not being met.

Understanding the pain points of the previous site was essential in making sure we met the needs of the client.

Ramsalt Media
At Ramsalt we’ve developed our own distribution of Drupal called Ramsalt Media which is specialised for online publishers including newspapers & magazines. Ramsalt Media includes all the tools are publisher needs including article scheduling, WYSIWYG, media management and frontpage management. We were able to use Ramsalt Media as a platform to build on top for the rest of the site needs which went outside that of our standard clients. At the time of project start in 2017, Ramsalt Media was only stable for Drupal 7 so initial development has been done in Drupal 7, but Ramsalt Media has since 2018 been available in Drupal 8 buildt with Thunder.

Key development steps
Content Migration
Expo produces both a physical magazine and regular online articles so all the old articles from the custom database had to be migrated into Drupal along with their related media assets. As mentioned above, the database had a very complex structure & naming convention, once information from the previous developer was provided we were able to start mapping the migration for the some 7000+ articles & 2500+ media assets. The migrate module was the main contrib module we used for the migration.

We also made use of rules autotag module which allowed us to read article titles & body content and auto tag articles on migration based on the topics they covered. The topics were all predefined as taxonomy terms, if an exact match was found in the title or body then the article was tagged with the given taxonomy term. This gave the editorials a helpful kick start in categorising all the articles within Drupal as taxonomy term landing pages (see: https://expo.se/tag/hatets-politik-2017 ) where deemed an important new piece of functionality on the site.

Just double click on any text and you jump into edit mode, with our module QuickerEdit

Improved Publishing Tools
As previously mentioned the site was built on top of our own distribution called Ramsalt Media. Ramsalt Media pulls together some of the best contrib modules out there to make article & content publishing easier and more streamlined.

Responsive Theming
We worked closely with Expo’s own design team led by Daniela Juvall throughout development. The goal was a simple, clean design with bold typography which was inline with Expo’s physical magazine style. The magazine has been nominated for a number of design awards in Sweden.
As mentioned the previous site was not responsive so it was essential the new site was optimised for all devices.
The theme was custom built for Drupal 7 using sass.

The New Wiki
Another major part of the development involved creating a new Wiki section to expo.se to house information on all the topics covered by Expo. This included information about right-wing political leaders and groups as well as their symbols and related articles. This section was built as a number of different content types which were then bridged together using taxonomy and entity reference fields. This approached allowed wiki nodes to be associated to a single taxonomy term which could in turn be associated with other content on the site. Binding the wiki together is a central search page which was built using the search API, facets & panels.

[embedded content] Long Reads
Long read or long form articles have become more and more popular with our publishing clients in recent years. They allow for a richer and longer form of article to be published.
Expo wanted long read functionality to be able to post longer articles from the physical magazine in a richer and more eye catching manner. We used the paragraphs module for this and created a number of custom paragraph types to store the different types of content needed to make up a long read. This included text paragraphs, call to actions, images and videos.
We also created a “layout” paragraph type which allowed all paragraph types to be laid out in a set responsive left/right column layout. On top of paragraphs we custom built a floating “table of content” (optional) and read indicator bar.
We found paragraphs to be the best option for this job although the node edit form is an area where we are hoping to improve in the future as it can become confusing on very long articles.

Site Building
The rest of the site was built out using custom content types & fields, views, entity collection, panels/page manager and views content panes. This allowed for a rapid & streamlined approach to site building. Using views content panes meant similar displays could reuse a single view using pane settings to vary the display as needed.

Key modules 

Scheduler: allows editors automatically set articles & content to publish (and unpublish) at a set date & time.

Entity Collection: allows editors to control the frontpage articles list in a custom order and apply custom styles to each article in the context of the frontpage. This along with views & panels allowed us to build a custom frontpage and inject custom blocks with the frontpage article flow.
Entity collection was used throughout the site to give a unified approach to all content lists/blocks you see throughout the site.

Media: allows editors to upload media to a central library allowing easy reuse of media throughout the site.

Fields: of course the fields module & it’s contrib modules are used to provide custom field types allowing editors to add galleries, videos, article sources, bylines and more.

Aug 27 2018
Aug 27

Expo just got nominated for two prestigious publishing awards in Sweden, best magazine and best magazine website. The winners will be announced 7th of November 2018 in Stocholm where Ramsalt Lab will be present. We are very excited for this news and have decided to share with you the secrets behind building Expo.se on Drupal. So stay tuned for more the following days. 

Short about the Expo 

Expo is a Swedish anti-racist magazine started in 1995 by Stieg Larsson, also known as the author of the Millennium novel series, where the inspiration comes from Expo. Expo magazine is issued by the non-profit Expo Foundation. The magazine contains investigative journalism focused on nationalist, racist, anti-democratic, anti-semitic, and far-right movements and organisations. Expo became widely known in Sweden after 1996 following a string of threats and attacks directed against companies printing and selling the magazine, and organisations supporting it. The magazine is headquartered in Stockholm. More about Expo on Wikipedia

Have a look at the website on Expo.se

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