Adiciona sub-módulo site_users_blog e melhora negociador de tema

Sub-módulo site_users_blog:
- Tipo de conteúdo blog_post (título, corpo, imagem, assuntos)
- Vocabulário blog_tags para categorias
- Listagem em /user/{uid}/blog via Views com filtro contextual por autor
- Padrão Pathauto: user/[node:author:uid]/blog/[node:title]
- hook_node_presave: preenche field_site_section com o autor
- hook_node_access: restringe criação às roles configuradas
- hook_preprocess_structural_pages_menu: injeta item "Blog" quando
  usuário tem posts publicados
- Plugin BlogUserHandler: resolve usuário ancestral para rotas de blog
  (post individual e listagem Views)
- Link "Post de blog" no menu "Adicionar" da conta
- Página de configuração de roles permitidas
- Update 10001: adiciona field_site_section a posts existentes

MicrositeThemeNegotiator:
- Injeta path.current para cobrir rotas sem parâmetro 'user' (ex.: Views)
- Qualquer path /user/{uid}/... recebe o tema do microsite

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 07:32:10 -03:00
parent 39de6a7493
commit d72f41de97
24 changed files with 931 additions and 2 deletions

View File

@@ -0,0 +1,61 @@
<?php
namespace Drupal\site_users_blog\Plugin\ParentEntityHandler;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\node\NodeInterface;
use Drupal\structural_pages\Attribute\ParentEntityHandler;
use Drupal\structural_pages\ParentEntityHandler\ParentEntityHandlerBase;
use Drupal\user\UserInterface;
/**
* Determina o usuário pai a partir de rotas de blog (post ou listagem).
*
* Cobre:
* - entity.node.canonical de blog_post → retorna o autor
* - view.user_blog.page_user_blog → retorna o usuário cujo UID é arg_0
*/
#[ParentEntityHandler(
id: 'blog_user',
label: new TranslatableMarkup('Blog do usuário'),
entity_type_id: 'user',
clears_site_section: FALSE,
sort_field: 'name',
weight: 20,
)]
class BlogUserHandler extends ParentEntityHandlerBase {
/**
* {@inheritdoc}
*/
public function getEntityFromRoute(RouteMatchInterface $route_match): ?EntityInterface {
$route_name = $route_match->getRouteName() ?? '';
if ($route_name === 'entity.node.canonical') {
$node = $route_match->getParameter('node');
if ($node instanceof NodeInterface && $node->bundle() === 'blog_post') {
return $node->getOwner();
}
return NULL;
}
if ($route_name === 'view.user_blog.page_user_blog') {
$uid = $route_match->getParameter('arg_0');
if (is_numeric($uid)) {
return $this->entityTypeManager->getStorage('user')->load($uid);
}
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function handlesEntity(EntityInterface $entity): bool {
return $entity instanceof UserInterface;
}
}