You are here

field_label.module in Field Label 8

Provides custom settings to format field labels.

File

field_label.module
View source
<?php

/**
 * @file
 * Provides custom settings to format field labels.
 */
use Drupal\Core\Field\FormatterInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\Html;

/**
 * Implements hook_theme_registry_alter().
 */
function field_label_theme_registry_alter(&$theme_registry) {

  // Only override the field template if it comes from core. Allow
  // theme overrides to take precedence.
  if (strpos($theme_registry['field']['path'], 'core') !== 0) {
    return;
  }
  $module_path = drupal_get_path('module', 'field_label');
  $theme_registry['field']['path'] = $module_path . '/templates';
}

/**
 * Implements hook_field_formatter_settings_summary_alter().
 */
function field_label_field_formatter_settings_summary_alter(&$summary, $context) {

  // Load formatter settings and module config.
  $settings = $context['formatter']
    ->getThirdPartySettings('field_label');
  $config = \Drupal::config('field_label.settings');
  if ($settings) {
    if ($config
      ->get('label_value_enabled') && !empty($settings['label_value'])) {
      $summary[] = t('Label: @label', [
        '@label' => $settings['label_value'],
      ]);
    }
    if ($config
      ->get('label_class_select_enabled') && !empty($settings['label_class_select'])) {
      $selected_style = $settings['label_class_select'];

      // Ensure the selected style is still valid.
      if ($valid_style = _field_label_is_valid_style($selected_style)) {
        $summary[] = t('Label class: @class', [
          '@class' => $valid_style['label'],
        ]);
      }
    }
    if ($config
      ->get('label_class_enabled') && !empty($settings['label_class'])) {
      $summary[] = t('Extra label classes: @class', [
        '@class' => $settings['label_class'],
      ]);
    }
    if ($config
      ->get('label_tag_enabled') && !empty($settings['label_tag'])) {
      $summary[] = t('Label wrapper: @tag', [
        '@tag' => $settings['label_tag'],
      ]);
    }
  }
}

/**
 * Implements hook_field_formatter_third_party_settings_form().
 *
 * Adds fields for modifying the class and label value for field that have
 * a label.
 */
function field_label_field_formatter_third_party_settings_form(FormatterInterface $plugin, FieldDefinitionInterface $field_definition, $view_mode, $form, FormStateInterface $form_state) {

  // Get the module config.
  $config = \Drupal::config('field_label.settings');

  // Get the current user.
  $user = \Drupal::currentUser();

  // Load the formatter settings.
  $setting_keys = [
    'label_class',
    'label_class_select',
    'label_value',
    'label_tag',
  ];

  // Ensure at least one feature enabled.
  $has_enabled = FALSE;

  // Ensure user has access to edit at least one setting.
  $has_access = FALSE;

  // Load up the settings array:
  foreach ($setting_keys as $key) {
    $settings[$key] = [
      'enabled' => $config
        ->get($key . '_enabled'),
      'value' => $plugin
        ->getThirdPartySetting('field_label', $key),
      'access' => $user
        ->hasPermission('edit_field_' . $key),
    ];
    $has_enabled = $has_enabled ?: $settings[$key]['enabled'];
    $has_access = $has_access ?: $settings[$key]['access'];
  }

  // Bail out if nothing is enabled, or user has no access.
  if (!$has_enabled || !$has_access) {
    return [];
  }

  // Detial wrapper element to keep things tidy.
  $elements['field_label'] = [
    '#type' => 'details',
    '#title' => t('Label settings'),
    // Default to open if we have any values to show.
    '#open' => $settings['label_class']['value'] || $settings['label_value']['value'] || $settings['label_tag']['value'],
  ];

  // For each available setting, build the full field if the user has access.
  // If not, build a hidden field to retain any previous values.
  // Label value field.
  if ($settings['label_value']['enabled']) {
    if ($settings['label_value']['access']) {
      $elements['field_label']['label_value'] = [
        '#type' => 'textfield',
        '#title' => t('Label value'),
        '#description' => t('Overwrite the default field label.'),
        '#default_value' => $settings['label_value']['value'],
      ];
    }
    else {
      $elements['field_label']['label_value'] = [
        '#type' => 'hidden',
        '#value' => $settings['label_value']['value'],
      ];
    }
  }

  // Label class list.
  if ($settings['label_class_select']['enabled']) {
    if ($settings['label_class_select']['access']) {

      // Ensure valid default value.
      $default = '';
      if ($valid_style = _field_label_is_valid_style($settings['label_class_select']['value'])) {
        $default = $valid_style['selector'];
      }
      $elements['field_label']['label_class_select'] = [
        '#type' => 'select',
        '#title' => t('Label class'),
        '#description' => t('Select a class to add to the label tag.'),
        '#empty_value' => '',
        '#options' => _field_label_generate_styles(),
        '#default_value' => $default,
      ];
    }
    else {
      $elements['field_label']['label_class_select'] = [
        '#type' => 'hidden',
        '#value' => $default,
      ];
    }
  }

  // Label class field.
  if ($settings['label_class']['enabled']) {
    if ($settings['label_class']['access']) {
      $elements['field_label']['label_class'] = [
        '#type' => 'textfield',
        '#title' => t('Extra label classes'),
        '#description' => t('Space-separated list of valid classnames (no dots). <b>Ex:</b> <code>class-one class__two</code>'),
        '#default_value' => $settings['label_class']['value'],
      ];
    }
    else {
      $elements['field_label']['label_class'] = [
        '#type' => 'hidden',
        '#value' => $settings['label_class']['value'],
      ];
    }
  }

  // Label tag field.
  if ($settings['label_tag']['enabled']) {
    if ($settings['label_tag']['access']) {
      $tag_options = [];
      $allowed_tags = $config
        ->get('allowed_tags');
      foreach ($allowed_tags as $tag) {
        $tag_options[$tag] = $tag;
      }
      $elements['field_label']['label_tag'] = [
        '#type' => 'select',
        '#title' => t('Label wrapper'),
        '#description' => t('Select a tag to wrap the label value. Choose "Default" to use the wrapper provided by the theme.'),
        '#empty_option' => '- Default -',
        '#empty_value' => '',
        '#options' => $tag_options,
        '#default_value' => $settings['label_tag']['value'],
      ];
    }
    else {
      $elements['field_label']['label_tag'] = [
        '#type' => 'hidden',
        '#value' => $settings['label_tag']['value'],
      ];
    }
  }
  return $elements['field_label'];
}

