No longer possible to customize the widget

Created on 15 July 2025, about 2 months ago

Problem/Motivation

Upgrading from Drupal 10 to Drupal 11, we have updated Double Field module from 4.2.0 to 5.0.0-beta1. In this version, the filed widget (located at src/Plugin/Field/FieldWidget/DoubleField.php) is declared as a final class, make it not possible to extend and add customizations to the widget. In Drupal 10, we customize a date field widget to add a calendar library to improve UX.

Steps to reproduce

Create a custom double_field widget extending the widget class in D10 and then update the core to Drupal 11 and the contrib to 5.0.0-beta1.

Proposed resolution

Remove final declaration from the FieldWidget class.

🐛 Bug report
Status

Active

Version

5.0

Component

Code

Created by

🇪🇸Spain rvilar Montcada i Reixac, Catalonia

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @rvilar
  • 🇪🇸Spain rvilar Montcada i Reixac, Catalonia
  • 🇪🇸Spain rvilar Montcada i Reixac, Catalonia
  • 🇪🇸Spain rvilar Montcada i Reixac, Catalonia

    Proposed the removal of final class.

  • 🇷🇺Russia Chi

    Can you share the widget code?

  • 🇪🇸Spain rvilar Montcada i Reixac, Catalonia

    Here it is the code for the widget:

    
    namespace Drupal\my_project\Plugin\Field\FieldWidget;
    
    use Drupal\Core\Field\FieldItemListInterface;
    use Drupal\Core\Form\FormStateInterface;
    use Drupal\double_field\Plugin\Field\FieldWidget\DoubleField;
    
    /**
     * Custom plugin implementation of the 'double_field' widget.
     *
     * @FieldWidget(
     *   id = "custom_double_field",
     *   label = @Translation("Custom Double Field"),
     *   field_types = {"double_field"}
     * )
     */
    class CustomDoubleField extends DoubleField {
    
      /**
       * {@inheritdoc}
       */
      public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state): array {
        $form_element = parent::formElement($items, $delta, $element, $form, $form_state);
        $field_settings = $this->getFieldSettings();
        $settings = $this->getSettings();
    
        // Create custom form element using Flatpickr as field datepicker.
        foreach (['first', 'second'] as $subfield) {
          $widget_type = $settings[$subfield]['type'];
          if ($widget_type == 'datetime') {
            if ($field_settings['storage'][$subfield]['datetime_type'] == 'date') {
              $name = 'open_position-' . $subfield;
              $default_value = $items[$delta]->createDate($subfield);
    
              $form_element[$subfield]['#attributes']['flatpickr-name'] = $name;
              $form_element[$subfield]['#attributes']['class'][] = 'field--widget-datetime-flatpickr';
              $form_element[$subfield]['#attached']['library'][] = 'datetime_flatpickr/flatpickr-init';
              $form_element[$subfield]['#attached']['drupalSettings']['datetimeFlatPickr'][$name] = [
                'settings' => [
                  'altInput' => TRUE,
                  'altFormat' => 'd/m/Y',
                  'dateFormat' => 'Y-m-d',
                  'defaultDate' => !empty($default_value) ? $default_value->format('Y-m-d') : date('Y-m-d'),
                  'position' => 'auto',
                  'disabledWeekDays' => [],
                ],
              ];
            }
            else {
              if ($form_element[$subfield]['#default_value']) {
                $form_element[$subfield]['#default_value']->setTimezone(new \DateTimezone(date_default_timezone_get()));
              }
              // Ensure that the datetime field processing doesn't set its own time
              // zone here.
              $form_element[$subfield]['#date_timezone'] = date_default_timezone_get();
            }
          }
        }
    
        return $form_element;
      }
    
      /**
       * {@inheritdoc}
       */
      protected function getSubwidgets(string $subfield_type, bool $list): array {
        $subwidgets = parent::getSubwidgets($subfield_type, $list);
    
        if ($subfield_type == 'datetime_iso8601') {
          $subwidgets['datetime'] = $this->t('Flatpickr Datepicker');
        }
    
        return $subwidgets;
      }
    
    }
    
    
  • 🇷🇺Russia Chi

    Generally plugin classes are not part of public API.
    https://www.drupal.org/about/core/policies/core-change-policies/bc-polic...

    In your case it should be simpler to implement hook_field_widget_single_element_WIDGET_TYPE_form_alter instead of creating new widget.

  • 🇪🇸Spain rvilar Montcada i Reixac, Catalonia

    Thanks for your suggestion. We are going to rewrite the widget using hook_field_widget_single_element_WIDGET_TYPE_form_alter. Very appreciated

Production build 0.71.5 2024