Skip to main content

Creating a Block in Drupal 10 Programmatically

Drupal's great feature is Custom Block. blocks are easy and fast to set in any region, with Drupal9 you can even set the same block in a few regions.

There are a few technical options to create a block, here we will overview the programming option only.

so, what is a block?

Blocks are chunks of content with ID and classes which can be placed in manipulated within the page. 

Blocks can contain simple text, forms, or some complex logic. The Block module is a core module since Drupal 8 and simply needs to be enabled to get it to work. Sometimes, installing other core or contributed modules can automatically enable them too.

 

Although these blocks can be modified to suit the layout, complete flexibility and customization can only be achieved with custom blocks. You can create a custom block programmatically or via the Drupal Interface. Here, we will be creating a block programmatically and enabling it through the admin interface.

Here are a few steps to create your first block:

Step 1: select your module and create structure inside it

the structure should include the following folders: src > Plugin > Block

the folder 'src' is just under the module folder

 

step 2: create PHP class / drupal block class

Create the drupal block class file.

the file should include the following PHP instructions:

a) namespace:  namespace Drupal\<modue_name>\Plugin\Block;
b) drupal library:  use Drupal\Core\Block\BlockBase;

drupal framework (not like PHP) is using the class documentation and search metadata for its implementation:

/**
 * Provides a 'UserData' Block.
 *
 * @Block(
 *   id = "complex_user_data_block",
 *   admin_label = @Translation("Complex User Data"),
 *   category = @Translation("ComplexMng"),
 * )
 */

The annotation should contain: 

  • id: should be a unique, machine-readable 
  • admin_label: defines the human-readable name which will be displayed in the admin interface.  
  • category: defines a category for the block, helpful when you search it under the admin interface

read more about annotations at drupal.org: https://www.drupal.org/docs/drupal-apis/plugin-api/annotations-based-plugins

 

Step 3 - Implement the block content

create method: build, that returns an HTML string

    /**
     * {@inheritDoc}
     */
    public function build() {
        $markup = '';
        $markup .= '<div>';
        $markup .= '    <p>Anything can come here: code, variables, html, etc.  </p>' ;
        $markup .= '</div>';
        return [
            '#type' => 'markup',
            '#markup' => $markup,
        ];
    }

if you need to create the block from customize form just do:

$build = \Drupal::formBuilder()->getForm(CustomForm::class);

return $build

 

Step 4 - Set Block in the site structure

After uploading your custom module, browse to '/admin/config/development/performance'  and clear all cache.

Browse to your Block Layout at: '/admin/structure/block', and set the block on your desired region.

Setting the block with category (step 2) will help you to find your block within the custom block list.

You can also configure the block as desired. save Block Layout and see the block as a user

 

Methods used in the class created for custom blocks

  • build(): This method will render a render-able array. In this example, a simple markup is returned. Even the complex contents like forms and views can also be returned.
  • blockAccess() :  This method defines a custom user access logic.

methods of custom block

                       • The AccessResult class is called here. 
                       • The method allowedIfHasPermission() checks if the current user has permission to view this content or not.
 

  • blockForm(): This method allows to define of a block configuration form. 

custom block in drupal 8 module

 

  • blockSubmit(): This method is used to save the configuration defined in the previous method blockForm(). 

    custom block in drupal 8

     

  • blockValidate(): This method validates the configuration form of the block. 

    custom block in drupal 8

     

Using Twig templates with custom blocks

If desire, you can also add a template for this customize block even though it is not a must.

Use '#theme' in the render array in the build method and pass the variables on the same level as the '#theme' - '#varname'.

  /**
   * {@inheritdoc}
   */
  public function build() {
    return [
      '#theme' => 'hello_block',
      '#data' => ['age' => '31', 'DOB' => '2 May 2000'],
    ];
  }

 

Add a hook_theme in your .module file. 
Note: Do not name the theming function like 'block__...'. This will not pass any variables down to the twig templates. Instead, you might use the module name as a prefix.

/**
 * Implements hook_theme().
 */
function mymodule_theme() {
  return [
    'hello_block' => [
      'variables' => [
        'data' => [],
      ],
    ],
  ];
}

Create template and place it under folder 'templates', template file: templates/mymodule-block.html.twig

{% for key,value in data %}
  <strong>{{ key }}:</strong> {{ value }}<br>
{% endfor%}
namespace Drupal\my_module\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\UncacheableDependencyTrait;

/**
 * Provides a 'SetTask' Block.
 *
 * @Block(
 *   id = "dashboard_newtask_block",
 *   admin_label = @Translation("Dashboard New Task"),
 *   category = @Translation("DrupalVIP"),
 * )
 */
class NewTaskBlock extends BlockBase implements BlockPluginInterface {
    use UncacheableDependencyTrait;
    
    /**
    * {@inheritdoc}
    */
    public function build() {
        // Do NOT cache a page with this block on it.
        \Drupal::service('page_cache_kill_switch')->trigger(); 
        // build from form               
        $build = \Drupal::formBuilder()->getForm('Drupal\drupalvip_dashboard\Form\NewTaskForm');
        $build['#attributes']['class'][] = 'my_class';
        $build['#cache']['max-age'] = 0;
        $build['#cache']['contexts'] = [];
        $build['#cache']['tags'] = [];                   
        return $build;
    }       
  
    /**
    * {@inheritdoc}
    */
    public function blockForm($form, FormStateInterface $form_state) {
        $form = parent::blockForm($form, $form_state);
        $config = $this->getConfiguration();
        $form['block_note'] = [
            '#type' => 'textfield',
            '#title' => $this->t('Note'),
            '#description' => $this->t('block note '),
            '#default_value' => isset($config['block_note']) ? $config['block_note'] : '',
        ];
        return $form;
    }  

    /**
    * {@inheritdoc}
    */
    public function blockSubmit($form, FormStateInterface $form_state) {
        parent::blockSubmit($form, $form_state);        
        $values = $form_state->getValues();
        $this->configuration['block_note'] = $values['block_note'];
    }    
    
} // end of class