Problem/Motivation

Site Settings provides 2 blocks, one is a rendered entity, the other is just plain field values, which is great, but limits the flexibility for site builders to control what is displayed and how.

Use case: I have a Site Setting type, Locations. In this type, I have an address field ( rendered as an address ) and a Geolocation field rendered as a Google Map. I have 3 view modes, Default, Address, and Map.

  • Default displays the address and map.
  • Address just displays the address.
  • Map just displays the map.

I want site builders to be able to place a map block in some contexts, and just an address block in other contexts. However, the Site Settings block only ever renders the default view_mode.

https://git.drupalcode.org/project/site_settings/-/blob/8.x-1.x/src/Plug...

$pre_render = $view_builder->view($entity, 'default');

Proposed resolution

Add a setting to the RenderedSiteSettingsBlock that allows for selecting any enabled view_mode for the selected bundle.

My thoughts are, add an AJAX callback on the BlockForm such that when a Site Setting Type is selected, a second select box is displayed with enabled view_modes for that Site Setting Type.

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
// Inject this service.
// ...
  public function defaultConfiguration() {
    return [
      'setting' => NULL,
      'label_display' => FALSE,
      'view_mode' => NULL,
    ] + parent::defaultConfiguration();
  }

 public function blockForm($form, FormStateInterface $form_state) {

    // Allow selection of a site settings entity type.
    $form['setting'] = [
      '#type' => 'entity_autocomplete',
      '#target_type' => 'site_setting_entity_type',
      '#title' => $this->t('Site setting type'),
      '#weight' => '20',
      '#required' => TRUE,
      // Add ajax callback
      '#ajax' => [
        'callback' => '::viewModeCallback',
        'event' => 'autocompleteclose change',
        'wrapper' => 'edit-view-mode',
      ],
    ];
    if (isset($this->configuration['setting']) && !empty($this->configuration['setting'])) {
      $setting_entity_type = $this->entityTypeManager
        ->getStorage('site_setting_entity_type')
        ->load($this->configuration['setting']);
      $form['setting']['#default_value'] = $setting_entity_type;

      // Load the view_mode widget if configuration 'view_mode' is set.
      $view_mode_default = NULL;
      if (isset($this->configuration['view_mode']) && !empty($this->configuration['view_mode'])) {
        $view_mode_default = $this->configuration['view_mode'];
      }
      array_push($form, $this->viewModeElement($setting_entity_type, $view_mode_default);
    }
    else {
      // Return empty div so we have a target container.
      $form['view_mode'] = [
        '#markup' => '<div class="view-mode"></div>',
        '#allowed_tags' => ['div'],
      ];
    }
    return $form;
  }

  public function getViewModes($entity_type) {
    $view_modes = $this->repository->getViewModeOptionsByBundle('site_setting_entity_type', $entity_type);
    return $view_modes;
  }

  public function viewModeCallback(array &$form, FormStateInterface $form_state) {
    $entity_type = $form_state->getValue('setting');
    $element = $this->viewModeElement($entity_type);
    return $element;
  }

  public function viewModeElement($entity_type = NULL, $default = NULL) {
    $view_modes = $this->getViewModes($entity_type);
    $options = $this->getViewModes($entity_type);
    if (is_array($options) && count($options) > 1) {
      $element['view_mode'] = [
        '#type' => 'select',
        '#title' => $this->t('Select View Mode'),
        '#options' => $options,
      ];
      if ($default != NULL) {
        $element['view_mode']['#default_value'] = $default;
      }
    }
    else {
      $element['view_mode'] = [
        '#type' => 'hidden',
        '#value' => ($default) ? $default : $options,
      ];
    }
    return $element;
  }

I haven't tested any of this, but I feel like it's the correct approach.

Remaining tasks

Build / test.

User interface changes

New field to select view mode.

API changes

Data model changes

Add a new setting for view mode.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

scottsawyer created an issue. See original summary.

scott_euser’s picture

Interesting issue and makes sense to add! I don't think we actually need to do the ajax as anyways there is a risk that the view mode is subsequently deleted for the entity. You could use https://git.drupalcode.org/project/entity_block/-/blob/8.x-1.x/src/Plugi... as an example - there they just get all view modes available for the entity type. We can fallback to the default view mode on render if the particular entity does not have that view mode available (it may even be that core automatically falls back to default for us).

Next step for this would be to provide this as a patch file.

Thanks!

scottsawyer’s picture

I am working on a patch now. I have the ajax-y bit working. Basically, if there is only one view mode, I set it a hidden field with a value of default, or if the setting field is either empty or invalid, hidden field with no value.

This works great in my environment where I have on Setting Type "Locations" which has fields like: phone, address, map, with corresponding view modes: Phone, Address, Map. Each view mode displays only one field. However, I have another Setting Type "Memberships", which has two different view modes, Organization, and Image. Being able to switch the available view modes every time the Setting Type is changed I think is a real win.

I will look at the link you shared. I am going to upload a WIP. It's working great on my dev site, so try it out.

scottsawyer’s picture

Status: Active » Needs work

Gah, I noticed a glitch, when the new field is brought in, it's missing the name attribute. Unfortunately ( or fortunately ), I am unavailable for a week or so. Unless someone else is willing to jump on this, it'll have to wait a bit.

scottsawyer’s picture

Status: Needs work » Needs review
StatusFileSize
new6.65 KB

Sorry for the delay, reworked the patch. Previously, it was not saving the settings when creating the block. I tested creating a block with a new view mode, placing the block, then deleting the view mode and it falls back to default. Please test it out.

I only built this with the Rendered Site Setting, not the Simple Site Setting.

  1. Create a site setting type.
  2. Create one or more view modes.
  3. Enable the view modes on your site setting type.
  4. Create a Site Settings block, select your site setting type. This will update the View Mode options with the enabled view modes for that site setting type.
scott_euser’s picture

Status: Needs review » Needs work
StatusFileSize
new8.4 KB
new2.42 KB

Thanks for the progress on this! I've tested it out and it works well.

On further examination of the code I think we need to have the view mode required and validated in case ajax is slow, to avoid inconsistency on saved data. So I think its adding this: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Block%21B...

I've also added in an update hook that installs the view mode.

Then once that is in place, I am currently getting some tests into https://www.drupal.org/project/site_settings/issues/3138260 for block - once completed, we can add an appropriate test here.

scottsawyer’s picture

Thank you for the review. Should we then mark this as postponed on tests?

scott_euser’s picture

Status: Needs work » Postponed

Sorry for the delayed reply. Yes, once #3138260 is completed we can finish this off and get it in.

rgeerolf’s picture

I have a project that needs updating to D10, depending on this functionality (my bad). Rerolled the patch for the current 8.x-1.x (1.20) and sharing it in case anyone needs it.

scott_euser’s picture

Version: 8.x-1.x-dev » 2.0.x-dev
Status: Postponed » Needs work

Thanks, this is open to an MR if someone wants to contribute it. Would also need test coverage adding please. Work should be done to the 2x branch. Thanks!

scott_euser’s picture

Status: Needs work » Needs review

  • scott_euser committed 384867ce on 2.0.x
    Issue #3171895 by scott_euser, scottsawyer, rgeerolf: Allow Site...
scott_euser’s picture

Status: Needs review » Fixed

Thanks everyone for the work on this! Managed to get around to it, so its merged and in now + has test coverage.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.