Descrição e thumbnail
Dois blocos cobrem os metadados visuais de uma página: page-description e thumbnail-block. Eles existem em paralelo e não têm dependência entre si, mas costumam aparecer juntos em páginas institucionais quando o tema precisa de resumo mais imagem de capa.
SGM: Descrição da Página
Como foi construído
Identificação
| Item | Valor |
|---|---|
| Classe | SGMBlocks\Site\BlockLayout\PageDescription |
block_layout | page-description |
| Form | SGMBlocks\Form\PageDescriptionForm |
| Factory | SGMBlocks\Service\BlockLayout\PageDescriptionFactory |
| Partial | common/block-layout/page-description |
Formulário
O PageDescriptionForm estende Laminas\Form\Fieldset e define um único elemento:
$this->add([
'name' => 'o:block[__blockIndex__][o:data][description]',
'type' => Element\Textarea::class,
'options' => ['label' => 'SGM: Descrição da Página'],
'attributes' => ['class' => 'block-html full wysiwyg'],
]);
A classe CSS block-html full wysiwyg é a chave para o Omeka inicializar o CKEditor sobre a textarea. block-html delimita o contexto, full libera toolbar completa, e wysiwyg é o gatilho do JS do Omeka.
Classe do bloco
PageDescription::form chama populateValues com a chave o:block[__blockIndex__][o:data][description] quando há $block. PageDescription::render passa description ao partial:
return $view->partial('common/block-layout/page-description', [
'description' => $block->dataValue('description'),
]);
Partial
<?php if (!empty($description)): ?>
<div class="page-description-block">
<?= $description ?>
</div>
<?php endif; ?>
Note a ausência de escape no <?= $description ?>. O partial assume conteúdo confiável vindo do CKEditor. Qualquer decisão de sanitizar deve acontecer antes de salvar, seja em form.add_input_filters, seja em um sanitizador explícito.
Persistência
Chave em o:data | Tipo | Observação |
|---|---|---|
description | string HTML | Conteúdo bruto do CKEditor, não escapado. |
SGM: Thumbnail da Página
Como foi construído
Identificação
| Item | Valor |
|---|---|
| Classe | SGMBlocks\Site\BlockLayout\ThumbnailBlock |
block_layout | thumbnail-block |
| Form | SGMBlocks\Form\ThumbnailBlockForm |
| Factory | SGMBlocks\Service\BlockLayout\ThumbnailBlockFactory |
| Partial | common/block-layout/thumbnail-block/render |
Formulário
$this->add([
'name' => 'o:block[__blockIndex__][o:data][asset]',
'type' => OmekaElement\Asset::class,
'options' => ['label' => 'Imagem de Capa'],
]);
O tipo Omeka\Form\Element\Asset renderiza o seletor nativo de assets do Omeka, com botões para escolher asset existente ou fazer upload.
Classe do bloco
ThumbnailBlock::prepareForm anexa admin.css para ajustar o preview do asset no editor:
public function prepareForm(PhpRenderer $view)
{
$view->headLink()->appendStylesheet($view->assetUrl('css/admin.css', 'SGMBlocks'));
}
ThumbnailBlock::render lê o id do asset e resolve o AssetRepresentation com try catch:
$assetId = $block->dataValue('asset');
$asset = null;
if ($assetId) {
try {
$asset = $view->api()->read('assets', $assetId)->getContent();
} catch (\Exception $e) {
// asset apagado ou inacessível
}
}
return $view->partial('common/block-layout/thumbnail-block/render', ['asset' => $asset]);
Partial
<?php
$this->headLink()->appendStylesheet($this->assetUrl('css/style.css', 'SGMBlocks'));
?>
<?php if ($asset): ?>
<div class="page-thumbnail-block">
<img class="page-thumbnail-image"
style="display: block; max-width: 200px; width: auto; height: auto;"
src="<?= $asset->assetUrl() ?>"
alt="<?= $this->escapeHtmlAttr($asset->altText() ?: 'SGM: Thumbnail da Página') ?>" />
</div>
<?php endif; ?>
O style inline aplica max-width: 200px, o que limita o tamanho do thumbnail independente do CSS do tema. O alt usa altText do asset quando disponível e cai no texto fixo caso contrário.
Persistência
Chave em o:data | Tipo | Observação |
|---|---|---|
asset | inteiro id de asset | Resolvido via api read assets. |
Diferenças de escape entre os dois partials
page-description.phtml imprime HTML cru. thumbnail-block/render.phtml escapa alt com escapeHtmlAttr e confia em $asset->assetUrl() como URL segura. Essa assimetria é intencional: a descrição precisa preservar marcações do CKEditor; o alt é texto simples.
Como usar como desenvolvedor
Sobrescrever o partial no tema
Copie o arquivo do módulo para o tema mantendo o caminho:
themes/<tema>/view/common/block-layout/page-description.phtmlthemes/<tema>/view/common/block-layout/thumbnail-block/render.phtml
O resolver do Laminas encontra o do tema primeiro e ignora o do módulo. Nada precisa ser registrado.
Ajustar o tamanho do thumbnail
O max-width: 200px está inline no partial. Para mudar, edite o partial do módulo ou escreva a versão própria no tema. Ajuste também asset/css/style.css para acompanhar.
Trocar a política de escape da descrição
Se precisar sanitizar, adicione um input filter no formulário. Exemplo:
// Em um handler novo, anexado a form.add_input_filters no SiteSettingsForm do bloco
$inputFilter->add([
'name' => 'o:block[__blockIndex__][o:data][description]',
'filters' => [['name' => 'HTMLPurifier']],
]);
Alternativamente, troque <?= $description ?> por <?= $this->escapeHtml($description) ?> no partial. A troca quebra marcações ricas, então use com cuidado.
Acessar os blocos de dentro de um template
Dada uma $page, itere os blocos e filtre pelo layout:
$page = $this->page;
foreach ($page->blocks() as $block) {
if ($block->layout() === 'thumbnail-block') {
$assetId = $block->dataValue('asset');
if ($assetId) {
$asset = $this->api()->read('assets', $assetId)->getContent();
echo '<img src="' . $this->escapeHtmlAttr($asset->assetUrl()) . '" alt="' . $this->escapeHtmlAttr($asset->altText() ?: 'Thumbnail') . '" />';
}
}
}
Renderizar o bloco diretamente em outro template
Use o helper blockLayout do Omeka:
foreach ($page->blocks() as $block) {
if ($block->layout() === 'thumbnail-block') {
$blockLayout = $this->blockLayout($block->layout());
echo $blockLayout->render($this, $block);
}
}
Obter apenas a URL do thumbnail em meta tags
function getPageThumbnail($page, $api)
{
foreach ($page->blocks() as $block) {
if ($block->layout() === 'thumbnail-block') {
$assetId = $block->dataValue('asset');
if ($assetId) {
try {
return $api->read('assets', $assetId)->getContent()->assetUrl();
} catch (\Exception $e) {
return null;
}
}
}
}
return null;
}
$thumbnailUrl = getPageThumbnail($this->page, $this->api());
if ($thumbnailUrl) {
echo '<meta property="og:image" content="' . $this->escapeHtmlAttr($thumbnailUrl) . '" />';
}
Verificar se a página tem thumbnail
function hasThumbnail($page)
{
foreach ($page->blocks() as $block) {
if ($block->layout() === 'thumbnail-block' && $block->dataValue('asset')) {
return true;
}
}
return false;
}
Acessar via API
$page = $api->read('site_pages', $pageId)->getContent();
foreach ($page->blocks() as $block) {
if ($block->layout() === 'thumbnail-block') {
$assetId = $block->dataValue('asset');
// fazer algo com $assetId
}
}
Observações
- O id do bloco é
thumbnail-block. Sempre compare com$block->layout(). - A descrição não tem validação nem sanitização. Qualquer HTML enviado pelo editor entra direto no DOM do site.
assetUrlemAssetRepresentationé uma URL absoluta resolvida pelo storage configurado no Omeka. Não é preciso passar peloassetUrlhelper.- Se o asset foi removido,
api read assetslança exceção. O bloco captura e segue com$asset = null, então o partial não renderiza nada.
