1

I have created a Drupal 9 site with articles that belongs to taxonomy terms. I want to give the ability to the administrator of the site to place a block with whatever taxonomy he wants.

How would I set up the block configuration with a drop-down of the taxonomy terms and pass the selected values to the Drupal views and filter based on the selected taxonomy terms?

In the block settings there is not any option to pass the filter to the block.

drupal views

block settings

Any Idea on this using existing module or with custom code?

1

Not answering directly, because I don't know if you could do this with a configurable Views block without custom code.

A different approach only using UI would be on entity level, creating a block type containing two fields, the taxonomy drop-down and an EVA field passing the other field's value via a token. The site admin has then to use the Custom Block Library to create a custom block for this block type.

Add the EVA field to the block type with this module: https://www.drupal.org/project/eva

13
  • thanks for your answer. it would be nice if you also give me some details about the way using configurable Views block with custom code.
    – marnaels
    Mar 31 at 12:09
  • I would start with a block plugin from scratch, add the taxonomy drop-down to the block config form and views_embed_view the view to the block build providing the term as argument.
    – 4k4
    Mar 31 at 15:34
  • After pass the term as an argument to views_embed_view, how can I filter the results with this argument and render this view to the block?
    – marnaels
    Apr 2 at 8:38
  • Add an Embed display to your View and add a contextual filter for the argument.
    – 4k4
    Apr 2 at 9:12
  • How to I map the tid of the selected taxonomy terms that I I pass as an argument with the contextual filter from the view?
    – marnaels
    Apr 2 at 9:40
1

We had a similar requirement on a previous project with Layout Builder: We used a block_content entity. We are using the Block field module to create a field_view containing a reference to the views block.

Every other field on the custom block content entity basically was a faked Views UI: Every filter that we wanted to expose to the editors, was created as field on the block_content (mostly taxonomy term references), and then mapped to views exposed filters in a special field formatter widget for the block field.

It is a bit of hack, but our editors were quite happy with it. The field formatter below is tailored to our specfic needs, but might help to get some ideas.

<?php

namespace Drupal\wt_dgm\Plugin\Field\FieldFormatter;

use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\block_field\Plugin\Field\FieldFormatter\BlockFieldFormatter;
use Drupal\Core\Plugin\ContextAwarePluginInterface;
use Drupal\views\Element\View;
use Drupal\views\Plugin\Block\ViewsBlock;

/**
 * Plugin implementation of the 'block_field' formatter.
 *
 * @FieldFormatter(
 *   id = "autolist_blockfield",
 *   label = @Translation("Block field with filters from Auto-List block"),
 *   field_types = {
 *     "block_field"
 *   }
 * )
 */
class AutoListBlockField extends BlockFieldFormatter {

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    /** @var $parentEntity \Drupal\block_content\Entity\BlockContent */
    $parentEntity = $items->getEntity();
    if ($parentEntity->getEntityTypeId() != 'block_content' || $items->getFieldDefinition()->getName() != 'field_view') {
      return parent::viewElements($items, $langcode);
    }

    $elements = [];
    foreach ($items as $delta => $item) {
      /** @var \Drupal\block_field\BlockFieldItemInterface $item */
      $block = $item->getBlock();

      if (!($block instanceof ViewsBlock)) {
        continue;
      }

      // copy & paste parent::viewElements()
      if ($block instanceof ContextAwarePluginInterface) {
        try {
          $contexts = \Drupal::service('context.repository')->getRuntimeContexts($block->getContextMapping());
          \Drupal::service('context.handler')->applyContextMapping($block, $contexts);
        }
        catch (ContextException $e) {
          continue;
        }
      }
      if (!$block || !$block->access(\Drupal::currentUser())) {
        continue;
      }

      // apply my custom filters and sort options to the views block
      $view = $block->getViewExecutable();
      $display = $view->current_display;

      $args = [$parentEntity->id()];
      $view->setArguments([$parentEntity->id()]);

      $filters = [];

      /* ### alter views filter ### */
      if ($parentEntity->hasField('field_contentypes')) {
        $filters['type'] = array_column($parentEntity->get('field_contentypes')->getValue(), 'value');
      }
      foreach ($parentEntity->getFields() as $fieldName => $field) {
        if ($field->getFieldDefinition()->getType() == 'entity_reference' && $field->getFieldDefinition()->getSetting('target_type') == 'taxonomy_term') {
          if (!$field->isEmpty()) {
            $filters[$fieldName . '_target_id'] = array_column($field->getValue(), 'target_id');
          }
        }
      }
      /* ### alter views sort ### */
      $sort = $parentEntity->get('field_sort')->value;
      $filters['sort_by'] = $sort;
      $view->setExposedInput($filters);

      $view->setItemsPerPage($parentEntity->get('field_quantity')->value);

      $view->display_handler->setOption('title', $parentEntity->get('field_title')->value);

      //@see \Drupal\views\Plugin\Block\ViewsBlock::build()
      $output = $view->buildRenderable($display, $args, FALSE);
      $output = View::preRenderViewElement($output);

      $elements[$delta] = $output;

      CacheableMetadata::createFromRenderArray($elements[$delta])
        ->addCacheableDependency($parentEntity)
        ->applyTo($elements[$delta]);
    }
    return $elements;
  }

}

PS: Ajax has to be enabled on the views block, otherwise setting $filter did not work correctly for us.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.