# Shortcodes públicos

Dados, variáveis, fluxo, conteúdo, URLs e shortcodes utilitários públicos.

## Dados

### `[#data resource#]`
Carrega todos os registros de um recurso em `data.<resource>`.

```
[#data articles#]
[#data articles sort=date|desc#]
[#data articles filter=published:1#]
[#data articles search=nimbly#]
[#data articles var=featured filter=featured:yes#]
[#data users.abc123#]           → loads single record into data.users.abc123
[#data users uuid=abc123#]      → same
[#data articles filter=published:1 sort=date|text|desc limit=20 offset=40#]   → the third page of 20
```

Parâmetros:
- `sort` - `field|asc`, `field|desc`, vários: `date|desc,title|asc`
- `filter` - `field:value`, vários: `published:1,status:new`, negação: `status:!draft`, ou: `status:new||todo`
- `search` - busca no texto completo de todos os campos
- `var` - nome próprio para a variável em vez de `data.<resource>`
- `op` - `read` (padrão) ou `list` (só UUIDs)
- `limit`, `offset` - uma página da lista: no máximo `limit` registros, depois de pular `offset`. O número de registros antes do corte fica em `data.<resource>-total` (ou `<var>-total`)

Com `limit` ou `offset`, a lista é respondida sem ler todos os registros. Para cada campo citado em `filter` e `sort`, os valores de todos os registros ficam juntos num arquivo de cache (`ext/data/.tmp/cache/_data/list/<resource>/<field>`), criado na primeira vez que o campo é pedido; só os registros da página são lidos. Uma escrita acrescenta uma linha a esses arquivos, um pull do Git faz com que sejam reconstruídos, e `./nimbly data:cache:clear` os remove. Use isso em toda lista de um recurso grande; uma ordenação com tipo (`date|text|desc`, `price|num|asc`) é a rápida. `search` continua lendo todos os registros. A partir do PHP: `data_query($resource, ['filter' => …, 'sort' => …, 'limit' => 20, 'offset' => 40])` em `core/lib/data-list.php` devolve `['records' => …, 'total' => …]`.

### `[#repeat data.articles#]`
Percorre uma variável de dados e exibe, para cada item, o template com o mesmo nome.

```
[#repeat data.articles#]
[#repeat data.articles tpl=article-card#]
[#repeat data.articles limit=3#]
[#repeat data.articles filter=published:1#]
[#repeat record.related_items csv tpl=related-item#]
[#repeat data.articles var=post#]   → item variable named "post" instead of "item"
```

Dentro do template, os campos de cada registro estão disponíveis como `item.<field>`:

```html
<h2>[#get item.title#]</h2>
<p>[#get item.intro#]</p>
```

Também disponíveis em cada repetição:
- `item.ix` - índice numérico (a partir de 0)
- `item.x` - chave do registro
- `item.key` - chave do registro (string)

Em campos de referência com UUIDs separados por vírgula, não crie uma biblioteca só para carregar uma parte. Carregue o recurso de destino uma vez com `[#data#]`, depois repita a lista de UUIDs com `csv` e leia da variável do recurso carregado:

```html
[#data participants#]
[#repeat stories.participants csv tpl=story-participant-item#]
```

```html
<!-- ext/tpl/story-participant-item/index.tpl -->
<a href="[#get data.participants.[#item.key#].link#]">
    [#get data.participants.[#item.key#].name#]
</a>
```

Isso usa a camada de dados do core e o cache dela, mantém a ordem dos UUIDs do registro de origem e dispensa código de backend próprio para exibir relações simples.

### `[#data-sort data.articles sort=title|string|asc#]`
Ordena uma variável de dados existente no próprio lugar.

```
[#data-sort data.articles sort=date|desc#]
[#data-sort data.articles sort=title|string|asc#]
[#data-sort data.articles sort=price|numeric|asc#]
```

### `[#data-join a b#]`
Junta `data.a` e `data.b` em `data.join`. Cada registro ganha um campo `resource_type` com o nome do recurso de origem.

### `[#data-count resource#]`
Exibe o número de registros de um recurso.

