Esta especificação define o lote de trabalho req-028 (BATCH-028) para o Engenheiro Executor. O escopo é composto por duas demandas integradas:
-
Persistência e Injeção de Recursos de Widgets: Gravar no banco de dados e aplicar na página publicada o CSS compilado (
css_compiled) e o cabeçalho extra (html_extra_head) gerados nos editores de templates dos módulosmenus,galleriesepublisher-highlights. -
Criação do Módulo Publicador Índice (
publisher-index): Desenvolver um novo módulo de indexação de publicações baseado na estrutura do publicador de destaques, adicionando paginação ("Carregar Mais"), busca AJAX client-side e ordenação em tempo de execução.
1. Banco de Dados e Migrações
1.1 Atualização de Migrações Existentes
Para garantir a consistência de novas instalações limpas do sistema, as migrações originais de criação das tabelas dos três módulos devem ser modificadas para incluir as colunas css_compiled e html_extra_head:
-
20260701100000_create_publisher_highlights_table.php: Adicionar após o campo
css:->addColumn('css_compiled', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true]) ->addColumn('html_extra_head', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true]) -
20260701110000_create_menus_table.php: Adicionar após o campo
css:->addColumn('css_compiled', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true]) ->addColumn('html_extra_head', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true]) -
20260701120000_create_galleries_table.php: Adicionar após o campo
css:->addColumn('css_compiled', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true]) ->addColumn('html_extra_head', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true])
1.2 Migração de Atualização de Ambiente Existente [NEW]
Criar uma nova migração Phinx com timestamp atual para atualizar bancos de dados em execução:
gestor/db/migrations/20260611110000_add_css_compiled_and_html_extra_head_to_widgets_tables.php
-
Lógica: Adicionar colunas
css_compiled(mediumtext, null: true) ehtml_extra_head(mediumtext, null: true) após a colunacssnas tabelaspublisher_highlights,menusegalleriescaso elas não existam (usando$this->table()->hasColumn()).
2. Injeção Centralizada de Recursos (gestor.php)
2.1 Criar Função Helper gestor_pagina_recursos_incluir
Na biblioteca comum gestor.php, criar uma nova função utilitária para centralizar a injeção e desduplicação de recursos:
/**
* Inclui recursos de página (CSS, CSS compilado e HTML extra head) no pipeline global.
* Controla duplicidades via hash MD5 para evitar inclusão redundante.
*
* @param array $params
* @param string $params['css']
* @param string $params['css_compiled']
* @param string $params['html_extra_head']
*/
function gestor_pagina_recursos_incluir($params = false){
global $_GESTOR;
if($params)foreach($params as $var => $val)$$var = $val;
if(!isset($_GESTOR['recursos-incluidos-hashes'])){
$_GESTOR['recursos-incluidos-hashes'] = Array();
}
// 1) HTML Extra Head
if(isset($html_extra_head) && existe($html_extra_head)){
$hash = md5($html_extra_head);
if(!isset($_GESTOR['recursos-incluidos-hashes'][$hash])){
$_GESTOR['recursos-incluidos-hashes'][$hash] = true;
$html_extra_head_formatted = preg_replace("/(^|\n)/m", "\n ", $html_extra_head);
$_GESTOR['html-extra-head'][] = $html_extra_head_formatted."\n";
}
}
// 2) CSS Customizado
if(isset($css) && existe($css)){
$hash = md5($css);
if(!isset($_GESTOR['recursos-incluidos-hashes'][$hash])){
$_GESTOR['recursos-incluidos-hashes'][$hash] = true;
$css_formatted = preg_replace("/(^|\n)/m", "\n ", $css);
$_GESTOR['css'][] = '<style>'."\n";
$_GESTOR['css'][] = $css_formatted."\n";
$_GESTOR['css'][] = '</style>'."\n";
}
}
// 3) CSS Compilado
if(isset($css_compiled) && existe($css_compiled)){
$hash = md5($css_compiled);
if(!isset($_GESTOR['recursos-incluidos-hashes'][$hash])){
$_GESTOR['recursos-incluidos-hashes'][$hash] = true;
$css_compiled_formatted = preg_replace("/(^|\n)/m", "\n ", $css_compiled);
$_GESTOR['css-compiled'][] = '<style>'."\n";
$_GESTOR['css-compiled'][] = $css_compiled_formatted."\n";
$_GESTOR['css-compiled'][] = '</style>'."\n";
}
}
}2.2 Refatorar gestor_componente()
Substituir o bloco de injeção direta de estilos da função gestor_componente() em gestor/bibliotecas/gestor.php (linhas 218 a 238) pela chamada à nova helper:
gestor_pagina_recursos_incluir(Array(
'css' => $css,
'css_compiled' => $css_compiled,
'html_extra_head' => $html_extra_head,
));3. Persistência de Estilos nos Módulos Menus, Galerias e Destaques
3.1 CRUD Administrativo (PHP)
Aplicar o mesmo tratamento de persistência e edição de css_compiled e html_extra_head nos arquivos:
Regras:
-
Mapeamento e Sanitização (
adicionareclonar/ submit do form): No submit de gravação no banco, ler os requests e aplicar opreg_replacede variáveis globais:$_REQUEST['css_compiled'] = preg_replace("/".preg_quote($openText)."(.+?)".preg_quote($closeText)."/", strtolower($open."$1".$close), $_REQUEST['css_compiled'] ?? ''); $_REQUEST['html_extra_head'] = preg_replace("/".preg_quote($openText)."(.+?)".preg_quote($closeText)."/", strtolower($open."$1".$close), $_REQUEST['html_extra_head'] ?? '');Mapear nas arrays de campos a serem inseridos:
foreach(['html','css','css_compiled','html_extra_head'] as $clonable_field){ if(isset($_REQUEST[$clonable_field]) && $_REQUEST[$clonable_field] !== ''){ $campos[] = Array($clonable_field, banco_escape_field($_REQUEST[$clonable_field])); } } -
Validação e Backup (
editar):-
Adicionar
'css_compiled'e'html_extra_head'ao array$camposBanco. -
No submit do update, sanitizar as variáveis e verificar alterações aplicando backups caso os valores anteriores existam (usando
banco_select_campos_anteseinterface_backup_campo_incluir).
-
-
Placeholders no Editor HTML (
editareclonar):-
Substituir placeholders do editor no DOM para alimentar o CodeMirror:
$_GESTOR['pagina'] = modelo_var_troca_tudo($_GESTOR['pagina'],'#pagina-css-compiled#',$css_compiled); $_GESTOR['pagina'] = modelo_var_troca_tudo($_GESTOR['pagina'],'#pagina-html-extra-head#',$html_extra_head); -
Na tela de clonagem, carregar os valores originais do banco e adicioná-los como campos de formulário ocultos no template para que trafeguem no submit:
$_GESTOR['pagina'] = modelo_var_troca_tudo($_GESTOR['pagina'],'#css-compiled-original#',htmlspecialchars($css_compiled, ENT_QUOTES)); $_GESTOR['pagina'] = modelo_var_troca_tudo($_GESTOR['pagina'],'#html-extra-head-original#',htmlspecialchars($html_extra_head, ENT_QUOTES));
-
3.2 Refatorar Renderização de Widgets (.widget.php)
Nos arquivos de widgets públicos, extrair css_compiled e html_extra_head do banco, repassá-los ao renderizador inline e modificar a função de montagem de saída:
Regras:
-
Selecionar do Banco: Adicionar
css_compiledehtml_extra_headno select do registro. -
Chamar Renderizador Inline: Passar
css_compiledehtml_extra_headnas propriedades do array de render. -
Montar Saída: Modificar as funções
xxx_widget_montar_saidapara realizar a injeção em$_GESTORe retornar apenas o HTML limpo:function xxx_widget_montar_saida($html, $css, $css_compiled = '', $html_extra_head = ''){ gestor_pagina_recursos_incluir(Array( 'css' => $css, 'css_compiled' => $css_compiled, 'html_extra_head' => $html_extra_head, )); return $html; }
4. Novo Módulo: Publicador Índice (Publisher Index)
4.1 Estrutura de Arquivos e Manifesto [NEW]
Criar a pasta gestor/modulos/publisher-index/ contendo:
-
publisher-index.json: Configuração do manifesto do módulo. Clonar a estrutura do
publisher-highlights.json, alterando todas as strings e identificadores depublisher-highlightsparapublisher-index. O nome visível do módulo deve ser "Publicador Índice" (pt-br) / "Publisher Index" (en). -
Recursos de Tradução: Criar a estrutura
resources/en/eresources/pt-br/com suas subpastas contendo os HTMLs/CSS e arquivos JSON de interface de CRUD de forma análoga a destaques, renomeando todas as variáveis e títulos.
4.2 Migração de Banco de Dados [NEW]
Criar a migração gestor/db/migrations/20260611120000_create_publisher_index_table.php para declarar a tabela do novo módulo:
-
Nome da Tabela:
publisher_index -
Chave Primária:
id_publisher_index -
Colunas: Copiar exatamente a estrutura física da tabela
publisher_highlights(comcss_compiledehtml_extra_headjá incorporados), ajustando índices e defaults.
4.3 CRUD Administrativo (publisher-index.php) [NEW]
Desenvolver o script do backend de administração clonado e adaptado do publisher-highlights.php.
-
Diferença no fields_schema: O
fields_schemadeste módulo suporta novas propriedades de exibição além derule,count,order_byeselected_items:-
items_per_page(int, default 10) -
show_search_input(bool, default true) -
show_sorting_select(bool, default true) -
show_load_more_btn(bool, default true)
-
-
Mapeamento e Serialização: Garantir a leitura, hidratação de variáveis globais client-side no page load, e a persistência correta destas chaves adicionais no banco.
4.4 Interface do Painel Administrativo (publisher-index.js) [NEW]
Desenvolver o JavaScript do painel clonado de publisher-highlights.js:
-
Substituir termos globais por
publisher-indexoupublisher_index. -
Inserir os elementos na aba de parâmetros para expor os novos campos (Exibição da barra de busca, ordenação de itens e paginação "Carregar Mais" com campo numérico para itens por página).
-
Incluir no parser e na serialização do schema estas novas variáveis.
4.5 Widget Renderer (publisher-index.widget.php) [NEW]
Criar o renderizador PHP do widget público em gestor/modulos/publisher-index/publisher-index.widget.php.
-
Inclusão do Script Público: A função
publisher_index_render($params)deve incluir o script frontend do widget:gestor_pagina_javascript_incluir(Array( 'tipo' => 'widget', 'modulo_id' => 'publisher-index', 'versao' => publisher_index_get_version(), )); -
Renderização Inicial (Backend - Page Load):
-
Seleciona o registro da tabela
publisher_indexpelo slug correspondente. -
Carrega as configurações (
fields_schemaJSON). -
Injeta os recursos no head chamando
gestor_pagina_recursos_incluir(). -
Busca as publicações da primeira página (de
0aitems_per_page) filtrando pelo publicador. -
Injeta no elemento HTML do contêiner atributos
data-*para que o script Javascript client-side consiga identificar os parâmetros de execução (ex:data-grupo-slug="[slug]" data-items-per-page="[N]" data-page="1" data-publisher-id="[pub_id]"). -
Caso haja mais itens no banco do que os exibidos na primeira página, renderizar o botão "Carregar Mais" (se ativo no schema).
-
Retornar o HTML gerado.
-
-
Roteamento AJAX (
publisher_index_render_ajax): Lógica acionada quando o widget faz requisição AJAX em produção:function publisher_index_render_ajax($params){ global $_GESTOR; $grupo_slug = $_REQUEST['ajaxRegistroId'] ?? ''; $busca = $params['busca'] ?? ''; $ordenacao = $params['ordenacao'] ?? 'date_desc'; $pagina = (int)($params['pagina'] ?? 1); if(empty($grupo_slug)) return; // 1) Buscar registro no banco de dados e ler fields_schema // 2) Calcular offsets de paginação baseados em $pagina e $items_per_page (lido de fields_schema) // 3) Realizar consulta SQL na tabela paginas/publisher_pages aplicando WHERE // para o publisher_id E filtrando registros cujo campo "nome" ou // campos customizados combinem com o termo $busca (LIKE %$busca%) // 4) Aplicar a ordenação $ordenacao correspondente (date_desc, date_asc, title_asc, title_desc) // 5) Renderizar os itens usando o template HTML // 6) Verificar se há uma próxima página (tem_mais) rodando count de controle // 7) Definir $_GESTOR['ajax-json'] com o resultado: $_GESTOR['ajax-json'] = Array( 'status' => 'Ok', 'html' => $html_itens_renderizados, 'tem_mais' => $tem_mais_itens ); }
4.6 Comportamento Público Client-Side (publisher-index.widget.js) [NEW]
Criar o script do widget público em gestor/modulos/publisher-index/publisher-index.widget.js para gerenciar a interface dinâmica na página de produção:
-
Escopo e Inicialização: Identificar todos os elementos
.conn2flow-publisher-indexna página. Para cada um, inicializar o estado inicial (Página = 1, Busca = '', Ordenação = inicial). -
Eventos:
-
Busca (Pesquisa): Escutar input em
.publisher-index-search. Aplicar debounce de 300ms. Atualizar estado local de busca, resetar página para 1 e disparar AJAX. -
Ordenação: Escutar change em
.publisher-index-sort. Atualizar estado local de ordenação, resetar página para 1 e disparar AJAX. -
Carregar Mais: Escutar clique em
.publisher-index-load-more. Incrementar a página local em 1 e disparar AJAX de paginação.
-
-
Chamada AJAX: Disparar requisição POST/GET para o endereço atual da página enviando os dados parametrizados no array
paramse os ponteiros de widgets:var requestData = 'ajax=sim' + '&ajaxOpcao=publisher-index-load' + '&ajaxRegistroId=' + encodeURIComponent(grupoSlug) + ((typeof gestor !== 'undefined' && gestor.widgetsToAjax) ? '&ajaxWidgets=' + encodeURIComponent(gestor.widgetsToAjax) : '') + '¶ms%5Bbusca%5D=' + encodeURIComponent(buscaEstado) + '¶ms%5Bpagina%5D=' + encodeURIComponent(paginaEstado) + '¶ms%5Bordenacao%5D=' + encodeURIComponent(ordenacaoEstado); $.ajax({ url: window.location.href, type: 'POST', data: requestData, dataType: 'json', success: function(res) { if(res.status === 'Ok') { if(paginaEstado === 1) { // Substitui os itens existentes $containerItens.html(res.html); } else { // Anexa os novos itens no final $containerItens.append(res.html); } // Exibir/ocultar botão "Carregar Mais" if(res.tem_mais) { $btnLoadMore.removeClass('hidden'); } else { $btnLoadMore.addClass('hidden'); } } } });
4.7 Modo de IA do Publicador Índice (publisher-index.md) [NEW]
Criar o arquivo markdown do modo de IA do índice:
-
gestor/modulos/publisher-index/resources/pt-br/ai_modes/publisher-index/publisher-index.md -
gestor/modulos/publisher-index/resources/en/ai_modes/publisher-index/publisher-index.md -
Regras: Clonar e adaptar as instruções de
publisher-highlights.mdpara suportar a injeção do contêiner de busca, ordenação de itens e o botão de carregamento condicional. Listar as novas variáveis e blocos para a IA (ex:[[items_per_page]],[[show_search_input]], etc.).
5. Regras de Homologação e Execução
-
Manifestos: Adicionar a configuração de IA correspondente em
publisher-index.json. -
Executar Rotina: O executor deve rodar o script de atualização de dados e recursos
atualizacao-dados-recursos.phppara registrar o novo módulo, componentes e alvos de IA. -
Restrição: Todas as edições permanecem locais na máquina de testes, sem commits/pushes por parte do executor.