Pular para o conteúdo principal

Barra de pesquisa

O bloco search-bar-block renderiza um formulário de busca do Omeka com sugestões opcionais. As sugestões não estão no o:data do bloco. Elas vêm do SiteSettings, na chave sgmblocks_search_suggestions, gerenciada pelo SiteCustomFieldsHandler. O bloco é o consumidor, a tela de edição do site é a produtora.


Como foi construído

Identificação

ItemValor
ClasseSGMBlocks\Site\BlockLayout\SearchBarBlock
block_layoutsearch-bar-block
FormSGMBlocks\Form\SearchBarBlockForm
FactorySGMBlocks\Service\BlockLayout\SearchBarBlockFactory
Partialcommon/block-layout/search-bar-block

Formulário

O SearchBarBlockForm tem um único elemento:

$this->add([
'name' => 'o:block[__blockIndex__][o:data][show_suggestions]',
'type' => Element\Checkbox::class,
'options' => ['label' => 'Mostrar sugestões de pesquisa'],
'attributes' => ['value' => true],
]);

O default é true. Sem configuração extra no bloco, a barra vem com sugestões habilitadas.

Classe do bloco

SearchBarBlock não sobrescreve prepareForm. form popula o único campo. render passa o valor ao partial:

return $view->partial('common/block-layout/search-bar-block', [
'show_suggestions' => $block->dataValue('show_suggestions') ?? true,
]);

Partial

<?php
$translate = $this->plugin('translate');
$escape = $this->plugin('escapeHtml');

$showSuggestions = isset($this->show_suggestions) ? $this->show_suggestions : true;

$searchType = $this->siteSetting('search_type', 'sitewide');
switch ($searchType) {
case 'cross-site':
$searchAction = $this->url('site/cross-site-search', ['action' => 'results'], true);
break;
case 'sitewide':
default:
$searchAction = $this->url('site/resource', ['controller' => 'index', 'action' => 'search'], true);
}
$searchValue = $escape($this->params()->fromQuery('fulltext_search', ''));

$suggestions = $showSuggestions ? $this->siteSetting('sgmblocks_search_suggestions', []) : [];
?>

<div class="sgm-search-bar-block">
<form action="<?php echo $escape($searchAction); ?>" class="sgm-search-form">
<button type="submit" class="sgm-search-button"><i class="fa fa-search"></i></button>
<input type="text"
id="fulltext-search-input"
class="sgm-search-input"
name="fulltext_search"
value="<?php echo $searchValue; ?>"
placeholder="<?php echo $translate('Search...'); ?>"
aria-label="<?php echo $translate('Search...'); ?>">
</form>

<?php if (!empty($suggestions) && is_array($suggestions)): ?>
<ul class="sgm-search-suggestions">
<?php foreach ($suggestions as $suggestion):
$text = $suggestion['text'] ?? '';
$url = $suggestion['url'] ?? '';
if (!empty($text) && !empty($url)): ?>
<li>
<a href="<?php echo htmlspecialchars($url); ?>">
<?php echo htmlspecialchars($text); ?>
</a>
</li>
<?php endif;
endforeach; ?>
</ul>
<?php endif; ?>
</div>

Dois pontos importantes do partial:

  • Resolve a URL da busca pelo siteSetting('search_type'). Quando a configuração do site é cross-site, usa a rota site/cross-site-search. Caso contrário cai em site/resource com controller = index e action = search.
  • Aplica htmlspecialchars nas sugestões. Isso é correto por escapar caracteres perigosos, mas difere do padrão do módulo que usa escapeHtml do view helper. Ao tocar o partial, avalie harmonizar para reutilizar o $escape.

Persistência no bloco

Chave em o:dataTipoDefaultObservação
show_suggestionsbooleanotrueQuando false, o partial não chama siteSetting das sugestões.

Persistência das sugestões no site

A chave sgmblocks_search_suggestions vive em Omeka\Settings\Site. Estrutura esperada ao salvar:

[
['text' => 'Documentos', 'url' => '/s/museu/documentos'],
['text' => 'Fotos', 'url' => '/s/museu/fotos'],
]

Quando lido via siteSetting, o retorno é o array acima ou [] se a chave não existe.


Cadeia de gravação das sugestões

O campo de sugestões é hidden e controlado pelo site-settings.js. A cadeia de gravação envolve três componentes:

