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 e segundo 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.
Neste artigo da série iremos extender as capacidades do tipo de publicações de maneira a personalizar ainda mais a sua apresentação e melhorar a organização dos elementos.
Sumário
- Definir mensagens de atualização personalizadas na administração
- Criar texto de ajuda contextualizada para o tipo de publicação
- Modificar e acrescentar colunas na página de listagem do tipo de publicação
- Editar e acrescentar “Ações em Massa”
Personalizar a administração às vezes requer algum trabalho. Entrando agora nesta parte o trabalho já não vai ser mais direto como foi nos últimos artigos – estamos no momento a “cavar” fundo no WordPress.
Porém, o nosso objetivo é apenas proporcionar as ferramentas para você poder trabalhar e fazer dos Post Types o que você quiser, inventando, experienciando e até descobrindo novas funcionalidades. Assim, vamos continuar a seguir uma linha condutora muito direta. O “grau da sua experiência” é você quem define depois de ler e aprender.
Mensagens de estado e atualização
As mensagens de estado e atualização são aquelas mensagens de noticia ou de erro (amarelas e vermelhas, respectivamente) que aparecem no cabeçalho das páginas da administração indicando que houveram ações de criação, edição, eliminação, outras ações ou estados que foram concluídos com êxito ou não.
Nesta parte iremos tratar de como implementar as nossas próprias mensagens de erro ou de estado quando o nosso tipo de publicação é atualizada, apagada, publicada, removida, etc., mapeando todas as ações possíveis.
Para isso chamamos o filtro post_updated_messages que contém um array com todas as strings de estado para todos os Post Types registadas. O código abaixo é a representação de como é possível modificar essas strings facilmente para o nosso Post Type film:
add_filter( 'post_updated_messages', 'film_updated_messages' );
function film_updated_messages( $messages ) {
global $post, $post_ID;
$messages['film'] = array(
1 => sprintf( 'O filme foi atualizado. <a href="%s">Ver Filme</a>', esc_url( get_permalink($post_ID) ) ),
2 => 'Campo customizado atualizado',
3 => 'Campo customizado apagado',
4 => 'Filme atualizado',
5 => isset( $_GET['revision'] ) ? sprintf( 'Filme atualizado para a revisão %s', wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
6 => sprintf( 'Filme publicado. <a href="%s">Ver Filme</a>', esc_url( get_permalink($post_ID) ) ),
7 => 'Filme guardado.',
8 => sprintf( 'Filme guardado. <a target="_blank" href="%s">Prever Filme</a>', esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
9 => sprintf( 'Filme agendado para: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Prever Filme</a>' ), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
10 => sprintf( 'Rascunho de Filme guardado. <a target="_blank" href="%s">Prever Filme</a>', esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
);
return $messages;
}
A função que faz a gestão das mensagens chama primeiro as variáveis globais $post e $post_ID de modo a serem acessíveis a partir da função. Em seguida, modificamos o array que representa este Post Type, passando novas strings para serem usadas no lugar das strings por defeito. A função nativa do PHP sprintf() é muito usada aqui, uma vez que ela ajuda na insersão de variáveis importantes para que as mensagens não fiquem descontextualizadas.
Você deve seguir uma linha igual à apresentada no código acima, modificando apenas as strings e fazendo o mínimo de mudanças possíveis à posição das variáveis para que a experiência do usuário seja uniforme em toda a administração.
Ajuda contextualizada
A administração do WordPress tem uma funcionalidade que quase toda a gente desconhece ou simplesmente não liga, mas que deveria ser o primeiro recurso de procura de informação em caso de dúvida.
Estou falando daquela aba que fica no cabeçalho de quase todas as páginas da Administração em que aparece o texto “Ajuda”. Ao clicar nessa aba, um painel se abre e apresenta uma ajuda dedicada apenas à página que estamos visualizando – por isso se chama “Ajuda Contextualizada”, pois encontra-se no contexto da página em que estamos.
Quando criamos um novo tipo de publicação, a ajuda contextualizada para esse tipo apresenta apenas dois links que ajudam muito pouco quem vai à procura de mais informação, na verdade nós podemos (e devemos) modificar esse painel de maneira a apresentar um texto de ajuda contextualizado tanto na página de edição de posts como no de listagem.
Para isso procedemos como anteriormente, chamando agora a ação contextual_help e passando uma função que retorna o texto HTML que queremos para ajuda. O código é o seguinte:
add_action( 'contextual_help', 'film_help_text', 10, 3 );
function film_help_text( $contextual_help, $screen_id, $screen ) {
if ( 'film' == $screen->id ) {
$contextual_help =
'<p>Este é um texto de ajuda ao nosso tipo de post Filme que aparece na página de edição.</p>' .
'<p>Você pode criar o texto que quiser aqui</p>';
} elseif ( 'edit-film' == $screen->id ) {
$contextual_help =
'<p>Este texto aparece na ajuda da página de listgem de filmes.</p>';
}
return $contextual_help;
}
Esta ação procura se a tela atual é a página de edição ou a página de listagem de filmes através da variável id do objeto $screen, retornando para cada um dos casos uma ajuda contextual que vai aparecer na aba de Ajuda.
Você pode colocar o quiser, seja HTML ou código script ou PHP (sendo que este será escapado e não irá correr, apenas será apresentado como referência), no entanto à medida que for escrevendo será cada vez mais complicado fazer a gestão destas strings – escrever HTML dentro de aspas não é a melhor coisa para organização.
É por isso que normalmente uso outra abordagem: em vez de colocar as strings aqui, crio um arquivo HTML para cada uma das ajudas contextuais e leio o arquivo para a variável em tempo de execução com ajuda da função nativa do PHP file_get_contents(). Desta forma ressalvo a organização do espaço nesta função e ao mesmo tempo possibilita a modificação do HTML sempre que necessário.
Desta maneira a abordagem ficaria a seguinte:
Arquivo film_help_text.html:
<p>Este é um texto de ajuda ao nosso tipo de post Filme que aparece na página de edição.</p>
<p>Você pode criar o texto que quiser aqui</p>
<ul>
<li>Aqui sou livre de criar o HTML que quiser.</li>
</ul>
Modificação do código acima:
add_action( 'contextual_help', 'film_help_text', 10, 3 );
function codex_add_help_text( $contextual_help, $screen_id, $screen ) {
if ( 'film' == $screen->id ) {
$contextual_help = file_get_contents( 'film_help_text.html' );
} elseif ( 'edit-film' == $screen->id ) {
$contextual_help = file_get_contents( 'edit-film_help_text.html' );
}
return $contextual_help;
}
Para isto funcionar, não se esqueça de colocar os arquivos .html no seu Tema WordPress, na mesma pasta que o arquivo functions.php. Lembre-se também de criar o .html para o arquivo edit-film_help_text.html que será apresentado na página de listagem.
Modificar colunas na listagem de publicações
A página de listagem apresenta apenas duas colunas: o título da publicação e a data de criação ou publicação. Porém, como seria óbvio, agora nós vamos modificar essa tabela de modo a usar mais colunas de forma personalizada, apresentando apenas os dados que queremos e como queremos.
Para modificar as colunas, teremos que chamar quatro ações e filtros, de modo a termos as funcionalidades necessárias. Isto requer algum treino e experiência pois não é muito intuitivo. Penso que a API aqui poderia ser melhorada, e provavelmente será um dia.
Para facilitar esta terefa vamos dividir em duas partes: a primeira diz respeito à apresentação das colunas em si e a segunda à possibilidade de dar a capacidade de sortear os resultados por coluna.
Primeira parte
Através do filtro manage_edit-<tipo-de-post>_columns criamos o cabeçalho das colunas que queremos que apareçam. Lembre daqueles campos personalizados (ano, realizador e produtor) que criamos na parte 02 da série? Pois bem, vamos usá-los aqui apresentando um por cada coluna:
add_filter( 'manage_edit-film_columns', 'film_manage_edit_columns' );
function film_manage_edit_columns( $columns ) {
$film_columns = array(
"cb" => $columns["cb"],
"title" => $columns["title"],
"film_ano" => 'Ano',
"film_realizador" => 'Realizador',
"film_produtor" => 'Produtor',
"date" => $columns["date"],
);
return $film_columns;
}
Neste momento temos as colunas já mapeadas e o WordPress sabe que colunas irá apresentar na página de listagem. Nesta função fizemos passar uma nova organização de colunas, mantendo-as com a Checkbox, Título e Data, e criando novas colunas que farão a apresentação dos campos personalizados.
Em seguida, iremos chamar a ação que fará o display efetivo do conteúdo de cada post dentro da tabela de listagem. Para isso usamos manage_posts_custom_column:
add_action( "manage_posts_custom_column", 'film_manage_columns', 10, 2);
function film_manage_columns( $column ) {
global $post;
switch ($column) {
case "film_ano":
echo get_post_meta( $post->ID, '_ano_film', true );
break;
case "film_realizador":
echo get_post_meta( $post->ID, '_realizador_film', true );
break;
case "film_produtor":
echo get_post_meta( $post->ID, '_produtor_film', true );
break;
}
}
Nesta função procuramos pelo nome da coluna pela condição switch, e caso seja igual a uma daquelas, corre o código correspondente. Neste caso fazemos o print dos próprios campos personalizados.
Segunda Parte:
As colunas já aparecem na página de listagem, porém, as únicas colunas que são sorteáveis são o título e a data. Caso queiramos sortear os filmes por ano ou realizador teremos que completar esta segunda parte.
Usando mais dois filtros, conseguimos fazer com que essas colunas sejam sorteáveis:
// Definindo que colunas devem ter a capacidade de sortear
add_filter( 'manage_edit-film_sortable_columns', 'manage_film_sortable_columns' );
function manage_film_sortable_columns( $columns ) {
$columns['film_ano'] = 'ano';
$columns['film_realizador'] = 'realizador';
return $columns;
}
// Aqui lemos as variáveis que estão no URL e fazemos buscas como quisermos
add_filter( 'request', 'film_request' );
function film_request( $vars ) {
// Procuramos saber se o URL pede para sortear uma das colunas
if ( isset( $vars['orderby'] ) ) {
// Sorteamos por coluna
switch ( $vars['orderby'] ) {
case 'ano' :
$vars = array_merge( $vars, array(
'meta_key' => '_ano_film',
'orderby' => 'meta_value'
) );
break;
case 'realizador' :
$vars = array_merge( $vars, array(
'meta_key' => '_realizador_film',
'orderby' => 'meta_value'
) );
break;
}
}
return $vars;
}
Este código é bem maior, mas é muito direto e de fácil compreensão. No primeiro filtro nós juntamos às colunas já sorteáveis por defeito (Título e Data) as colunas Ano e Realizador. Decidi não colocar a coluna Produtor como sorteável apenas por questões didáticas.
O segundo filtro define, para cada uma das colunas, caso seja pedido o seu sorteio, o que o WordPress deve fazer. Neste caso, o WordPress irá fazer o pedido à base de dados e sortear ascendentemente pelos campos personalizados.
Na verdade, este filtro serve muito mais do que sortear colunas… você pode criar variáveis na URL que irão fazer novos pedidos à base de dados e apresentar novas publicações, mas isso está fora do escopo deste artigo. Fica só a ideia.
Editar e acrescentar ações em massa
Esta dica é por enquanto um pouco complicada, pois a API do WordPress aqui nunca ficou concluída e possívelmente ainda vai levar algum tempo até ficar pronta. No entanto é possível contornar essa situação.
Vamos dividir esta parte em duas: uma dedicanda ao dropdown de ações em massa e outra aos links de estado listados por cima do cabeçalho da tabela.
Dropdown de Acções em Massa:
Este dropdown é um dos exemplos de uma API inacabada. Neste momento você só poderá eliminar opções da dropdown, não podendo acrescentar mais. Existe forma de se fazer isso utilizand jQuery, porém este é assunto um tanto complexo pois será necessário executar a ação que criamos, e por isso ficará para a próxima vez.
No entanto fica aqui como exemplo o código de como remover a ação de editar em massa. Você poderá retirar todas as ações que estiverem pelo dropdown, basta apenas procurar a chave do array correspondente à ação:
add_filter( 'bulk_actions-edit-film', 'film_bulk_actions', 10, 1 );
function film_bulk_actions( $actions ){
unset( $actions['edit'] );
return $actions;
}
O filtro bulk_actions-edit-<tipo-de-post> recebe um array com as ações disponíveis, bastando ao programador retirar as que quiser.
Links de Estados:
Normalmente uso este espaço para apresentar links para publicações personalizadas complexas. Deixo como exemplo uma captura de tela de um plugin para Encomendas que criei para um cliente:
Fantástico, não é?
O código é simples e muito direto. Darei apenas os componentes necessários para você criar as suas próprias estruturas:
add_filter( 'views_edit-film', 'film_views', 10, 1 );
function film_views( $views ){
// Aqui vão as views customizadas
}
Este é o filtro que pode usar para criar os links de estado personalizados. Imagine que gostaria de criar novos estados para os filmes, por exemplo: “Pré-lançamento” e “Estreias”.
Primeiro Passo: vamos criar um campo personalizado chamado ‘_estado_film’ da maneira descrita no artigos anteriores.
Segundo Passo: criamos os links que vão aparecer no espaço das views (dentro da função film_views):
Primeiro vamos pesquisar se não estamos acessando um destes estados e, em seguida, criamos os links para cada um deles:
// Pré-lançamento
$class = ( isset( $_REQUEST['meta_value'] ) && $_REQUEST['meta_value'] == 'pre' ) ? 'current' : '';
$views['pre'] = '<a class="'.$class.'" href="'.admin_url().'edit.php?post_type=film&meta_key=_estado_film&meta_value=pre">Pré-lançamento</a>';
// Estreias
$class = ( isset( $_REQUEST['meta_value'] ) && $_REQUEST['meta_value'] == 'estreias' ) ? 'current' : '';
$views['estreias'] = '<a class="'.$class.'" href="'.admin_url().'edit.php?post_type=film&meta_key=_estado_film&meta_value=estreias">Estreias</a>';
return $views;
Neste código nós criamos mais dois estados que irão aparecer como links. Em cada um, procuramos se a URL contém a variável meta_value e se o seu valor é um dos dois estados definidos anteriormente para aplicar a class current. Em seguida criamos os links para cada view.
Breve nota sobre WordPress e PHP
O WordPress é uma fantástica plataforma de framework para criação de novas funcionalidades. É bem desenhada e de fácil compreensão pois apresenta uma variedade de filtros e ações, além de permitir o uso de classes apenas onde é necessário.
Pessoalmente, não sou muito fã do sistema de classes em PHP, primeiro porque instanciar objetos em scripts torna-se lento. Segundo porque o sistema de classes no PHP5 está, no meu entender, “mal” acabado – são muitas as questões que não estão bem explicadas e não se sabe bem para que servem, e portanto na prática estas não têm muita utilizade.
Porém, assim que você se torna um bom programador de Post Types vai perceber que são muitas as APIs que necessitam de serem corrigidas ou acabadas, mas que há sempre uma forma de contornar esta situação.
Sempre que você encontrar alguma lacuna, pode criar um patch e enviá-lo no trac do WordPress em http://core.trac.wordpress.org/
Espero que este artigo tenha aumentado a sua visão em relação aos Post Types. E lembre-se: a curva de aprendizagem existe, mas com gosto e persistência conseguimos vencer os obstáculos.
Lembre-se de comentar este artigo, e se tiver novos codigos compartilhe.
Bons estudos e até a próxima!