/**
 * Implements hook_preprocess_HOOK() for field templates.
 */
function field_label_preprocess_field(&$variables) {

  // Get the module config.
  $config = \Drupal::config('field_label.settings');
  if (isset($variables['element']['#third_party_settings']['field_label'])) {
    $settings = $variables['element']['#third_party_settings']['field_label'];

    // Update the label.
    if ($config
      ->get('label_value_enabled') && !empty($settings['label_value'])) {
      $variables['label'] = $settings['label_value'];
    }

    // Create the class attribute array if it doesn't already exisit.
    if (!isset($variables['title_attributes']['class'])) {
      $variables['title_attributes']['class'] = [];
    }

    // Add any free-form classes.
    if ($config
      ->get('label_class_enabled') && !empty($settings['label_class'])) {
      $classes = explode(' ', $settings['label_class']);
      foreach ($classes as $class) {
        $variables['title_attributes']['class'][] = Html::cleanCssIdentifier($class);
      }
    }

    // Add class selected from class list.
    if ($config
      ->get('label_class_select_enabled') && !empty($settings['label_class_select'])) {
      if (_field_label_is_valid_style($settings['label_class_select'])) {
        $classes = explode('.', $settings['label_class_select']);
        foreach ($classes as $class) {
          $variables['title_attributes']['class'][] = Html::cleanCssIdentifier($class);
        }
      }
    }

    // Add the wrapper tag if enabled and set.
    if ($config
      ->get('label_tag_enabled') && !empty($settings['label_tag'])) {
      $variables['label_tag'] = $settings['label_tag'];
    }
  }
}

/**
 * Ensure a style selector is still available in the configured class list.
 *
 * @param string $selector
 *   The CSS selector to check.
 *
 * @return array
 *   An array with valid values, or empty array if invalid
 */
function _field_label_is_valid_style($selector) {
  $styles = _field_label_generate_styles();
  if (isset($styles[$selector])) {
    return [
      'selector' => $selector,
      'label' => $styles[$selector],
    ];
  }
  return [];
}

/**
 * Create an array of validated key/value pairs of class selector and labels.
 *
 * @return array
 *   An array with valid values, or empty values if selector is not valid
 */
function _field_label_generate_styles() {
  $class_list = \Drupal::config('field_label.settings')
    ->get('class_list');
  $styles = [];

  // Return early if class list is emptty.
  $class_list = trim($class_list);
  if (empty($class_list)) {
    return $styles;
  }

  // Handle newlines.
  $class_list = str_replace([
    "\r\n",
    "\r",
  ], "\n", $class_list);
  foreach (explode("\n", $class_list) as $style) {

    // Ignore empty lines in between non-empty lines.
    if (empty($style)) {
      continue;
    }

    // Validate syntax: [.class...]|label pattern expected.
    if (!preg_match('@^(\\.[a-zA-Z0-9_-]+)+\\| *.+ *$@', $style)) {

      // Skip invalid patterns.
      continue;
    }
    list($selector, $label) = explode('|', $style);
    $styles[$selector] = $label;
  }
  return $styles;
}

Functions

Namesort descending Description
field_label_field_formatter_settings_summary_alter Implements hook_field_formatter_settings_summary_alter().
field_label_field_formatter_third_party_settings_form Implements hook_field_formatter_third_party_settings_form().
field_label_preprocess_field Implements hook_preprocess_HOOK() for field templates.
field_label_theme_registry_alter Implements hook_theme_registry_alter().
_field_label_generate_styles Create an array of validated key/value pairs of class selector and labels.
_field_label_is_valid_style Ensure a style selector is still available in the configured class list.