---

## Variáveis

### `[#set key=value#]`
Define uma variável de template.

```
[#set page-title="About us"#]
[#set active-nav=about#]
[#set body-classes=editor-role append#]    → appends with a space separator
[#set tags=news append=,#]                 → appends with a custom separator
[#set key=value session#]                  → persists in session
[#set key=value overwrite#]                → replaces value even if already set
```

O parâmetro `append` acrescenta em vez de definir. Sem separador, ele coloca um espaço entre o valor existente e o novo; informe um caractere para usar outro separador. Útil para montar listas de classes CSS ou textos separados por vírgula:

```
[#set body-classes=site-body#]
[#set body-classes=editor-role append#]    → "site-body editor-role"
[#set body-classes=dark-mode append#]      → "site-body editor-role dark-mode"
```

**`[#set#]` não sobrescreve por padrão.** Se a variável já tem um valor, um `[#set#]` simples não faz nada. Isso facilita definir valores de reserva em templates compartilhados ou do core, enquanto os templates de rota podem substituí-los antes. Só acrescente `overwrite` quando quiser substituir de propósito um valor existente (por exemplo, ao passar dados para um template reutilizável).

### `[#get varname#]`
Exibe um valor. `[#get#]` é a forma única de ler valores.

Ordem de busca:
1. Variável simples: variáveis de sessão, depois variáveis do sistema. A URL e os cookies só são lidos quando o template pede, com `from` (veja abaixo)
2. Caminho com pontos em variáveis do sistema aninhadas, usando o maior início de variável que corresponda
3. Recurso aos dados para caminhos `resource.uuid.field`
4. Escolha automática do idioma quando o resultado é um objeto com os códigos de idioma configurados como chaves

A entrada da requisição é opt-in: `from=url` lê o parâmetro de consulta com o mesmo nome, `from=cookie` um cookie, `from=url,cookie` (ou `url|cookie`) os dois na ordem dada, e `from=(any)` o cookie e depois a URL. Uma variável de página com esse nome sempre vence. `[#if#]` aceita o mesmo `from` nas suas condições.

```
[#get page-title#]
[#get item.title default="Untitled"#]
[#get q from=url#]
[#get language#]
[#get data.settings.theme#]
[#get users.abc123.name empty="Unknown"#]
[#get item.title lang=nl#]
[#get item json#]
```

Os padrões antigos `[#get-key#]`, `[#jget#]`, `[#get-i18n#]` e `[#lookup#]` devem ser migrados para `[#get#]`.

### `[#fmt var=data.articles json#]`
Formata uma variável para a saída.

```
[#fmt var=data.records json#]              → JSON encode
[#fmt var=myvar empty={} json#]            → JSON with fallback
[#fmt var=item.date type=date fmt="d-m-Y"#]
[#fmt var=item.body type=html#]            → strips all tags
[#fmt var=item.body type=plain#]           → strips tags and decodes entities
[#fmt var=item.size type=bytes#]           → human-readable bytes
[#fmt var=item.hours type=hours#]          → 3h 30m, 6m, 37h (whole minutes)
[#fmt var=item.created type=ago#]          → "3 days ago"
[#fmt val=[#data-count users#] type=number round=-2 round_mode=floor#]
[#fmt var=item.invoice type=file#]         → file download markup
[#fmt var=item.order type=pad length=4#]   → zero-padded number
```

Tipos: `text`, `plain`, `html`, `date`, `ago`, `json`, `bytes`, `hours`, `number`, `boolean`, `image`, `file`, `pad`

`var=` lê uma variável; `val=` recebe o próprio valor, normalmente um shortcode aninhado. O tipo é `type=`, ou uma palavra solta como último parâmetro: `[#fmt var=list empty={} json#]` codifica, `[#fmt var=list json empty={}#]` não.

### `[#count varname#]`
Exibe o número de itens de uma variável array.

```
[#count data.articles#]
```

---

## Controle de fluxo

### `[#if condition action#]`

