1

I created a view that list items from a content type. I have a block display for this view. I want to be able to put a different background image on each instances of this block.

Ideally, it could show up as an option in Block Settings > Allowed settings so this way every instance would have its own background image.

A second option would be that there is an other option in Block Settings below Block Name, something like Block Bakgorund. This time the same background image would be use as every instance of the block.

An other option would be to create a custom block that has 2 fields, a background image and a entity reference field on the content type my view was listing. Two problems with this, first this come to the same as re-write the functionality of Views, and second I am not sure if I would be able to create a field that is an entity reference on a block created programmatically (module plugin)

Any solution to this or thoughts?

2 Answers 2

2

I finally had time to make a custom module for that: ctool_views_extender

In your MODULE.module:

<?php

use Drupal\views\Plugin\views\display\Block as CoreBlock;
use Drupal\MODULE\Plugin\Display\Block;

/**
 * Implements hook_views_plugins_display_alter().
 */
function MODULE_views_plugins_display_alter(&$displays) {
  if (!empty($displays['block']['class'])) {
    $displays['block']['class'] = Block::class;
  }
}

In src/Plugin/Display/Block.php:

<?php
/**
 * @file
 * Contains \Drupal\MODULE\Plugin\Display\Block.
 */

namespace Drupal\MODULE\Plugin\Display;

use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\Block\ViewsBlock;
use Drupal\ctools_views\Plugin\Display\Block as CtoolsBlock;

/**
 * Provides a Block display plugin that allows for greater control over Views
 * block settings.
 */
class Block extends CtoolsBlock {

  /**
   * {@inheritdoc}
   */
  public function optionsSummary(&$categories, &$options) {
    parent::optionsSummary($categories, $options);
    $filtered_allow = array_filter($this->getOption('allow'));
    $filter_options = [
      'background' => $this->t('Background')
    ];
    $filter_intersect = array_intersect_key($filter_options, $filtered_allow);

    $options['allow'] = array(
      'category' => 'block',
      'title' => $this->t('Allow settings'),
      'value' => empty($filtered_allow) ? $this->t('None') : implode(', ', $filter_intersect),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);
    $options = $form['allow']['#options'];
    $options['background'] = $this->t('Background');
    $form['allow']['#options'] = $options;
  }

