Do you want to know how to Drupal?

Let's Drupal


How to set a custom redirection after form submission Drupal 9?

To redirect a user after form submit to a custom URL. We need to implement custom submit function.

use Drupal\Core\Form\FormStateInterface;

 * Implements hook_form_FORM_ID_alter().
function mydoule_form_YOUR_FORM_ID_alter(&$form, FormStateInterface $form_state, $form_id) {
  // add custom function as submit handler.
  $form['#submit'][] = '_mymodule_custom_submit_handler';

  // Sometime forms doesn't into account '#submit' parameter. So, we have to set custom handler to the specific button of the form
  $form['actions']['submit']['#submit'][] = '_mymodule_custom_submit_handler';

 * Custom submit handler for your form form.
function _mymodule_custom_submit_handler($form, FormStateInterface $form_state) {
  // Set a custom redirect.

You will need to replace module name and put into install file of your module and also don't forget to replace form id.

How to use dependency injection for Plugins in Drupal 9?

Services are very powerful way to make our code reusable. How can we pass service to our plugin in Drupal 9?

For this example we take code of simple plugin EntityLink. It doesn't actually it could be any plugin

use Drupal\views\Plugin\views\field\EntityLink;
use Drupal\views\ResultRow;

 * Field handler to present a link to approval.
 * @ingroup views_field_handlers
 * @ViewsField("approve_link")
class ApproveLInk extends EntityLink {

   * {@inheritdoc}
  protected function getEntityLinkTemplate() {
    return 'approve';

   * {@inheritdoc}
  protected function renderLink(ResultRow $row) {
    $this->options['alter']['query'] = $this->getDestinationArray();
    return parent::renderLink($row);

   * {@inheritdoc}
  protected function getDefaultLabel() {
    return $this->t('Approve');


We don't call constructor for our plugin. In order to pass our service. Let's take current_user service.

First we need implement 

class ApproveLInk extends EntityLink implements ContainerFactoryPluginInterface {

Add create method, where we pass our service

   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   * @param array $configuration
   * @param string $plugin_id
   * @param mixed $plugin_definition
   * @return static
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(

After that add parameters to our constructor

   * @var AccountInterface $account
  protected $account;

   * @param array $configuration
   * @param string $plugin_id
   * @param mixed $plugin_definition
   * @param \Drupal\Core\Session\AccountInterface $account
  public function __construct(array $configuration, $plugin_id, $plugin_definition, AccountInterface $account) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->account = $account;


How to list content entities in Drupal 9?

If you need to get a list of content entitles in your Drupal 9 website for example for drop down on the configuration page you can use the next code snippet
use Drupal\Core\Entity\ContentEntityType;

$content_entities = [];

// Get all entities definitions.
$entity_type_definations = \Drupal::entityTypeManager()->getDefinitions();

foreach ($entity_type_definations as $definition) {
  // Check that definition is instance of ContentEntityType
  if ($definition instanceof ContentEntityType) {
    $content_entities [] = $definition;


How to remove (uninstall) entity type in Drupal 8?

If we don't need some entity type anymore we can easily remove it.
// Get update manager.
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
// Get entity type.
$entity_type = $definition_update_manager->getEntityType('your_entity_type_id');
if ($entity_type ) {
    // Uninstall entity type.


How to update entity field in Drupal 8?

Sometimes we need to update some settings for a field. In our case we will be update drop down field
function your_module_update_8001() {
  // First we need to get update manager.
  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();

  // Load the storage definition of the field.
  $field_storage = $definition_update_manager->getFieldStorageDefinition('field_name',
  // Set a new list of options for the list field.
    'allowed_values' => [
      'link' => 'Link',
      'posts' => 'Posts',
      'events' => 'Events',
      'page' => 'Page',

  // Update the field storage definition.


How to create programmatically a redirect for Redirect module in Drupal 8?

If use Redirect module sometimes you need to create URL programmatically. You can do it using the code bellow

use Drupal\redirect\Entity\Redirect;

    'redirect_source' => 'your_custom_url', // Set your custom URL.
    'redirect_redirect' => 'internal:/node/[NID]', // Set internal path to a node for example.
    'language' => 'und', // Set the current language or undefined.
    'status_code' => '301', // Set HTTP code.


How to load entity by a specific field value in Drupal 9?

Quite often it is required to get data by a field value. In our example I will use nodes, but it can be any entity type.

In first example we load entities by based fields. For example vid, type, language and etc.

I want to get all the nodes of the type post  for my custom block. For this we will use EntityTypeManager class

// Load a storage for node entity type
$items = \Drupal::entityTypeManager() 
      ->loadByProperties(['type' => 'post']); // load all nodes with the node type

After we can run through the items and apply our custom logic here.

In the second example, we will get entities based on custom fields. For example we have field "field_type"

$query = $this->entityTypeManager->getStorage('node')->getQuery();
$query->condition('status', 1)
    ->condition('changed', REQUEST_TIME, '<')
    ->condition('field_type', 'post');

$nids = $query->execute();

More examples can be found here: EntityFieldQuery

How to run a migration programmatically in Drupal 9?

The code bellow display how to execute the migration not through the command line, but through the code

First we need to load Migration. You can create it from a plugin, in this case the migration file is stored in migrations folder


use Drupal\migrate\MigrateMessage;
use Drupal\migrate_plus\Entity\Migration;
use Drupal\migrate_tools\MigrateExecutable;

// Load migration plugin.
$migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id);

or load it it from config entity

// Load migration from config entity.

$migration = \Drupal\migrate_plus\Entity\Migration::load($migration_id);

And then run the import

$executable = new MigrateExecutable($migration, new MigrateMessage());

How to update URL for migration programmatically in Drupal 8?

Sometimes we need to dynamically set URL for migrations, for example we have specific parameters restricting results.

We have default configuration

  plugin: url
  data_fetcher_plugin: http
  data_parser_plugin: json
    - 'http://your_domain/data.php'


// Get configuration factory.
$config_factory = \Drupal::configFactory();
// Load your migration configuration.
// Replace with your migration ID.
$migration_config = $config_factory->getEditable('migrate_plus.migration.[MIGRATION_ID]');
// Set your URL here.
$migration_config ->set('source.urls', ['YOUR_URL']);
$migration_config ->save();


How to add / remove user role programmatically in Drupal 8 ?

User access system based on roles and in some cases we want to assign role based on specific business requirements. 

For this we need to load a user first:

use Drupal\user\Entity\User;

// pass the correct user id here.

or we can load current user

use Drupal\user\Entity\User;


Then we add a user role 

// pass machine name of the user.

To remove the role we can use this code

// pass machine name of the user.

How to add local tasks dynamically in Drupal 8?

In some cases we want to generate local task based on some data. In our example we want to provide custom settings per node type for it we will provide local tasks based on node types. 

As usual full example you can find here:

First we need to define deriver plugin, which will expose the local tasks dynamically for us.

We will setup a route, which will accept a parameter "type" and we will just print it in order to see that it is a different page.

  path: '/dynamic-tasks/{type}'
    _controller: '\Drupal\local_tasks\Controller\LocalTasksController::dynamicTasks'
    _title: 'Dynamic tasks'
    type: ''
    _permission: 'access content'

and controller method

public function dynamicTasks($type = NULL) {
    return [
      '#markup' => $this->t('This is an example : @type', [
        '@type' => $type

Then we add in your file [your_module_name].links.task.yml (in our case local_tasks.links.task.yml), we set a deriver class

# Dynamically add local tasks.
  route_name: 'local_tasks.dynamic_tasks'
  title: 'Dynamic tasks'
  base_route: 'local_tasks.dynamic_tasks'
  deriver: Drupal\local_tasks\Plugin\Derivative\NodeTypeLocalTask # We set derive class, which will provide local tasks dynamically.


Now we can add a class Drupal\local_tasks\Plugin\Derivative\NodeTypeLocalTask.php


namespace Drupal\local_tasks\Plugin\Derivative;

use Drupal\Component\Plugin\Derivative\DeriverBase;

 * Provides dynamic tabs based on node types.
class NodeTypeLocalTask extends DeriverBase {

   * {@inheritdoc}
  public function getDerivativeDefinitions($base_plugin_definition) {
    // Get node types.
    $node_types = \Drupal::entityTypeManager()

    foreach ($node_types as $node_type_name => $node_type) {
      $this->derivatives[$node_type_name] = $base_plugin_definition;
      $this->derivatives[$node_type_name]['title'] = $node_type->label();
      $this->derivatives[$node_type_name]['route_parameters'] = ['type' => $node_type_name];

    return $this->derivatives;



As you can see above, we get list of node types and pass title and route parameters. The route name comes from local_tasks.links.task.yml

The only thin left is to clean the cache and open /dynamic-tasks/, you should see the list of node types as tabs.

Like this you can easily add local tasks dynamically on your custom page applying more complicated logic in Drupal.


How to hide a local task (tab) in Drupal?

Quite often we want to have a parent tab to be selected, but the sublevel tasks are not displayed or we just want remove completely some tabs for user of specific roles. 

There are two ways to do it:

The first option is to use hook_menu_local_tasks_alter

function your_module_local_tasks_alter(&$local_tasks) {

This code will remove your tab completely from the system, it means it will not be displayed anywhere, but sometimes we want to hide the tab only on the specific pages

The second option is to use hook_menu_local_tasks_alter

function your_module_menu_local_tasks_alter(&$data, $route_name) {
  $routes = ['entity.node.canonical']; // add your routes to this array and your tab will be hidden for this routes
  if (in_array($route_name, $routes)) {


How to render programatically custom entity form mode in Drupal?

Sometime we want to render entity form on a custom page or even a block. It is possible to do in Drupal 8, because we can create custom entity form mode.

Let's imagine we have a node type "Post" and  this content type has a lot of custom fields. We have technical field "E-mails" and we want to send e-mails, when someone comments this node.

For the sake of the example we don't want to "pollute" the main node form with "E-mails" field and we want to create a separate form mode "email_settings" for it.

If you try to display it programatically, you will face the exception:

public function emailSettings($node) {
    return $this->entityFormBuilder()->getForm($node, 'email_settings');


The website encountered an unexpected error. Please try again later.

Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException: The "node" entity type did not specify a "email_settings" form class. in Drupal\Core\Entity\EntityTypeManager->getFormObject() (line 223 of core/lib/Drupal/Core/Entity/EntityTypeManager.php). Drupal\Core\Entity\EntityFormBuilder->getForm(Object, 'email_settings') (Line: 10)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 582)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 693)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

but it the same time if we use "default" form mode, it works perfectly

public function emailSettings($node) {
    return $this->entityFormBuilder()->getForm($node, 'default');

Why it happens? Well, it is quite simple the entity, in our case node, just has no idea how to handle our custom form mode. To be more precise entity doesn't know, which class to use to handle form mode.

If you check node entity annotation, there is no information about our custom form mode. Unfortunately, It is not done automatically.

 *     "form" = {
 *       "default" = "Drupal\node\NodeForm",
 *       "delete" = "Drupal\node\Form\NodeDeleteForm",
 *       "edit" = "Drupal\node\NodeForm",
 *       "delete-multiple-confirm" = "Drupal\node\Form\DeleteMultiple"
 *     },

We have to alter the entity for this we will use hook_entity_type_alter. Full code could be found here:

 * Implements hook_entity_type_alter().
function custom_entity_form_mode_entity_type_alter(array &$entity_types) {
  // You can provide more complex logic and checks here, we are sure that node
  // module is active and it is enabled in our case.
  $default_handler_class = $entity_types['node']->getHandlerClasses()['form']['default'];
  $entity_types['node']->setFormClass('emails_settings', $default_handler_class);

Now you can create a node of content type, for which you have create form mode and open your custom page. In our example /email-settings/[nid]


Now you can display your form in any place you want