```
[#if user=(empty) redirect=login#]
[#if language=en tpl=intro-en#]
[#if status=published echo=yes#]
[#if user=(not-empty) tpl=dashboard tpl_else=login#]
[#if score=0 echo_else=[#get score#]#]
[#if not role=admin redirect=home#]
[#if lang=en or lang=nl tpl=western-layout#]
```

Condições: `key=value`, `key=(empty)`, `key=(not-empty)`
Ações: `tpl=`, `tpl_else=`, `echo=`, `echo_else=`, `redirect=`
Modificadores: `not`, `or`, `and`

**`[#if#]` é sempre uma única tag que se fecha sozinha; não existe forma de bloco (`[#if#]...[#/if#]`), e isso é de propósito.** Os templates não contêm lógica de negócio. O conteúdo condicional sempre fica num template separado, chamado com `tpl=`. Nunca escreva um bloco `[#if#]…[#/if#]` num template.

### `[#redirect url#]`
Redireciona na hora.

```
[#redirect login#]
[#redirect [#base-url#]/dashboard#]
```

---

## URL e caminho

### `[#base-url#]`
Devolve o caminho base da instalação na URL. Use em todos os links internos.

```html
<a href="[#base-url#]/about">About</a>
<link href="[#base-url#]/ext/static/app.css">
```

**Em JavaScript**, `[#base-url#]` não está disponível como tag de template. Use `nb.base_url`; o core a define antes de qualquer script da página rodar. Isso é essencial ao montar URLs de imagens ou caminhos da API no código, principalmente quando o site roda sob um alias ou uma subpasta (como no staging). Nunca escreva `/img/` ou `/api/` como caminho solto em JS.

```js
// wrong - breaks on staging aliases
return '/img/' + uuid + '/240w';

// correct
return nb.base_url + '/img/' + uuid + '/240w';
```

### `[#base-path#]`
Devolve o caminho no sistema de arquivos até a raiz da instalação. Para incluir arquivos no servidor.

### `[#url#]`
Devolve a URL completa atual.

### `[#is-url segment#]`
Define `is-url` como `true` se a URL atual começa com o segmento informado. Use para o estado ativo na navegação.

```
[#is-url about#]
[#if is-url=true echo=active#]

[#is-url (home) =#]   → exact match for homepage
```

## Conteúdo

### `[#get-html field#]`
Exibe um campo de conteúdo HTML editável. Permite edição na página pelos administradores.

```
[#get-html main_text#]
[#get-html content.home.intro default="<p>Edit this text</p>"#]
```

Os links no conteúdo são escritos a partir da raiz do site, `/contact` ou `/en/article/deep-space`, sem `[#base-url#]`. Quando o site roda numa subpasta (staging sob um alias), `get-html` coloca o caminho base na frente ao exibir a página, e o editor o retira ao salvar, então o link guardado funciona em todos os ambientes. Um link que já começa com o caminho base, e um link para outro site, ficam como estão.

Os campos i18n são resolvidos automaticamente por `[#get#]` e `[#fmt#]` quando o valor é um objeto com os códigos de idioma configurados como chaves. Use `lang=` para forçar um idioma.

```
[#get item.title#]
[#get item.title lang=en#]
[#fmt var=item.title type=plain lang=nl#]
```

### `[#text Label_key#]`
Exibe um rótulo traduzido dos arquivos `.po`. Use sublinhados no lugar de espaços na chave.

```
[#text Search#]
[#text Save_changes#]
[#text No_results_found#]
```

As traduções ficam em `ext/data/.i18n/text.<lang>.po`.

### `[#cfield field#]`
Determina o caminho completo com pontos de um campo de conteúdo no contexto atual do template. É usado com `[#get-html#]` para conteúdo fixo da página, editável na própria página, guardado no recurso `.content`.

O recurso `.content` guarda, por chave, blocos de HTML editáveis que não pertencem a nenhum registro de dados. Cada bloco é identificado por `content.<page>.<field>`. Quando `[#get-html#]` aponta para um caminho de `.content` que ainda não existe, ele cria o registro automaticamente e exibe o valor `default`.

