Drupal 11:编程创建带自定义字段的词汇表,字段不显示于UI
问题分析与解决方案
核心问题
你遇到的问题是:通过entity_insert钩子自动创建词汇表和实体引用字段后,字段无法在分类术语的添加/编辑表单中显示,但手动创建同类型字段却能正常显示。
代码中的问题点及修复
1. 字段存储的provider配置错误
你的字段存储定义中'provider' => 'field_create'是无效的,provider必须是你的模块名称(比如mymodule)。Drupal需要通过provider识别字段的归属模块,错误的provider会导致字段无法被表单系统正确加载。
2. 不恰当的全量缓存刷新
在entity_insert钩子中调用drupal_flush_all_caches()会干扰实体保存的正常流程——此时刚创建的词汇表和字段可能还未完全写入数据库,缓存刷新会导致后续操作无法正确读取实体信息。
3. 表单显示组件配置缺失(可选优化)
虽然不是必须,但明确添加widget的settings配置可以避免潜在的配置缺失问题,确保字段组件被正确初始化。
修复后的完整代码
function mymodule_entity_insert(\Drupal\Core\Entity\EntityInterface $entity) { // 创建顶部菜单词汇表(仅针对section类型节点) if ($entity->bundle() == "section") { /*** * Top menu vocabulary */ $vocabulary_id = $entity->id() . '_top_menu'; $vocabulary_name = t('@entity_name Top Menu', ['@entity_name' => $entity->label()]); // 创建并保存词汇表 $vocabulary = Vocabulary::create([ 'vid' => $vocabulary_id, 'name' => $vocabulary_name, ])->save(); // 定义字段信息 $field_name = 'field_parent_entity_reference'; $entity_type = 'taxonomy_term'; $bundle = $vocabulary_id; // 检查字段存储是否存在,不存在则创建 if (!$field_storage = FieldStorageConfig::loadByName($entity_type, $field_name)) { $field_storage = FieldStorageConfig::create([ 'field_name' => $field_name, 'entity_type' => $entity_type, 'type' => 'entity_reference', 'settings' => [ 'target_type' => 'node', ], 'cardinality' => 1, 'provider' => 'mymodule', // 替换为你的模块名称 ]); $field_storage->save(); } // 检查字段实例是否存在,不存在则创建 if (!FieldConfig::loadByName($entity_type, $bundle, $field_name)) { FieldConfig::create([ 'field_name' => $field_name, 'entity_type' => $entity_type, 'field_storage' => $field_storage, 'bundle' => $bundle, 'label' => t('Content to show'), 'settings' => [ 'handler' => 'default', 'handler_settings' => [ 'target_bundles' => [ 'announcement' => 'announcement', 'section' => 'section', 'page' => 'page', 'event' => 'event', 'article' => 'article', ], ], ], ])->save(); } // 加载或创建表单显示配置 $form_display = EntityFormDisplay::load('taxonomy_term.' . $bundle . '.default'); if (!$form_display) { $form_display = EntityFormDisplay::create([ 'targetEntityType' => 'taxonomy_term', 'bundle' => $bundle, 'mode' => 'default', ]); } // 配置字段的表单组件(添加完整的widget设置) $form_display->setComponent($field_name, [ 'type' => 'entity_reference_autocomplete', 'weight' => 50, 'settings' => [ 'match_operator' => 'CONTAINS', 'size' => 60, 'placeholder' => '', ], ])->save(); // 加载或创建视图显示配置 $view_display = EntityViewDisplay::load('taxonomy_term.' . $bundle . '.default'); if (!$view_display) { $view_display = EntityViewDisplay::create([ 'targetEntityType' => 'taxonomy_term', 'bundle' => $bundle, 'mode' => 'default', ]); } // 配置字段的视图组件 $view_display->setComponent($field_name, [ 'label' => 'above', 'type' => 'entity_reference_label', 'weight' => 50, ])->save(); // 仅重置相关实体类型的缓存,而非全量刷新 \Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary')->resetCache(); \Drupal::entityTypeManager()->getStorage('field_config')->resetCache(); \Drupal::entityTypeManager()->getStorage('entity_form_display')->resetCache(); // 日志调试(可选) \Drupal::logger('mymodule')->info('Form display updated for field: @field', ['@field' => $field_name]); $vocab_load = Vocabulary::load($vocabulary_id); $field_load = FieldConfig::loadByName('taxonomy_term', $bundle, $field_name); \Drupal::logger('mymodule')->info('Vocabulary: @vocab, Field: @field', [ '@vocab' => $vocab_load ? $vocab_load->id() : 'Not Found', '@field' => $field_load ? $field_load->id() : 'Not Found', ]); // 测试创建术语(可选) $term = \Drupal\taxonomy\Entity\Term::create([ 'vid' => $vocabulary_id, 'name' => 'Test Term', ]); $term->save(); $loaded_term = \Drupal\taxonomy\Entity\Term::load($term->id()); \Drupal::logger('mymodule')->info('Field Value: @value', [ '@value' => $loaded_term->get($field_name)->value ?? 'Empty', ]); } }
额外说明
- 替换代码中的
mymodule为你实际的模块名称,确保provider配置正确。 - 使用针对性的缓存重置替代全量缓存刷新,既保证缓存更新,又不破坏当前实体操作流程。
- 若修复后仍有问题,可以检查:
- 字段的权限设置是否允许当前用户编辑该字段
- 词汇表的bundle是否被正确注册到
taxonomy_term实体类型中(可通过drush entity:list taxonomy_term查看)
内容的提问来源于stack exchange,提问作者Zathrus Writer
相关产品推荐
相关产品推荐

