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
| Item | Valor |
|---|---|
| Classe | SGMBlocks\Site\BlockLayout\SearchBarBlock |
block_layout | search-bar-block |
| Form | SGMBlocks\Form\SearchBarBlockForm |
| Factory | SGMBlocks\Service\BlockLayout\SearchBarBlockFactory |
| Partial | common/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 rotasite/cross-site-search. Caso contrário cai emsite/resourcecomcontroller = indexeaction = search. - Aplica
htmlspecialcharsnas sugestões. Isso é correto por escapar caracteres perigosos, mas difere do padrão do módulo que usaescapeHtmldo view helper. Ao tocar o partial, avalie harmonizar para reutilizar o$escape.
Persistência no bloco
Chave em o:data | Tipo | Default | Observação |
|---|---|---|---|
show_suggestions | booleano | true | Quando 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]
- O JS
site-settings.jsrenderiza a lista, controla adição e remoção, e serializa tudo em JSON no campo hiddensgmblocks-search-suggestions. - Ao submeter o
SiteSettingsForm, o eventoform.add_input_filtersdispara e o handlerSiteCustomFieldsHandler::handleSiteSettingsFiltersregistra um filterCallbackno inputsgmblocks_search_suggestions. - O callback aceita array ou string JSON. Quando recebe string, faz
json_decode. Em qualquer outro caso retorna[]. - O array normalizado segue para o
SiteSettingse é 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:
- Via API de
SiteSettingsdo Omeka S, chamandosetcom o array normalizado. - Via formulário, enviando o campo hidden
sgmblocks_search_suggestionscom uma string JSON válida. O filterCallbackfaz a conversão.
Adicionar outra configuração de site
Estenda SiteCustomFieldsHandler:
- Em
handleSiteSettings, chame$form->add([...])com o novo elemento. - Em
handleSiteSettingsFilters, registre o filter de normalização apropriado. - 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. Usevar_dump($this->siteSetting('sgmblocks_search_suggestions', []))em um template. - Se o formulário de busca joga para rota errada, confirme o valor de
search_typenoSiteSettings. O defaultsitewidemanda parasite/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
escapeHtmleescapeHtmlAttr; o partial misturahtmlspecialcharsdireto do PHP e o pluginescapedentro 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 comorole="listbox"nem está ligada ao input. Para suporte completo a leitores de tela, estenda o partial no tema.