log - smart software development. great user experience

Desenvolvimento sobre WordPress (3) — Shortcodes

Nas primeiras duas partes da nossa série de artigos introdutórios sobre desenvolvimento em WordPress, centrámo-nos na API de hooks, que serve para invocar funções que executem acções ou filtrem dados em resposta a acontecimentos na plataforma.

Trataremos agora da API de shortcodes do WordPress, que permite que usemos, no conteúdo de artigos e páginas, um conjunto de códigos macro delimitados por parênteses rectos ([]) e inspirados pela linguagem de formatação BBCode. No momento da apresentação ao visitante do site, estes macros são substituídos pelo resultado da função que abstraem.

O WordPress inclui de origem alguns destes shortcodes. Por exemplo, o shortcode [gallery] é substituído por uma galeria de fotografias com todas as imagens que estiverem anexadas ao artigo ou página onde se encontra. Um shortcode é descrito de forma muito semelhante a uma vulgar tag HTML, permitindo atributos e tags de abertura e fecho. Por exemplo, [gallery id="3"] ou [block]Lorem ipsum[/block].

Para além dos shortcodes oferecidos pelo WordPress, tanto temas como plugins podem criar novos códigos. É o que iremos descobrir neste artigo.

O meu primeiro shortcode

Como nos artigos anteriores, concentraremos as nossas modificações no ficheiro functions.php do tema, situado em /wp-content/themes/pasta do tema/functions.php, e só mais tarde aplicaremos o conhecimento adquirido ao desenvolvimento de uma nova extensão.

Para criar um novo shortcode em código basta, muito simplesmente, declarar uma função que o implemente e associá-la ao nome pretendido com add_shortcode(). A forma de o fazer é semelhante ao que já fazíamos para os hooks:

function tutorial_hello_world_shortcode ( $atts, $content = null ) {
    return 'Olá, mundo!';
}

add_shortcode( 'hello', 'tutorial_hello_world_shortcode' );

E pronto! Experimente inserir o shortcode [hello] no conteúdo de qualquer página ou artigo, e este será substituído pela expressão “Olá, mundo!” aquando da visualização.

Atributos do shortcode

Como já demos a entender, é possível passar atributos a um shortcode, à semelhança do que acontece em BBCode ou em HTML. Os mais atentos terão reparado que a função tutorial_hello_world_shortcode() aceita um parâmetro $atts, que recebe precisamente um array de parâmetros passados no shortcode.

Não é preciso fazer nada de especial para obter estes parâmetros, já que a API do WordPress abstrai o processo de análise da string para recolha dos parâmetros. Um shortcode com o seguinte formato:

[hello name="Luís Rodrigues" other="Outro atributo"]

irá invocar a nossa função tutorial_hello_world_shortcode() com o seguinte array passado por parâmetro:

Array
(
    [name] => Luís Rodrigues
    [other] => Outro atributo
)

Isto significa que podemos modificar a nossa função para lhe dar um toque mais pessoal:

function tutorial_hello_world_shortcode ( $atts, $content = null ) {
    if (empty( $atts['name'] ))
        return 'Olá, mundo!';
    else
        return 'Olá, ' . $atts['name'] . '!';
}

add_shortcode( 'hello', 'tutorial_hello_world_shortcode' );

Assim, podemos escrever o shortcode

[hello name="Luís Rodrigues"]

e obter

Olá, Luís Rodrigues!

Conteúdo do shortcode

O shortcode acima limita-se a substituir todo o código pelo retorno da função associada. Contudo, também é possível usar shortcodes para filtrar blocos de conteúdo sem o substituir por completo.

Aqui entra em palco o segundo parâmetro da nossa função, $content, que guarda todo o conteúdo existente entre a abertura e fecho de um shortcode.

function tutorial_hello_world_shortcode ( $atts, $content = null ) {
    $name = empty( $atts['name'] ) ? 'mundo' : $atts['name'];
    $output = "<strong>Olá, $name!</strong> ";
    if (!is_null( $content )) {
        $output .= $content;
        $output .= " <strong>Adeus, $name!</strong>";
    }
    return $output;
}

add_shortcode( 'hello', 'tutorial_hello_world_shortcode' );

A inserção do shortcode revisto no nosso artigo ou página poderia ter o formato

[hello name="Luís Rodrigues"]Lorem ipsum dolor sit amet...[/hello]

resultando em

Olá, Luís Rodrigues! Lorem ipsum dolor sit amet… Adeus, Luís Rodrigues!

A invocação anterior, contendo apenas um código [hello] simples, com o sem atributo, continuaria a funcionar da mesma forma, já que o código da nossa função verifica a existência ou não-existência do atributo name e do conteúdo.