```html
<!-- In ext/tpl/about-intro/index.tpl -->
[#get-html content.about.intro default="<p>Edit this text</p>"#]
[#get-html content.about.body default="<p>Body text here</p>"#]
```

`[#cfield field#]` determina o caminho do campo a partir do contexto atual do template; útil quando o mesmo template é usado em vários lugares:

```html
[#get-html [#cfield intro#] default="<p>Edit this</p>"#]
```

Esse padrão exige que o módulo user esteja ativo (carregado automaticamente).

### `[#get-img-html uuid sizes="..." mode=w#]`
**A forma recomendada de exibir imagens.** Gera um `<img>` responsivo com `srcset`, `sizes`, carregamento lazy e limites que evitam ampliar a imagem. Use sempre em vez de uma tag `<img>` escrita à mão.

```
[#get-img-html [#record.main_img#] sizes="sm-100,md-50,lg-33"#]
```

**Parâmetro `sizes`**: pares de breakpoint e porcentagem separados por vírgula. Cada parte é `breakpoint-vw`, em que `vw` é a porcentagem da largura da tela que a imagem ocupa a partir daquele breakpoint. Breakpoints omitidos usam `100vw`.

| Exemplo | Significado |
|---|---|
| `sm-100,md-50` | Largura total no celular, metade a partir de md |
| `sm-100,md-33` | Largura total no celular, um terço a partir de md |
| `sm-100,md-50,lg-25` | Total → metade → um quarto |

**Parâmetro `mode`**: define como o servidor dimensiona a imagem:

| Modo | Forma da URL | Resultado |
|---|---|---|
| `w` (padrão) | `480w` | Redimensionada para essa largura, altura proporcional |
| `c` | `480c` | Redimensionada para essa altura, largura proporcional; boa para layouts com altura uniforme |
| `w?ratio=1.0` | `480w?ratio=1.0` | Recorte quadrado (centro); para avatares e miniaturas |

Exemplo de recorte quadrado:
```
[#get-img-html [#record.avatar#] sizes="sm-50,md-25" mode=w?ratio=1.0#]
```

Os estilos inline `max-width`/`max-height` no `<img>` gerado só evitam ampliar a imagem; não atrapalham o `object-fit: cover` do CSS nem layouts em grid quando as imagens são maiores que o tamanho exibido (o que sempre acontece com conteúdo real).

---

## Página HTML

### `[#html#]`
Exibe a shell HTML completa da página (doctype, head, body). Coloque no fim dos templates de rota.

Estas variáveis influenciam a shell HTML quando definidas antes de `[#html#]`:

| Variável | Descrição |
|---|---|
| `page-title` | Define a tag `<title>` e o título para OG/Twitter |
| `body-classes` | Acrescenta classes CSS à tag `<body>` |
| `page-settings-link` | Faz o botão de configurações do menu de ações da página apontar para a página de edição do registro atual no admin, em vez do modal de configurações da página. Use em páginas de detalhe para dar acesso rápido ao admin a partir do site. Exemplo: `[#base-url#]/nb-admin/articles/[#record.uuid#]`. O rótulo vira "Edit <resource>" (por exemplo "Edit article"). |
| `page-settings-label` | Substitui esse rótulo. |
| `page-actions` | Defina como `off` para ocultar o menu de ações numa página sem contexto de página. Ele nunca aparece no admin. |
| `page-description` | Substitui a meta description do site inteiro nesta página. Usa a description da configuração do site quando ausente. |
| `og-image` | Imagem para compartilhamento em redes sociais. Aceita um **UUID** (expandido para uma URL absoluta `/img/UUID/1200w`), um **caminho relativo** (`img/og-card.png`) ou uma **URL absoluta**. Usa o padrão do projeto definido em `ext/tpl/meta/index.tpl` quando ausente. |
| `og-type` | Tipo OG desta página. O padrão é `website`. Use `article` em páginas de detalhe de conteúdo. |
| `page-canonical-url` | Substitui a URL canônica normalizada e o `og:url` correspondente. Defina antes de `[#html#]`. |

