Upgrade Your Drupal Skills

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

See Advanced Courses NAH, I know Enough
Apr 28 2021
Apr 28

Bluehost is among the 20 largest hosting companies in the world, handling over 2 million domains. The company's offer includes a wide range of services. We will show you how to install Droopler, the Drupal distribution, using the basic shared hosting offer (Basic Web Hosting).


Step 1. Server preparation

First, you need to configure the database and PHP. This stage is necessary because, without it, it won't be possible to install Droopler. But before you start, you need to get familiar with the requirements for the system on which you want to run Droopler.

To configure your hosting, after logging in to the account using the login form, go to the "Advanced" tab, where you'll find all the necessary functions:

The Advanced tab in Bluehost, where you'll find all the necessary functions for the hosting configuration



1. Database configuration

First, you need to create a new database. To do this, click on the "MySQL Database Wizard" in the "Databases" section.

The Databases section in Bluehost


You'll be redirected to the database wizard page. In the first step, you need to define the database name. It can be any name but in our example, we’ll use the most intuitive one - droopler. The full database name will consist of a prefix (usually associated with the account id) and a second part/name defined by you.

Defining the database name in MySQL Database Wizard


In the next step, you need to define the database users (at least one) and their passwords. You can generate the password using the Password Generator located in the form.

Defining the database users in MySQL Database Wizard


In the third step, you need to assign the user permissions to your database. For the Droopler installation to work correctly, it's safest to assign all permissions by selecting the "ALL PRIVILEGES'' option.

Assigning all database privileges to a user to make the Droopler installation work properly


2. PHP configuration

Setting the appropriate version of the PHP language and adjusting its configuration is crucial and can significantly affect the installation process. To make the necessary changes, go to the "Software" section in the "Advanced" tab.

The Software section in the Advanced tab in Bluehost


To set a specific PHP version, click on "MultiPHP Manager". In our installation, we'll use the proven PHP 7.3 version.

Selecting a specific PHP version in MultiPHP Manager


To change the environmental settings, click on "MultiPHP INI Editor".

With MultiPHP INI Editor, we can change the environmental settings


In the first step, you need to select the domain for which you want to make the necessary changes.

Selecting the domain for which you want to make the changes in MultiPHP INI Editor


Then you need to adjust the configuration for the needs of the Droopler installer and for the smooth operation of the website. We increase the maximum script execution time (max_execution_time) to 180 and the memory limit to 512 MB.

Adjusting PHP configuration for the needs of the Droopler installer and the smooth operation of the website


We leave the other values in accordance with the default settings.


Step 2. Downloading Droopler

The Droopler distribution can be downloaded from the official website of the project.

1. Download the latest version of Droopler as a zip archive.

A place on the Drupal distribution's page from where you can download the Droopler


2. Go to the File Manager located in the "Files" section in the "Advanced" tab.

The Files section in the Advanced tab in Bluehost


3. After opening the file manager, click on the "Settings" button in the upper right corner to unlock the option to display hidden files.

After coming to the Settings section, we can unlock the option to display hidden files


4. In the file explorer located in the left column, click on the public_html directory.

The public_html directory in File Manager in Bluehost


5. Click on the "Upload" button in the top menu in order to upload the file from the archive downloaded in the first step.

The Upload button in File Manager


6. Drag and drop or select the file using the system file explorer.

Adding the Droopler file to File Manager in Bluehost


7. After loading the file, right-click on it and select the "Extract" option.

Selecting the Extract option for the Droopler file


8. Set the target directory for the extraction to /public_html.

Setting the target director for the extraction of the Droopler file


