How to make a title block with a custom background
March 18, 2018•667 words
How to make a title block with a custom background
drupal
A common request I’ve received lately when building sites in Drupal is to make the background of the page title configurable to allow the user upload and change it.
Of course, this could be solved with a new block type with two fields, one for the image and one for the title. But then we would need to add the block for each page where we want to show the title.
How does Drupal handle page titles? Looking in the block admin page, I found that actually it is a block. Well, we need the same functionality of that block in our new one.
So looking for the class that contains the block machine name page_title_block I found Drupal\Core\Block\Plugin\Block\PageTitleBlock
which implements TitleBlockPluginInterface
. This is all the interface:
php
interface TitleBlockPluginInterface extends BlockPluginInterface {
/**
- Sets the title.
*
- @param string|array $title
- The page title: either a string for plain titles or a render array for
- formatted titles.
*/
public function setTitle($title);
}
Searching what uses that interface, I found that `BlockPageVariant` uses it to assign it a title:
``` php
foreach ($this->blockRepository->getVisibleBlocksPerRegion($cacheable_metadata_list) as $region => $blocks) {
/** @var $blocks \Drupal\block\BlockInterface[] */
foreach ($blocks as $key => $block) {
$block_plugin = $block->getPlugin();
if ($block_plugin instanceof MainContentBlockPluginInterface) {
$block_plugin->setMainContent($this->mainContent);
$main_content_block_displayed = TRUE;
}
elseif ($block_plugin instanceof TitleBlockPluginInterface) {
$block_plugin->setTitle($this->title);
}
//...
This means that if I create a custom block that implements TitleBlockPluginInterface
I will get the page title automatically (thanks to BlockPageVariant
)? Apparently, yes.
Lets start writing the custom block extending PageTitleBlock
to use the title field implementation:
php
/**
- @Block(
- id = "myimagetitleblock",
- adminlabel = "Image title block"
- )
*/
class ImageTitleBlock extends PageTitleBlock {
/**
- The image field.
*
- @var mixed
*/
protected $image;
public function defaultConfiguration() {
return [
'image' => [
'value' => '',
],
'label_display' => FALSE,
] + parent::defaultConfiguration();
}
/**
- {@inheritdoc}
*/
public function build() {
$build = [];
if (isset($this->configuration['image'])
&& !empty($this->configuration['image'])) {
$imagefield = $this->configuration['image'];
$imageuri = File::load($image_field[0]);
$build['image'] = [
'uri' => ImageStyle::load('titlebar')->buildUrl($imageuri->getFileUri()),
];
} else {
$build['image']['#markup'] = '[' . t('Picture') . ']';
}
return $build + parent::build();
}
/**
- {@inheritdoc}
*/
public function blockForm($form, FormStateInterface $form_state) {
$form['image'] = array(
'#type' => 'managedfile',
'#uploadlocation' => 'public://images/',
'#title' => $this->t('Image'),
'#description' => $this->t("Background image"),
'#defaultvalue' => $this->configuration['image'],
'#uploadvalidators' => array(
'filevalidateextensions' => array('gif png jpg jpeg'),
'filevalidatesize' => array(25600000),
),
'#states' => array(
'visible' => array(
':input[name="image_type"]' => array('value' => t('Upload New Image')),
)
)
);
return $form;
}
public function validateConfigurationForm(array &$form, FormStateInterface $formstate) {
if (!$formstate->getValue('image')) {
$form_state->setError($form['image'], $this->t('Select an image'));
}
}
/**
- {@inheritdoc}
/
public function blockSubmit($form, FormStateInterface $form_state) {
/ Fetch the array of the file stored temporarily in database */
$image = $form_state->getValue('image');
$this->configuration['image'] = $image;
/* Load the object of the file by it's fid */
$file = \Drupal\file\Entity\File::load($image[0]);
/* Set the status flag permanent of the file object */
$file->setPermanent();
/* Save the file in database */
$file->save();
}
}
After clearing Drupal cache, you will find your new shiny block waiting for you in the _Add block_ list. The build method returns the processed image URL (using _title_bar_ style) instead of the render array for an image so we can use it later.
Let’s create _title_bar_ image style and configure it accordingly (in my case, resize and crop to a predefined size will do).
![](https://i.snap.as/ewM5PVG.png)
Then, update your theme to make sure that image url shows in a `style` attribute, or a `data-*` if you’re using javascript to load the image.
_block—image-title-block.html.twig_
``` twig
<div{{ attributes.setAttribute('style',
'background: #787c8a url(' ~ content.image.uri ~ ') no-repeat center;') }}>
{{ title_prefix }}
{% if label %}
<h2{{ title_attributes }}>{{ label }}</h2>
{% endif %}
{{ title_suffix }}
{% block content %}
{{ content }}
{% endblock %}
</div>
...
Lets test it!