Score:0

How to extend core block class SystemBrandingBlock

ph flag

Please advice how we can extend the core block class Drupal\system\Plugin\Block\SystemBrandingBlock to add custom method.

In my case, I want to include function buildToArray() to get the block data in array format rather than rendered array.

Existing build() method:

public function build() {
    $build = [];
    $site_config = $this->configFactory->get('system.site');

    $build['site_logo'] = [
      '#theme' => 'image',
      '#uri' => theme_get_setting('logo.url'),
      '#alt' => $this->t('Home'),
      '#access' => $this->configuration['use_site_logo'],
    ];

    $build['site_name'] = [
      '#markup' => $site_config->get('name'),
      '#access' => $this->configuration['use_site_name'],
    ];

    $build['site_slogan'] = [
      '#markup' => $site_config->get('slogan'),
      '#access' => $this->configuration['use_site_slogan'],
    ];

    return $build;
}

Required method to add:

public function buildToArray() {
    $site_config = $this->configFactory->get('system.site');

    return [
      'site_logo' => theme_get_setting('logo.url'),
      'site_name' => $site_config->get('name'),
      'site_slogan' => $this->configuration['use_site_slogan'],
    ];
}
in flag
Hello, and welcome to Drupal Answers! Could you please describe what you've tried, what hasn't worked, and post any relevant code?
ph flag
@Beau Thank you for your comment. I have updated the question to more specific.
Score:0
in flag

Extending a Block

To extend the block, you'll define a new block, as described in the following tutorial, except that you would extend the class Drupal\system\Plugin\Block\SystemBrandingBlock, instead of the class Drupal\Core\Block\BlockBase. You can then add your custom method to the newly defined block.

https://www.valuebound.com/resources/blog/drupal-8-how-to-create-a-custom-block-programatically

Alternative consideration

If what you need from SystemBrandingBlock is just the data, and not necessarily an actual block, I would advise to instead define a service that provides the data from your buildToArray() method.

Comment Responses

It is true that this will create a new block type, in addition to the SystemBrandingBlock. Blocks are managed, organized and retrieved by the Block Plugin Manager. You could write a decorator for this service and override the getDefinitions() method in order to prevent the original SystemBrandingBlock from being available as a plugin definition, achieving the effect of replacing the original SystemBrandingBlock with your new block.

It still sounds to me like a service is what you need. By examining the code in the original SystemBrandingBlock class definition, we see that SystemBrandingBlock only relies on one service, config.factory. So your service only needs to inject the config.factory service in order to retrieve the information that you need for the buildToArray() method (which might be better renamed as something like getBrandingInfo()). Defining a service in this way means that you won't need to worry about implementing or deploying a block (which doesn't seem to be what you need, anyway), or needing to write a service decorator.

Bear in mind, also, that the SystemBrandingBlock is not the original source of the data, but rather a plugin for displaying those data in a rendered format. The block is completely irrelevant if all you want are the data.

Finally, speaking in broader terms, Drupal is organized largely around plugins, services and dependency injection, and becoming familiar with these concepts will give you the tools to systematically solve many problems in Drupal.

ph flag
Thank you for your suggestions.
ph flag
I want to extend all available blocks. The first approach "Extending a block" leads to blocks duplication. The second approach "From service" I could not access the protected properties of the block so I have to implement that block logic in the service.
ph flag
you answer gave me another perspective. Thanks
ph flag
As far as I understand, we can override the blocks by hook_block_alter and plugin decorator. I'm clear about the hook. Can you please give an example about plugin decorator for the block. It will help for many since there is no proper documentation about plugin decorator.
in flag
In Drupal, all plugin types are managed by a plugin manager, which is a service. A plugin decorator is really a service decorator for a plugin manager. Here is a great tutorial on Drupal 8 service decorators: https://www.phase2technology.com/blog/using-symfony-service-decorators-drupal-8. In your case, you'll want to decorate the service whose ID is `plugin.manager.block`. But I still feel that a custom service of your own is what you really need, and will require less work.
ph flag
Thank you @Beau
Score:0
gb flag

If you are using Drupal 9 and don't want to create a block duplication here is the simplest way to override a block class: To override Block class you can use hook_block_alter like this.

/**
 * Implements hook_block_alter().
 */
function [MODULE]_block_alter(&$definitions) {
  foreach ($definitions as $id => $definition) {
    // Check on your plugin Id here.
    if ($id === 'system_branding_block') {
      // Set your new class here.
      $definitions[$id]['class'] = 'Drupal\MODULE\Plugin\Block\SystemBrandingBlockAlter';
    }
  }
}

And then create your new class SystemBrandingBlockAlter in MODULE/src/Plugin/Block like this:

<?php

namespace Drupal\MODULE\Plugin\Block;

use Drupal\system\Plugin\Block\SystemBrandingBlock;

class  SystemBrandingBlockAlter extends SystemBrandingBlock {
  
  public function build() {
    $site_config = $this->configFactory->get('system.site');
    return [
      'site_logo'   => theme_get_setting('logo.url'),
      'site_name'   => $site_config->get('name'),
      'site_slogan' => $this->configuration['use_site_slogan'],
    ];
  }
  
}

Now the responsible class for your block is Drupal\MODULE\Plugin\Block\SystemBrandingBlockAlter and not Drupal\system\Plugin\Block\SystemBrandingBlock

ph flag
Thank you so much. This is exactly what I'm looking for.
ph flag
In definitions array, we can see 'provider' => 'system' but we'll override the block class from our custom module. Will it make any impact?
berramou avatar
gb flag
if you check of `'provider' == 'system'` you will override all classes of blocks created by system module not only SystemBrandingBlock
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.