  /**
   * {@inheritdoc}
   */
  public function blockForm(ViewsBlock $block, array &$form, FormStateInterface $form_state) {
    $form = parent::blockForm($block, $form, $form_state);

    $allow_settings = array_filter($this->getOption('allow'));
    $block_configuration = $block->getConfiguration();

    if(!empty($allow_settings['background'])){
      $form['override']['background'] = array(
        '#type' => 'managed_file',
        '#title' => $this->t('Background'),
        '#description' => $this->t('Enter background image'),
        '#default_value' => isset($block_configuration['background'])?$block_configuration['background']:'',
        '#upload_location' => 'public://backgrounds'
      );
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function blockSubmit(ViewsBlock $block, $form, FormStateInterface $form_state) {
    // Set default value for items_per_page if left blank.
    if (empty($form_state->getValue(array('override', 'items_per_page')))) {
      $form_state->setValue(array('override', 'items_per_page'), "none");
    }

    parent::blockSubmit($block, $form, $form_state);
    $configuration = $block->getConfiguration();
    $allow_settings = array_filter($this->getOption('allow'));

    if (!empty($allow_settings['background'])) {
        $background = $form_state->getValue(['override', 'background']);
        $configuration['background'] = $background;
        // fix bug in Drupal which does not put the image as permanent
        $fid = $form_state->getValue(['override', 'background'])[0];
        /** @var \Drupal\file\Entity\File $file */
        $file = \Drupal\file\Entity\File::load($fid);
        /** @var \Drupal\file\FileUsage\DatabaseFileUsageBackend $file_usage */
        $file_usage = \Drupal::service('file.usage');
        $file_usage->add($file, 'ctools_views', 'image', 1);
    }

    $block->setConfiguration($configuration);
  }
}

Then all you need to do is output it in a twig template. I use another module that I made to simplify things (get_url_from_fid on github or How to get path of image from file id on SE)

{% set background = '' %}
{% if configuration.background.0 %}
  {% set background = 'background-image: url(' ~     get_url_from_fid(configuration.background.0) ~ ')' %}
{% endif %}

<div{{ attributes.addClass(classes) }} style="{{ background }}">

Cheers!

-1

Finally I decided to patch ctools view block. I have plan to replaced this patch with an object that will extend ctools' view's Block (core/modules/ctools_views/src/Plugin/Display/Block.php) I paste here for anyone to use.

[apache{} patches]$ more ctool-add-bg-to-block.patch
diff --git a/modules/ctools_views/src/Plugin/Display/Block.php b/modules/ctools_views/src/Plugin/Display/Block.php
index 9b72f34..19b64aa 100644
--- a/modules/ctools_views/src/Plugin/Display/Block.php
+++ b/modules/ctools_views/src/Plugin/Display/Block.php
@@ -31,7 +31,8 @@ class Block extends CoreBlock {
       'hide_fields' => $this->t('Hide fields'),
       'sort_fields' => $this->t('Reorder fields'),
       'disable_filters' => $this->t('Disable filters'),
-      'configure_sorts' => $this->t('Configure sorts')
+      'configure_sorts' => $this->t('Configure sorts'),
+      'background' => $this->t('Background')
     ];
     $filter_intersect = array_intersect_key($filter_options, $filtered_allow);

@@ -54,6 +55,7 @@ class Block extends CoreBlock {
     $options['sort_fields'] = $this->t('Reorder fields');
     $options['disable_filters'] = $this->t('Disable filters');
     $options['configure_sorts'] = $this->t('Configure sorts');
+    $options['background'] = $this->t('Background');
     $form['allow']['#options'] = $options;
     // Update the items_per_page if set.
     $defaults = array_filter($form['allow']['#default_value']);
@@ -79,6 +81,16 @@ class Block extends CoreBlock {
       unset($form['override']['items_per_page']['#options']);
     }

+    if(!empty($allow_settings['background'])){
+      $form['override']['background'] = array(
+        '#type' => 'managed_file',
+        '#title' => $this->t('Background'),
+        '#description' => $this->t('Enter background image'),
+        '#default_value' => isset($block_configuration['background'])?$block_configuration['background']:'',
+        '#upload_location' => 'public://backgrounds'
+      );
+    }
+
     // Provide "Pager offset" block settings form.
     if (!empty($allow_settings['offset'])) {
       $form['override']['pager_offset'] = [
@@ -270,6 +282,19 @@ class Block extends CoreBlock {
       }
     }

+    if (!empty($allow_settings['background'])) {
+        $background = $form_state->getValue(['override', 'background']);
+        $configuration['background'] = $background;
+        // fix bug in Drupal which does not put the image as permanent
+//      kint($form_state->getValue(['override', 'background'])[0]);
+        $fid = $form_state->getValue(['override', 'background'])[0];
+        /** @var \Drupal\file\Entity\File $file */
+        $file = \Drupal\file\Entity\File::load($fid);
+        /** @var \Drupal\file\FileUsage\DatabaseFileUsageBackend $file_usage */
+        $file_usage = \Drupal::service('file.usage');
+        $file_usage->add($file, 'ctools_views', 'image', 1);
+    }
+
     // Save "Pager offset" settings to block configuration.
     if (!empty($allow_settings['offset'])) {
       $configuration['pager_offset'] = $form_state->getValue(['override', 'pager_offset']);
2
  • Unless I'm missing something you are hacking a contrib. module ( a/modules/ctools_views/src/Plugin/Display/Block.php), this is really bad practice as your changes will be lost if you update the module. You should be able to add your customisations via a custom module. Commented Nov 25, 2016 at 14:59
  • @mediaashley I know this is not the best way. I am trying to move that to a custom module but I can't find how to tell Drupal to use my Block class instead of ctools' Commented Dec 9, 2016 at 16:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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