Dos projetos que você pode atuar como um desenvolvedor WordPress, os blogs são a integração mais básica a ser feita com o WordPress. No entanto, a grande maioria dos trabalhos são formados por conteúdos personalizados e características específicas a ele.

Essa necessidade de se trabalhar com conteúdo diferenciado é o caso do projeto que vamos estudar nesse artigo, o site da agência de modelos Top Model. A proposta consiste em criar um projeto capaz de divulgar os ensaios e as modelos, sem abrir mão do blog. O trabalho conta ainda com algumas obrigações a cumprir:

  • Oferecer um destaque maior para três modelos na home do site
  • Criar um blog com paginação de resultados, formulário de busca, links na área lateral e também uma nuvem de tags
  • Necessita de uma área que exiba apenas os textos dinâmicos ocupando todo o espaço do layout, sem a presença de uma barra lateral
  • Fornecer um formulário de contato capaz de enviar os dados preenchidos pelo visitante ao email do administrador do site
Tema WordPress desenolvido para a agência de modelos TopModel

Tema WordPress desenvolvido para a agência de modelos TopModel

Após efetuar a integração dos elementos já conhecido, você precisa definir a exibição das categorias e tags de cada post. Do mesmo modo que foi lhe apresentado anteriormente, é possível recuperar tais informações em um primeiro momento para depois exibí-las quando necessário; como também utilizar-se das funções de conteúdo nativas do WordPress. Ao invés de usar get_the_categories e get_the_tags, prefira as seguintes funções para gerar os links automaticamente:

<p>
    Categorias:
    <span><?php the_category( ', ' ); ?></span> |
    <span><?php the_tags(); ?></span>
</p>

Metadata API

A edição de conteúdo no WordPress permite adicionar dados pertinentes ao material em que você está trabalhando, e que não estão previstos na estrutura original de organização e armazenamento das informações pelo sistema. Essa manipulação dos dados é possível mediante o uso das tabelas auxiliares de meta dados. Os meta dados são justamente dados extras referente ao conteúdo que estão relacionados.

Ao passo que os conteúdos são armazenados na tabela posts, os meta dados dos posts estão localizados em postmeta. Da mesma forma os comentários estão em comments e seus meta dados em commentmeta; e também os usuários que estão em users, possuem meta dados salvos em usermeta.

Os meta dados são constituídos por uma chave e um valor. Funcionam como a atribuição de uma variável: determina-se um nome e o valor que deve receber. Os dados são relacionados a tabela principal através de uma chave secundária post_id, comment_id ou user_id; cada qual para a respectiva tabela especificada anteriormente.

Na tela de edição de posts a aba Campos Personalizados possibilita a manipulação dos meta dados

Na tela de edição de posts a aba Campos Personalizados possibilita a manipulação dos meta dados

Através desse recurso você poderá definir o nome da Modelo que cada post trata. Adicione um novo post e localize a aba Campos Personalizados; informe no campo nome ‘Modelo’ e em valor o nome da modelo. Após submeter o envio e confirmar a inserção do post, já nos arquivos do Tema informe no espaço que deseja exibir o nome da Modelo:

<h3><?php echo get_post_meta( $post->ID, 'Modelo', true ); ?></h3>

Com get_post_meta qualquer valor da tabela auxiliar de posts pode ser recuperado, basta para isso informar inicialmente o identificador do post pretendido, a chave de consulta (o nome do campo) e se deseja recuperar apenas um único (verdadeiro) ou todos os valores (false) daquela chave e posts correspondentes. Ao retornar um valor único, o tipo de retorno será string; enquanto que para múltiplos valores, o retorno será dado em um array (mesmo que vazio, não encontrado, para ambos os casos).

Metaboxes

A aba Campos Personalizados é um metabox. Os metaboxes são justamente essas caixas de informações auxiliares que complementam a informação da tela na qual estão inseridos. Esse metabox para inserção dos meta dados funciona bem, porém é pouco prático e agradável aos olhos do gestor de conteúdo. O principal problema é a obrigatoriedade do preenchimento do campo chave, responsável por definir a informação que se deseja armazenar. Qualquer pequena alteração nesse valor já implica no correto funcionamento do recurso.

A solução para esse caso é a criação de metaboxes personalizados. Com isso você pode, dentro desses metaboxes, inserir formulários que solicitam apenas as informações pretendidas e ter a certeza que a chave será mantida.

Adicione uma ação para a tag admin_init no arquivo de funções e em seguida a função capaz de adicionar um metabox customizado que fora referenciada no primeiro momento:

add_action( 'admin_init',   'pw_admin_init' );

function pw_admin_init()
{
    add_meta_box( 'box_model', 'Informações da Modelo', 'pw_box_model', 'post', 'normal', 'high' );
}

