You are here

field_formatter_filter.module in Field Formatter Filter 8

Same filename and directory in other branches
  1. 7 field_formatter_filter.module
  2. 2.0.x field_formatter_filter.module

Allows different text format filters to be applied to text fields.

Provides additional formatter settings for text fields.

D8 code port modelled on field_formatter_class.

File

field_formatter_filter.module
View source
<?php

/**
 * @file
 * Allows different text format filters to be applied to text fields.
 *
 * Provides additional formatter settings for text fields.
 *
 * D8 code port modelled on field_formatter_class.
 */
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Field\FormatterInterface;
use Drupal\filter\Entity\FilterFormat;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;

/**
 * Adds a 'filter' selection to all text formatters.
 *
 * @see hook_field_formatter_third_party_settings_form()
 *
 * Implements hook_field_formatter_third_party_settings_form().
 *
 * @inheritdoc
 */
function field_formatter_filter_field_formatter_third_party_settings_form(FormatterInterface $plugin, FieldDefinitionInterface $field_definition, $view_mode, $form, FormStateInterface $form_state) {

  // Only offer this option to text formatters.
  if (!_field_formatter_filter_target_field_type($field_definition
    ->getType())) {
    return NULL;
  }
  $filter_id = $plugin
    ->getThirdPartySetting('field_formatter_filter', 'format');
  $filter_format_options = [
    FALSE => '<none>',
  ];

  /* @var \Drupal\filter\FilterFormatInterface $format */
  $filter_formats = filter_formats();
  foreach ($filter_formats as $format) {
    $filter_format_options[$format
      ->id()] = $format
      ->label();
  }
  $element['format'] = [
    '#type' => 'select',
    '#title' => t('Additional Text Filter/Format'),
    '#options' => $filter_format_options,
    '#default_value' => $filter_id,
    '#description' => t('The selected format will be used <em>instead</em> of whatever the originally selected format is.'),
  ];
  return $element;
}

/**
 * Displays the formatter setting on the manage field display overview.
 *
 * Implements hook_field_formatter_settings_summary_alter().
 *
 * @param string[] $summary
 *   An array of summary messages.
 * @param object[] $context
 *   An associative array with the following elements:
 *   - formatter: The formatter object.
 *   - field_definition: The field definition.
 *   - view_mode: The view mode being configured.
 */
function field_formatter_filter_field_formatter_settings_summary_alter(array &$summary, array $context) {

  /* @var \Drupal\Core\Field\FormatterInterface $formatter */
  $formatter = $context['formatter'];
  $format_id = $formatter
    ->getThirdPartySetting('field_formatter_filter', 'format');
  if (!empty($format_id)) {
    $format = FilterFormat::load($format_id);
    $summary[] = t('Text Format: @format', [
      '@format' => Xss::filter($format
        ->label(), []),
    ]);
  }
}

/**
 * Applies an additional filter on the text field being rendered.
 *
 * Implements hook_preprocess_HOOK().
 *
 * @param array $variables
 *   Theme variables.
 */
function field_formatter_filter_preprocess_field(array &$variables) {

  // This runs on all fields all the time - surely that's overkill?
  // Can I inject instructions further upstream?
  // It feels this hook is a bit late.
  // Also, it's a hook. Whither plugins?
  $element = $variables['element'];

  // Only process recognised text formatters.
  if (!_field_formatter_filter_target_field_type($element['#field_type'])) {
    return;
  }

  // Get a few convenient handles.

  /* @var $entity \Drupal\Core\Entity\FieldableEntityInterface */
  $entity = $variables['element']['#object'];
  $field_name = $variables['element']['#field_name'];
  $view_mode = $variables['element']['#view_mode'];

  // Drill down to field formatter settings.
  $render_display = EntityViewDisplay::collectRenderDisplay($entity, $view_mode);
  $field_display = $render_display
    ->getComponent($field_name);
  if (empty($field_display['third_party_settings']['field_formatter_filter']['format'])) {
    return;
  }
  $format_id = $field_display['third_party_settings']['field_formatter_filter']['format'];

  // Avoid problems if the named format was invalid, such being deleted.
  if (!FilterFormat::load($format_id)) {

    // This is rare and wrong enough to warn loudly about.
    // Be as informative as we can.
    $message = "The %field_name field displayed on the %view_mode view of %bundle %entity_type was set to use text format '%format_id' - which is invalid or unavailable. Default rendering will be used until this is fixed.";
    $strings = [
      '%field_name' => $field_name,
      '%view_mode' => $view_mode,
      '%bundle' => $entity
        ->bundle(),
      '%entity_type' => $entity
        ->getEntityTypeId(),
      '%format_id' => $format_id,
    ];
    \Drupal::logger('field_formatter_filter')
      ->warning($message, $strings);
    return;
  }
  $children_keys = Element::children($element);
  foreach ($children_keys as $key) {

    /*
     * REPLACE the expected format rule.
     * When the render process eventually hits
     * @see Drupal\filter\Element\ProcessedText::preRenderText
     * It will use my given format.
     */
    $variables['items'][$key]['content']['#format'] = $format_id;

    /*
     * Or,
     * ADD my process to the $variables['items']['content'][#pre_render']
     * array.
     * $variables[$key]['#pre_render'][] = [];
     */
  }
}

/**
 * Returns true if the field type is filterable.
 *
 * Internal utility.
 *
 * @param string $type
 *   Field type.
 *
 * @return bool
 *   Is this a filterable field type.
 */
function _field_formatter_filter_target_field_type($type) {

  // Only alter longtext sorta fields.
  return in_array($type, [
    'text',
    'text_long',
    'text_with_summary',
  ]);
}

Functions

Namesort descending Description
field_formatter_filter_field_formatter_settings_summary_alter Displays the formatter setting on the manage field display overview.
field_formatter_filter_field_formatter_third_party_settings_form Adds a 'filter' selection to all text formatters.
field_formatter_filter_preprocess_field Applies an additional filter on the text field being rendered.
_field_formatter_filter_target_field_type Returns true if the field type is filterable.