Valores por omissão

No código do nosso exemplo anterior, ocorre uma verificação prévia do atributo name e a atribuição do valor por omissão "mundo" caso este não se encontre definido.

Há, no entanto, uma forma mais elegante e recomendada de indicar os valores por omissão e extrair os valores de um conjunto de atributos. Assim, em vez de

$name = empty( $atts['name'] ) ? 'mundo' : $atts['name'];

podemos escrever

extract( shortcode_atts( array(
    'name' => 'mundo',
    'other' => 'XPTO' // Valor por omissão para outro atributo
), $atts ) );

Exemplo útil

Os shortcodes têm inúmeras aplicações práticas, uma das quais sendo a possibilidade de limitar a visualização de conteúdos tendo em conta um conjunto de condições.

Por exemplo, podemos criar um novo shortcode [access] que limite o acesso de utilizadores não-autenticados aos conteúdos delimitados pelo shortcode.

function shortcode_access_control ( $atts, $content = null ) {
    extract( shortcode_atts( array(
        'capability' => 'read',
        'error' => 'Este conteúdo está reservado a utilizadores autenticados.',
    ), $atts ) );
    if (current_user_can( $capability ) && !is_null( $content ))
        return $content;
    else
        return $error;
}

add_shortcode( 'access', 'shortcode_access_control' );

O shortcode pode ser invocado digitando o seguinte texto algures no conteúdo de uma página ou artigo:

[access]TOP SECRET![/access]

Um utilizador autenticado verá o seguinte:

TOP SECRET!

Todos os restantes verão antes a mensagem:

Este conteúdo está reservado a utilizadores autenticados.

Por omissão, esta função verifica se o utilizador tem a autorização read (ou a capacidade que for indicada no parâmetro capability). Se a autorização tiver sido concedida, é apresentado o conteúdo, caso contrário mostramos a mensagem de erro (ou a que for indicada no atributo message).

Dado que este novo shortcode permite parametrizar a capacidade requerida do utilizador e a mensagem de erro, temos alguma flexibilidade nas opções de validação e apresentação. Por exemplo:

[access capability="admin" error="Este conteúdo só pode ser visto por administradores."]TOP SECRET![/access]

Precauções

Apesar de poderosa, a API de shortcodes apresenta algumas limitações a ter em consideração.

Uma destas particularidades tem a ver com o facto de a função que interpreta os shortcodes varrer o conteúdo dos artigos e das páginas uma única vez. Isto significa que incluir shortcodes dentro uns dos outros pode não surtir os efeitos desejados. Por exemplo:

[access]
    O meu primeiro shortcode: [hello]
[/access]

Não funciona, apresentando aos utilizadores autenticados apenas o texto “O meu primeiro shortcode: [hello]”, sem substituir o fragmento “[hello]” como seria de esperar.

Uma forma de contornar esta limitação é passar o $content do shortcode pela função do_shortcode() antes de o devolver. Feita a alteração, a função terá o seguinte aspecto:

function shortcode_access_control ( $atts, $content = null ) {
    extract( shortcode_atts( array(
        'capability' => 'read',
        'error' => 'Este conteúdo está reservado a utilizadores autenticados.',
    ), $atts ) );
    if (current_user_can( $capability ) && !is_null( $content ))
        return do_shortcode( $content ); // Processamento de sub-shortcodes
    else
        return $error;
}

add_shortcode( 'access', 'shortcode_access_control' );

Aqui, a função do_shortcode() obriga o WordPress a interpretar recursivamente o conteúdo em busca de novos shortcodes para substituir.

Mais problemático é o facto do interpretador do WordPress não reconhecer duas ou mais ocorrências do mesmo shortcode encadeadas. Por exemplo:

[shortcode]
    [shortcode][/shortcode]
[/shortcode]

Não irá funcionar, mesmo usando a função do_shortcode(), dado que a função que interpreta os shortcodes privilegia a velocidade de processamento e não a correcta interpretação de estruturas complexas destes códigos.

Deve-se evitar usar hífens no nome do shortcode, pois estes não são correctamente reconhecidos pelo interpretador devido a um bug nas actuais versões do WordPress. Prefere-se aqui o uso do carácter _ (underscore). Também não são aceites parênteses rectos no valor de um atributo: algo como [shortcode atributo="[valor]"] irá falhar.

No próximo artigo, iremos explicar o processo de desenvolvimento de novas widgets para apresentação nos temas. Até lá, aguardamos questões e sugestões dos nossos leitores na nossa página no Facebook.