Make site section vocabulary configurable and simplify settings form

Add a vocabulary selector to the settings form so the site section
vocabulary is no longer hardcoded. Remove node bundle checkboxes
(section_page/content_page are always included), keep user and group
as configurable parent targets. All hardcoded 'site_sections'
references in PHP replaced with dynamic config reads via helper.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-05 13:22:57 -03:00
parent ffca330c89
commit c1274bf3ce
9 changed files with 139 additions and 81 deletions

View File

@@ -169,7 +169,7 @@ class SectionBreadcrumbBuilder implements BreadcrumbBuilderInterface {
];
}
// If parent is taxonomy_term, that's our context (handled via site_sections).
// If parent is taxonomy_term, that's our context (handled via configured vocabulary).
if ($parent_entity_type === 'taxonomy_term') {
return [
'type' => 'taxonomy_term',

View File

@@ -105,34 +105,39 @@ class StructuralPagesSettingsForm extends ConfigFormBase {
foreach ($allowed_targets as $target) {
$key = $target['entity_type'] . ':' . $target['bundle'];
$enabled_targets[$key] = TRUE;
// Handle wildcard bundles.
if ($target['bundle'] === '*') {
$enabled_targets[$target['entity_type'] . ':*'] = TRUE;
}
}
$form['description'] = [
'#type' => 'markup',
'#markup' => '<p>' . $this->t('Select which entity types and bundles can be used as parent for Content Page nodes. This allows creating hierarchical structures where content pages can be children of different entity types.') . '</p>',
];
$form['context_info'] = [
'#type' => 'markup',
'#markup' => '<p>' . $this->t('<strong>Context behavior:</strong><br>
- <em>Node/Taxonomy</em>: Content pages inherit the site section from the parent.<br>
- <em>User</em>: Content pages are associated with the user profile page.<br>
- <em>Group</em>: Content pages are associated with the group.') . '</p>',
// Site section vocabulary selector.
$vocabularies = $this->entityTypeManager->getStorage('taxonomy_vocabulary')->loadMultiple();
$vocabulary_options = [];
foreach ($vocabularies as $vid => $vocabulary) {
$vocabulary_options[$vid] = $vocabulary->label();
}
$form['site_section_vocabulary'] = [
'#type' => 'select',
'#title' => $this->t('Site section vocabulary'),
'#description' => $this->t('Select the taxonomy vocabulary used for site sections. Content pages and section pages will reference terms from this vocabulary.'),
'#options' => $vocabulary_options,
'#default_value' => $config->get('site_section_vocabulary') ?? 'site_sections',
'#required' => TRUE,
];
// Additional parent targets (user, group).
$form['allowed_parent_targets'] = [
'#type' => 'fieldset',
'#title' => $this->t('Allowed Parent Targets'),
'#title' => $this->t('Additional Parent Targets'),
'#tree' => TRUE,
];
$supportedEntityTypes = $this->handlerManager->getSupportedEntityTypes();
foreach ($supportedEntityTypes as $entity_type => $label) {
// Skip taxonomy_term and node — managed automatically.
if ($entity_type === 'taxonomy_term' || $entity_type === 'node') {
continue;
}
$form['allowed_parent_targets'][$entity_type] = [
'#type' => 'details',
'#title' => $label,
@@ -190,11 +195,23 @@ class StructuralPagesSettingsForm extends ConfigFormBase {
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
$targets = [];
$values = $form_state->getValue('allowed_parent_targets');
$vocabulary = $form_state->getValue('site_section_vocabulary');
$values = $form_state->getValue('allowed_parent_targets') ?? [];
$supportedEntityTypes = $this->handlerManager->getSupportedEntityTypes();
// Fixed targets: taxonomy vocabulary + module content types.
$targets = [
['entity_type' => 'taxonomy_term', 'bundle' => $vocabulary],
['entity_type' => 'node', 'bundle' => 'section_page'],
['entity_type' => 'node', 'bundle' => 'content_page'],
];
// Configurable targets: user, group, etc.
foreach ($supportedEntityTypes as $entity_type => $label) {
if ($entity_type === 'taxonomy_term' || $entity_type === 'node') {
continue;
}
if (empty($values[$entity_type])) {
continue;
}
@@ -209,7 +226,6 @@ class StructuralPagesSettingsForm extends ConfigFormBase {
}
foreach ($values[$entity_type] as $bundle => $enabled) {
// Skip the special "_all" key for groups if not enabled.
if ($bundle === '_all') {
continue;
}
@@ -223,12 +239,16 @@ class StructuralPagesSettingsForm extends ConfigFormBase {
}
$this->config('structural_pages.settings')
->set('site_section_vocabulary', $vocabulary)
->set('allowed_parent_targets', $targets)
->save();
// Update field configuration to reflect new targets.
$this->updateFieldConfiguration($targets);
// Update field_site_section target_bundles on both content types.
$this->updateSiteSectionFieldConfiguration($vocabulary);
parent::submitForm($form, $form_state);
}
@@ -297,4 +317,31 @@ class StructuralPagesSettingsForm extends ConfigFormBase {
$this->messenger()->addStatus($this->t('Field configuration updated successfully.'));
}
/**
* Updates field_site_section target_bundles on both content types.
*
* @param string $vocabulary
* The vocabulary machine name to set as target bundle.
*/
protected function updateSiteSectionFieldConfiguration(string $vocabulary): void {
$field_names = [
'node.section_page.field_site_section',
'node.content_page.field_site_section',
];
$storage = $this->entityTypeManager->getStorage('field_config');
foreach ($field_names as $field_name) {
$field_config = $storage->load($field_name);
if (!$field_config) {
continue;
}
$settings = $field_config->getSettings();
$settings['handler_settings']['target_bundles'] = [$vocabulary => $vocabulary];
$field_config->setSettings($settings);
$field_config->save();
}
}
}

View File

@@ -20,7 +20,7 @@ use Drupal\taxonomy\TermInterface;
entity_type_id: 'taxonomy_term',
clears_site_section: FALSE,
sort_field: 'name',
bundle_restrictions: ['site_sections'],
bundle_restrictions: [],
weight: 0,
)]
class TaxonomyTermHandler extends ParentEntityHandlerBase {
@@ -61,6 +61,19 @@ class TaxonomyTermHandler extends ParentEntityHandlerBase {
}
}
/**
* {@inheritdoc}
*/
public function handlesEntity(EntityInterface $entity): bool {
if ($entity->getEntityTypeId() !== 'taxonomy_term') {
return FALSE;
}
$vocabulary = \Drupal::config('structural_pages.settings')
->get('site_section_vocabulary') ?? 'site_sections';
return $entity->bundle() === $vocabulary;
}
/**
* {@inheritdoc}
*/
@@ -69,8 +82,7 @@ class TaxonomyTermHandler extends ParentEntityHandlerBase {
return NULL;
}
// Only site_sections terms can be site sections.
if ($entity->bundle() !== 'site_sections') {
if (!$this->handlesEntity($entity)) {
return NULL;
}