Esta série de Tutoriais WordPress pretende ser um complemento de estudo tanto para iniciantes como para profissionais de como programar tipos de post customizados no WordPress. Não esqueça de ler o primeiro, segundo e terceiro artigos desta série: Guia definitivo para criar Custom Post Types (Parte 1) + Guia definitivo para criar Custom Post Types (Parte 2) + Guia definitivo para criar Custom Post Types (Parte 3) + Guia definitivo para criar Custom Post Types (Parte 4). Tenha em atenção que todos os códigos desta série, servem apenas como exemplo. Você pode e DEVE fazer as suas experiências o modificar o código a seu gosto e necessidades.

Este será o último artigo desta série de como criar custom post types. Será aqui que tudo o que você aprendeu irá culminar.

Iremos tratar de extender os links permanentes de forma a adicionar e modificar endpoints e rewrite rules para os seus tipos de post. Desta forma poderá ter posts organizados de maneira diferente sem ser o que normalmente está consagrado por defeito no WordPress. Vamos adicionar novos papeis e atribuir a papeis existentes capacidades para o nosso tipo de post Filmes e vamos falar de segurança no código e como combater ataques XSS e CSRF (os mais comuns).

SUMÁRIO

  • Adicionar um novo papel de utilizador e novas meta capacidades ao tipo de post
  • Validar e segurar os inputs dos seus usuários
  • Bónus: Extender as URLs permanentes através da Rewrite API

Até aqui aprendemos a criar e a extender tipos de post e taxonomias existentes de forma a encaixar plenamente às nossas necessidades. No entanto, por motivos didáticos, não falámos sobre segurança tanto no código, como em inputs dos usuários e até em ACL (lista de controlos de acesso). É sobre este tema que iremos falar. Como bónus, falaremos também sobre a poderosa ferramenta embutida no WordPress que possibilita criar seus próprios links / URLs personalizados.

PAPÉIS DE USUÁRIOS E CAPACIDADES (ACL)

Por defeito o WordPress vem com cinco grandes grupos de acesso que se podem atribuir aos usuários, esses grupos são chamados de papeis (roles, em inglês) e que controlam que partes da Administração do WordPress os usuários podem ver ou alterar. Por exemplo, um usuário cujo papel atribuído é o de administrador terá acesso a tudo, enquanto que um usuário com o papel de autor apenas poderá escrever os seus posts e terá acesso limitado à interface.

Embora possa parecer simples, este processo é mais complexo do que parece. O sistema do WordPress inicial (versões anteriores à 2.1) centrava o controlo dos acessos no grupo, porém este método não era flexível e não possibilitava a sua modificação. Com as novas versões o processo foi-se modificando. Foram criadas as capacidades e os grupos passaram a ser papeis que agregam capacidades que os usuários podem deter, sendo que uma capacidade é uma função em determinado sitio da administração como por exemplo a capacidade de publicar ou remover um post, ou a capacidade de alterar as opções do tema ativo.

Com este método conseguimos criar novos papeis agregando apenas as capacidades necessárias para essa função.

Como exemplo, vamos criar o papel de Revisor de Filmes e assim os usuários que tiverem este papel atribuído terão apenas acesso a criar, editar, remover e publicar filmes. Todos as outras áreas da administração serão barradas a estes usuários.

Para tal colocamos este código no functions.php:

<?php
add_action( 'admin_init', 'add_role_film' );
function add_role_film() {
  add_role( 'films_reviewer', 'Revisor de Filmes', array(
    'edit_film', 'delete_film', 'read_film'
    )
  );
}
?>

Esta função add_role() cria um novo papel que poderá ser usado em usuários. Aceita como argumentos um ID único do role, uma string de apresentação do papel e um array com as capacidades incluídas nesse papel. No nosso caso adicionamos apenas as capacidades que necessitamos.

Neste momento as capacidades usadas na função em cima ainda não existem, não estão definidas. Para isso vamos ter que modificar a nossa função register_post_type() anteriormente registada na parte 1 desta série, acrescentando uma capacidade personalizada mudando o valor de capability_type para film:

add_action( 'init', 'create_post_type_film' );
function create_post_type_film() {
  register_post_type( 'film', array(
    [...]
    'capability_type' => 'film', // Mudamos de post para film
    [...]
    )
  );
}

