logo

额外区块类型 (EBT) - 全新的布局构建器体验❗

额外区块类型 (EBT) - 样式化、可定制的区块类型:幻灯片、标签页、卡片、手风琴等更多类型。内置背景、DOM Box、JavaScript 插件的设置。立即体验布局构建的未来。

演示 EBT 模块 下载 EBT 模块

❗额外段落类型 (EPT) - 全新的 Paragraphs 体验

额外段落类型 (EPT) - 类似的基于 Paragraph 的模块集合。

演示 EPT 模块 滚动

滚动
04/10/2025, by Ivan

Menu

字段小部件用于在表单中渲染字段。字段小部件被定义为插件,因此在编写新的字段类型之前,建议先熟悉 插件 API

在 Drupal 8 中创建字段小部件,需要一个带有 FieldWidget 注解的类。

类的位置 应该是 /[MODULE_NAME]/src/Plugin/Field/FieldWidget,例如:/foo/src/Plugin/Field/FieldWidget/BarWidget.php。

类的命名空间 应该是 [MODULE_NAME]\Plugin\Field\FieldWidget,例如:\Drupal\foo\Plugin\Field\FieldWidget。

类上的注解 必须包含唯一的 ID、标签以及此小部件可以处理的字段类型 ID 数组。

/**
 * A widget bar.
 *
 * @FieldWidget(
 *   id = "bar",
 *   label = @Translation("Bar widget"),
 *   field_types = {
 *     "baz",
 *     "string"
 *   }
 * )
 */

必须实现 WidgetInterface,并且可以扩展 WidgetBase 来提供通用实现。唯一必须实现的方法是 ::formElement(),它必须返回实际渲染你的小部件的表单元素。

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

//...
class BarWidget extends WidgetBase {

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $element = [];
    // 构建元素渲染数组。
    return $element;
  }

}

小部件设置

如果你的小部件需要额外的设置,需要执行以下三个步骤:

步骤 1: 重写 PluginSettingsBase::defaultSettings() 设置默认值

/**
 * {@inheritdoc}
 */
 public static function defaultSettings() {
  return [
    // 创建自定义设置 'size',默认值为 60
    'size' => 60,
  ] + parent::defaultSettings();
}

步骤 2: 为自定义设置定义配置 schema

配置 schema 文件路径:

/[MODULE_NAME]/config/schema/[MODULE_NAME].schema.yml

在该文件中描述在 defaultSettings() 中声明的设置的数据类型:

field.widget.settings.[WIDGET ID]:
  type: mapping
  label: 'WIDGET NAME widget settings'
  mapping:
    size:
      type: integer
      label: 'Size'

步骤 3: 创建表单,让用户修改设置

通过重写 WidgetBase::settingsForm() 创建表单:

/**
 * {@inheritdoc}
 */
public function settingsForm(array $form, FormStateInterface $form_state) {
  $element['size'] = [
    '#type' => 'number',
    '#title' => $this->t('Size of textfield'),
    '#default_value' => $this->getSetting('size'),
    '#required' => TRUE,
    '#min' => 1,
  ];

  return $element;
}

你还可以在小部件的摘要中列出这些设置:

/**
 * {@inheritdoc}
 */
public function settingsSummary() {
  $summary = [];

  $summary[] = $this->t('Textfield size: @size', array('@size' => $this->getSetting('size')));

  return $summary;
}

你可以使用 getSetting() 方法在小部件中获取设置值:

class BarWidget extends WidgetBase implements WidgetInterface {

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $element['value'] = $element + [
      '#type' => 'textfield',
      '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
      '#size' => $this->getSetting('size'),
    ];

    return $element;
  }

}

小部件示例

TextWidget 示例来自 Examples 模块 的 field_example:

namespace Drupal\field_example\Plugin\Field\FieldWidget;

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

/**
 * Plugin implementation of the 'field_example_text' widget.
 *
 * @FieldWidget(
 *   id = "field_example_text",
 *   module = "field_example",
 *   label = @Translation("RGB value as #ffffff"),
 *   field_types = {
 *     "field_example_rgb"
 *   }
 * )
 */
class TextWidget extends WidgetBase {

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $value = isset($items[$delta]->value) ? $items[$delta]->value : '';
    $element += [
      '#type' => 'textfield',
      '#default_value' => $value,
      '#size' => 7,
      '#maxlength' => 7,
      '#element_validate' => [
        [static::class, 'validate'],
      ],
    ];
    return ['value' => $element];
  }

  /**
   * 验证颜色文本字段。
   */
  public static function validate($element, FormStateInterface $form_state) {
    $value = $element['#value'];
    if (strlen($value) == 0) {
      $form_state->setValueForElement($element, '');
      return;
    }
    if (!preg_match('/^#([a-f0-9]{6})$/iD', strtolower($value))) {
      $form_state->setError($element, t("Color must be a 6-digit hexadecimal value, suitable for CSS."));
    }
  }

}