mirror of
https://gitlab.unicamp.br/infimecc_drupal11_modules/structural_pages.git
synced 2026-04-24 08:11:58 -03:00
Add field_redirect_page to site_sections terms and fix root page hierarchy
- Add field_redirect_page to site_sections taxonomy terms, with a custom EntityReferenceSelection plugin that filters content_page nodes by section - Redirect taxonomy term canonical URLs to the configured node (301) - Fix root page detection in MenuBlock and views to also match nodes whose field_parent_page points to a taxonomy_term (not only empty parent) - Move root taxonomy-term option to the top of the parent-page dropdown - Add breadcrumb workaround for Gavias notech theme separator rendering - Add imecc_menu_helper submodule - Translate config labels and default terms from English to Portuguese Co-Authored-By: Henrique Bauer <henrique@webcontent.com.br> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
6
imecc_menu_helper/imecc_menu_helper.info.yml
Normal file
6
imecc_menu_helper/imecc_menu_helper.info.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
name: 'IMECC Menu Helper'
|
||||
type: module
|
||||
description: 'Automatiza a hierarquia de menus baseada na Taxonomia de Setores.'
|
||||
core_version_requirement: ^10
|
||||
package: Custom
|
||||
configure: imecc_menu_helper.settings
|
||||
5
imecc_menu_helper/imecc_menu_helper.links.menu.yml
Normal file
5
imecc_menu_helper/imecc_menu_helper.links.menu.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
imecc_menu_helper.settings_link:
|
||||
title: 'Hierarquia de Menus IMECC'
|
||||
parent: system.admin_config_content
|
||||
description: 'Mapear Setores para Itens de Menu.'
|
||||
route_name: imecc_menu_helper.settings
|
||||
202
imecc_menu_helper/imecc_menu_helper.module
Normal file
202
imecc_menu_helper/imecc_menu_helper.module
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
use Drupal\node\NodeInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Menu\MenuTreeParameters;
|
||||
use Drupal\Core\Routing\TrustedRedirectResponse;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_node_presave().
|
||||
* (Mantido intacto)
|
||||
*/
|
||||
function imecc_menu_helper_node_presave(NodeInterface $node) {
|
||||
if ($node->getType() != 'pagina') return;
|
||||
|
||||
$field_name = 'field_taxinomia_setor';
|
||||
if (!$node->hasField($field_name) || $node->get($field_name)->isEmpty()) return;
|
||||
|
||||
$setor_tid = $node->get($field_name)->target_id;
|
||||
$config = \Drupal::config('imecc_menu_helper.settings');
|
||||
$parent_mapping_string = $config->get('mapping_' . $setor_tid);
|
||||
|
||||
if (empty($parent_mapping_string)) return;
|
||||
|
||||
$current_parent = $node->menu['menu_parent'] ?? 'main:';
|
||||
|
||||
if ($current_parent != 'main:') {
|
||||
if ($current_parent != $parent_mapping_string) return;
|
||||
}
|
||||
|
||||
if (!$node->isNew() && strpos($parent_mapping_string, $node->uuid()) !== false) return;
|
||||
|
||||
$node->menu['enabled'] = 1;
|
||||
$node->menu['title'] = $node->getTitle();
|
||||
$node->menu['menu_parent'] = $parent_mapping_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_alter().
|
||||
*/
|
||||
function imecc_menu_helper_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
|
||||
if (!in_array($form_id, ['node_pagina_form', 'node_pagina_edit_form'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// --- LÓGICA DO MENU (AJAX) ---
|
||||
|
||||
// REMOVIDO: O wrapper 'imecc-menu-wrapper' que causava erro.
|
||||
// Agora atacamos direto o ID nativo 'edit-menu'.
|
||||
|
||||
if (isset($form['field_taxinomia_setor'])) {
|
||||
$form['field_taxinomia_setor']['widget']['#ajax'] = [
|
||||
'callback' => '_imecc_menu_helper_update_menu_options',
|
||||
'wrapper' => 'edit-menu', // <--- CORREÇÃO: Volta para o ID nativo
|
||||
'event' => 'change',
|
||||
'progress' => [
|
||||
'type' => 'throbber',
|
||||
'message' => t('Carregando menu...'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// --- LÓGICA DO REDIRECIONAMENTO (Barra Lateral) ---
|
||||
|
||||
$node = $form_state->getFormObject()->getEntity();
|
||||
|
||||
$should_open = FALSE;
|
||||
if ($node->hasField('field_redirecionar_para') && !$node->get('field_redirecionar_para')->isEmpty()) {
|
||||
$should_open = TRUE;
|
||||
}
|
||||
|
||||
$form['redirection_settings'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => t('Redirecionamento'),
|
||||
'#group' => 'advanced',
|
||||
'#open' => $should_open,
|
||||
'#weight' => -10,
|
||||
'#attributes' => [
|
||||
'class' => ['node-form-redirection-settings'],
|
||||
],
|
||||
];
|
||||
|
||||
if (isset($form['field_redirecionar_para'])) {
|
||||
$form['field_redirecionar_para']['#group'] = 'redirection_settings';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback AJAX (CORRIGIDO)
|
||||
*/
|
||||
function _imecc_menu_helper_update_menu_options(array &$form, FormStateInterface $form_state) {
|
||||
$values = $form_state->getValue('field_taxinomia_setor');
|
||||
$tid = 0;
|
||||
|
||||
if (is_array($values) && isset($values[0]['target_id'])) {
|
||||
$tid = $values[0]['target_id'];
|
||||
} elseif (is_array($values) && isset($values['target_id'])) {
|
||||
$tid = $values['target_id'];
|
||||
} elseif (is_numeric($values)) {
|
||||
$tid = $values;
|
||||
}
|
||||
|
||||
// CORREÇÃO: Garante que o ID do formulário se mantenha estável para não quebrar o AJAX
|
||||
$form['menu']['#attributes']['id'] = 'edit-menu';
|
||||
|
||||
if (empty($tid)) return $form['menu'];
|
||||
|
||||
$config = \Drupal::config('imecc_menu_helper.settings');
|
||||
$parent_mapping_string = $config->get('mapping_' . $tid);
|
||||
|
||||
if (empty($parent_mapping_string)) return $form['menu'];
|
||||
|
||||
list($menu_name, $root_plugin_id) = explode(':', $parent_mapping_string, 2);
|
||||
|
||||
/** @var \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree_service */
|
||||
$menu_tree_service = \Drupal::service('menu.link_tree');
|
||||
|
||||
$parameters = new MenuTreeParameters();
|
||||
$parameters->setRoot($root_plugin_id);
|
||||
$parameters->excludeRoot();
|
||||
$parameters->setMaxDepth(NULL);
|
||||
|
||||
$tree = $menu_tree_service->load($menu_name, $parameters);
|
||||
|
||||
$allowed_ids = [];
|
||||
$allowed_ids[$parent_mapping_string] = true;
|
||||
_imecc_menu_helper_extract_ids($tree, $menu_name, $allowed_ids);
|
||||
|
||||
if (isset($form['menu']['link']['menu_parent']['#options'])) {
|
||||
$options = $form['menu']['link']['menu_parent']['#options'];
|
||||
$filtered_options = [];
|
||||
|
||||
foreach ($options as $key => $label) {
|
||||
if (isset($allowed_ids[$key])) {
|
||||
$filtered_options[$key] = $label;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($filtered_options) && isset($options[$parent_mapping_string])) {
|
||||
$filtered_options[$parent_mapping_string] = $options[$parent_mapping_string];
|
||||
}
|
||||
|
||||
$form['menu']['link']['menu_parent']['#options'] = $filtered_options;
|
||||
|
||||
$current_val = $form_state->getValue(['menu', 'link', 'menu_parent']);
|
||||
if (empty($current_val) || !isset($filtered_options[$current_val])) {
|
||||
$form['menu']['link']['menu_parent']['#value'] = $parent_mapping_string;
|
||||
}
|
||||
}
|
||||
|
||||
$form['menu']['#open'] = TRUE;
|
||||
if (isset($form['menu']['enabled'])) {
|
||||
$form['menu']['enabled']['#value'] = 1;
|
||||
}
|
||||
|
||||
// CORREÇÃO: Retorna o array direto, sem envelopar em arrays novos
|
||||
return $form['menu'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Função auxiliar recursiva (Mantida intacta)
|
||||
*/
|
||||
function _imecc_menu_helper_extract_ids(array $tree, $menu_name, array &$allowed_ids) {
|
||||
foreach ($tree as $element) {
|
||||
$plugin_id = $element->link->getPluginId();
|
||||
$key = $menu_name . ':' . $plugin_id;
|
||||
$allowed_ids[$key] = true;
|
||||
|
||||
if ($element->subtree) {
|
||||
_imecc_menu_helper_extract_ids($element->subtree, $menu_name, $allowed_ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_view().
|
||||
* (Mantido intacto)
|
||||
*/
|
||||
function imecc_menu_helper_node_view(array &$build, NodeInterface $node, EntityViewDisplayInterface $display, $view_mode) {
|
||||
if ($view_mode !== 'full') return;
|
||||
|
||||
$route_name = \Drupal::routeMatch()->getRouteName();
|
||||
if ($route_name != 'entity.node.canonical') return;
|
||||
|
||||
$field_redirect = 'field_redirecionar_para';
|
||||
|
||||
if ($node->hasField($field_redirect) && !$node->get($field_redirect)->isEmpty()) {
|
||||
|
||||
$url_object = $node->get($field_redirect)->first()->getUrl();
|
||||
$destination = $url_object->toString();
|
||||
|
||||
$current_url = Url::fromRoute('<current>')->toString();
|
||||
|
||||
if ($destination == $current_url) return;
|
||||
|
||||
$response = new TrustedRedirectResponse($destination, 302);
|
||||
$response->addCacheableDependency($node);
|
||||
$response->send();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
3
imecc_menu_helper/imecc_menu_helper.permissions.yml
Normal file
3
imecc_menu_helper/imecc_menu_helper.permissions.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
administer imecc menu helper:
|
||||
title: 'Administrar configuração de menus do IMECC'
|
||||
description: 'Permite configurar o relacionamento entre Setores e Páginas Pai.'
|
||||
7
imecc_menu_helper/imecc_menu_helper.routing.yml
Normal file
7
imecc_menu_helper/imecc_menu_helper.routing.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
imecc_menu_helper.settings:
|
||||
path: '/admin/config/imecc/menu-helper'
|
||||
defaults:
|
||||
_form: '\Drupal\imecc_menu_helper\Form\MenuHelperSettingsForm'
|
||||
_title: 'Configuração de Hierarquia IMECC'
|
||||
requirements:
|
||||
_permission: 'administer imecc menu helper'
|
||||
79
imecc_menu_helper/src/Form/MenuHelperSettingsForm.php
Normal file
79
imecc_menu_helper/src/Form/MenuHelperSettingsForm.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\imecc_menu_helper\Form;
|
||||
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Menu\MenuParentFormSelectorInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
class MenuHelperSettingsForm extends ConfigFormBase {
|
||||
|
||||
protected $menuParentSelector;
|
||||
|
||||
public function __construct(MenuParentFormSelectorInterface $menu_parent_selector) {
|
||||
$this->menuParentSelector = $menu_parent_selector;
|
||||
}
|
||||
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('menu.parent_form_selector')
|
||||
);
|
||||
}
|
||||
|
||||
protected function getEditableConfigNames() {
|
||||
return ['imecc_menu_helper.settings'];
|
||||
}
|
||||
|
||||
public function getFormId() {
|
||||
return 'imecc_menu_helper_settings_form';
|
||||
}
|
||||
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$config = $this->config('imecc_menu_helper.settings');
|
||||
|
||||
$form['description'] = [
|
||||
'#markup' => '<p>Mapeie cada <strong>Setor</strong> (Taxonomia) a um <strong>Item de Menu Pai</strong>. Quando uma página for criada com este setor, ela será automaticamente movida para dentro deste pai.</p>',
|
||||
];
|
||||
|
||||
// Carrega todos os termos do vocabulário 'setores'.
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree('setores');
|
||||
|
||||
// Opções de menu (apenas do menu principal).
|
||||
$menu_options = $this->menuParentSelector->getParentSelectOptions('main:', NULL);
|
||||
|
||||
$form['mappings'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Mapeamento Setor -> Menu Pai'),
|
||||
'#open' => TRUE,
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
|
||||
foreach ($terms as $term) {
|
||||
$default_value = $config->get('mapping_' . $term->tid);
|
||||
|
||||
$form['mappings'][$term->tid] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $term->name . ' (' . $term->tid . ')',
|
||||
'#options' => $menu_options,
|
||||
'#default_value' => $default_value,
|
||||
'#empty_option' => '- Sem automação -',
|
||||
'#description' => 'Selecione a página pai para o setor ' . $term->name,
|
||||
];
|
||||
}
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$config = $this->config('imecc_menu_helper.settings');
|
||||
$mappings = $form_state->getValue('mappings');
|
||||
|
||||
foreach ($mappings as $tid => $menu_parent) {
|
||||
$config->set('mapping_' . $tid, $menu_parent);
|
||||
}
|
||||
|
||||
$config->save();
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user