Agora já temos ativadas as capacidades personalizadas para o tipo de post film e os usuários com o papel de Revisor de Filmes vão poder criar, editar, remover e publicar filmes.

Caso queiramos acrescentar estas novas capacidades a papeis já existentes como o de Editor, basta adicionar como seguinte código:

<?php
add_action( 'admin_init', 'add_capability_film' );
function add_capability_film() {
  $role = get_role( 'editor' );
  $role->add_cap( 'edit_film' );
  $role->add_cap( 'read_film' );
}
?>

Estas são as funções básicas para adicionar capacidades e papeis aos tipos de post. Mais funções podem ser usadas, este é apenas o básico. Para mais informações sugiro dar uma olhada aqui no codex.

VALIDAÇÃO E SEGURANÇA DOS INPUTS

Todos nós sabemos que segurança é um questão muito importante quando criamos código de qualidade para qualquer software. A necessidade de preocupação com essa questão aumenta na elaboração de websites e webapplications.

Conhecemos e ouvimos ou lemos (quase) todos os dias sites que são atacados ou informação confidencial que é extraída ilegalmente, normalmente isso acontece por falta de mecanismos de segurança ao nível da configuração dos servidores, mas o crescente número de exploits (pedaços de código expostos a ataques) ao nível de scripts na Web é uma preocupação que todos temos que ter em mente quando elaboramos código.

Há dois tipos de ataque muito comuns, e normalmente são os único que nos deve preocupar em sites de pequena e média dimensão, chamam-se XSS (cross-site scripting) e CSRF (Cross-site request forgery). O primeiro existe quando o usuário clica num link mal-intensionado que cria danos à sua própria instalação de WordPress e o segundo é o chamado tipo de ataque de força bruta, em que um usuário mal intencionado usa, por exemplo, formulários para tentar ganhar permissões ou criar exploits em instalações de WordPress alheias.

Felizmente o WordPress e o PHP vêm com proteções nativas contra este tipo de ataques, porém, em muitos casos podem não ser suficientes. Nesta secção iremos tratar de combater com funções e métodos muito simples este tipo de ataques usando validações de input e de links.

Limpar as informações de um formulário submetido:

É muito simples usando a função nativa do PHP strip_tags() limpando todos os caracteres que não sejam alfanuméricos. Isto consiste num ótimo meio de proteção primordial.

Assim, no caso de validação dos inputs em hora de guardar os campos personalizados, vamos usar esta função primeiro, antes de passar os seus conteúdos à função update_post_meta(). Vamos então alterar o código criado na parte 2:

<?php
add_action( 'save_post', 'ewp_film_save_post', 10, 2 );
function ewp_film_save_post( $film_id, $film ) {
   if ( ! $_POST['ano_film'] ) return;

   // Fazer a saneação dos inputs com a função strip_tags() e guardá-los
   update_post_meta( $film_id, '_ano_film', strip_tags( $_POST['ano_film'] ) );
   update_post_meta( $film_id, '_realizador_film', strip_tags( $_POST['realizador_film'] ) );
   update_post_meta( $film_id, '_produtor_film', strip_tags( $_POST['produtos_film'] ) );

   return true;

}
?>

Esta é a função mais usada no saneamento de inputs e aquela que deve ser sempre colocada antes de salvar algum registo para a base de dados.

Checar as permissões do usuário:

O WordPress vem com a função nativa current_user_can( $capability ) que, dada uma capacidade, retorna true ou false se o usuário corrente tiver ou não a permissão que estamos testar, respetivamente. Este é o segundo patamar da nossa protecção  contra ataques de força bruta.

No nosso caso vamos voltar a alterar o nosso código anterior para acrescentar esta função. Desta forma estamos a avaliar se o o usuário que está a tentar guardar um registo é um usuário com permissões para isso:

