🇬🇧
Drupal Documentation and Guides
Guides
English
English
  • Getting Started with Drupal
  • Installing Drupal
  • Drush
  • Theme & Module Development Concepts
  • Modules
  • Themes
  • FrontEnd
    • Javascript
  • Backend
    • Helpful Drupal Classes and Methods
    • Entities
    • Nodes
    • Taxonomies
    • Hooks
    • Twig
    • Libraries
    • Queries
    • Forms
    • Files & Images
    • Helpful functions and solutions
  • Guides
    • Custom Fields
      • Entity Reference and integer
      • Two Text Fields
      • Textfields, formatted text and numbers
      • Links and media elements
Powered by GitBook
On this page
  • FieldType
  • FieldWidget
  • FieldFormatter
  1. Guides
  2. Custom Fields

Links and media elements

Mutiple fields of different types in a custom field

This example showcases a Custom field that's composed of links, media elements

FieldType

The FieldType is the class that will handle the storage of the field. It will be responsible for storing the data in the database and retrieving it. It will also be responsible for validating the data.

When creating the schema, there are some rules you should follow:

  • Links need two columns in the database, a column for the uri and another one for the title

  • URIs are of type varchar and length is 2048

  • The title of the link is of type varchar and the length is 255

  • You should add indexes so that Drupal can index the content

<?php

namespace Drupal\MODULE_NAME\Plugin\Field\FieldType;

use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;

/**
 * @FieldType(
 *   id = "YOUR_FIELD_TYPE_ID",
 *   label = @Translation("THE LABEL THAT WILL BE DISPLAYED"),
 *   description = @Translation("A SIMPLE DESCRIPTION OF THE FIELD"),
 *   category = @Translation("THE CATEGORY WHERE IT WILL BE DISPLAYED"),
 *   default_widget = "YOUR_DEFAULT_WIDGET",
 *   default_formatter = "YOUR_DEFAULT_FORMATTER",
 * )
 */

 class FieldTypeName extends FieldItemBase {

  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties['title'] = DataDefinition::create('string')
                                          ->setLabel(t('Title'));

    $properties['link_uri'] = DataDefinition::create('string')
                                              ->setLabel(t('URL'));

    $properties['link_title'] = DataDefinition::create('string')
                                                ->setLabel(t('TITLE'));

    $properties['image_target_id'] = DataDefinition::create('integer')
                                                    ->setLabel(t('IMAGE'));

    $properties['description'] = DataDefinition::create('string')
                                                     ->setLabel(t('description'));

    return $properties;
  }

  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    return [
      'columns' => [
        'title'            => [
          'type'     => 'text',
          'size'     => 'tiny',
          'not null' => FALSE,
        ],
        'link_uri'        => [
          'type'     => 'varchar',
          'length'   => 2048,
          'not null' => FALSE,
        ],
        'link_title'      => [
          'type'     => 'varchar',
          'length'   => 255,
          'not null' => FALSE,
        ],
        'description' => [
          'type'     => 'text',
          'size'     => 'tiny',
          'not null' => FALSE,
        ],
        'image_target_id'  => [
          'type'     => 'int',
          'size'     => 'normal',
          'not null' => FALSE,
          'unsigned' => TRUE,
        ],
      ],
      'indexes' => [
        'image_target_id' => ['image_target_id'],
        'link_uri'       => ['link_uri'],
      ],
    ];
  }

  public function isEmpty() {
    if (!empty($this->title)
        || !empty($this->link_uri)
        || !empty($this->link_title)
        || !empty($this->description)
        || !empty($this->image_target_id)) {
      return FALSE;
    }

    return TRUE;
  }

}

FieldWidget

The FieldWidget is the class that will handle the display of the field in the form. It will be responsible for displaying the field in the form and handling the data that is sent from the form.

