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 e segundo artigos desta série: Guia definitivo para criar Custom Post Types (Parte 1) + Guia definitivo para criar Custom Post Types (Parte 2). 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.

Neste artigo da série iremos extender as capacidades do tipo de posts de maneira a customizar ainda mais a sua apresentação e melhorar a organização dos elementos.

SUMÁRIO

  • Definir mensagens de actualização customizadas na administração
  • Criar texto de ajuda contextualizada para o tipo de post
  • Modificar e acrescentar colunas na página de listagem do tipo de post
  • Editar e acrescentar “Ações em Massa”

custom post types

Customizar a administração por vezes requer algum trabalho, e entrando agora nesta parte o trabalho já não vai ser mais direto como foi nos últimos artigos – estamos neste momento a “escavar” fundo no WordPress.

Porém, o nosso objectivo é apenas proporcionar as ferramentas para você poder trabalhar e fazer dos tipos de post o que você quiser, inventando, experienciando e até descobrindo novas funcionalidades, assim sendo nós aqui vamos continuar a seguir uma linha condutora muito directa. O “grau da sua experiência” é você que 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 houve acções de criação, edição, eliminação outras acçõ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 post é atualizado, apagado, publicado, removido, etc, mapeando todas as acçõ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 tipos de post registados. O código abaixo é a representação de como é possível modificar essas strings facilmente para o nosso tipo de post 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 primeiro chama as variáveis globais $post e $post_ID de modo a serem acessíveis a partir da função. Seguidamente, modificamos o array que representa este tipo de post, 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 a falar daquela aba que fica no cabeçalho de quase todas as páginas da Administração que apresenta o texto “Ajuda”. Se clicar nessa aba, abre-se um painel que apresenta uma ajuda dedicada apenas à página que estamos a observar – é por isso que se chama “Ajuda Contextualizada”, pois encontra-se no contexto da página em que estamos.

Por defeito, quando criamos um novo tipo de post 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 acção contextual_help e passando-lhe 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 acçã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 objecto $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á apresentaod 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 ficheiro HTML para cada uma das ajudas contextuais, e leio o ficheiro para a variável em tempo de execução com ajuda da função nativa do PHP file_get_contents(). Desta forma salvaguardo a organização do espaço nesta função e ao mesmo tempo possibilita-me a modificação do HTML sempre que necessário.

Desta maneira a abordagem ficaria o seguinte:

Ficheiro 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 ficheiros html no seu Tema WordPress, na mesma directoria que o ficheiro functions.php. Lembre-se também de criar o html para o ficheiro edit-film_help_text.html que será apresentado na página de listagem.

MODIFICAR COLUNAS NA LISTAGEM DE POSTS

A página de listagem apresenta por defeito apenas duas colunas: o título do post e a data de criação ou publicação. Porém, como seria óbvio, nós vamos agora modificar essa tabela de modo a podermos usar mais colunas de maneira customizada, apresentando apenas os dados que queremos e como queremos.

Para modificarmos as colunas teremos que chamar quatro acçõ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 isto 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. Lembra-se daqueles campos customizados (ano, realizador e produtor) que criámos na parte dois 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, o WordPress sabe que colunas deve apresentar na página de listagem. Nesta função fizémos passar uma nova organização de colunas, mantendo as colunas com a Checkbox, Título e Data, e criando novas colunas que farão a apresentação dos campos customizados.

Seguidamente iremos chamar a acção que irá fazer 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 customizados.

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 deve o WordPress fazer. Neste caso, o WordPress vai fazer o pedido à base de dados de sortear ascendentemente pelo campos customizado. Na verdade, este filtro serve muito mais do que sortear colunas… você pode criar variáveis no URL que irão fazer novos pedidos à base de dados e apresentar novos posts, mas isso está fora do escopo deste artigo. Fica só a ideia. :)

EDITAR E ACRESENTAR ACÇÕES EM MASSA

Este truque é por enquanto um pouco tricky, pois a API do WordPress aqui nunca ficou concluída, e possívelmente ainda vai levar algum tempo até ficar concluída. No entanto é possível dar a volta à situação.

Vamos dividir esta parte em duas uma dedicando-se ao dropdown de acçõ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 o fazer, nomeadamente usando jQuery, porém este é assunto um tanto complexo, pois será necessário trigar a acção que criamos, e por isso ficará para outra altura.

No entanto fica aqui como exemplo o código de como remover a acção de editar em massa. Você poderá retirar todas as acções que estiverem pelo dropdown, basta simplesmente procurar a chave do array correspondente à acçã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 acções disponíveis, bastando ao programador retirar as que quiser.

Links de Estados:

Normalmente uso este espaço para apresentar links para posts customizados que sejam complexos. Deixo como exemplo daquilo que é possível atingir um printscreen destes links dum plugin de encomendas que criei para um cliente:

É fantático não é? :) Então vamos a isso. O código é simples e muito direto irei apenas dar 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 customizados. Imagine que gostava de criar novos estados para os filmes, por exemplo: “Pré-lançamento” e “Estreias”.

Primeiro Passo: vamos criar um campo customizado 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 a aceder a um destes estados e seguidamente criamos os links, isto 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 anteriores, para se poder aplicar a class current. Em seguida criamos os links para cada view.

NOTA BREVE SOBRE WORDPRESS E PHP

O WordPress é uma fantástica plataforma como framework de criação de novas funcionalidades e bastante bem desenhada e fácil de compreender, pois apresenta uma variedade enorme de filtros e acções para utilizar, isto além de racionar bastante o uso de classes, fazendo-o onde é apenas necessário.

Pessoalmente, não sou muito fã do sistema de classes em PHP, primeiro porque instanciar objectos em scripts torna-se lento, e 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ê começar a ser um bom programador de tipos de posts vai perceber que são muitas as APIs que necessitam de ser corrigidas ou acabadas, mas há sempre uma forma de se dar a volta. :)

Sempre que você encontrar alguma lacuna, pode sempre criar um patch e submetê-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 tipos de post. E lembre-se, a curva de aprendizagem existe sempre, mas com gosto e persistência acabamos sempre por conseguir vencer os obstáculos.

Lembre-se de comentar este artigo, e se tiver novos codigos compartilhe. :)

Bons estudos e até para a semana.