[...]
function ewp_film_save_post( $film_id, $film ) {
   if ( ! $_POST['ano_film'] ) return;

   // Caso o usuário não tenha permissões de edição de filmes, não faz nada
   if ( ! current_user_can( 'edit_film' ) ) return;
[...]

Garantimos assim que os registos para os campos customizados são legítimos e que, pelo menos, o usuário que está a tentar guardar tem permissões para isso. Esta é a segunda defesa contra ataques, porém, garantir que o usuário tem permissões para editar filmes não chega. Falámos à pouco de ataques XSS e ainda precisamos de garantir que o pedido para guardar estes dados provém da própria administração. Para isso vamos validar os links com nonces.

Validar o referer dos links com a técnica de nonces:

A técnica de nonces é muito simples e prática. A ideia é gerar uma senha aleatória que será guardada na base de dados temporariamente  e colocada na query do pedido através de um hidden input. Assim de toda a vez que o usuário acessar essa página uma nova senha será gerada com a função wp_nonce_field() e, em tempo de salvar os dados, iremos checar se essa senha existe na base de dados e corresponde com a acção que queremos realizar com a função check_admin_referer(). Vamos alterar dois códigos, o da metabox, adicionando a função criadora do nonce e novamente a função para guardar os campos personalizados:

[...]
function film_inner_meta_box( $film ) {
  wp_nonce_field( 'edit_film', __FILE__ );
?>
<p>
  <label for="realizador">Ano:</label>
[...]

e alteramos o código para guardar:

[...]
function ewp_film_save_post( $film_id, $film ) {
   if ( ! $_POST['ano_film'] ) return;

   // Caso o usuário não tenha permissões de edição de filmes, não faz nada
   if ( ! current_user_can( 'edit_film' ) ) return;

   // Verfificamos se este pedido é legítimo, ou seja, se provém da administração
   check_admin_referer( 'edit_film', __FILE__ );

[...]

Usando estas três técnicas protegemos os nossos websites WordPress contra os dois tipos de ataques mais comuns.

EXTENDER AS URLS USANDO A API REWRITE

A API de Rewrites do WordPress não tem propriamente a ver com custom post types, no entanto, achámos por bem falar um pouco nela uma vez que pode ser útil na organização de alguns tipos de post mais complicados.

Esta API cria endpoints de URLs, ou seja, estruturas permanentes de URL customizadas. No caso do nosso tipo de post Filme, podemos querer apresentar os filmes por vários tipos de organização estrutural na URL, seja por Realizador ou Produtos ou por Ano do filme.

Peguemos no exemplo do caso mais lógico e vamos criar uma estrutura de URLs que apresente os filmes organizados por ano de lançamento. Basta passar a função add_rewrite_rule(). O código seguinte viabiliza o que queremos alcançar:

<?php
add_action( 'init', 'add_film_rewrite' );
function add_film_rewrite() {
  add_rewrite_rule( 'filmes/ano/?(^[^/]*)', 'index.php?post_type=film&meta_key=_ano_film&meta_value=$matches[1]', 'top' );
}
?>

Colocando este código no functions.php estamos a permitir que o nosso tipo de post filme seja navegável também por ano de lançamento. Se um usuário entrar na URL filmes/ano/2011/ irá obter uma lista de todos os filmes realizados no ano de 2011 em género de blogue.

Mas antes disso acontecer terá que regenerar as rewrite rules. A melhor maneira é, depois de colocar os códigos, ir à secção de Ligações permanentes nas Opções da administração. Apenas visitando essa página de opções regenera as rewrite rules.

Esta é uma poderosa ferramenta que você pode usar para criar outras estruturas de URL para os seus tipos de post.

DOWNLOAD DO CÓDIGO COMPLETO

Este é o último artigo para finalizar esta série de custom post types e como prometido nos artigos anteriores, disponibilizamos os códigos de todos os artigos desta série num único download. Segue o ficheiro que poderá descarregar.

Faça o Download do Código!

Tenha em atenção ao usar este código: evite o copy e paste e leia com atenção cada um dos pedaços de código que disponibilizamos assim como os comentários ao código e, necessariamente, os artigos correspondentes.

Uma palavra final…

Espero que esta série tenha sido do vosso agrado e que tenha valorizado a sua aprendizagem no desenvolvimento para WordPress. Este guia definitivo tentou dar as luzes iniciais para as matérias mais importantes dentro do mundo dos custom post types. No entanto, vale sempre a pena referir que o conhecimento vai muito mais além que ler, é necessário pôr em prática e aprender cada vez mais. Se souber Inglês, sugiro sempre o uso da wiki oficial do WordPress, o CODEX.

Partilhe os seus códigos através dos comentários e participe nesta comunidade colocando questões e tirando dúvidas aos colegas!

Um forte abraço e até breve,

Vitor