When working with links, there are certain rules that you should follow:

  • The link_type attribute means internal, or external. 16 is external, 17 is internal.

  • We should add a element_validate attribute so that Drupal can validate if the url is correct

  • The states attribute helps prevent saving the form if the user is trying to submit a link title without a url. In this case we're indicating that the link_title is related to link_uri.

When working with media elements, there are certain rules you should follow:

  • allowed_bundles will indicate which type of media element we want to show up for the user.

<?php

namespace Drupal\MODULE_NAME\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * @FieldWidget(
 *   id = "YOUR_DEFAULT_WIDGET",
 *   label = @Translation("THE LABEL THAT WILL BE DISPLAYED"),
 *   description = @Translation("A SIMPLE DESCRIPTION OF THE FIELD"),
 *   field_types = {
 *     "YOUR_FIELD_TYPE_ID"
 *   }
 * )
 */
class FieldWidgetName extends WidgetBase {

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {

    // Get the field name and field type.
    $field_name = $this->fieldDefinition->getName();

    // Create form elements for each field in the field type.
    $element['title'] = [
      '#type'          => 'textfield',
      '#title'         => t('title'),
      '#default_value' => $items[$delta]->title ?? NULL,
      '#attributes'    => [
        'style' => 'width: 100%;',
      ],
    ];


    $element['link_uri'] = [
      '#type'             => 'url',
      '#title'            => t('URL'),
      '#default_value'    => $items[$delta]->link_uri ?? NULL,
      '#maxlength'        => 2048,
      "#link_type"        => 16,
      "#required"         => FALSE,
      '#attributes'       => [
        'style' => 'width: 100%;',
      ],
      '#element_validate' => [
        [LinkWidget::class, 'validateUriElement'],
      ],
      '#states'           => [
        'required' => [
          ':input[name="' . $field_name . '[' . $delta . '][link_title]"]' => ['filled' => TRUE],

        ],
      ],
    ];

    $element['link_title'] = [
      '#type'          => 'textfield',
      '#title'         => t('link_title'),
      '#default_value' => $items[$delta]->link_title ?? NULL,
      "#maxlength"     => 255,
      '#attributes'    => [
        'style' => 'width: 100%;',
      ],
    ];

    // Image field
    $element['image_target_id'] = [
      '#type'            => 'media_library',
      '#title'           => t('Image'),
      '#allowed_bundles' => ['image'],
      '#default_value'   => $items[$delta]->image_target_id ?? NULL,
      '#attributes'      => [
        'style' => 'width: 100%;',
      ],
    ];


    $element['description'] = [
      '#type'          => 'textfield',
      '#title'         => t('Description'),
      '#default_value' => $items[$delta]->description ?? NULL,
      '#attributes'    => [
        'style' => 'width: 100%;',
      ],
    ];


    return $element;
  }

}

FieldFormatter

The FieldFormatter is the class that will handle the display of the field in the view. It will be responsible for displaying the field in the view.

<?php

namespace Drupal\MODULE_NAME\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;

/**
 * @FieldWidget(
 *   id = "YOUR_DEFAULT_WIDGET",
 *   label = @Translation("THE LABEL THAT WILL BE DISPLAYED"),
 *   description = @Translation("A SIMPLE DESCRIPTION OF THE FIELD"),
 *   field_types = {
 *     "YOUR_FIELD_TYPE_ID"
 *   }
 * )
 */
class FieldFormatterName extends FormatterBase {

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = [];

    foreach ($items as $delta => $item) {
      // The text value has no text format assigned to it, so the user input
      // should equal the output, including newlines.
      $elements[$delta] = [
        '#type' => 'inline_template',
        '#template' => '{{ value|nl2br }}',
        '#context' => ['value' => $item->value],
      ];
    }

    return $elements;
  }

}
PreviousTextfields, formatted text and numbers

Last updated 2 years ago

If you want your form field to show as a media library, you should install the [Media Library Form API Element Module]()

https://www.drupal.org/project/media_library_form_element