Post

Drupal Cheatsheet

Drupal website install and configuration guide.

Lots of parts to building a Drupal site. Installing core, Modules and Themes. This article is documentation for setting up some powerful drupal modules and build an awesome drupal site.

Drupal permission

when configuring a specific role. Allowing the correct permissions can be difficult as their are so many permissions.

allow permissions for custom blocks

/admin/people/permissions

edit permissions for content editors /admin/people/permissions/content_editor

  • best to search for the block name. then allow permissions this way. custom blocks often require every permission to be switched on for roles like content editors.

Drupal Settings.php file

Set the config sync directory. This will allow drush updatedb to sync your site configuration to the database. Note: for a composer installed drupal site you will have 2 settings.php files. The settings.php file you want to update is located in the web directory. You can rename the other settings.php to be settings_backup.php

1
$settings['config_sync_directory'] = '../config/sync';

Essential Modules and themes

When creating pretty basic stock standard website. This is modules I must have and This is what I use these modules for.

Pathauto module

Automatically change the urls to be prettier https://www.drupal.org/project/pathauto

1
composer require 'drupal/pathauto:^1.13'

Linkit Module

Break up links into 2 parts. The URL and the label.

https://www.drupal.org/project/linkit

Dev version for drupal 11

1
composer require 'drupal/linkit:^6.1'

Media Library (core module)

Use existing images in media library Ensure fields are set to media rather then image.

MicroContent module

For creating global blocks

Works with drupal 11 https://www.drupal.org/project/microcontent

1
composer require 'drupal/microcontent:^2.0'

Entity Reference Display Module

Configure the display of Referenced entities

Not yet ready for D11

entity Reference display

1
composer require 'drupal/entity_reference_display:^2.0'

Paragraphs

For creating flexible / movable / resusable global blocks. Pair it with Microcontent.

1
composer require 'drupal/paragraphs:^1.18'

https://www.drupal.org/project/paragraphs/

Block field

Reference blocks created with views from the paragraphs modules

There is only a development version of this module which is not ready for Drupal 11

reference a block from a paragraph field

Development for D11 underway

block field

1
composer require 'drupal/block_field:^1.0@RC'

https://www.drupal.org/project/block_field

Backup and Migrate Module

Not ready for Drupal 11

1
composer require 'drupal/backup_migrate:^5.0'

Better Exposed Filters Module

The Better Exposed Filters module replaces the Views’ default single- or multi-select boxes with radio buttons or checkboxes, respectively. Description fields and Select All/None links can be added to exposed filters to make for a better user experience.

Dev version for Drupal 11

1
composer require 'drupal/better_exposed_filters:^7.0@beta'

https://www.drupal.org/project/better_exposed_filters

Metatag Module

  • Set certain content types to no index
  • Set individual pages to no index
  • Add seo meta tags to content

https://www.drupal.org/project/metatag

Works with Drupal 11

1
composer require 'drupal/metatag:^2.0'

Current Page Breadcrumbs Module

Breadcrumbs are native to drupal, however we need the current page Breadcrumb to display

No D11 version

1
composer require 'drupal/current_page_crumb:^1.5'

For a more advanced module that is compadible with D11.

Easy breadcrumb Module

1
composer require 'drupal/easy_breadcrumb:^2.0'

Mega Menu Module

Not compadible with D11

1
https://www.drupal.org/project/simple_megamenu

Antibot Module

Prevent forms from being submitted without JavaScript enabled

No version for drupal 11

1
composer require 'drupal/antibot:^2.0'

reCAPTCHA v3 Module

antispam

Webforms and Webforms UI Modules

forms

Bootstrap5 Themes

1
composer require 'drupal/bootstrap5:^4.0'

Preprocess Functions

Preprocess functions are used to modify variables before they are used in the template. This allows developers to customize the output of a page without having to modify the template itself. Preprocess functions are used to add, remove, or alter variables that are used in the template.

Preprocess functions are typically used when you need to modify the variables that are used in the template. For example, if you need to add a custom variable to the template, you can use a preprocess function to do so.

Where to add these functions

themename.theme

Overview

  • preprocess functions are optional - if they can be used they will be if not they will be skipped
  • preprocess functions are Specific to a template (hook) based on naming convention
  • preprocess functions always has 1 param

When to use Preprocess functions

  • Use a preprocess function to alter/remove or add variables
  • Make small alterations to the html output
  • Any logic that is more complex then a simple if / else file consider refactoring into a preprocess function to keep template files nice and clean.

Naming Convention

function THEME_preprocess_H00K()

  • HOOK is the name of the template your preprocessing variables for

The easiest way to determine what hook to use is to enable twig debug mode

Example

1
2
3
4
5
function THEMENAME_preprocess_node(&$variables) {
   $variables['simple_string'] = array(
   '#markup' => 'a simple_string'
   );
}
1
2
3
<div class = "string">
   {{simple_string}}
</div>

** Example - Add suffix to post author lable if logged in **

1
2
3
4
5
function THEMENAME_preprocess_node(&$variables) {
   if($variables['logged_in'] == TRUE && $variables['node']->getOwnerId() == $variables['user']->id()) {
      $variables['label']['#suffix'] = '-you are the author';
   }
}