```
[#set page-title="[#get record.title#]"#]
[#set og-type=article#]
[#set og-image=[#record.main_img#]#]
[#set page-description="[#fmt var=record.main_text type=html max_length=160#]"#]
[#set page-settings-link="[#base-url#]/nb-admin/event/[#record.uuid#]"#]
[#set body-classes=site-body#]
[#html#]
```

A imagem OG padrão do projeto é definida uma vez em `ext/tpl/meta/index.tpl`, sem `overwrite`, para que os valores por página sempre tenham prioridade. Há dois utilitários de imagem como shortcode:

- `[#img-url UUID-or-path-or-URL#]` - transforma qualquer referência de imagem numa URL absoluta (útil fora do meta, por exemplo em JSON-LD)
- `[#first-img-uuid var=record.main_text#]` - extrai o UUID da primeira imagem incorporada num campo HTML; devolve `(empty)` quando não há nenhuma

## Importar registros de recursos de DOCX

Os formulários de criação de registros podem exibir a ação **Import document** do core. Ela aceita um `.docx`, extrai os parágrafos e hiperlinks e envia o texto limitado do documento ao endpoint de importação da OpenAI configurado, para propor valores para os campos do recurso. Os editores revisam o formulário preenchido antes de salvar; a importação não cria registro sozinha.

A extração de DOCX exige a extensão ZIP do PHP, porque um documento Office Open XML é um arquivo ZIP. Todo runtime de CLI e web/FPM que possa executar a importação ou os testes dela precisa ter `ZipArchive`. No Debian e no Ubuntu, ela costuma ser instalada com o pacote `php-zip` da versão correspondente; as imagens Docker do Nimbly para desenvolvimento e produção incluem `php-zip` explicitamente. Verifique um servidor configurado à mão com:

```bash
php -r 'echo class_exists("ZipArchive") ? "available\n" : "missing\n";'
php core/tests/docx-test.php
```

Não deduza a disponibilidade na web só pela CLI quando a CLI e o PHP-FPM carregam configurações separadas. Confirme a extensão nos dois runtimes depois da instalação e teste a importação de documentos pela aplicação web.

## Documentos PDF

Instale a dependência do módulo PDF do core com `php core/cli/nimbly.php module:install pdf`. As rotas da aplicação fornecem o próprio HTML e usam a biblioteca PDF do core para gerar, guardar em cache por conteúdo e baixar com segurança no navegador:

```php
load_library('pdf');
$pdf_bytes = pdf_render_cached_document([
    'paper_size' => 'a4',
    'orientation' => 'portrait',
    'margins' => ['top' => 20, 'right' => 18, 'bottom' => 20, 'left' => 18],
    'pages' => [$document_html],
]);
pdf_send_download($pdf_bytes, 'Document-123.pdf');
exit();
```

`pdf_render_document()` sempre gera bytes novos. Para downloads, prefira `pdf_render_cached_document()`: a identidade do cache inclui a configuração completa do documento e os arquivos do renderizador do core, então conteúdo ou código de renderização alterados invalidam o cache automaticamente. Não monte timestamps de recursos nem listas de dependências de templates em rotas individuais. `pdf_send_download()` limpa o nome do arquivo e envia cabeçalhos de download de PDF privados, que o navegador não guarda em cache.

---

## Utilitários

### `[#include file=path#]`
Inclui um arquivo no servidor. O caminho precisa ficar dentro do projeto; caso contrário, não exibe nada.

```
[#include file=[#base-path#]ext/tpl/head-scripts/index.tpl#]
```

A normalização de UUID, salt, slug, MD5 e chaves de recurso, e a remoção de formatação para texto simples, são funções auxiliares do PHP em `core/lib/util.php`, não shortcodes. Use-as em bibliotecas PHP, arquivos de rota, scripts de instalação e scripts de CLI:

```php
load_library('util');

$uuid = generate_uuid();
$salt = generate_salt();
$slug = make_slug($title);
$hash = md5_uuid($slug);
$text = plain_text($html);
```

