diff --git a/config/install/structural_pages.settings.yml b/config/install/structural_pages.settings.yml
index a1e90bf..f149931 100644
--- a/config/install/structural_pages.settings.yml
+++ b/config/install/structural_pages.settings.yml
@@ -1,10 +1,11 @@
+site_section_vocabulary: site_sections
allowed_parent_targets:
- - entity_type: node
- bundle: content_page
- - entity_type: node
- bundle: section_page
- entity_type: taxonomy_term
bundle: site_sections
+ - entity_type: node
+ bundle: section_page
+ - entity_type: node
+ bundle: content_page
- entity_type: user
bundle: user
- entity_type: group
diff --git a/config/schema/structural_pages.schema.yml b/config/schema/structural_pages.schema.yml
index 8026e38..56c91e8 100644
--- a/config/schema/structural_pages.schema.yml
+++ b/config/schema/structural_pages.schema.yml
@@ -2,6 +2,9 @@ structural_pages.settings:
type: config_object
label: 'Structural Pages settings'
mapping:
+ site_section_vocabulary:
+ type: string
+ label: 'Site section vocabulary'
allowed_parent_targets:
type: sequence
label: 'Allowed parent targets'
diff --git a/src/Breadcrumb/SectionBreadcrumbBuilder.php b/src/Breadcrumb/SectionBreadcrumbBuilder.php
index 355c4c8..0939498 100644
--- a/src/Breadcrumb/SectionBreadcrumbBuilder.php
+++ b/src/Breadcrumb/SectionBreadcrumbBuilder.php
@@ -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',
diff --git a/src/Form/StructuralPagesSettingsForm.php b/src/Form/StructuralPagesSettingsForm.php
index 753582a..42f06b8 100644
--- a/src/Form/StructuralPagesSettingsForm.php
+++ b/src/Form/StructuralPagesSettingsForm.php
@@ -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' => '
' . $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.') . '
',
- ];
-
- $form['context_info'] = [
- '#type' => 'markup',
- '#markup' => '' . $this->t('Context behavior:
- - Node/Taxonomy: Content pages inherit the site section from the parent.
- - User: Content pages are associated with the user profile page.
- - Group: Content pages are associated with the group.') . '
',
+ // 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();
+ }
+ }
+
}
diff --git a/src/Plugin/ParentEntityHandler/TaxonomyTermHandler.php b/src/Plugin/ParentEntityHandler/TaxonomyTermHandler.php
index 718d0fe..8dd1bde 100644
--- a/src/Plugin/ParentEntityHandler/TaxonomyTermHandler.php
+++ b/src/Plugin/ParentEntityHandler/TaxonomyTermHandler.php
@@ -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;
}
diff --git a/structural_pages.install b/structural_pages.install
index 7048d10..d960d39 100644
--- a/structural_pages.install
+++ b/structural_pages.install
@@ -13,7 +13,7 @@ use Drupal\taxonomy\Entity\Term;
* Implements hook_install().
*/
function structural_pages_install(): void {
- // Create default terms for site_sections vocabulary.
+ // Create default terms for the configured vocabulary.
_structural_pages_create_default_terms();
// Display success message.
@@ -21,10 +21,10 @@ function structural_pages_install(): void {
}
/**
- * Creates default terms for the site_sections vocabulary.
+ * Creates default terms for the configured site section vocabulary.
*/
function _structural_pages_create_default_terms(): void {
- $vocabulary = 'site_sections';
+ $vocabulary = _structural_pages_get_vocabulary();
// Check if terms already exist (avoid duplication on reinstall).
$existing = \Drupal::entityQuery('taxonomy_term')
@@ -210,10 +210,11 @@ function structural_pages_uninstall(): void {
}
}
- // Remove terms from site_sections vocabulary.
+ // Remove terms from the configured vocabulary.
+ $vocabulary = _structural_pages_get_vocabulary();
$tids = \Drupal::entityQuery('taxonomy_term')
->accessCheck(FALSE)
- ->condition('vid', 'site_sections')
+ ->condition('vid', $vocabulary)
->execute();
if ($tids) {
$terms = $entity_type_manager->getStorage('taxonomy_term')->loadMultiple($tids);
@@ -227,7 +228,7 @@ function structural_pages_uninstall(): void {
// Pathauto patterns.
'pathauto.pattern.section_page',
'pathauto.pattern.content_page',
- 'pathauto.pattern.site_sections_term',
+ 'pathauto.pattern.' . $vocabulary . '_term',
// Entity displays.
'core.entity_form_display.node.section_page.default',
'core.entity_view_display.node.section_page.default',
@@ -246,7 +247,7 @@ function structural_pages_uninstall(): void {
'node.type.section_page',
'node.type.content_page',
// Vocabulary.
- 'taxonomy.vocabulary.site_sections',
+ 'taxonomy.vocabulary.' . $vocabulary,
];
$config_factory = \Drupal::configFactory();
@@ -290,15 +291,16 @@ function structural_pages_update_10003(): void {
}
/**
- * Fix content translation config and update site_sections term translations.
+ * Fix content translation config and update term translations.
*/
function structural_pages_update_10004(): void {
// Ensure content translation is properly configured for the vocabulary.
_structural_pages_ensure_content_translation();
+ $vocabulary = _structural_pages_get_vocabulary();
$terms = \Drupal::entityTypeManager()
->getStorage('taxonomy_term')
- ->loadByProperties(['vid' => 'site_sections']);
+ ->loadByProperties(['vid' => $vocabulary]);
if ($terms) {
_structural_pages_add_term_translations($terms);
@@ -306,14 +308,15 @@ function structural_pages_update_10004(): void {
}
/**
- * Ensures content translation settings exist for site_sections vocabulary.
+ * Ensures content translation settings exist for the configured vocabulary.
*/
function _structural_pages_ensure_content_translation(): void {
if (!\Drupal::moduleHandler()->moduleExists('content_translation')) {
return;
}
- $config = \Drupal\language\Entity\ContentLanguageSettings::loadByEntityTypeBundle('taxonomy_term', 'site_sections');
+ $vocabulary = _structural_pages_get_vocabulary();
+ $config = \Drupal\language\Entity\ContentLanguageSettings::loadByEntityTypeBundle('taxonomy_term', $vocabulary);
$config->setDefaultLangcode('site_default');
$config->setLanguageAlterable(TRUE);
$config->setThirdPartySetting('content_translation', 'enabled', TRUE);
@@ -327,19 +330,20 @@ function structural_pages_requirements(string $phase): array {
$requirements = [];
if ($phase === 'runtime') {
- // Check if site_sections vocabulary has terms.
+ // Check if the configured vocabulary has terms.
+ $vocabulary = _structural_pages_get_vocabulary();
$term_count = \Drupal::entityQuery('taxonomy_term')
->accessCheck(FALSE)
- ->condition('vid', 'site_sections')
+ ->condition('vid', $vocabulary)
->count()
->execute();
if ($term_count === 0) {
$requirements['structural_pages_terms'] = [
'title' => t('Structural Pages'),
- 'value' => t('No terms in site_sections vocabulary'),
- 'description' => t('The Structural Pages module requires terms in the "Site Sections" vocabulary. Add terms.', [
- ':url' => '/admin/structure/taxonomy/manage/site_sections/add',
+ 'value' => t('No terms in @vocabulary vocabulary', ['@vocabulary' => $vocabulary]),
+ 'description' => t('The Structural Pages module requires terms in the site section vocabulary. Add terms.', [
+ ':url' => '/admin/structure/taxonomy/manage/' . $vocabulary . '/add',
]),
'severity' => REQUIREMENT_WARNING,
];
diff --git a/structural_pages.links.menu.yml b/structural_pages.links.menu.yml
index 1494e8b..e80b0ad 100644
--- a/structural_pages.links.menu.yml
+++ b/structural_pages.links.menu.yml
@@ -1,6 +1,6 @@
structural_pages.settings:
title: 'Structural Pages'
- description: 'Configure allowed parent entity types for content pages.'
+ description: 'Configure the Structural Pages module settings.'
route_name: structural_pages.settings
parent: site_tools.admin_config
weight: 0
diff --git a/structural_pages.module b/structural_pages.module
index 3183f13..f594ef4 100644
--- a/structural_pages.module
+++ b/structural_pages.module
@@ -67,6 +67,17 @@ function structural_pages_entity_presave(EntityInterface $entity): void {
}
}
+/**
+ * Returns the configured site section vocabulary machine name.
+ *
+ * @return string
+ * The vocabulary ID (e.g., 'site_sections').
+ */
+function _structural_pages_get_vocabulary(): string {
+ return \Drupal::config('structural_pages.settings')
+ ->get('site_section_vocabulary') ?? 'site_sections';
+}
+
/**
* Gets the site section ID from a parent entity.
*
@@ -82,9 +93,9 @@ function _structural_pages_get_section_from_parent(string $parent_entity_type, i
$entity_type_manager = \Drupal::entityTypeManager();
if ($parent_entity_type === 'taxonomy_term') {
- // If parent is a taxonomy term, verify it's from site_sections vocabulary.
+ // If parent is a taxonomy term, verify it's from the configured vocabulary.
$term = $entity_type_manager->getStorage('taxonomy_term')->load($parent_id);
- if ($term instanceof TermInterface && $term->bundle() === 'site_sections') {
+ if ($term instanceof TermInterface && $term->bundle() === _structural_pages_get_vocabulary()) {
return $term->id();
}
return NULL;
@@ -224,7 +235,7 @@ function structural_pages_token_info(): array {
$info['tokens']['node']['site-section-path'] = [
'name' => t('Site Section Path'),
- 'description' => t('The hierarchical path of the site_sections taxonomy (e.g., undergraduate/courses).'),
+ 'description' => t('The hierarchical path of the site section taxonomy (e.g., undergraduate/courses).'),
];
$info['tokens']['term']['hierarchy-path'] = [
diff --git a/translations/structural_pages.pt-br.po b/translations/structural_pages.pt-br.po
index 8e53554..14f0c51 100644
--- a/translations/structural_pages.pt-br.po
+++ b/translations/structural_pages.pt-br.po
@@ -134,12 +134,12 @@ msgid "Deleted @count @bundle nodes."
msgstr "@count nós do tipo @bundle excluídos."
#: structural_pages.install
-msgid "No terms in site_sections vocabulary"
-msgstr "Nenhum termo no vocabulário site_sections"
+msgid "No terms in @vocabulary vocabulary"
+msgstr "Nenhum termo no vocabulário @vocabulary"
#: structural_pages.install
-msgid "The Structural Pages module requires terms in the \"Site Sections\" vocabulary. Add terms."
-msgstr "O módulo Páginas Estruturais requer termos no vocabulário \"Seções do Site\". Adicionar termos."
+msgid "The Structural Pages module requires terms in the site section vocabulary. Add terms."
+msgstr "O módulo Páginas Estruturais requer termos no vocabulário de seções do site. Adicionar termos."
#: structural_pages.install
msgid "@count terms configured"
@@ -154,8 +154,8 @@ msgid "Site Section Path"
msgstr "Caminho da Seção do Site"
#: structural_pages.module
-msgid "The hierarchical path of the site_sections taxonomy (e.g., undergraduate/courses)."
-msgstr "O caminho hierárquico da taxonomia site_sections (ex: graduacao/cursos)."
+msgid "The hierarchical path of the site section taxonomy (e.g., undergraduate/courses)."
+msgstr "O caminho hierárquico da taxonomia de seções do site (ex: graduacao/cursos)."
#: structural_pages.module
msgid "Hierarchy Path"
@@ -174,32 +174,16 @@ msgid "Structural Pages Settings"
msgstr "Configurações das Páginas Estruturais"
#: src/Form/StructuralPagesSettingsForm.php
-msgid "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."
-msgstr "Selecione quais tipos de entidade e bundles podem ser usados como pai para nós de Página de Conteúdo. Isso permite criar estruturas hierárquicas onde páginas de conteúdo podem ser filhas de diferentes tipos de entidade."
+msgid "Site section vocabulary"
+msgstr "Vocabulário de seções do site"
#: src/Form/StructuralPagesSettingsForm.php
-msgid "Context behavior:
\n - Node/Taxonomy: Content pages inherit the site section from the parent.
\n - User: Content pages are associated with the user profile page.
\n - Group: Content pages are associated with the group."
-msgstr "Comportamento de contexto:
\n - Node/Taxonomia: Páginas de conteúdo herdam a seção do site do pai.
\n - Usuário: Páginas de conteúdo são associadas à página de perfil do usuário.
\n - Grupo: Páginas de conteúdo são associadas ao grupo."
+msgid "Select the taxonomy vocabulary used for site sections. Content pages and section pages will reference terms from this vocabulary."
+msgstr "Selecione o vocabulário de taxonomia usado para seções do site. Páginas de conteúdo e páginas institucionais referenciarão termos deste vocabulário."
#: src/Form/StructuralPagesSettingsForm.php
-msgid "Allowed Parent Targets"
-msgstr "Alvos de Pai Permitidos"
-
-#: src/Form/StructuralPagesSettingsForm.php
-msgid "Content Types (node)"
-msgstr "Tipos de Conteúdo (node)"
-
-#: src/Form/StructuralPagesSettingsForm.php
-msgid "Taxonomy Vocabularies (taxonomy_term)"
-msgstr "Vocabulários de Taxonomia (taxonomy_term)"
-
-#: src/Form/StructuralPagesSettingsForm.php
-msgid "Users (user)"
-msgstr "Usuários (user)"
-
-#: src/Form/StructuralPagesSettingsForm.php
-msgid "Groups (group)"
-msgstr "Grupos (group)"
+msgid "Additional Parent Targets"
+msgstr "Alvos de Pai Adicionais"
#: src/Form/StructuralPagesSettingsForm.php
msgid "User accounts"
@@ -222,8 +206,8 @@ msgid "Field configuration updated successfully."
msgstr "Configuração do campo atualizada com sucesso."
#: structural_pages.links.menu.yml
-msgid "Configure allowed parent entity types for content pages."
-msgstr "Configure os tipos de entidade pai permitidos para páginas de conteúdo."
+msgid "Configure the Structural Pages module settings."
+msgstr "Configure as opções do módulo Páginas Estruturais."
#: src/Plugin/Block/StructuralPagesMenuBlock.php
msgid "Structural Pages Menu"
@@ -258,22 +242,18 @@ msgid "Site structure navigation"
msgstr "Navegação da estrutura do site"
#: src/Plugin/ParentEntityHandler/TaxonomyTermHandler.php
-#: src/Form/StructuralPagesSettingsForm.php
msgid "Taxonomy Vocabularies (taxonomy_term)"
msgstr "Vocabulários de Taxonomia (taxonomy_term)"
#: src/Plugin/ParentEntityHandler/UserHandler.php
-#: src/Form/StructuralPagesSettingsForm.php
msgid "Users (user)"
msgstr "Usuários (user)"
#: src/Plugin/ParentEntityHandler/NodeHandler.php
-#: src/Form/StructuralPagesSettingsForm.php
msgid "Content Types (node)"
msgstr "Tipos de Conteúdo (node)"
#: modules/structural_pages_group/src/Plugin/ParentEntityHandler/GroupHandler.php
-#: src/Form/StructuralPagesSettingsForm.php
msgid "Groups (group)"
msgstr "Grupos (group)"