Esta série de artigos pretende ser um complemento de estudo tanto para iniciantes como para profissionais em como programar Custom Post Types no WordPress. Não esqueça de ler o primeiro, segundo, terceiro e quarto artigos desta série. Fique atento: todos os códigos desta série servem apenas como exemplo. Você pode e DEVE fazer as suas experiências ao modificar o código a seu gosto e necessidades.
Este é o último artigo da série e é aqui que tudo o que você aprendeu irá culminar.
Iremos extender os links permanentes para adicionar e modificar endpoints e rewrite rules dos Post Types. Assim, poderá ter publicações organizadas de maneira diferente das que normalmente estão por padrão no WordPress.
Sumário
- Adicionar um novo papel de usuário e novas meta informações ao Post Type
- 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 Post Types e taxonomias existentes de forma a encaixar plenamente às nossas necessidades. No entanto, por motivos didáticos, não falamos sobre segurança tanto no código, como em inputs dos usuários e até em ACL (lista de controles de acesso).
É sobre este tema que iremos falar. Como bónus, falaremos também sobre a poderosa ferramenta embuttida no WordPress que possibilia criar seus próprios links / URLs personalizados.
Papéis de usuário e capacidades (ACL)
Por padrão, o WordPress vem com cinco grandes grupos de acesso que podem ser atribuídos aos usuários. Esses grupos são chamados de papéis (roles, em inglês) e controlam quais 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 suas publicações e terá acesso limitado à interface.
Este processo é mais complexo do que parece, embora possa parecer bastante simples. O sistema do WordPress inicial (versões anteriores à 2.1) centrava o controle 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 papéis que agregam capacidades que os usuários podem deter.
Uma capacidade é uma função em determinado site da administração como, por exemplo, a capacidade de publicar ou remover uma publicação ou a capacidade de alterar as opções do tema ativo.
Com este método conseguimos criar novos papéis agregando apenas as capacidades necessárias para essa função.
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'
)
);
}
?>
A 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 precisamos.
Neste momento, as capacidades usadas na função em cima ainda não estão definidas. Para isso, vamos ter que modificar a nossa função register_post_type() anteriormente registada no primeiro artigo 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 as capacidades personalizadas ativadas personalizadas para o Post Type film e os usuários com o papel de Revisor de Filmes vão poder criar, editar, remover e publicar filmes.
Caso queria acrescentar estas novas capacidades a papéis já existentes como o de Editor, basta adicionar o 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 papéis aos Post Types. Outras funções podem ser usadas e 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 preocupação com essa questão aumenta na elaboração de websites e webapplications.
Conhecemos e ouvimos sobre 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 deve nos preocupar em sites de tamanhos pequeno e médio. Chamam-se XSS (cross-site scripting) e CSRF (Cross-site request forgery).
O primeiro existe quando o usuário clica num link mal intencionado 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 esses tipo de ataques, porém, em muitos casos podem não ser suficientes. Nesta seçã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 enviado:
É 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 na hora de guardar os campos personalizados, vamos usar esta função primeiro antes de passar o conteúdo à função update_post_meta(). Vamos, então, alterar o código criado no segundo artigo:
<?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 atual tiver ou não a permissão que testamos. Este é o segundo patamar da nossa proteção contra ataques de força bruta.
No nosso caso vamos voltar a alterar o código anterior para acrescentar esta função. Desta forma estamos a avaliar se o o usuário que está tentando salvar 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 personalizados são legítimos e que, pelo menos, o usuário que está tentando salvar tem permissões para isso.
Esta é a segunda defesa contra ataques, mas garantir que o usuário tenha permissões para editar filmes não basta. Falamos há pouco de ataques XSS e ainda precisamos garantir que o pedido para salvar estes dados venha 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 é simples e prática. A ideia é gerar uma senha aleatória que será gravada na base de dados temporariamente e colocada na query do pedido através de um hidden input.
Toda a vez que o usuário acessar essa página, uma nova senha será gerada com a função wp_nonce_field() e, antes de gravar os dados, iremos verificar se essa senha existe na base de dados e corresponde com a açã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 gravar:
[...]
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, achamos por bem falar um pouco nela uma vez que pode ser útil na organização de alguns Post Types mais complicados.
Esta API cria endpoints de URLs, ou seja, estruturas permanentes de URL personalizadas. No caso do nosso Post Type Filme, podemos querer apresentar os filmes por vários tipos de organização estrutural na URL, seja por Realizador ou Produtor ou por Ano do filme.
Vamos pegar no exemplo do caso mais lógico e 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 permitimos que o Post Type 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.
Mas antes disso acontecer terá que regenerar as rewrite rules. A melhor maneira é, depois de colocar os códigos, ir na seçã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 Post Types.
Download do código completo
Este é o último artigo para finalizar a 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. Para fazer o download, basta clicar aqui.
Tenha atenção ao utilizar este código: evite o "copiar e colar" e leia com atenção cada uma das partes de código que disponibilizamos, assim como os comentários ao código e, necessariamente, os artigos correspondentes.
Uma palavra final…
Espero que tenham gostado desta série e que tenha valorizado a sua aprendizagem no desenvolvimento para WordPress.
Este guia definitivo tentou dar a luz inicial para as matérias mais importantes dentro do mundo dos Custom Post Types. No entanto, sempre vale a pena referir que o conhecimento vai muito mais além de 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 dos colegas!
Não esqueça de ler os outros artigos desta série:
Guia definitivo para criar Custom Post Types - Parte 01 - Parte 02 - Parte 03 - Parte 04.
Até a próxima!