Drupal 8: How to Reference a Views' Block Display from a Field

Michelle
Drupal Developer
Jan
25
2017

Drupal 8: How to Reference a Views' Block Display from a Field

alt=””

In Drupal 7, if you wanted to reference a view display from a node field, you had to use a module such as Viewfield. In Drupal 8, this can be done with Drupal core alone by using the built in entity reference to reference a block instance created from the view.

Step 1: Create a hidden region in your theme.

1. Open your THEMENAME.info.yml file.
2. Find the section for "regions:"
3. Add a new line: hidden: 'Hidden region for referenced blocks'

4. Save and clear the cache.
 

Step 2: Create a view with a block display.

1. Go to admin/structure/views/add
2. Create your view with a block display.

3. Do any additional tweaking you'd like and save the view.
 

Step 3: Place an instance of the block in the hidden region.

1. Go to admin/structure/block
2. Find the hidden region you just added in step 1.

3. Click "Place block".
4. Find your Views block.
5. Click "Place block".
6. Configure as desired and save.

 

Step 4: Create a reference field.

1. Go to the field admin of your content type at admin/structure/types/manage/TYPE/fields.
2. Click "Add field".
3. In the "Add a new field" dropdown, choose "Other" under "Reference".

4. Label the field and save.
5. Under "Type of item to reference" choose "Block" under "Configuration" and save.

6. Configure as desired. Leave "Reference method" set to "Default".

7. Optionally set a block as the default:

a. If you are only going to ever reference one view from this field and you want it automatically added, you can set it as the default value.

b. If you would like to be able to select from multiple blocks, leave the default value blank and the user can choose when entering content. The default format of the field is autocomplete but this can be changed to a dropdown in admin/structure/types/manage/TYPE/form-display to make the choices more obvious.

8. Save the field.
 

Step 5: Add the block to your content.

1. Add a new item of the content type from step 4 at /node/add/TYPE.
2. You should see your new field. If you set the default in Step 4, the view will automatically be filled in.

 

(Optional) Step 6: Alter code to limit the field.

If you are allowing the user to choose the view when entering content, you'll notice that the list is cluttered because it is showing _all_ the blocks on the site.

 

To make things cleaner, you can limit the list to just blocks placed in the hidden region with this:

1. If you don't already have one, create a custom module for site wide alterations.
2. Add the following directory structure under the root directory of the module: src/Plugin/EntityReferenceSelection.

3. In EntityReferenceSelection, add a file named BlockSelection.php. (The filename can be changed; just be sure it matches the class name.)
4. In this file, add the following code. Be sure to replace "MODULE_NAME_HERE", "YOUR_SITE_THEME". Also change "hidden" if you chose a different name for the region.
 

<?php

namespace Drupal\MODULE_NAME_HERE\Plugin\EntityReferenceSelection;

use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection;
use Drupal\Component\Utility\Html;

/**
 * Filters the block listing for an entity reference field.
 *
 * @EntityReferenceSelection(
 *   id = "blocks",
 *   label = @Translation("Blocks: Filter by blocks in hidden region"),
 *   entity_types = {"block"},
 *   group = "blocks",
 *   weight = 1
 * )
 */
class BlockSelection extends DefaultSelection {

  /**
   * {@inheritdoc}
   */
  public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
    $target_type = $this->configuration['target_type'];

    $query = $this->buildEntityQuery($match, $match_operator);
    if ($limit > 0) {
      $query->range(0, $limit);
    }

    $result = $query->execute();

    if (empty($result)) {
      return array();
    }

    $options = array();
    $entities = $this->entityManager->getStorage($target_type)->loadMultiple($result);
    foreach ($entities as $entity_id => $entity) {
      $block_theme = $entity->getTheme();
      $block_region = $entity->getRegion();

      // Only add blocks that are in the hidden region of the main theme.
      if ($block_theme == 'YOUR_SITE_THEME' && $block_region == 'hidden') {
        $bundle = $entity->bundle();
        $options[$bundle][$entity_id] = Html::escape($this->entityManager->getTranslationFromContext($entity)
          ->label());
      }
    }

    // Sort the options alphabetically.
    asort($options['block']);
    return $options;
  }

}

5. Save the file and clear the cache.
6. Edit the field you added in step 4 above.
7. Change the reference method to "Blocks: Filter by blocks in hidden region" and save.

8. Add a new item of the content type from step 4 at /node/add/TYPE.
9. The field will now be restricted to only showing blocks in the "hidden" region.

 

As you can see, with just Drupal core you can give your content editors the flexibility to choose from different sets of data (views) while creating a node. For even more flexibility, add the Paragraphs module and add your block reference field to a paragraph type. If you then assign the field on the content type to reference paragraphs, you can set it up so your editor can choose either a premade list (one of the views) or curate the list themselves by choosing a paragraph that allows them to pick individual items of content. With a single content type, your editors can create a variety of different pages depending on their needs.
 

Additional Resources
Migration With Custom Values in Drupal 8 | Blog
Migrating Content References in Drupal 8 | Blog
5 Drupal 8 Development Tips | Video

comments powered by Disqus