O uso de add_meta_box determina-se um identificador para o metabox, seu título, a função responsável pelo seu conteúdo, a qual tipo de conteúdo ele se destina, o contexto e a prioridade de exibição. Com os parâmetros acima setados, você acaba de criar um metabox posicionado logo abaixo do editor de conteúdo dos Posts. Falta determinar seu conteúdo:

function pw_box_model()
{
    global $post; ?>
    <table>
        <tr>
            <th>Modelo</th>
            <td><input type="text" name="pw_model" value="<?php echo get_post_meta( $post->ID, 'pw_model', true ); ?>" /></td>
        </tr>
    </table>
    <?php
}

Exibi-se um campo de texto para ser preenchido o nome da modelo. Note que, tanto para o nome do input e também para a chave do meta dado, está sendo aplicada a técnica de prefixação. Para o input é importante fazer uso dessa prática para evitar que os novos campos entrem em conflito com os campos já existentes. Quanto a chave a ser armazenada em banco de dados, o prefixo auxilia na organização dos dados e também evita o mesmo problema de conflito com as informações tratadas pelo WordPress ou por plugins.

Inserido o formulário no metabox é necessário atualizar o valor do campo no banco de dados. Esse processo será realizado cada vez que o post for atualizado através do gatilho save_post.

add_action( 'save_post',    'pw_box_model_save' );

function pw_box_model_save( $id )
{
    if ( isset( $_POST[ 'pw_model' ] ) ) {

        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
            return $id;

        update_post_meta( $id, 'pw_model', $_POST[ 'pw_model' ] );
    }
}

O bloco de instruções responsável por aplicar a ação pretendida a cada atualização do post determina a execução de tal processo mediante a verificação do recebimento do campo do formulário. Em seguida é verificado o envio manual das informações, para garantir que ele não tenha sido realizado através do recurso de salvar alterações no post de modo automático, o autosave do WordPress.

Shortcodes

Shortcodes são instruções em texto delimitadas por colchetes que permitem o uso de recursos especiais no conteúdo do site de modo simples e prático. O WordPress possui shortcodes para recursos nativos como é o caso da galeria e a aplicação de legenda, ambos para os arquivos de imagem; são respectivamente [ gallery ] e .

A manipulação desse recurso se dá pelas funções oferecidas pela Shortcode API. Através dessa API você consegue criar e remover shortcodes, aplicá-los em textos específicos e tratar as informações recebidas.

Apesar da galeria gerada pelo respectivo shortcode funcionar muito bem, as definições de estilo e HTML não estão de acordo com a estrutura fornecida pelo template em uso. Corrija esse comportamento removendo e adicionando uma nova galeria personalizada em seu lugar.

function pw_theme_setup()
{
    remove_shortcode( 'gallery' );
    add_shortcode( 'gallery', 'pw_code_gallery' );
}

Se desejar apagar todos os shortcodes registrados, não preocupe-se em definir a remoção de cada um dos códigos. Ao invés disso utilize a função remove_all_shortcodes.

Com add_shortcode informa-se como parâmetros o texto do shortcode e a função de tratamento do mesmo. As funções que tratam do conteúdo dos shortcodes, assim como na atribuição de filtros, devem sempre retornar algum valor; no caso a definição HTML da informação a ser exibida no local onde fora inserido. Nesse contexto não aplica-se instruções de exibição de conteúdo como echo e print.

Além de disparar a execução da função determinada ao adicionar um shortcode, são passados como parâmetros os atributos do shortcode e também o conteúdo que esse limita. Os atributos são as configurações que o recurso poderá ou não possuir, enquanto que o conteúdo é justamente a informação a ser formatada seguindo as diretrizes de funcionamento do referido shortcode.

[ gallery link="post" ids="1,2,3" orderby="rand" ]

Formatação de conteúdo

No exemplo da galeria, o atributo link define o tipo de link para o qual as imagens linkarão (arquivo ou tela de exibição de anexos), ids são os identificadores das imagens que compõem a galeria e orderby a ordem que os resultados serão exibidos. Sobre o conteúdo a ser tratado, funciona da seguinte forma:

add_shortcode( 'alert', 'pw_code_alert' );

function pw_code_alert( $atts, $content=null )
{
    return '<div>' . $content . '</div>';
}

Após adicionar tal shortcode, inserindo no conteúdo de um post ou página a definição…

[alert]Texto de alerta[/alert]

…o conteúdo que é segundo parâmetro recebido pela função de tratamento do shortcode, receberá o valor de ‘Texto de alerta’. A partir de então esse conteúdo é tratado e retornado como pretendido.

Aplicação dos shortcodes

