Don’t forget to subscribe to our YouTube channel to stay up-to-date.
Video sections:
- 01:39 Discuss bugs from last live stream
- 09:37 Create custom module for layouts
- 19:33 Review layout code
- 22:04 Start creating custom layout
- 25:37 Create layout plugin class
- 28:00 Create twig template for layout
- 31:46 Install custom module
- 33:46 Delete inline block template (no longer needed)
- 37:36 Discuss what needs to be implemented in new layout
- 39:05 Implement custom code in new layout
- 42:49 Debug build method in layout class
- 47:53 Override the build method in layout class to add custom classes
- 54:08 Review Bootstrap 4 grid system and necessary classes
- 57:37 Create custom method to determine grid width
- 1:03:04 Fix “Add block” button
- 1:11:15 Discuss implementing carousel
- 1:14:55 Discuss bug with Paragraphs module and block types
- 1:17:43 Create Carousel block type
- 1:22:12 Download Inline Entity Form
- 1:23:14 Create Carousel item block type
- 1:25:21 Create Carousel items field
- 1:27:20 Configure the Inline Entity Form widget
- 1:33:25 Start implementing Bootstrap carousel markup
- 1:34:27 Create new carousel layout
- 1:42:16 Customize Carousel item entity
- 1:52:14 Implement preprocess function
- 2:05:31 Implement markup changes in Twig
- 2:16:49 Change image style size
- 2:19:52 Create carousel Sass file
- 2:23:30 Discuss next live streams
Series:
- Drupal Live Site Build (Part 1) – Project Set Up, Build Bootstrap Card Component using Layout Builder
- Drupal Live Site Build (Part 2) – Create Layout Builder Section, Bootstrap Carousel
- Drupal Live Site Build (Part 3) – Create Bootstrap Grid using Views and Display Related Content
In the show notes below, I outline what we implement in part 2 of the Drupal live site build. We start off by fixing a few bugs, which I introduced and didn’t notice until I started playing around with the site after the first video. For example, we couldn’t drag-and-drop any of the card components because I overrode the inline-block template.
Part 2 (this video) is a little more advanced because we create a custom module, implement two layouts and implement a hook_preprocess_HOOK
.
So we start off by creating a Row layout which fixes the bug from part 1 and we implement the Bootstrap Carousel component (clients love carousels) using block types.
Get a copy of the built site from GitHub.
New Row Layout
To fix a few bugs created in the previous video, I decided we needed to create a custom layout. This layout would be called BS Row and it’ll be used as a section in layout builder.
Create Custom Module
Go ahead and create a custom module called ww_bootstrap4_layouts
.
If you use Drush, just run the following command and fill in the prompts.
drush generate module
NOTE: The generate command only works in Drush 9 and up.
Or, you can do it the old fashion way.
1. Create a folder in modules/custom/ww_bootstrap_layouts
.
2. Create a ww_bootstrap4_layouts.info.yml
file and add the following into it:
name: WW Bootstrap4 layouts type: module description: Bootstrap4 layouts package: WebWash core: 8.x core_version_requirement: ^8 || ^9
3. Create a ww_bootstrap4_layouts.module
file. This file is not required in Drupal 8 and above, but we’ll need it for later.
Create Row Layout
The Row layout will allow users to add any blocks into 1 to 4 columns using layout builder. The layout is not something specific for the Card component.
1. Create a ww_bootstrap4_layouts.layouts.yml
. In this file you define your custom layouts. Add the following into it:
bs_row: label: 'BS row' path: layouts/bs_row template: layout--bs-row class: 'Drupalww_bootstrap4_layoutsPluginLayoutBsRowLayout' category: 'WW Bootstrap4' default_region: content icon_map: - [content] regions: content: label: Content
2. Create the following file in the module layouts/bs_row/layout--bs-row.html.twig
. You’ll need to create a layouts
and bs_row
directory.
Add the following Twig code:
{% if content %} <div{{ attributes }}> {% if content.content %} <div {{ region_attributes.content.addClass('layout__region', 'layout__region--content', 'row') }}> {{ content.content }} </div> {% endif %} </div> {% endif %}
3. Create a file called BsRowLayout.php
at the path src/Plugin/Layout
. Add the following:
<?php namespace Drupalww_bootstrap4_layoutsPluginLayout; use Drupallayout_builderPluginLayoutMultiWidthLayoutBase; /** * Configurable Bootstrap4 row layout plugin class. * * @internal * Plugin classes are internal. */ class BsRowLayout extends MultiWidthLayoutBase { /** * {@inheritdoc} */ protected function getWidthOptions() { return [ '1-col' => '1 column', '2-col' => '2 column', '3-col' => '3 column', '4-col' => '4 column', ]; } public function build(array $regions) { foreach ($this->getPluginDefinition()->getRegionNames() as $region_name) { if (array_key_exists($region_name, $regions)) { foreach ($regions[$region_name] as $uuid => $block) { $regions[$region_name][$uuid]['#attributes']['class'][] = $this->getColumnWidth(); } } } return parent::build($regions); } protected function getColumnWidth() { $col = [ '1-col' => 'col-lg-12 mb-4', '2-col' => 'col-lg-6 mb-4', '3-col' => 'col-lg-4 mb-4', '4-col' => 'col-lg-3 mb-4', ]; return $col[$this->configuration['column_widths']]; } }
The getWidthOptions()
method is used to populate the get “Column widths” drop-down when you configure a section.
The getColumnWidth()
method is used to determine the Bootstrap column widths depending on the selection from the drop-down. The returned value from this method is just a Bootstrap class.
Then we override the build()
method to add the classes to the inline blocks.
Use new Row Layout
Go and edit a layout and click on “Add section” and you should see the “BS Row” layout on the right.
Select the column option then click on “Add section”.
Then any block added into the section will be displayed as the selected column width.
Fix “Add block” Button
You’ll notice that the “Add block” button in the section isn’t displayed full width. It’s floated to the left or right. Let’s fix that now.
What we need to do is add a column 12 style to the button so it always displays full width. We’ll add the 12 column grid style using Sass.
Bootstrap allows you to apply grid styles via Sass Mixins.
1. Create a file in scss/custom/row/_row.scss
in the sub-theme. Add the following into it:
.layout-builder__section { .layout-builder__add-block { @include make-col-ready(); @include make-col(12); } }
2. Then add the @import 'custom/row/row';
into scss/style.scss
. So it gets compiled.
The button should go from this:
To this:
Create Carousel Component
We’re going to implement the Bootstrap Carousel using two custom block types.
We’ll need to create two block types: Carousel and Carousel item. The Carousel block type will have an entity reference field, referencing the Carousel item.
The Carousel item block type will have a Caption, Image and Title field.
Implement Carousel Item Block Type
First, let’s go and implement the Carousel item block type.
1. Go to Structure, “Block layout”, “Custom block library”, “Block types” and click on “Add custom block type”.
2. Enter in Carousel item as the label and click on Save.
3. Go and create the three following fields:
- Caption (field_caption) Text (plain, long)
- Image (field_image) Media
Under “Media type” select Image - Title (field_title) Text (plain)
4. On the “Manage form display” reorder the widgets like so:
Customize Carousel Item Formatters
Now we need to customize the markup that Drupal outputs so it matches the Bootstrap carousel markup. We’ll stick with using a combination of a Field group element and Display Suite for this.
1. Go to “Manage display” on the Carousel item, scroll down to “Layout for carousel item in default” and select “Reset layout”.
2. Click on “Add field group” and select “HTML element” and enter Caption into Label.
3. Add carousel-caption d-none d-md-block
into “Extra CSS classes”.
4. Add the field group below Image and indent Title and Caption under the field group.
5. For the Image field make sure you select “Rendered entity” as the formatter. Click on the cog-wheel and select Bare as the View mode and “Full reset” as the field template.
6. Click on the Title cog-wheel and select Expert as the field template and set h5
as the element on the “Field item”.
7. Click on the Caption field cog-wheel and set the field template to Expert and set p
as the element on the “Field item”.
Implement Carousel Block Type
Now let’s go ahead and implement the Carousel block type.
1. Go to Structure, “Block layout”, “Custom block library”, “Block types” and click on “Add custom block type”. Enter in Carousel as the label and click on Save.
2. Click on “Add field”, select Content under Reference from “Add a new field”, and enter in Carousel items as the label.
3. On the field settings page select “Carousel item” from the “Custom block type” checkboxes.
4. We’ll use the Inline entity form module to allow an editor to create carousel items when they add the carousel block using layout builder.
Download and install Inline entity form.
composer require drupal/inline_entity_form
5. Once the above module is installed, go to “Manage form display” on the Carousel block type and select “Inline entity form – Complex” as the widget.
6. Click on the widget cog-wheel and change the labels, Item for singular and Items for plural. And make sure only “Allow users to add new items” is checked.
Then click Update.
At this point, we’ve done all the site building, now we need to roll up our sleeves and write a bit of code.
Create Carousel Layout
To implement the required markup we’ll create a custom layout called “BS carousel”. We’ll add this layout to the existing ww_bootstrap4_layouts
module.
1. Open ww_bootstrap4_layouts.layouts.yml
and define the new layout:
bs_carousel: label: 'BS carousel' path: layouts/bs_carousel template: layout--bs-carousel category: 'WW Bootstrap4' default_region: content icon_map: - [content] regions: content: label: Content
2. Create the layout template at the path, layouts/bs_carousel/layout--bs-carousel.html.twig
{% if content %} <div{{ attributes }}> {% if content.content %} <div {{ region_attributes.content.addClass('layout__region', 'layout__region--content') }}> <div id="carousel--{{ carousel_id }}" class="carousel slide" data-ride="carousel"> <ol class="carousel-indicators"> {% for item in items %} <li data-target="#carousel--{{ carousel_id }}" data-slide-to="{{ loop.index0 }}" class="{{ loop.first ? 'active' }}"></li> {% endfor %} </ol> <div class="carousel-inner"> {% for item in items %} <div class="carousel-item {{ loop.first ? 'active' }}"> {{ item }} </div> {% endfor %} </div> <a class="carousel-control-prev" href="#carousel--{{ carousel_id }}" role="button" data-slide="prev"> <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="sr-only">Previous</span> </a> <a class="carousel-control-next" href="#carousel--{{ carousel_id }}" role="button" data-slide="next"> <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="sr-only">Next</span> </a> </div> {{ content.content|without('field_carousel_items') }} </div> {% endif %} </div> {% endif %}
3. Open up ww_bootstrap4_layouts.module
and add the following preprocess function:
function ww_bootstrap4_layouts_preprocess_layout__bs_carousel(&$variables) { if ($variables['content']['#entity'] instanceof Drupalblock_contentEntityBlockContent) { /** @var Drupalblock_contentEntityBlockContent $block */ $block = $variables['content']['#entity']; if (!$block->get('field_carousel_items')->isEmpty()) { $carousel_items = $block->get('field_carousel_items')->referencedEntities(); foreach($carousel_items as $item) { $view_builder = Drupal::entityTypeManager()->getViewBuilder($item->getEntityTypeId()); $variables['items'][] = $view_builder->view($item);; } } $variables['carousel_id'] = $block->id(); } }
4. Jump back into the “Manage display” on the carousel block type and select “BS carousel”.
Change Large Image Style
For the image in the carousel to look good we need to change the “Large (480×480)”. Go to Configuration, “Image styles” and edit “Large (480×480)”.
Change the scale to 1920×1080.
Add Carousel Sass
Create a sass file in the sub-theme, scss/custom/carousel/_carousel.scss
and add the following:
.carousel-item { img{ @extend .img-fluid; } }
This will make the image responsive.
Don’t forget to add @import 'custom/carousel/carousel';
into style.scss
and recompile.
Create Carousel
1. Go edit a layout and click on “Add section”
2. Select “BS row” and select 1 column.
3. Click on “Add block” and “Create custom block”, then Carousel.
4. Enter in the carousel items then click on “Add block”. If everything has been configured you should see a carousel.
Summary
This video was a little more advanced than the previous one. We implemented two custom layouts, Row and Carousel. I’m happy with the Row layout because we can reuse it with any type of block, not just a card block.
Thank you for the notes. The first part I have implemented.
A small change I had to add on ” 2. Then add the @import ‘custom/row/_row’; into scss/style.scss.” as it has to load _row.
Hi Bruno,
You normally don’t have to add “_row”. Here’s a link to the actual code, https://github.com/WebWash/drupal-bootstrap-live-demo-site/blob/bd0a5c7422cc20f2b1cdefe99daf3da12b982b71/web/themes/custom/ww_bootstrap4/scss/style.scss#L12
Not sure why it’s not working for you.
I am loving these, thank you!
Also how good is LANDO! I have continued to use it for this one and even configured xdebug following here https://docs.lando.dev/guides/lando-with-vscode.html (then lando rebuild, install xdebug helper in browser).
I had to go back and do a few things I missed in the video and not mentioned in the notes to get the bs_rows in the layout working.
Remove the old themes/ww_bootstrap4/templates folder.
Install the new module before we can use it.
Remove the previous layout sections from the last video.
Will tackle the carousel part of the video soon and give some feedback if I have any.