### `[#env KEY default=value#]`
Devolve um valor do `.env`, com `default` quando a chave falta. As configurações que o core mantém em segredo (`PEPPER`, `STATS_KEY`, `ADMIN_PASSWORD`, `SMTP_PASSWORD`, `AGENT_REMOTE_PASSWORD`, `OPENAI_API_KEY`, `RESEND_API_KEY`, `GIT_TOKEN`) nunca são exibidas: leia-as no PHP com `env()`.

```
[#env STRIPE_LINK_ANNUAL#]
[#env MAIL_SERVICE default=resend#]
```

### `[#logged-in#]`
Devolve `"logged-in"` se há uma sessão de usuário ativa.

```
[#if logged-in=(empty) redirect=login#]
```

### `[#feature-cond features=name#]`
Exibe conteúdo conforme o usuário atual tenha ou não uma permissão específica.

```
[#feature-cond features=edit-articles tpl=edit-button#]
[#feature-cond features=view-admin-dashboard echo="<a href='/nb-admin'>Admin</a>"#]
[#feature-cond features=view-admin-dashboard tpl=admin-panel tpl_else=access-denied#]
[#feature-cond features=edit-articles,view-reports tpl=dashboard#]
```

Parâmetros:
- `features` - lista de permissões separadas por vírgula; o acesso é dado se o usuário tem **qualquer** uma delas, ou `(all)` (admin)
- `tpl` - template exibido quando há acesso
- `tpl_else` - template exibido quando não há acesso
- `echo` - texto exibido quando há acesso
- `echo_else` - texto exibido quando não há acesso

As permissões têm a forma `<operation>-<resource_id>`, por exemplo `view-articles`, `create-products`, `edit-.content` ou `delete-users`. Ids de recursos ocultos mantêm o ponto inicial nas permissões guardadas. `manage-<resource_id>` dá todas as operações padrão daquele recurso. A função admin sempre tem `(all)`, que pula todas as verificações de permissão.

As permissões são atribuídas às funções em `/nb-admin/roles/`. Use a tela de permissões da função para editar as permissões com caixas de seleção; tokens próprios ainda podem ser guardados para verificações específicas do projeto. Tokens antigos como `manage-content`, `(any)`, `get_<resource>`, `add-<resource>` e `(any)_<resource>` são convertidos ao carregar a sessão e na migração de atualização, mas o código novo usa a forma padrão.

### `[#date input fmt=Y-m-d#]`
Formata uma data. A entrada pode ser um timestamp Unix, um texto de data ou omitida (hoje). Use `fmt=full`, `long`, `medium` ou `short` para uma saída legível no idioma da página. Qualquer outro valor de `fmt` usa a sintaxe de data do PHP para um formato técnico exato. Informe `lang=` para substituir o idioma detectado.

```
[#date fmt=d-m-Y#]                        → today in d-m-Y format
[#date item.date fmt="j F Y"#]            → formats item.date
[#date 1741265734 fmt=Y-m-d#]             → formats Unix timestamp
[#date item.date fmt=long#]               → locale-aware long date
```

`[#fmt var=item.date type=date fmt=long#]` usa o mesmo formatador de datas. Os formatos com nome usam a extensão `intl` do PHP quando disponível e, sem quebrar a página, recorrem a formatos fixos em inglês do PHP.

### `[#get-first dataset#]`
Guarda o primeiro item de um conjunto de dados em `first` (ou numa variável própria).

```
[#get-first data.articles#]
[#get first.title#]

[#get-first data.articles var=latest#]
[#get latest.date#]
```

### `[#last-update#]`
Devolve um timestamp Unix do arquivo-fonte modificado mais recentemente em `ext/` e `core/`. Útil com `[#fmt type=ago#]` para mostrar quando o site foi atualizado pela última vez.

```
[#fmt val=[#last-update#] type=ago#]   → "3 days ago"
[#fmt val=[#last-update#] type=date fmt=d-m-Y#]
```

### `[#obfuscate text#]`
Exibe um texto com caracteres Unicode invisíveis e Alpine.js, de modo que bots e scrapers não o veem, mas os usuários conseguem ler. Use para endereços de e-mail e números de telefone.