A exibição dos shortcodes no conteúdo dos posts é dado pela aplicação do filtro the_content. O filtro executa uma série de tratamentos ao texto, inclusive a atribuição da função do_shortcode, que cuida de localizar e aplicar a referida função aos shortcodes localizados. Da mesma maneira, se você pretende aplicar os shortcodes a um texto qualquer, faça uso dessa instrução.

<?php
echo do_shortcode( $text );
// se $text possuir um shortcode, ele será executado
?>

Remover shortcodes

Você pode também remover shortcodes de uma certa string. Isso é muito importante de ser feito quando recupera-se conteúdos e resumos de modo manual sem o uso das funções, e consequente aplicação dos filtros do sistema. Nessas situações os shortcodes não são interpretados e suas marcações permanecem visíveis aos visitantes.

<?php
$text = strip_shortcodes( $text );
// shortcodes removidos da string
?>

Shortcodes personalizados

Já que a galeria não assume nenhum conteúdo, essa verificação não será feita. O projeto propõe ainda que os links de cada miniatura de imagem enviem o visitante para o arquivo com as dimensões originais; portanto o atributo link também poderá ser descartado.

function pw_code_gallery( $atts )
{
    $atts = shortcode_atts( array(
        'orderby'   => 'menu_order',
        'order'     => 'ASC',
        'ids'       => false
    ), $atts );
    $html = ''; // define-se o conteúdo a ser exibido no lugar do shortcode
    return $html;
}

Aplicando shortcode_atts são recuperados os valores dos atributos e passados para o array associativo $atts. Essa função recebe os valores padrão que você determinar e executa a mesclagem dos mesmos com os atributos fornecidos pelas instruções estabelecidas no uso do shortcode. De posse de todas as informações necessárias para a composição da galeria, basta definir a exibição da mesma.

<?php
function pw_code_gallery( $atts )
{
    $atts = shortcode_atts( array(
        'orderby'   => 'menu_order',
        'order'     => 'ASC',
        'ids'       => false
    ), $atts );

    if ( $atts[ 'ids' ] ) {
        $atts[ 'include' ] = $atts[ 'ids' ];
        unset( $atts[ 'ids' ] );
    }

    global $post;
    $args = array(
        'post_type'         => 'attachment',
        'post_mime_type'    => 'image',
        'post_parent'       => $post->ID
    );
    $args = array_merge( $args, $atts );
    $images = get_children( $args );

    $html = '';
    if ( is_array( $images ) && count( $images ) > 0 ):
        $html = '<ul>';

        foreach ( $images as $image ):
            if ( isset( $image->ID ) && isset( $image->post_title ) ) {
                $alt = get_post_meta( $image->ID, '_wp_attachment_image_alt', true );
                if ( !$alt ) $alt = $image->post_title;
                list( $src ) = wp_get_attachment_image_src( $image->ID, 'thumbnail' );
                $url = wp_get_attachment_url( $image->ID );

                $html .= '<li><a rel="gallery" href="' . $url .
                    '" title="' . esc_attr( $image->post_title ) .
                    '"><img alt="' . esc_attr( $alt ) . '" src="' . $src . '"></a></li>';
            }
        endforeach;

        $html .= '</ul>';
    endif;

    return $html;
} ?>

Imagens no WordPress

As imagens, assim como os diferentes tipos de arquivos que você enviar a partir do WordPress, é tratada como um tipo de conteúdo próprio chamado attachment, ou simplesmente anexo. Os anexos são gerenciados pela mesma tabela dos posts e suas peculiaridades pela tabela de meta dados.

Durante o desenvolvimento de um tema você poderá consultar ‘posts’ do tipo ‘attachment’ e recuperar suas imagens, criar uma tela específica para os anexos seguindo as diretrizes da hierarquia do sistema ou também adequar melhor as informações ao trabalho que está sendo feito, uma vez que você sabe de onde os dados estão sendo recuperados.

Imagem destacada (Post Thumbnail)

A tela inicial do projeto propõe o uso de imagens que ilustrem o conteúdo em exibição. O recurso oferecido pelo WordPress para atribuir uma imagem de capa para cada conteúdo nele cadastrado, chama-se Imagem destacada. A manipulação das miniaturas do post é ativada mediante o uso de add_theme_support no arquivo de funções do Tema.

<?php
function pw_theme_setup()
{
    add_theme_support( 'post-thumbnails' );
    // ... demais configurações do tema
} ?>

A partir do momento que é incorporado o recurso, a tela de posts já exibe uma nova aba Imagem destacada para escolha da imagem a ser utilizada.

Tamanho das imagens

Quando arquivos do tipo imagem são enviados para o WordPress, automaticamente são geradas miniaturas dessas imagens. Por padrão existem três tamanhos de miniaturas: thumbnail, medium e large (que definem respectivamente os formatos pequeno, médio e grande). As dimensões desses formatos são editáveis nas opções de mídia do painel de controle.

