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
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
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
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
.