```
[#obfuscate info@example.com#]
```

### `[#uri-path#]`
Devolve o caminho no sistema de arquivos da pasta da rota atual.

### `[#url-key#]`
Devolve uma chave normalizada da URL atual, útil para classes do body ou para reconhecer a página em JS.

```
[#set body-classes=[#url-key#]#]
```

`/admin/users/` → `admin_users`, página inicial → `_home`.

### `[#http-header type#]`
Envia um cabeçalho Content-Type na resposta. Use no topo de rotas que não devolvem HTML.

```
[#http-header json#]
[#http-header css#]
[#http-header csv#]
```

Tipos: `css`, `js`, `json`, `xml`, `txt`, `woff`, `csv`, `403`, `404`, `500`.

Um segundo parâmetro também envia cabeçalhos de cache longo (`Cache-Control: private`, `Expires`, `Last-Modified`) e responde `304` a uma requisição condicional: `[#http-header css cached#]`.

### `[#system-messages#]`
Exibe as mensagens do sistema na fila (definidas no servidor pela sessão). Use no template HTML ou no layout para mostrar avisos rápidos.

### `[#empty-img#]`
Devolve um GIF transparente de 1×1 como data URI. Use como `src` provisório antes de haver uma imagem real.

### `[#max-upload-size#]`
Exibe o valor `upload_max_filesize` do PHP em forma legível. Útil como dica em formulários de envio.

### `[#unquote varname#]`
Exibe o valor de uma variável com as aspas escapadas em HTML (`"` → `&quot;`, `'` → `&apos;`). Seguro para colocar valores dentro de atributos HTML.

```html
<div x-data='{"title": "[#unquote item.title#]"}'></div>
```

### `[#collect-script path#]`
Adia a inclusão de um script para que todos sejam exibidos juntos no fim da página, sem duplicatas. Chame sem argumentos para exibir todos os scripts coletados.

```
[#collect-script [#base-url#]/ext/static/chart.js#]
...
[#collect-script#]   ← renders all collected scripts here
```

### `[#is-dev-env#]`
Exibe `DEV` ou `PROD`. Útil para saída de depuração ou comportamento por ambiente.

```
[#if [#is-dev-env#]=DEV tpl=debug-panel#]
```

### `[#detect-language#]`
Devolve o código do idioma ativo. Ordem de detecção:
1. Prefixo da URL (`/en/`, `/nl/`)
2. Preferência do usuário (`?lang=en`)
3. TLD do domínio (`.en`, `.nl`)
4. Cabeçalho de idioma do navegador
5. Alternativa: o primeiro idioma definido na configuração do site

### `[#debug#]`
Exibe informações de depuração. Use só durante o desenvolvimento.

```
[#debug#]
[#debug variables session#]
```

### `[#log message#]`
Grava em `ext/data/.tmp/logs/system.log`.

### `[#nop#]`
Não faz nada. Use para desativar shortcodes temporariamente.

## Classificação da API de shortcodes

O inventário abaixo é gerado a partir das implementações `*_sc()` em `core/lib` e `core/modules/*/lib` e conferido com o uso no `ext/` local. Os shortcodes públicos são estáveis para templates de projeto. Os shortcodes internos e do admin são suportados em templates e módulos do core, mas não devem ser tratados como API para projetos.

| Classificação | Shortcodes |
|---|---|
| Público do core | `base-path`, `base-url`, `cfield`, `collect-script`, `count`, `data`, `data-count`, `data-join`, `data-last-update`, `data-sort`, `date`, `debug`, `detect-language`, `empty-img`, `env`, `fmt`, `get`, `get-first`, `get-html`, `http-header`, `if`, `include`, `is-url`, `last-update`, `log`, `logged-in`, `max-upload-size`, `module`, `nop`, `obfuscate`, `redirect`, `repeat`, `set`, `system-messages`, `text`, `unquote`, `uri-path`, `url`, `url-key` |
| Público de módulo | `access`, `api-allow`, `build-form`, `feature-cond`, `first-img-uuid`, `form-key`, `get-form-errors`, `get-img-html`, `get-user`, `honeypot-field`, `img-url`, `json2post`, `logout`, `post`, `role-cond`, `role-switch`, `sanitize`, `sticky`, `userfield`, `username`, `validate` |
| Interno/admin | `api-session`, `api-token`, `disk-space-resource`, `exif`, `field-name`, `files`, `files-unused`, `files-usage`, `find`, `get-resource-meta`, `get-resource-record`, `get-resource-records`, `get-system-log`, `get-user-resources`, `json`, `openai-complete`, `openai-translate`, `pages`, `render-field`, `resource-name`, `resources`, `sys-messages`, `thumbnail` |