9. After the extraction is complete, go to the newly created directory with Droopler (in our example, it'll be the directory named droopler-8.x-2.1) and select all files.

The newly created directory with Droopler in File Manager in Bluehost


10. Move the selected files and subdirectories directly to the /public_html directory using the move button available in the top menu or after right-clicking.

Moving the selected files to the public_html directory


11. Leave only /public_html in the name of the path to which you'll move all the contents of the directory.

Defining the path to which you'll move all the contents from the directory with Droopler


12. After moving the files, go back to the /public_html directory and remove the uploaded .zip archive (droopler-8.x-2.1-core.zip) and the directory created during the unpacking (droopler-8.x-2.1).

Removing .zip archive and the Droopler directory from the public_hml directory


Step 3. Droopler installation

Everything is ready now. To start the installation process, all you need to do is to go to the website by entering your domain address in the browser bar.

The Droopler installer


The Bluehost web hostings don't offer PHP OPcache, so you'll see a warning when verifying your requirements. You can ignore it and proceed with the installation by clicking on the "continue anyway" link at the bottom of the page.

The warnings during the requirements verification in the Droopler installer


The last important step is database configuration. Here we enter the data that we previously set in the Bluehost panel, i.e., the database name, the database user's name and their password. The host and port number remain as in the attached screenshot.

Database configuration in the Droopler installer


After clicking on "Save and continue", you have nothing else to do other than to take a short break for coffee or tea, during which the rest of the Droopler installation will be performed.

Jan 21 2021
Jan 21

In the era of increasingly distributed architecture of applications and web portals, there is a need to provide flexible methods of authentication while maintaining convenience for the user. From this article, you will learn how to easily create an authentication server and client application in Drupal using OAuth2 and OpenID Connect.

Distributed systems, their scaling and maintenance is a problem for many clients who come to our company to take advantage of the Drupal consulting services. Very often, there is a need to implement a central login system for all platforms belonging to a wider federation of websites. Large companies and organisations have separate portals – we have created image-building websites, intranet systems and Drupal Commerce services for them many times, taking into account various functions. The need to register a separate account and log in by users in every single place separately seems to be an archaic way of dealing with the problem. After all, who among us does not make it easier for themselves to register on websites on a daily basis – for example by employing quick registration methods using an account on a social network or a Google profile?

Why not do the same, especially since – as it will turn out in a moment – using Drupal for this is very easy.

OAuth2 and OpenID Connect

In order to shed some light on the whole problem, one should, first of all, focus on the commonly used standards in web applications that are used in the authentication process.

The first is OAuth2, an open standard for authorisation that does not require sharing authenticators between applications. Access to resources (if it has been granted) is being verified on the basis of a token issued to client applications by the authorisation server.

As OAuth2 was designed with authorisation in mind, that is – with granting specific access to given resources; it is not really directly intended for a standard user authentication (logging-in) process. For this purpose, it was decided to propose an additional (authentication) layer to the OAuth2 protocol, which standardises this exact process in it. This technology is called OpenID Connect and – apart from the logging-in process – it also unifies the method of exchanging user profile data between applications. We will, therefore, take a look at how to employ both technologies in practice.

Installation of the modules

If you want to set up both the OAuth2-based authentication server and the client applications based on OpenID Connect, in Drupal, you can basically use ready-made solutions. In the case of a server, you have several appropriate modules, including the most popular one (simple_oauth). In our example, we will use the OAuth2 Server module. It is slightly less popular and has not yet been released as a stable version for Drupal 8 and 9, but it is supported by significant companies and organisations related to Drupal.

Additionally, the second client application module, OpenID Connect, is a project being maintained and developed by exactly the same organisations and development team. You can, therefore, be sure that both projects will be developed simultaneously and that no problems with their compatibility will arise at a later time.

The modules' installation is standard. First, you need to download and install the modules on our server:

composer require drupal/oauth2_server
drush en oauth2_server -y && drush cr

Then, in a similar way – for the client:

composer require drupal/openid_connect
drush en openid_connect -y && drush cr

The main dependency needed to install the server is the oauth2-server-php library which provides the basic mechanisms to fulfil this role. If you are using Composer in PHP, all dependencies are already terminated automatically for you.

Server setup

The setup of the OAuth2 Server module is mostly based on entities. Therefore, among the things it provides are the entity of the server, client, token, etc. Our setup must begin with defining the server. So, we go to the setup page /admin/structure/oauth2-servers.


And add a new server (Add Server). In the next step, we see the server entity form:


In the simplest configuration variant, we leave all the values selected by default and filled out. In addition, we check the "Use OpenID Connect" option as the default layer used in the logging-in process.

As you can see from the settings, the authentication and authorisation process takes place without the use of the authentication data sent by the client, but on the basis of an authorisation code – exchanged then for the access token and the refresh token, which are exchanged during the communication between the applications. The technical details of the OAuth2 protocol go beyond the scope of this article, so if you want to know more about how the individual options and the protocol itself work, you can do so using the official documentation.

In the next step, we should define the clients that can connect to our server. We must, however, have at least one client application in order to do this.

Client setup

OpenID Connect is a very user-friendly module also in terms of setup. To configure the clients you want to use, go to /admin/config/services/openid-connect.


As you can see, there is a list of clients in the form. The module, therefore, allows you to easily login using, e.g., well-known social networks. Each type of client is defined as a separate plugin (OpenIDConnectClient), which makes it easy to extend the project with completely new clients. Our example, however, is about connecting to our own server, so we will use the client for generic uses (Generic).

The configuration is quite simple because it consists of defining the client's name and the so-called secret key, as well as providing the server addresses:


While we are at it, we will add a small improvement, namely – replace the logging-in form with a login button using our authorisation server. It is very simple and accessible from the setup form:


Great! The client looks ready to use. The only drawback is the lack of a convenient option of changing the name from "Generic" at the moment without a bit of coding, but the result still looks great for such a quick setup:


Server setup part two

We have a pre-configured server, as well as a ready client. So, let us define our client in the server setup so that it knows it can connect to it and request access to its resources. Drupal is a very secure CMS compared to the competition, but the security is also based on its correct setup.

Always remember that it is up to you to verify and configure what client applications should be able to connect to the server and use its resources.

In order to add new clients, go to the Clients tab, and then click the button for adding new clients.


You should see a form, the data of which should be filled out in the same way as what you set up in the OpenID Connect module in the client application.


We save the form, and it is ready... almost. You still have to grant the appropriate permission, so that it would be possible to use the OAuth2 server at all. In order to do this, go to the /admin/people/permissions page and assign the Use OAuth2 Server permission for the anonymous user.



All is set. So, let us check the actual logging-in scenario. First, we will register the test user on our server so that they can log in into our other applications.


Go to the client's application (login form) and click the Log in with Generic button (form screenshot).

You are redirected to the server login page on the server along with the destination parameter destination


After correctly entering the login and the password (test:test), you should see this additional step ...

the form

...in which you decide as a logging-in user whether you actually want to authorise our client page to your user data from the server, on the basis of which a local user account will be created.

After approving it, you are redirected to the client application page as a logged-in user:


Success! We can now fully enjoy our central login system.


The possibility of creating a central login system is a more and more frequently occurring need among the clients who have various types of distributed services, sites, and applications. By choosing Drupal, you can focus on implementing specific business rules, instead of reinventing the wheel. Using the ready-made solutions, such as OAuth2 Server or OpenIDConnect, supported by well-known organisations, gives you the certainty that you will easily implement the mechanism you need – even without the need for detailed knowledge of the protocols used in them.

In our Drupal agency, we always use the already available solutions which we often extend, and we adapt Drupal modules to the specific business model. I hope that the above article and the modules used will also prove useful in your project.

Nov 13 2020
Nov 13

Theme creation in Drupal is not as easy as it may seem. Therefore, there is space here to make your work easier. Often, however, we take shortcuts for this purpose, but these do not always bring the desired results or contradict Drupal's philosophy and generally accepted best practices.

Probably many of you know that as in any other CMS or framework we work on, in Drupal, we can achieve the same goals by choosing different paths to reach them. In the course of my experience, I have faced common mistakes made by Drupal beginners repeatedly, and I have managed to track many codes created by novice and experienced Drupal developers. I have seen how much different the approaches they use. As part of this article, I would like to introduce 7 tricks I have selected (or just shortcuts) that make it easier to work on creating a theme, which many programmers I have never heard of.

Due to the fact that with each release of the Drupal subversion there are various significant changes, I would like to emphasize the examples discussed here that are compatible with the core 8.9.x version. All presented tricks, although they may be sometimes controversial in use, they are fully consistent with the art and can be used for projects.

1. Use of the #context key in the rendering array

One of the common problems when creating templates is the ability to pass data between them. This usually requires programmers to perform complex operations, e.g. when processing templates. The challenge becomes even more difficult when some hooks have already been cached and data upload was still needed. There may be many ideas for solving the problem, but with the Drupal 8.8 version, the problem is solved by the #context key.

Suppose we have implemented hook_preprocess_node, in which we add some additional element using a dedicated template, but we would like to still have access to the node object in it. This is where the #context key comes in handy.

function my_module_preprocess_node(array &$variables) {
  $node = $variables['node'];

  $variables['my_custom_element'] = [
    '#theme' => 'my_custom_theme',
    '#title' => t('My custom theme title'),
    '#context' => [
      'entity' => $node,

This makes it possible to pass any data from one rendering table to another. You can fit anything in it, e.g. an instance of an object that we will need in further processing:

function my_module_preprocess_my_custom_theme(array &$variables) {
  $node = $variables['#context']['entity'];
  // Do whatever you needed with the node entity in your custom theme...

It's worth mentioning that this variable is also available in hook_theme_suggestion_alter, which can further facilitate making suggestions for additional context-dependent template names.

2. Cache support in twig templates

More and more demanding graphic designs of websites, as well as page optimization (in terms of the amount of HTML code returned), forces us to use some shortcut solutions, e.g. extracting the field value directly in the entity template (node type).

Solutions such as

{{ content.field_my_reference_field.0 }}

displaying only single field instead of the content variable can have disastrous consequences in the form of cache problems. In the rendering arrays, apart from the final HTML code, there are also keys responsible for storing such cache metadata: tag, context and max-age. If you want to be sure that the metadata will be collected correctly by the renderer service, just add one magic line in the template:

{% set rendered = content|render %}

In the example of a node template, it will be the content variable, but it can be any "main" variable of your template. Passing such a main rendering array through the render filters allows you to correctly collect all cache metadata, without having to display the entire content variable. At the same time, the solution does not have any negative impact on the performance of code execution, as long as we use cache mechanisms.

3. Theme suggestion without using hook_theme_suggestion_

Yes, it sounds like something completely crazy. However, this solution is available "out of the box". It is enough to add the suggestion to the values hidden in #theme or theme_hook_original in any rendering array (e.g. in hook_preprocess_HOOK) keeping the template naming convention.

As a result, the variable value set in this way

function my_module_preprocess_paragraph(array &$variables) {
  $paragraph = $variables['paragraph'];

  if ($paragraph->bundle() === 'my_awesome_bundle') {
    $variables['theme_hook_original'] = 'paragraph__my_custom_theme_suggestion';

records a suggestion for a given base template (paragraph), allowing you to create a template file named: paragraph-my-custom-theme-suggestion.html.twig Nevertheless, I would limit this solution to exceptional cases. For general use, I would recommend a hook dedicated for this purpose.

4. Safe filter replacement | raw

This filter is generally considered to be potentially dangerous (increases the possibility of successful XSS attacks) and is used in single cases. But it should be avoided as much as possible. I suggest looking for a better way, especially since one of them is extremely easy to use, as you will see in an example.

Let's assume that we have a field that is to finally display the image, but for some reason we would like to omit all the HTML code generated along the way.

The easiest way to do this is:

{{ content.field_my_image_field|render|striptags('')|trim }}

Experienced Drupal developers know that such a solution, instead of displaying an image on the page, will display the whole as plain text encoded into HTML entities. Yes, you can add a raw filter, but you can do it differently using Drupal's Render API with the #markup key:

{{ {'#markup': content.field_my_image_field|render|striptags('')|trim} }}

The method is perhaps a bit less readable than with the filter, but it is safe. HTML code will still be filtered here and only allowed safe tags will be passed through.

5. Referencing a template file from a different theme/module

If you haven't used Twig mechanisms such as include, embed or extend in your template files, I suggest to take the DRY rule into account in every aspect of programming (or web development in general). Themes are the places that suffer most from duplicate code, both in template files and in style sheets.

Many times I have encountered the entire template file was copied, e.g. from an inherited theme or a module, only to add some surrounding HTML code or modify a single template block. The same effect can be achieved by referring to a parent file using the aliases @module_name @theme_name. Suppose we have a template file (card) in our sample module named custom_card

  {% block card_header %}
  {% endblock %}
  {% block card_content %}

{{ content }}

{% endblock %} {% block card__footer %} {% endblock %}

And now in our theme, we would need to add some additional elements in the header block, e.g. an icon. The most common thing is to copy the entire template code, but this can be done more simply and without repeating the code:

{% extends '@custom_card/card.html.twig' %}

{% block header %}
{% endblock %}

6. View reloading using InvokeCommand

As you know, the Views module allows to create views that use AJAX technology. This is done to dynamically switch between the different pages of the view, but also to display the results of the response to value changes from the provided form. But what to do when the content of the view needs to be refreshed due to performing some action outside it, e.g. after sending a request to the controller from another block? Or to submit a form on the same page? Well, there are two very convenient functionalities available in the Drupal core.

The first one is the default RefreshView event registered on the view, which causes the view to be refreshed using AJAX (I recommend that you enter it in the browser console on your example view and observe the effect).

The second mechanism is InvokeCommand, which allows in the AJAX response to return the jQuery method call, along with the given parameters on the DOM element. Combined, this gives you this example code:

class MyCustomController extends ControllerBase {

   * Perform the update and refresh the view.
   * @return \Drupal\Core\Ajax\AjaxResponse
   *   Ajax response.
  public function doUpdateAndRefresh(): AjaxResponse {
    // Perform some sort of logic needed for your controller.

    // Refresh the view.
    $response = new AjaxResponse();
    $response->addCommand(new InvokeCommand('#my-view-block', 'trigger', ['RefreshView']));

    return $response;


In my example, there were forms for user approval inside the generated view. In response to the entry of such a form, I needed to display an updated list. As you can see, basically one extra line did all the magic without any extra effort.

7. Use of Drupal.debounce

For the very end I want to describe something which is not so much a trick as good practice. The Underscore.js library is bundled with Drupal core, but many developers do not use it at all. It includes a number of functionalities. One of the most common cases where the capabilities of this library are not used is the so-called deboucing, i.e. preventing multiple code execution in response to a given event - most often it is a change in the width of the browser window.

I have come across code many times that resembled:

function onResize(callback) {
  var timer;
  return function (event) {
    if (timer) {
    timer = setTimeout(callback,100, event);

$(window).resize(onResize(function(e) {
  // Resize implementation goes here.

Of course, this is an exemplary and the simplest implementation, and such code will execute correctly. The question is: why reinvent the wheel? Answer: to improve Drupal compatibility in the core of Drupal, and also to increase the convenience of work for developers - there is a debouncer port from the underscore library.

Just add a dependency to your library

- core/drupal.debounce

and add the following implementation in the JS code:

$(window).resize(Drupal.debounce(function () {
  // Resize implementation goes here.
}, 100));

Isn't it easier? And most importantly, we use something that has already been well written once.


Although I have come across a lot of interesting approaches to working with themes in our Drupal agency, it must be emphasized that many things come with experience. Especially novice developers should follow Drupal's philosophy from the very beginning. They should understand why they are doing something in a certain way. This allows us to see Drupal's capabilities more easily and learn to use them to increase the comfort and efficiency of work, without losing the cleanliness of the code.

Oct 01 2020
Oct 01

Creating groups of users with access to selected content is one of the frequent requirements set out in specifications for web portals. The Group module allows saving hundreds of programming hours by providing ready-made and easily extensible mechanisms. Check how many useful functions you can find in this module.

Group was created as an alternative to Organic Groups (OG), in which relationship mechanisms are based on fields and content. Created in the group module, on the other hand, were full-fledged entities with their own fields that can be extended and exported. Every group can have its own users or uniquely configured permissions.


The origins of the module date back to the Drupal 7 version, for which the first dev version was released in 2010. The Drupal 8 version of the module was first released in March 2016 and is still being developed today. The latest stable version 1.2. was released on 4 August 2020.

Module's popularity

The Group module is quite popular and is currently used by over 9,000 websites. The vast majority, about 8,200, are projects based on Drupal 8.

Module's creators

The main keeper of the module is Kristiaan Van den Eynde (kristiaanvandeneynde), responsible for almost 900 commits to the module. The module is financially supported by Factorial GmbH and has been supported by other companies and organisations in the past. Of course, the development of the module and its sub-modules is also supported by a large crowd of Drupal developers.

So far, 56 developers have contributed to the development of the module; the full list can be found here: https://www.drupal.org/node/711148/committers

What is the module used for?

The Group module solves a problem that cannot be solved in Drupal with the help of built-in mechanisms. It allows you to divide users into groups within which you can both manage user rights and create content dedicated only to the group members.

It is an extremely complex project from the programming point of view. It has several classes and functions that provide key functionalities like permission support, cache, or integration with Drupal's core modules. There is a gnode sub-module in the module's repository that allows you to create relationships between content and groups. The Group module can also be extended with the functionality of creating subgroups, and this is possible with the use of Subgroup or Subgroup (Graph) modules.

Examples of using it:

  • classroom management at schools, where teachers function as administrators, students are members of a given group, and they all have access to common materials,
  • access to paid content by limiting the accessibility of materials for group members (an example can be found in our article Drupal Commerce - Sell electronic products)
  • portals for organisations/communities with a hierarchical structure (several co-dependent units, but with different members and administrators)
  • organisation and management of conferences (registration for lectures, access to materials, discussions). Group is therefore a great tool when you need to create closed user groups with access to specific content.

The Group is therefore a great tool that we use as part of Drupal services to create closed groups of users with access to specific content.


You can download the module at https://www.drupal.org/project/group

After installation, a new group will appear in the Groups (/admin/group) menu between the Configuration and Users tabs in the main system menu.

Group provides a new type of entity, so in the submenu, you will find links to pages such as group types or list. It also has a configuration page, where it is possible to set an administration skin for group-editing, group users pages, etc.

The Group module does not require any specific configuration to be able to use it.

Module's use

In order to create groups, you must first define at least one group type. To do this, go to "/admin/group/types" and create a new group type. This process is similar to creating a new content type or a vocabulary, but also has additional configuration fields related to the permissions of users in given groups.

create groupe type

After creating the group type, you can configure the group fields, as well as the associated form and group display views.


In order to define the rights, you also have the option of going to the Permissions tab, under which you can define basic permissions broken down into:

  • anonymous users,
  • group members,
  • users not being group members 
  • group members with a defined role in the group

Available is also an advanced configuration of the permissions of a user from outside the group with the use of system roles.


It is possible to define roles for a given group type (similarly to the roles defined in the Drupal's core). It is possible to do it in the Roles tab:


One of the most important tabs is Content, where you can install available extensions for a group, and these include content types, group membership or subgroups (after installing the previously mentioned modules).

content 0

After going through all the forms, creating new groups of as given type becomes very simple. You just go to the group list page (/admin/group) and add the groups you need.


As you can see, there are quite a lot of configuration options, especially regarding module permissions. However, they are necessary for its proper operation and it is easy to appreciate their advantages during the use of the module. You can find a very interesting application of the Group module in the Open Social distribution.

Hooks and integrations

The module has the ability to modify links with entity operations embedded in a block on the group's website using the hook_group_operations_alter hook, which in its arguments accepts a table of links and a group object.

Group provides integration with the following modules:

  • Views, offering plug-ins such as: access, argument, default argument, relationship.
  • Tokens - 21 tokens for group and its contents.


The Group module is very mature and programmatically complex. It adds a mechanism for creating groups and their related content that you cannot find in a clean CMS Drupal installation. It was written with due care for the high quality of the code, while at the same time ensuring its easy extension with new functionalities. If this module fits the needs of your project, our Drupal consultants recommend to use it without hesitation.

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