flowchart LR
UI["UI de sugestoes no admin"] --> JsHidden["site-settings.js grava JSON no hidden"]
JsHidden --> FormSubmit["SiteSettingsForm submit"]
FormSubmit --> Filter["SiteCustomFieldsHandler handleSiteSettingsFilters Callback"]
Filter --> Array["array normalizado"]
Array --> DB[Omeka SiteSettings]
  1. O JS site-settings.js renderiza a lista, controla adição e remoção, e serializa tudo em JSON no campo hidden sgmblocks-search-suggestions.
  2. Ao submeter o SiteSettingsForm, o evento form.add_input_filters dispara e o handler SiteCustomFieldsHandler::handleSiteSettingsFilters registra um filter Callback no input sgmblocks_search_suggestions.
  3. O callback aceita array ou string JSON. Quando recebe string, faz json_decode. Em qualquer outro caso retorna [].
  4. O array normalizado segue para o SiteSettings e é persistido.

Implementação do callback:

'callback' => function ($value) {
if (is_array($value)) { return $value; }
if (is_string($value)) {
$value = trim($value);
if (empty($value) || $value === '[]') { return []; }
$decoded = json_decode($value, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
return $decoded;
}
}
return [];
},

A injeção de admin.css e site-settings.js acontece em outro handler do mesmo SiteCustomFieldsHandler, anexado a view.layout do controller Omeka\Controller\SiteAdmin\Index. O handler só age quando params fromRoute retorna action = edit, evitando carregar os assets em outras telas do admin do site.


Como usar como desenvolvedor

Sobrescrever o partial no tema

Copie view/common/block-layout/search-bar-block.phtml para themes/<tema>/view/common/block-layout/search-bar-block.phtml. Se o tema tem seu próprio padrão de formulário de busca, mantenha só a parte de sugestões ou troque a UI inteira.

Ajustar a resolução da URL de busca

A URL é escolhida pelo siteSetting('search_type'). Se o site configura busca cruzada, a rota é site/cross-site-search. Caso contrário, site/resource. Para mudar esse comportamento, edite o switch do partial ou extraia a lógica para um helper de view próprio do tema.

Ler sugestões fora do bloco

Em qualquer template do tema:

$suggestions = $this->siteSetting('sgmblocks_search_suggestions', []);

O retorno já é um array no formato descrito acima.

Escrever sugestões por código

Duas rotas:

  1. Via API de SiteSettings do Omeka S, chamando set com o array normalizado.
  2. Via formulário, enviando o campo hidden sgmblocks_search_suggestions com uma string JSON válida. O filter Callback faz a conversão.

Adicionar outra configuração de site

Estenda SiteCustomFieldsHandler:

  1. Em handleSiteSettings, chame $form->add([...]) com o novo elemento.
  2. Em handleSiteSettingsFilters, registre o filter de normalização apropriado.
  3. Em handleSiteSettingsAssets, se a nova UI exigir JS ou CSS extras, anexe aqui.

Desabilitar as sugestões por bloco

Marque show_suggestions = false no formulário do bloco. O partial ignora a chave de site setting e a lista some.

Depurar

  • Se as sugestões não aparecem, confirme que o site tem valor em sgmblocks_search_suggestions. Use var_dump($this->siteSetting('sgmblocks_search_suggestions', [])) em um template.
  • Se o formulário de busca joga para rota errada, confirme o valor de search_type no SiteSettings. O default sitewide manda para site/resource.
  • Se o JS de admin não inicializa, confirme que action === 'edit' na URL do admin do site. O handler só injeta os assets nessa action.

Observações

  • Mistura de escapes no partial. O Omeka expõe escapeHtml e escapeHtmlAttr; o partial mistura htmlspecialchars direto do PHP e o plugin escape dentro de atributos. O padrão do módulo é o helper do Laminas. Ao tocar o partial, harmonize.
  • Dependência de Font Awesome. O ícone da lupa é <i class="fa fa-search"></i>. O tema precisa carregar Font Awesome ou substituir o ícone por SVG inline.
  • Sugestões vazias. O partial trata array vazio. Não há estado visual para "sem sugestões".
  • Acessibilidade. O input tem aria-label, mas a lista de sugestões não é marcada como role="listbox" nem está ligada ao input. Para suporte completo a leitores de tela, estenda o partial no tema.