---

## Outras interfaces públicas

Estas notas descrevem shortcodes públicos do inventário do framework cujo uso não foi detalhado acima. Use os guias específicos para fluxos completos.

| Shortcode | Comportamento |
|---|---|
| `[#module forms#]` | Não faz nada: os módulos são encontrados em toda requisição. Templates antigos ainda o contêm; ele pode ser removido. |
| `[#data-last-update events#]` | Devolve o timestamp do arquivo mais recente do recurso, ou zero quando o recurso não existe. |
| `[#access feature=view-events#]` | Exige uma permissão antes de uma saída protegida; sem acesso, redireciona para o endereço de recusa configurado. |
| `[#api-allow method=post resource=applications#]` | Permite e executa uma operação restrita sobre um recurso para uma rota, com as verificações públicas de chave de requisição do framework; não use para contornar permissões de recursos protegidos. |
| `[#role-cond roles=editor tpl=editor-tools tpl_else=visitor-tools#]` | Exibe o template escolhido quando uma das funções citadas está ativa; senão, a alternativa opcional. |
| `[#role-switch tpl=account-panel#]` | Exibe um template com o sufixo da primeira função ativa, ou `.anonymous` sem sessão. |
| `[#get-user var=user#]` | Carrega o registro do usuário atual numa variável; `uuid=` escolhe um registro explicitamente. Verifique as permissões antes de exibir campos de outro usuário. |
| `[#userfield name#]` | Devolve um campo do usuário atual; um UUID explícito pode escolher outro registro e exige a verificação de permissão adequada no fluxo que o chama. |
| `[#username#]` | Devolve o nome do usuário autenticado, ou `anonymous`. |
| `[#logout#]` | Encerra a sessão do usuário atual e redireciona; `redirect=` escolhe o destino. |
| `[#form-key contact#]` | Exibe campos ocultos com a chave da requisição e o identificador do formulário; `plain` devolve a chave, e `x-init` prepara o estado do formulário no navegador. |
| `[#honeypot-field#]` | Exibe o campo honeypot oculto configurado para um formulário público. |
| `[#post#]` | Processa um POST com chave pelos arquivos de validação e envio da rota. A validação é obrigatória antes do processamento. |
| `[#get-form-errors email#]` | Carrega as mensagens de validação do campo em `validation_errors`; sem argumento, os erros gerais. |
| `[#sticky email default=you@example.com#]` | Recupera um valor do formulário do estado enviado ou guardado, para exibir de novo. |
| `[#json2post#]` | Converte um objeto JSON enviado em valores POST do PHP para um processador existente. |
| `[#first-img-uuid var=record.body#]` | Encontra o UUID da primeira imagem num conteúdo formatado. |
| `[#img-url image-reference#]` | Transforma um UUID, um caminho ou uma URL de imagem numa URL absoluta de imagem. |

### Limites de validação e limpeza

O inventário inclui hoje `validate` e `sanitize`, mas esses shortcodes não validam nem limpam nada. Não confie na chamada dessas tags para proteger a entrada. Use as funções reais de validação do PHP e o tratamento de campos e da API do framework, como descrito em [Formulários](/pt/docs/guides/forms/) e [Pontos de extensão do PHP](/pt/docs/reference/php/).

`feature-cond` e a apresentação baseada em funções escolhem quais templates exibir. Os processadores do backend continuam verificando as permissões de cada ação protegida.