Anteriormente no arquivo da tela inicial do site você aplicou o uso de the_post_thumbnail passando as dimensões pretendidas como parâmetro dessa função. No entanto, mesmo passando as dimensões exatas, o mais provável de acontecer é o Tema exibir cortes diferentes para as imagens; ainda mais se as opções de mídia e as dimensões dos arquivos contiverem valores bem distintos aos pretendidos.

Isso acontece pelo fato do WordPress gerar as miniaturas sem forçar o recorte das imagens (exceto pelo tamanho thumbnail, cujo comportamento também é editável pelo dashboard.

Dimensões de imagens

Com o propósito de padronizar essa exibição das imagens adicione seus próprios formatos ao tema através de add_image_size em sua função de setup.

add_image_size( 'model', 250, 215, true );
add_image_size( 'gallery', 195, 150, true );

Pela ordem você deve definir um identificador do formato, largura, altura e se o recorte nas medidas exatas deve (verdadeiro) ou não (falso) ser realizado. Após essa implementação, todas as imagens enviadas para o sistema possuirão as miniaturas padrão e também as personalizadas de acordo com as definições indicadas.

Resize otimizado

Contudo isso nos leva a um outro problema. Considere a utilização de muitos formatos de imagem dentro de um projeto. Muitas vezes alguns formatos são aplicáveis apenas em certas partes do site, ou para determinados conteúdos. Ao fazer uso de vários formatos seriam geradas grandes quantidades de arquivos que por vezes poderiam não ter serventia. Faça então uso da API de Plugins com o filtro intermediate_image_sizes para estabelecer quais formatos de imagem pretende gerar; abaixo são definidos os formatos de acordo com o tipo de conteúdo para o qual ele está sendo incorporado.

add_filter( 'intermediate_image_sizes', 'pw_image_sizes', 10, 3 );

function pw_image_sizes( $sizes )
{
    global $post;
    $post_type = '';
    if ( isset( $_POST[ 'post_id' ] ) ) {
        $post_type = get_post_type( $_POST[ 'post_id' ] );
    } else if ( isset( $post ) && isset( $post->post_parent ) && ( $post->post_parent > 0 ) ) {
        // A variável global $post contém os dados do anexo e não do post a qual ele pertence
        $post_type = get_post_type( $post->post_parent );
    }

    $sizes = array( 'thumbnail', 'medium', 'large' );

    switch( $post_type ):
        case 'post':
            array_push( $sizes, 'model', 'gallery' );
            break;
        default:
            array_push( $sizes, 'gallery' );
            break;
    endswitch;

    return $sizes;
}

O post para o qual a imagem está sendo adicionada ou cuja relação já existe e pretende-se remover tal imagem do sistema, tem seu identificador recuperado através de $_POST[ ‘post_id’ ] ou $post->post_parent para as respectivas situações. Em seguida, através de get_post_type recupera-se o tipo de conteúdo do referido post para posterior verificação.

A função recebe como parâmetro os formatos existentes no WordPress e também os personalizados em forma de array numérico. No exemplo acima, em vez de remover os formatos da variável $sizes, foi escolhido atribuir os formatos padrão e inserir os formatos adicionais de acordo com a necessidade do projeto.

Modelos de Páginas

As páginas no WordPress representam o conteúdo estático, institucional referente ao próprio site. Enquanto os posts são organizados através de tags e categorias as páginas diferem entre si através de seus atributos. São os atributos das páginas: Página mãe, Modelo de página e sua ordem de exibição.

Definindo uma página mãe, define-se também a estrutura de navegação; de modo que o conteúdo da página ‘filha’ possua alguma relação com a mãe. O modelo de página determina arquivos distintos para apresentar o conteúdo. Por fim a ordem de exibição é utilizada para organizar as páginas em menus e listas de links do site.

Adicionar modelos de página

Um modelo de página, ou Template Page, nada mais é que um arquivo PHP com a seguinte instrução no cabeçalho em forma de comentário:

<?php // Template Name: Nome do template ?>

Somente a partir da presença de modelos de páginas dentro do Tema ativo é que o WordPress exibe o referido campo na edição de página. Confirme que o modelo recém-criado foi reconhecido pelo sistema editando ou inserindo uma página e verifique a presença do novo template no campo Modelo. Pela proposta apresentada, existem conteúdos que devem ser exibidos em tela cheia, ocupando além de seu espaço habitual, o conteúdo reservado para a sidebar. Essa situação será trabalhada com um modelo de página específico; para isso atribua um nome de sua preferência ao modelo e determine a exibição do conteúdo como é sugerido pelo HTML:

<?php
/**
 *
 * Template Name: Full-Width
 *
 */
get_header(); ?>

<div>
    <?php the_post(); ?>
    <h1><?php the_title(); ?></h1>
    <div>
        <?php the_content(); ?>
    </div>
</div>

<?php get_footer(); ?>

Através da hierarquia de templates você pôde conhecer os caminhos que o WordPress traça para alcançar o arquivo que deverá ser exibido para certos tipos de conteúdo. A escolha de um template para a página determina que seu conteúdo será apresentado pelo referido arquivo e não por page.php ou index.php tal como define a ordem padrão da hierarquia de arquivos.

Atente-se ao nome que você definirá aos modelos de páginas. Evite colocar nomes totalmente distintos, ao contrário disso, escolha por exemplo um prefixo comum para todos os modelos. Essa prática facilitará a localização e organização dos mesmos.

No entanto tenha cuidado ao nomear seus modelos de páginas para que não entre em conflito com a nomenclatura usada pelas condicionais da hierarquia. O uso de page-[nome-do-modelo].php não deve ser adotado, pois é justamente essa estrutura usada para definir o arquivo referente a um slug em específico; logo, [nome-do-modelo] seria compreendido também como page-[slug-da-pagina].php. O mais prático e aconselhável é o uso de pg-[nome-do-template].php; mas essa especificação e o uso ou não dessa técnica, fica a seu critério.

Página de Contato sem plugin no WordPress

A agência precisa se comunicar com seus clientes e por isso uma de suas metas é criar um formulário de contato. Escolha por criar um modelo de página e dentro dele exibir um formulário com os dados do cliente e da mensagem que este pretende enviar: Nome, Email, Telefone, Assunto e Mensagem.

<form action="<?php the_permalink(); ?>" method="post">
    <fieldset>
        <ul>
            <li>Nome*<input type="text" name="pw_name" /></li>
            <li>Email*<input type="text" name="pw_email" /></li>
            <li>Telefone<input type="text" name="pw_phone" /></li>
            <li>Assunto<input type="text" name="pw_subject" /></li>
            <li>Mensagem*<textarea name="pw_message" rows="7" cols="100"></textarea></li>
            <li><input type="submit" value="Enviar" /></li>
        </ul>
    </fieldset>
</form>

Note que o envio do formulário está definido para o mesmo endereço da tela atual. Desse modo podemos atribuir as ações decorrentes da submissão do formulário no mesmo arquivo do modelo de página recém-criado.

<?php
if ( !empty( $_POST ) ) {
    if ( $_POST[ 'pw_name' ] && $_POST[ 'pw_email' ] && $_POST[ 'pw_message' ] ) {
        $message = sprintf(
            'Mensagem enviada por "%s" <%s> (%s) através do formulário de contato do site: %s',
            $_POST[ 'pw_name' ],
            $_POST[ 'pw_email' ],
            $_POST[ 'pw_phone' ],
            $_POST[ 'pw_message' ]
        );
        wp_mail( get_option( 'admin_email' ), 'Mensagem de contato: ' . $_POST[ 'pw_subject' ], $message );
    }
} ?>

O trecho acima verifica o envio de variáveis via método Post, e em seguida testa os campos de preenchimento obrigatório. Atendida as condições prepara o conteúdo do email e o envia utilizando wp_mail. A função recebe como parâmetro o email do destinatário (no caso o administrador do WordPress), Assunto e a Mensagem.

Por padrão o conteúdo dos emails enviados via wp_mail são disparados no formato texto, logo um texto com marcações HTML não seria corretamente interpretado. Ajuste esse comportamento atribuindo a seu Tema um novo filtro:

add_filter( 'wp_mail_content_type', 'pw_mail_content_type' );

function pw_mail_content_type()
{
    return "text/html";
}

Validação dos dados

O WordPress oferece funções prontas para verificação dos dados antes de submetê-los a tarefas do sistema; seja ao inserir valores em banco de dados, ou como no projeto que você está desenvolvendo, enviar emails de notificação.

A validação deve ser empregada em dados recuperados por envios de formulários, requisições via método $_GET, em geral onde não se conhece a origem e a integridade dos mesmos. Dependendo o tipo de variável que se deseja tratar, podem ser aplicadas:

sanitize_text_field( $text )

A função remove quebras de linha, tabulações e tags HTML. Retorna apenas os caracteres alfanuméricos e símbolos especiais como entidades HTML.

sanitize_email( $email )

Retira da variável todos os caracteres não permitidos em endereços de email

is_email( $email )

Verifica se a informação passada como parâmetro é um email válido

Acrescente o tratamento do email e dos demais campos ao envio do formulário de contato. Isso lhe trará uma maior segurança para seguir com as rotinas do seu Tema. Além do tratamento das informações enviadas e recuperadas, o WordPress permite verificar a origem do envio das informações e também a autenticidade do preenchimento utilizando um recurso chamado Nonce.

Nonces

Trata-se de um número usado a cada vez que lhe é proposto, uma senha dinâmica. Você deve criar essa chave na origem da requisição, no local onde os dados serão enviados; e nas instruções que recebem os dados você efetua a validação desse número. Trate de incorporar esse recurso ao seu formulário de contato acrescentando ao formulário:

<?php wp_nonce_field( 'user_check', 'hdn_hash' ); ?>

O primeiro parâmetro trata-se da ação que você pretende especificar para seu código (valor da chave Nonce criada) e o segundo é o nome do campo que armazenará o código no formulário e que será enviado para checagem. Feito isso, dentro das verificações dos campos enviados, verifique se a chave recebida condiz com a chave criada.

if ( !wp_verify_nonce( $_POST[ 'hdn_hash' ], 'user_check' ) )
    wp_die( 'Trapaceando, é?!' );

A verificação estipula o valor da Nonce e a ação sob a qual foi criada. Retornará verdadeiro ou falso para correspondência certa ou errada, pela ordem. Você pode ainda verificar se a origem da requisição é a mesma do envio, evitando assim ataques e tentativas de inserção de código e conteúdos provenientes de outro local que não seja o próprio formulário.

if ( $_POST[ '_wp_http_referer' ] !== $_SERVER[ 'REQUEST_URI' ] )
    wp_die( 'Não é permitido enviar informações de fora para dentro desse site...' );

Tela Inicial

A tela de abertura do projeto em que você está trabalhando requer um tratamento diferenciado para suas marcações e definições de estilo. Você poderá atribuir um arquivo específico para a home do site de dois modos distintos: ao definir uma página para ser exibida na requisição da URL principal ou através da hierarquia de páginas ao fazer uso do arquivo home.php, cujo conteúdo possui prioridade em ser exibido ao arquivo index.php do Tema.

A definição de uma página a ser exibida como home do site é feita através das Configurações de Leitura do Dashboard. Ao especificar uma página como Página inicial, o conteúdo da Home será exatamente o conteúdo da página com as formatações definidas no correspondente arquivo de exibição (arquivo do modelo de página, page.php ou seus derivados). Enquanto que ao escolher uma página como Página de posts, seu conteúdo será trocado pela listagem de resultados exercida por home.php ou o próprio index.php; tal como determina a hierarquia do WordPress.

is_home() x is_front_page()

Atenção com a prática de determinar uma home diferenciada ao site em conjunto com o uso das Conditional Tags. Ao trabalhar apenas com a hierarquia e a denominação dos arquivos do Tema tal como ela sugere, independentemente do arquivo a ser carregado, seja ele o home.php ou o index.php; em ambos os casos o resultado de is_home e também is_front_page será verdadeiro. Porém ao fazer uso da definição via painel de controle, a página escolhida para substituir o conteúdo da home terá is_home com falso e is_front_page como verdadeiro; e quanto a outra página, que terá seu conteúdo substituído pela listagem de posts, terá is_home como verdadeiro e is_front_page como falso.

As diferentes técnicas para uma homepage diferenciada e a respectiva relação com as tags condicionais

As diferentes técnicas para uma homepage diferenciada e a respectiva relação com as tags condicionais

Escolher entre qual técnica usar depende das situações de cada projeto. O uso de home.php não deve lhe trazer complicações, porém se a proposta do projeto é manter um conteúdo sempre atualizado na página inicial, o uso de uma página para tal ação pode ser uma boa escolha. Quanto a definição de uma página para exibição dos posts publicados, através dessa técnica é possível escolher facilmente uma URL personalizada para tal situação; nesse caso o slug, endereço da página é o endereço adotado. Uma página com slug ‘blog’ seria uma boa prática a ser adotada.

Apenas previna seu projeto de eventuais alterações que possam ocorrer, principalmente quando a escolha da home ou da página de post estiver definida via Dashboard. Em ambas as situações, as configurações ficam visíveis aos administradores do projeto e o comportamento pode ser facilmente alterado, modificando assim a estrutura original do projeto.

Template Tags & WordPress Loop

Escolha a criação de um arquivo para a home do projeto. Defina dentro dele as instruções que o template impõe, e também aproveite para realizar a integração com a exibição dos resultados:

<div id="three-column">
    <?php
    $i=1;
    while ( have_posts() ) { the_post(); ?>
    <div id="column<?php echo $i; ?>">
        <p>
            <a href="<?php the_permalink(); ?>" title="Ver post completo">
                <?php
                if ( has_post_thumbnail() )
                    the_post_thumbnail( array( 250, 215 ) );
                else
                    echo '<img src="' . PW_URL_THEME . 'img/no-image.png" alt="Nenhuma imagem definida" />'?>
            </a>
        </p>
        <h2><?php the_title(); ?></h2>
        <h3><?php echo get_post_meta( $post->ID, 'pw_model', true ); ?></h3>
        <p><?php the_excerpt(); ?></p>
    </div>
    <?php $i++; } ?>
</div>

Está sendo utilizada a função the_post_thumbnail para recuperar a imagem destacada de cada post. O parâmetro da função diz respeito as dimensões (largura, altura) desejadas. Antes de exibir a imagem verifica-se sua existência com has_post_thumbail a fim de apresentar uma imagem padrão caso ela não tenha sido definida.

Nesse ponto você já tem um grande problema a resolver. Por padrão o WordPress determina quantos resultados exibir com base nas configurações de Leitura do painel de controle. Porém a idéia do projeto é exibir apenas três resultados. Caso você mude a opção no painel, apesar de corrigir o comportamento na home, irá também afetar a exibição dos resutlados nas outras telas como a de resultados de busca e paginações em geral.

Uma solução rápida para esse caso é o uso de query_posts. Através dessa função você consegue alterar a consulta principal do WordPress e também os valores globais recuperados a partir dela.

<?php
$i=1;
query_posts( array(
        'posts_per_page' => 3
    )
);
while ( have_posts() ) { the_post(); // ... ?>

Filtro prévio de consultas (pre_get_posts)

Ainda assim essa não é a melhor proposta, isso porque o sistema já efetuou suas consultas assim que a URL foi requisitada e com o uso de query_posts você está fazendo ele repetir todo o processo novamente apenas para atender essa nova condição. Prefira então atribuir um filtro a consulta realizada pelo sistema antes mesmo dela ser processada.

Function pw_theme_setup()
{
    add_filter( 'pre_get_posts', 'pw_pre_get_posts' );
    // ... demais funções
}

function pw_pre_get_posts( $q )
{
    if ( !$q->is_admin && $q->is_home )
        $q->set( 'posts_per_page', 3 );

    return $q;
}

A função executada a partir do gatilho criado recebe como parâmetro a consulta a ser realizada com base no endereço solicitado. Dentro da mesma é verificado o momento de limitar os resultados, ou seja, será do lado público do site (não deve aplicar o filtro no painel) e apenas na tela inicial. Aplicado o filtro, apenas uma única vez será feita a consulta já com as definições personalizadas para a situação.

Como visto anteriormente, a integração proposta exibe uma imagem padrão caso o post não possua uma imagem atribuída a ele. No entanto, se preferir você poderá adicionar um novo filtro com o propósito de recuperar apenas os posts com imagens destacadas.

function pw_pre_get_posts( $q )
{
    if ( !$q->is_admin && $q->is_home ) {
        $q->set( 'posts_per_page', 3 );
        $q->set( 'meta_key', '_thumbnail_id' );
    }
    return $q;
}

Atenção ao aplicar esse filtro. Se não existir nenhum ou um número menor de posts com imagens destacadas em relação a quantidade proposta pelo template; certamente causará impactos negativos no fechamento da tela.

O recurso imagem destacada atribui o identificador da imagem como um meta dado do post ao qual fora atribuída tal imagem, sob a chave _thumbnail_id. Por isso o filtro define a recuperação dos posts que possuirem tal especificação.

Ocorre então outro problema. Do mesmo modo que nem todos os posts possuem imagem destacada, pode ocorrer de alguns não possuirem a definição do nome da modelo. Assim como a imagem destacada, o nome da modelo é armazenado como um meta valor do post; logo a definição de outra meta_key apenas iria sobreescrever a primeira, sendo recuperados os posts que atendam a uma ou a outra condição (no caso, a última definida).

Como a proposta é recuperar todos os posts com imagens destacadas e também com o nome das modelos; ao invés de meta_key, a variável a ser alterada na consulta será meta_query.

function pw_pre_get_posts( $q )
{
    if ( !$q->is_admin && $q->is_home ) {
        $meta_query = array(
            'relation' => 'AND',
            array(
                'key' => 'pw_model'
            ),
            array(
                'key' => '_thumbnail_id'
            )
        );
        $q->set( 'posts_per_page', 3 );
        $q->set( 'meta_query', $meta_query );
    }
    return $q;
}

WP_Query

O filtro criado e a atribuição de novas configurações a consulta realizada pelo WordPress funciona muito bem, porém existem casos onde é preferível manter a consulta intacta e incorporar novos resultados a ela. No caso desse projeto é preciso exibir logo abaixo dos destaques a listagem comum de resultados enfileirados pela data de publicação. Ao alterar a consulta antes dela ser definida teríamos que refazê-la manualmente com o propósito de exibir esses itens. Já que a consulta pretendida está pronta, não há razão para modificá-la e depois refazê-la. Por isso apenas será acrescentada a nova consulta dos posts com imagem de capa e modelo definidos.

<?php
$q = new WP_Query( array(
        'posts_per_page'    => 3,
        'meta_query'        => array(
            array(
                'key' => 'pw_model'
            ),
            array(
                'key' => '_thumbnail_id'
            )
        )
    )
); ?>

Cria-se uma instância de WP_Query com os parâmetros desejados. Estão omitidos nessa consulta o tipo de conteúdo e status do post, pois por padrão recebem o tipo post e o status de publicado. Pela mesma razão de assumir o valor padrão, também foi ocultada a opçao relation de meta_query. Feita a consulta, atualize o laço do WordPress a fim de informar a ele qual consulta utilizar:

while ( $q->have_posts() ) { $q->the_post(); // ...

Alterando a consulta do WordPress

Em programação, você sabe, que existem diversas maneiras de se resolver um mesmo problema. O mesmo pôde ser verificado no desenvolvimento dos Temas para WordPress, em especial para recuperação do conteúdo em consultas próprias com atribuição de filtros personalizados. Foram apresentadas a você as funções get_posts e query_posts, a classe WP_Query e o uso do filtro pre_get_posts.

Tanto para get_posts e query_posts, os processos que são feitos passam pela criação de uma instância de WP_Query. Do mesmo modo, a variável global $wp_query que possui os valores recuperados pela consulta feita pelo WordPress a cada requisição; é também uma instância dessa classe. Portanto, dedique-se a estudar o comportamento geral dessa classe!

Todos esses recursos basicamente possuem o mesmo propósito. Porém a escolha entre um e outro pode ser determinada diante de situações distintas. Veja o uso do filtro pre_get_posts. Sua aplicação determina a incorporação de filtros adicionais aqueles já definidos pelo WordPress. Em ocasiões onde será preciso modificar o conteúdo todo de uma página, a técnica é muito bem vista; por exemplo se a home do site deve exibir apenas um único post, ou então determinar qual tipo de conteúdo será apresentado nos resultados de busca.

add_filter( 'pre_get_posts', 'pw_pre_get_posts' );

function pw_pre_get_posts( $q )
{
    if ( $q->is_search )
        $q->set( 'post_type', 'post' );

    return $q;
}

Ao aplicar um filtro com pre_get_posts tenha cuidado em estabelecer os locais onde o filtro deve ser incorporado. Pelo fato do filtro ser vinculado a requisição feita pela classe WP_Query, e essa por sua vez, ser utilizada por outras funções de recuperar conteúdo; o resultado de consultas adicionais em uma mesma tela pode ser prejudicado.

query_posts, get_posts, WP_Query e pre_get_posts

A função query_posts possui um comportamento peculiar de realizar uma nova consulta e atribuir os novos valores recuperados ao contexto global da aplicação, sobrepondo os originais. Assim, ela define o novo resultado como único, independente da requisição realizada. Seu uso é bem visto em oposição ao uso do filtro anteriormente visto; ao invés de filtrar toda requisição que possui as definições pretendidas, aplica-se uma nova consulta apenas no arquivo onde a função estiver inserida.

Para ilustrar essa diferença, considere a aplicação de um filtro que limite a quantidade de resultados para as consultas realizadas na tela inicial do site, sendo verificada tal atribuição com is_home. Toda consulta feita nessa tela seja ela com query_posts, get_posts ou mesmo aquela definida pelo sistema de acordo com a requisição; terá esse filtro aplicado a ela. Por outro lado ao usar query_posts apenas o conteúdo global, trabalho pelo Loop do WordPress, que será alterado.

A fim de gerar consultas adicionais, onde não se interfere no resultado obtido a partir do endereço visitado, são melhores aplicadas a função get_posts ou a criação de uma nova instância de WP_Query. Em comparação, a função retorna apenas um array com os resultados obtidos, já a classe por sua vez traz consigo uma série de valores auxiliares e métodos prontos para serem utilizados. Com get_posts não é possível utilizar a estrutura do laço do WordPress.

Prefira get_posts para listagem simples de resultados como lista de links, posts relacionados e últimas publicações. Enquanto que WP_Query é mais prático de ser trabalho em locais onde necessitam de mais informações como em áreas de destaques do site; isso porque o uso de uma instância da classe aliada a estrutura do Loop permite a você utilizar as variáveis de contexto global de modo seguro.

Para não esquecer

  • Meta dados e a criação de metaboxes
  • Trabalho com shortcodes e imagens dentro do WordPress
  • Modelos de páginas
  • Validação dos dados e a manipulação de Nonces
  • Tela inicial diferenciada
  • Diferentes técnicas de consultas