** Example - Add new variable to template **

Use twig dump function to see the new variable added to the template

1
2
3
4
5
6
7
8
function THEMENAME_preprocess_node(&$variables) {
   $variables['current_user_is_owner'] = FALSE;

   if($variables['logged_in'] == TRUE && $variables['node']->getOwnerId() == $variables['user']->id()) {
      $variables['label']['#suffix'] = '-you are the author';
      $variables['current_user_is_owner'] = TRUE;
      }
}

Function Naming Conventions

Function THEME_preprocess_HOOK()

1
2
**example**
function bartik_preprocess_page()

** More specific targeting example **

1
2
3
THEMENAME_preprocess_node__42(): This is the most specific version and will only be called for a node with an ID of 42.
THEMENAME_preprocess_node__article(): This would be called for any article node, but not for other node types.
THEMENAME_preprocess_node(): This will be called for all nodes.
  • The hook refers to the base name of the template file
  • Use Twig Debug to find the hook name for the template file

You can ommit the hook part and add hook as param instead, for adding a variable to every template file - warning this will be called alot

Prepocess Examples

Inject var into every template

1
2
function THEMENAME_preprocess(&$variables, $hook)

Dynamically add layout class to a field

Based on a boolean value which is set in the paragraph block.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function THEME_preprocess_paragraph(&$variables) {
  // Get the paragraph type.
  $paragraph_type = $variables['paragraph']->bundle();

  if ($paragraph_type === 'cards') {
    // Add a class to the paragraph's attributes.
    $variables['attributes']['class'][] = 'container cards__wrapper';

    //dynamically add layout class to cards to set the layout
    // Access the boolean field value.
    $boolean_value = $variables['paragraph']->get('field_brand')->value;

    // Add a variable for use in the Twig template.
    $variables['is_active'] = (bool) $boolean_value;

    // Optionally, add logic based on the value.
    if ($boolean_value) {
      if (isset($variables['content']['field_card_micro_content'])) {
        // Add a custom CSS class to the field wrapper.
        $variables['content']['field_card_micro_content']['#attributes']['class'][] = 'row-cols-2';
      }
    } else {
      if (isset($variables['content']['field_card_micro_content'])) {
        // Add a custom CSS class to the field wrapper.
        $variables['content']['field_card_micro_content']['#attributes']['class'][] = 'row-cols-4';
      }
    }
  }
  }

Extensive example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
function DERO_preprocess_field(&$variables) {

  /**
   * title 1 for edge advantage
   */
    if ($variables['element']['#field_name'] == 'field_dero_edge_title_1') {
      // Pass a flag or tag type to the template.
      $variables['custom_tag'] = 'h3';
      $variables['attributes']['class'][] = 'edge-advantage__title';
    }

  /**
   * title 2 for edge advantage
   */
  if ($variables['element']['#field_name'] == 'field_dero_edge_title_2') {
    // Pass a flag or tag type to the template.
    $variables['custom_tag'] = 'h3';
    $variables['attributes']['class'][] = 'edge-advantage__title';
  }

  /**
   * title 3 for edge advantage
   */
  if ($variables['element']['#field_name'] == 'field_dero_edge_title_3') {
    // Pass a flag or tag type to the template.
    $variables['custom_tag'] = 'h3';
    $variables['attributes']['class'][] = 'edge-advantage__title';
  }

  // Add a custom CSS class to edge_text field
  if ($variables['element']['#field_name'] == 'field_dero_edge_text_1') {
    $variables['attributes']['class'][] = 'edge-advantage__text';
  }

  if ($variables['element']['#field_name'] == 'field_dero_edge_text_2') {
    $variables['attributes']['class'][] = 'edge-advantage__text';
  }

  if ($variables['element']['#field_name'] == 'field_dero_edge_text_3') {
    $variables['attributes']['class'][] = 'edge-advantage__text';
  }
}

//More efficient way to add classes to fields

function DERO_preprocess_field(&$variables) {
  // Define a mapping of field names to CSS classes.
  $field_class_map = [
    'field_stat_number_1' => 'stats__number',
    'field_stat_number_2' => 'stats__number',
  ];

  // Check if the current field is in the map and apply the corresponding class.
  $field_name = $variables['element']['#field_name'];
  if (isset($field_class_map[$field_name])) {
    $variables['attributes']['class'][] = $field_class_map[$field_name];
  }
}

//Target paragraphs on a page

function THEMENAME_preprocess_paragraph(&$variables) {

  /**
   * Implements hook_preprocess_paragraph().
   */
    // Get the paragraph type.
    $paragraph_type = $variables['paragraph']->bundle();

    // Add a CSS class based on paragraph type.
    if ($paragraph_type === 'stats') {
      // Add a class to the paragraph's attributes.
      $variables['attributes']['class'][] = 'container stats__wrapper';
    }

    // Add a class based on specific conditions.
    if ($paragraph_type === 'image_block' && $variables['paragraph']->id() == 123) {
      $variables['attributes']['class'][] = 'special-image-block-class';
    }
}

More info

more

CKEditor 5

It’s in core by default and enabled on all long formatted text fields. CKEditor allows you to set heading tags as h2 or h3 rather then thew default div.

This post is licensed under CC BY 4.0 by the author.