Esse artigo é para você que deseja criar o seu primeiro plugin com WordPress. Na realidade, você será convidado a criar dois plugins. O primeiro deles, mais simples, servirá para você se adaptar ao modo como o WordPress trata os plugins, quais hooks utilizar, disparar os gatilhos de ativação/desativação e outras funcionalidades básicas. Em seguida você fará o uso de Custom Post Types e Taxonomias para criar o seu próprio plugin de carrossel de imagens. Para isso será empregado o script Owl Carousel Slider.

Pois bem, antes de iniciar de fato o desenvolvimento de Plugins é preciso ter bem sedimentado questões mais básicas. A primeira delas é compreender o que são, qual a importância e o motivo da utilização desse artifício. No WordPress os plugins são um conjunto de arquivos de programação web baseada na linguagem servidor PHP e banco de dados MySQL assim como todo seu sistema. Eles servem para agregar ao CMS recursos inexistentes (que não acompanham o WP em sua instalação inicial); por exemplo a integração com diferentes redes sociais e o uso de um slider, itens que você poderá conferir em detalhes mais a frente.

Diretório brasileiro de Plugins WordPress

Diretório oficial de plugins do WordPress (Brasil)

Muito importante observar que uma das principais características dos Plugins é justamente a não interferência nos arquivos e consequente funcionamento do WordPress, ou seja, os plugins instalados devem se adequar ao método de trabalho do sistema e não obrigar a alteração do código-fonte existente. Existem diversos meios de realizar essa integração de modo seguro, portanto lembre-se que não deverá modificar arquivos além daqueles que você mesmo criou.

Além de permitir a inclusão de novos recursos, o uso de plugins permite aperfeiçoar determinadas tarefas e modificar o modo como o WordPress funciona. Através de técnicas específicas você terá condições de se comunicar, alterar e também (em alguns casos) sobrescrever as instruções executadas pelo sistema.

Quando criar um Plugin no WordPress?

Plugins são feitos para resolver problemas e não criá-los. A necessidade de uso de um plugin em geral é determinada pelas condições, requisitos do projeto no qual está trabalhando e seu nível de interferência no mesmo.

Um ponto a ser considerado é sobre a ativação e desativação do recurso. Em um projeto que faz uso de um plugin o administrador do projeto pode facilmente optar por utilizar ou não determinado recurso mediante gerenciamento via painel de controle sem modificar linhas de código.

De acordo com a situação, os recursos a serem adicionados ou aperfeiçoados através de Plugins podem ser trabalhos diretamente nos arquivos do Tema ativo; caso seja você também o desenvolvedor do Tema ou tenha permissão para isso, poderá optar por esse caminho. Em geral agregar recursos ao Tema ao invés da criação de um Plugin pode ser vantajoso em recursos fáceis de serem replicados, como a inserção dos botões de compartilhar de redes sociais; ou que sejam pertencentes apenas aquele determinado projeto, por exemplo a aplicação de um sistema personalizado para gerenciamento de imagens para um site de fotografia.

Perceba que mesmo os exemplos dos recursos a serem adicionados através dos arquivos do Tema podem também se transformarem em plugins. Justamente por essa razão é que a análise e viabilidade do desenvolvimento do plugin precisa ser feita com cuidado; assim você adota melhores estratégias, otimiza a reutilização de seus recursos e evita desperdício de tempo tanto em desenvolvimento, quanto em manutenção.

Atente-se obviamente ao custo de desenvolvimento. Não apenas referente ao valor monetário do trabalho a ser feito, mas também sobre as horas de trabalho que serão empregadas nesse objetivo. O desenvolvimento de um plugin trata de criar uma nova solução, um novo projeto com finalidades e requisitos próprios; logo deve ser levado em consideração se tal recurso compensa o investimento.

Plugins sob medida

Analisadas as questões que conferem a criação de um plugin, tenha sempre em mente que a existência do plugin consiste na resolução de um problema, e é justamente essa solução que você propõe desenvolver. Assim você evitará desenvolver recursos dispensáveis e manterá o foco na essência do projeto. Veja também alguns pontos importantes e cuidados a serem levados em conta sobre a criação de plugins para WordPress:

Performance

Os plugins são carregados antes dos Temas, logo se o plugin necessitar de muitos processos ou contiver processos demorados podem ocorrer alguns atrasos na exibição do site. Procure sempre usar resoluções simplificadas dos problemas, carregue e execute apenas os arquivos necessários para realização de tais tarefas.

Aplicação

Defina o modo que o recurso será aplicado ao site, procure sempre torná-lo fácil de ser utilizado; principalmente se houver a necessidade da interferência de terceiros (editores, autores e usuários por exemplo) para que ele funcione.

Relação com o Tema

Do mesmo modo que não se deve alterar o código-fonte do WordPress, ao desenvolver um plugin não modifique arquivos do Tema para que o plugin funcione. O funcionamento do plugin deve ser independente ao Tema em uso. Desse modo seu Plugin poderá ser facilmente replicado em novos e diferentes projetos.

Por onde começar?

O início do desenvolvimento de um plugin ocorre na análise do problema encontrado e levantamento de eventuais soluções. Enquanto analisa as situações e o problema encontrado, visualize também o modo como a solução se desenhará e como será possível aplicá-la ao projeto. Faça um levantamento das opções oferecidas pelo plugin, modelo de integração com o WordPress, qual o resultado final e o que será preciso fazer para chegar até ele. Esses passos serão constantemente apresentados durante o curso em diferentes projetos.

Lembre-se que o seu plugin é um projeto com demandas e objetivos próprios a serem alcançados, portanto respeite suas etapas de desenvolvimento, não comece a desenvolver sem conhecer qual caminho será trilhado.

Modelos de integração

Um plugin pode se comunicar com o WordPress por diferentes maneiras. O modelo de integração do plugin deve ser adequado ao seu propósito e também à facilidade de uso do recurso perante o público-alvo que se pretende trabalhar. Um programador será mais auto-suficiente durante a instalação e ativação de um recurso comparado a um gestor de conteúdo. Dessa forma, se o plugin for diretamente voltado às questões de gerenciamento das informações, o melhor a ser feito é otimizar os processos de instalação e uso para facilitar essas operações ao usuário.

A comunicação do seu Plugin com o usuário e WordPress pode ser feita de modo automático. O uso automático de um plugin ocorre quando tal plugin se encontra instalado e nenhuma outra ação necessita ocorrer para que ele venha a funcionar e prover seus recursos. Mesmo se o plugin em questão oferecer uma página de opções, o que define o uso automático é o fato do recurso estar relacionado a eventos que possam ocorrer dentro do sistema. Como exemplos do uso dessa técnica temos o envio de notificações personalizadas por e-mail logo após a publicação de um artigo, redirecionamento de usuários ao realizarem login no sistema, contadores de downloads, entre outros.

Você também pode optar por aplicar o recurso desenvolvido através de funções personalizadas. Atribuindo nos arquivos do seu Plugin funções próprias de escopo global você permite o uso de tais instruções dentro dos arquivos do tema. Outras alternativas para executar os processos de um plugin são a criação de Widgets e Shortcodes personalizados.

Definidos o objetivo a ser alcançado e para qual tipo de usuário, nível de acesso o Plugin estará disponível; você pode determinar o melhor modo de acioná-lo. Caso o plugin apenas ofereça funções a serem aplicadas, você define que a sua utilização implica em mudanças dentro do Tema, portanto seu uso é feito pelo desenvolvedor do mesmo. Por outro lado se optar por Widgets ou Shortcodes, os usuários com acesso aos mencionados recursos poderão fazê-lo sem a necessidade de alterações no Tema.

Reconhecimento do Plugin

Algumas medidas devem ser tomadas para que o WordPress reconheça os arquivos criados como um Plugin e então ter condições de incorporá-lo ao sistema. Devemos criar um arquivo principal do tipo PHP que servirá como centralizador dos recursos que o Plugin irá oferecer a seus utilizadores. Você não necessariamente precisa denominar o arquivo como index.php, apesar de ser interessante e de fácil entendimento; fique à vontade para escolha de outro nome, porém procure sempre ter um index.php dentro de suas pastas, mesmo que esse estiver vazio, por questões de segurança.

A partir desse arquivo deverão ser disparados os eventos, chamadas de funções e todas as demais funcionalidades. Dentro desse arquivo deverá ser incluído um cabeçalho de informações específicas para formatar o modo como o plugin será visualizado dentro do Dashboard.

<?php 
// Plugin Name: Nome do Plugin
?>

Definindo o nome do plugin limitado por comentários, permitimos ao WordPress interpretar aquele arquivo como sendo um arquivo de plugin e também seu principal arquivo, o qual deve ser acionado quando tal plugin estiver ativo. Além da informação básica necessária, podemos acrescentar mais itens ao cabeçalho de modo a personalizar a exibição do plugin na lista de plugins instalados.

<?php
/*
Plugin Name: Custom Plugin
Description: Teste de reconhecimento de Plugin
Version: 1.0
Author: WPDeveloper
Author URI: http://localhost/wpdeveloper
*/
?>

Crie um arquivo PHP contendo apenas os comentários exibidos acima dentro da pasta de plugins do WordPress. Ao acessar o painel de controle, verifique na tela de Plugins o reconhecimento desse código como um novo plugin e o modo como os dados do cabeçalho são interpretados e exibidos pelo sistema.

Tela de plugins com o novo plugin reconhecido

Tela de plugins com o novo plugin reconhecido

Boas Práticas de Desenvolvimento

Adote algumas medidas para o desenvolvimento de plugins de modo a tornar sua experiência mais produtiva, inteligente e menos suscetível a erros. Conheça alguns recursos do WordPress importantes de serem aplicados e veja algumas dicas de como otimizar seu plugin.

Nomenclatura

Ao atribuir um nome ao plugin, procure ser o mais específico possível. Desse modo você evitará conflitos e erros ocasionados por redeclarar certas classes ou funções. Sempre que possível utilize prefixos, assim dificilmente você terá esse tipo de problema.

// Plugin: Custom Slider with Thumbnails
function cswt() { // iniciais
function cswt_activate() { // iniciais como prefixo
function pw_slider() { // prefixo qualquer e nome do plugin

Performance

Apesar das funções do WordPress facilitarem e muito a recuperação de certas informações do banco de dados, ocorre que elas podem sobrecarregar o servidor com a quantidade excessiva de requisições que necessitam realizar para manter o funcionamento. A função bloginfo é um bom exemplo disso; ela é facilmente substituída e garante uma boa otimização quando não utilizada, ou usada com bastante moderação.

get_bloginfo( 'url' ); // recupera a informação
bloginfo( 'url' ); // exibe a informação, echo

De acordo com o projeto em pauta, você talvez pode substituir a bloginfo nas meta tags charsetlanguagetext_direction e algumas opções mais sem que ocorram perdas na integração do projeto; isso porque tais opções não devem mudar depois de inicialmente definidas e mesmo que mudem, podem ser facilmente alteradas.

Caminhos relativos e absolutos

No entanto caso você trabalhe com URL’s principalmente o uso de bloginfo é quase imprescindível, pois mudanças de servidor e diretórios são comuns de ocorrer. Nesses casos, se não utilizar a recuperação de URL dinamicamente, uma pequena alteração na estrutura dos links pode significar uma grande dor de cabeça na manutenção do site.

Atente-se ao fato que get_bloginfo recupera a informação pretendida; com isso você pode armazenar tais valores em constantes e em uma próxima utilização basta realizar a referência a referida constante sem a necessidade de requisitar novamente o banco de dados.

define( 'PW_URL', get_home_url() . '/' );
define( 'PW_URL_THEME', get_bloginfo( 'template_url' ) . '/' );
define( 'PW_SITE_NAME', get_bloginfo( 'title' ) );

Pelo fato do WordPress trabalhar com caminhos absolutos, crie variáveis ou constantes que armazenem o endereço completo do plugin no servidor para atribuir ao uso de imagens e arquivos externos sem grandes complicações, erros ou repetições de código.

$url_base = plugins_url( basename( dirname( __FILE__ ) ) ) . '/';
// $url_plugin = WP_PLUGIN_URL . '/' . basename( dirname( __FILE__ ) ) . '/';
// não use o nome da pasta padrão do plugin pois o usuário poderá alterá-lo
$url_img = $url_base . 'img/';

Dados serializados

Usando a API de opções, armazene todas as opções de um único plugin em um array e salve esse array com add_option ou update_option. Dessa forma será realizada apenas uma requisição ao banco de dados onde serão resgatadas de uma vez, todas as opções editáveis do plugin.

$opt = array(
  'option_1' => 1,
  'option_2' => 2
);
add_option( 'plugin_options', $opt, null, 'no' );

O mesmo serve para meta valores, ao passar um array como valor a ser armazenado no banco de dados o WordPress serializa os dados e quando os recupera torna a convertê-los novamente em array.

Por outro lado se houver a necessidade de utilizar múltiplos meta valores de usuários, posts ou comentários; através da Metadata API você pode recuperar todos os valores em uma única vez e também evitar inúmeras consultas ao servidor.

get_post_meta( $post->ID ); // recupera todos os meta valores do post em questão
get_post_meta( $post->ID, 'post_options' ); // recupera todos os valores armazenados com o nome 'post_options'
get_post_meta( $post->ID, 'post_options', true ); // recupera apenas um único valor com o referido nome

Instalar e Desinstalar

O WordPress disponibiliza as funções register_activation_hook e register_deactivation_hook com o propósito de executar determinadas rotinas para os momentos em que o plugin é ativado ou desativado respectivamente. Esse tipo de tratamento é ideal para inicializar as opções com valores padrão e também limpar os rastros que o plugin cria enquanto ativo.

register_activation_hook( __FILE__, 'plugin_activate' );
register_deactivation_hook( __FILE__, 'plugin_deactivate' );
// o primeiro parâmetro se refere ao caminho absoluto do arquivo principal do plugin

Você pode ainda utilizar a função register_uninstall_hook caso queira realizar alguma tarefa no momento em que seu plugin está sendo desinstalado do WordPress; os parâmetros são os mesmos dos citados acima: caminho absoluto do arquivo base do plugin e função de callback.

Orientação a Objetos

Boa parte das informações utilizadas pelo WordPress, principalmente os resultados de consultas ao banco de dados, retornam por padrão seus valores em um objeto, instância de uma certa classe. Caso você prefira desenvolver seus trabalhos fazendo uso de classes personalizadas, sinta-se livre para isso. Assim como as constantes e as funções tiveram um prefixo adicionado a seus nomes, é recomendável adotar essa prática também para as classes. Definido um nome único para sua classe, a denominação dos métodos ocorre de forma segura.

class PW_Classe {
    public function add_action() {
        // instruções do método
    }
}

No exemplo acima não há problema em definir add_action para o método pois ele está dentro da classe de nome único; logo não haverá conflito com a função homônima do WordPress.

A definição de escopo, encapsulamento e mais detalhes sobre orientação a objetos são inerentes ao PHP; logo para melhor entendimento de tais conceitos seu estudo deve ser aprofundado do mesmo modo que o funcionamento geral da linguagem e os recursos que ela oferece.

Estilos e Scripts

Ao aplicar scripts e estilos ao plugin não aplique a marcação direta desses no HTML. Atente ao fato que os plugins, assim como qualquer site ou projeto web, devem possuir o processamento (PHP), exibição (HTML), formatação (CSS) e comportamento em tela (JS) bem definidos e separados; portanto separe bem cada tipo de informação, pois desse modo corrigir erros e providenciar atualizações do projeto torna-se uma tarefa menos árdua. Use o recurso de registro e aplicação de estilos e scripts com:

  • wp_register_script
  • wp_register_style
  • wp_enqueue_script
  • wp_enqueue_style

É possível carregar arquivos contidos dentro do WordPress e arquivos externos. Através dessas funções é possível se certificar que determinado arquivo seja carregado antes de carregar o arquivo pretendido determinando a dependência do mesmo em seus parâmetros.

<?php
// funções de registro
wp_register_script( 'script_id', PW_PLUGIN_URL . '/js/script.js', array( 'jquery' ), '1.0' );
wp_register_style( 'style_id', PW_PLUGIN_URL . '/css/style.css', array(), null, 'screen' );
// funções de aplicação
wp_enqueue_script( 'script_id' ); // incorpora também a biblioteca jQuery se não estiver incorporada
wp_enqueue_style( 'style_id' ); // com media="screen", sem versão ou arquivos dos quais depende
?>

Banco de dados

Diante da declaração do nome de uma tabela utilize $wpdb->nome_da_tabela para trabalhar com as tabelas existentes e $wpdb->prefix para tabelas personalizadas. Como é de fácil acesso e comum à alteração dos prefixos até por uma questão de segurança, o plugin deve estar apto a funcionar com qualquer prefixo que o usuário utilizar.

$count = $wpdb->get_results( “SELECT ID, post_title FROM {$wpdb->prefix}posts WHERE post_type='page' AND post_status='publish'” ); // ou então $wpdb->posts

Com o objetivo de otimizar recursos do servidor, realize suas consultas ao banco de dados de modo específico, evitando selecionar campos que não serão utilizados, em especial campos com muita informação vinculada. Lembre-se também de limitar os resultados obtidos no próprio SQL e não posteriormente na estrutura de repetição.

$sql = “SELECT user_email FROM {$wpdb->users} LIMIT 5”;
// caso vá utilizar apenas o e-mail de cinco usuários, prefira a opção acima ao invés de
$sql = “SELECT * FROM {$wpdb->users}”;

Usando a classe de manipulação do banco de dados, informe antes de qualquer instrução que carregue consigo o uso de valores passados por visitantes ou recuperados via código, o método $wpdb->prepare para tratar os valores da query no mesmo modelo de sprintf. Essa prática serve para evitar ataques de SQL Injection.

$count = $wpdb->get_var( $wpdb->prepare( “SELECT COUNT(post_id) FROM {$wpdb->postmeta} WHERE post_id=%d”, $post_id ) );

Para criar ou atualizar tabelas próprias utilize a função dbDelta. A função examina a estrutura da tabela atual e compara com a estrutura informada. Em seguida adiciona ou altera somente modificações necessárias de acordo com a nova estrutura passada como parâmetro.

$sql = "CREATE TABLE `{$wpdb->prefix}custom` (
  `custom_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  `post_id` BIGINT UNSIGNED NOT NULL ,
  `custom_text` LONGTEXT ,
  `custom_date` DATETIME NOT NULL
)";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );

API de Plugins

O funcionamento de um plugin necessita de alguns recursos específicos para ser executado de modo otimizado. Imagine que você precisa a cada post publicado realizar alguma alteração no banco de dados, obviamente que essa tarefa somente será chamada após o post ter sido publicado e não a todo momento.

Para efetuar esse reconhecimento de ações existe a API de plugins do WordPress.

Criação de um Plugin WordPress

Compreenda melhor o funcionamento do recurso através de sua aplicação em um Plugin personalizado responsável por gerir a subscrição de comentários. O objetivo do plugin será inserir um campo verificador no formulário de comentários dos posts, permitindo ao usuário que enviou o comentário seguir a publicação de novas mensagens.

Desse modo a cada novo comentário publicado, os usuários que seguem a publicação são notificados da nova mensagem por e-mail. Importante também possibilitar aos cadastrados uma opção para deixar de receber os avisos.

Plugin de subscrição de comentários em ação

Plugin de subscrição de comentários em ação

Objetivos do plugin

  • O usuário pode optar por receber notificações de novos comentários de um post que ele comentou
  • Notificação de novo comentário via e-mail
  • Permitir cancelamento da subscrição

Note que as tarefas a serem executadas pelo plugin são desencadeadas em momentos específicos: inserção do campo extra ao formulário, envio do formulário e publicação de um novo comentário. Em cada referido momento o WordPress disponibiliza e permite o uso de ganchos específicos.

Hooks: Actions e Filters

Os Hooks (ganchos) são identificadores que tornam possível a execução de instruções personalizadas. Através do uso dos ganchos é possível informar ao sistema quando e como ele deve realizar determinadas tarefas.

Usar os ganchos do WordPress é um jeito seguro de alterar o comportamento e as atividades executadas pelo CMS. A própria programação do WordPress é baseada em Hooks; veja por exemplo a incorporação de scripts e estilos ao Tema que ocorre nos locais e momentos exatos quando necessários.

A manipulação da Plugin API é feita por dois tipos distintos de ganchos: Actions e Filters. As ações (actions) são justamente os gatilhos executados em determinados momentos pelo sistema; são atividades executadas mediante o disparar de um evento. Recomenda-se que as primeiras ações de um plugin devem partir do momento que ele acaba de ser carregado, para isso atribui-se uma função a ser executada ao gancho ‘plugins_loaded’:

add_action( 'plugins_loaded', 'kdm_comments_init' );

function kdm_comments_init()
{
    // rotinas a serem executadas
}

Os filtros (filters) por sua vez permite a você modificar ou como o próprio nome diz, filtrar as informações antes de serem utilizadas. No plugin de subscrição de comentários os avisos enviados por e-mail possuirão links; logo é preciso que você certifique-se que o tipo de e-mail enviado seja formatado como HTML e não apenas texto puro (a configuração padrão do WordPress). Insira a função add_filter (e também as demais instruções) dentro da função inicial do plugin com o seguinte identificador:

function kdm_comments_init()
{
    add_filter( 'wp_mail_content_type', 'kdm_comments_mailtype' );
}

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

Como você pôde verificar, o funcionamento da API consiste em utilizar os ganchos para realização de tarefas e manipulação de dados sempre atribuindo uma função a um identificador em específico. Para conhecer os ganchos disponíveis pelo WordPress consulte as referências de Actions e Filters disponíveis no Codex.

Com o propósito de trabalhar com as boas práticas, prefira a criação de uma classe para cada plugin que você desenvolverá; nesse caso a chamada para as funções manipuladoras de ações e filtros sofrerá uma pequena alteração:

add_action( 'plugins_loaded', array( 'KDM_Subscriber_Comments', 'init' ) );

class KDM_Subscriber_Comments
{
    function init()
    {
        add_filter( 'wp_mail_content_type', create_function( '', 'return "text/html";' ) );
    }
}

Como o filtro do tipo de formatação do e-mail apenas retorna a string específica, você pode optar por simplificar tal chamada como foi demonstrado acima.

Ações específicas

Mediante o uso da API em estudo, você precisa inserir um campo de checagem no formulário capaz de definir se o usuário deseja ou não receber notificações:

add_action( 'comment_form', array( 'KDM_Subscriber_Comments', 'show_form' ) );

function show_form()
{
    ?>
    <label>
        <input type="checkbox" name="kdm_subscribe" value="1" />
        Quero receber atualizações por e-mail de novos comentários para esse post.
    </label>
    <?php
}

O próximo passo para o desenvolvimento do plugin é recuperar o momento em que a ação a ser trabalhada (verificar a escolha por seguir o comentário) é disparada pelos usuários, ou seja, ao enviar um comentário. Empregue o gancho ‘comment_post’ e na função de callback verifique se o campo criado foi marcado ou não.

add_action( 'comment_post', array( 'KDM_Subscriber_Comments', 'check_subscribe' ), 10, 2 );

function check_subscribe( $comment_id, $approved )
{
    if ( isset( $_POST[ 'kdm_subscribe' ] ) && $_POST[ 'kdm_subscribe' ] ) {
        $comment = array(
            'comment_ID'    => $comment_id,
            'comment_karma' => 1
        );
        wp_update_comment( $comment );
    }
}

Dentro da tabela de comentários o campo comment_karma é disponibilizado justamente para servir de apoio aos plugins personalizados dos utilizadores do WordPress. Por padrão tal campo recebe o valor zero. Dentro da lógica do plugin em desenvolvimento, ao definir o valor 1 ao campo você estabelece o comportamento que todos os comentários assinalados com karma igual a um devem ser notificados a cada nova publicação de um comentário do mesmo post.

Perceba que a chamada da ação define o recebimento de dois parâmetros para a função, o identificador do comentário no banco de dados e sua situação (do tipo boolean) de aprovado ou não. Cada site possui suas regras de moderação de comentários, portanto nem todo comentário enviado é necessariamente um comentário publicado. Porém caso o comentário enviado tenho sido aprovado de modo automático no instante do envio, realize o disparo das notificações aos usuários subscritos adicionando ao método ‘check_subscribe’ as seguintes instruções:

function check_subscribe( $comment_id, $approved )
{
    // ...
    if ( $approved ) {
        $c = get_comment( $comment_id );
        self::notify( $c, $comment_id );
    }
}

Comportamento interno da aplicação

A interação proposta pelo plugin foi estabelecida, o usuário já escolhe se deseja seguir os comentários de um post; agora através do método ‘notify’ cujos parâmetros são o objeto do comentário e seu identificador no banco de dados respectivamente, formate a mensagem a ser disparada por e-mail.

A mensagem da notificação deve possuir em seu conteúdo um link para visitação do post e outro para cancelar o recebimento dos avisos.

function notify( $comment, $comment_id=0 )
{
    $post_id = $comment->comment_post_ID;
    $permalink = get_permalink( $post_id );
    $message = sprintf(
        'O post <a href="%s" title="Ver post e novo comentário">"%s"</a> recebeu um novo comentário.' .
        'Para cancelar o recebimento de notificações desse post <a href="[unsubscribe]" title="Cancelar subscrição">clique aqui</a>.',
        $permalink,
        get_the_title( $post_id )
    );
}

Veja que foi recuperado o ID do post para facilitar sua manipulação e entendimento das instruções e com base nele a mensagem foi estruturada. O link de descadastro recebe um código personalizado pois você precisará alterá-lo para cada usuário, sendo que cada um somente poderá solicitar seu próprio cancelamento.

Recupere então todos os comentários que estão marcados para receber notificação, aqueles com o campo karma atualizado; em seguida crie o link personalizado, atualize a mensagem e dispare a notificação aos e-mails dos usuários:

function notify( $comment, $comment_id=0 )
{
    // ...
    $comments = get_comments(
        array(
            'post_id'   => $post_id,
            'karma'     => 1
        )
    );
    foreach( $comments as $comment ) {
        if ( $comment->comment_ID !== $comment_id ) {
            $msg = str_replace( '[unsubscribe]', add_query_arg( 'unsubscribe', $comment->comment_ID, $permalink ), $message );
            wp_mail( $comment->comment_author_email, 'Notificação de comentário', $msg );
        }
    }
}

Está feito! A partir desse momento todos os comentários publicados e aprovados no mesmo momento já estão disparando notificações. No entanto, como foi abordado anteriormente, cada site possui suas peculiaridades no que diz respeito a moderação de comentários e nem todos os comentários serão aprovados no momento em que são publicados.

Para definir o envio de notificações nesse caso você deverá criar um novo gatilho para o momento em que os comentários trocam seu status para aprovado. Utilize para isso a action comment_[antigo-status]_to_[novo-status] como demonstrado abaixo:

add_action( 'comment_unapproved_to_approved', array( 'KDM_Subscriber_Comments', 'notify' ) );

Gatilhos (hooks) Personalizados

O fechamento do plugin e das instruções recebidas no ínicio de seu desenvolvimento ocorre quando recebemos a intenção de cancelamento das notificações por parte do usuário. Dentro da função ‘notify’, você pode reparar que o link de cancelamento é uma referência ao post que o usuário se subscreveu seguido da variável ‘unsubscribe’ que carrega o ID do comentário.

Como a essência dos plugins se baseia em reaproveitá-los em diferentes projetos e também não intererir no código-fonte do WordPress ou dos Temas, você precisa definir um gancho capaz de recuperar o valor passado através da URL antes que ela seja interpretada e exibida normalmente como se não recebesse parâmetro algum. Escolha por exemplo o gatilho ‘wp_loaded’, disparado logo após o WordPress ser carregado.

add_action( 'wp_loaded', array( 'KDM_Subscriber_Comments', 'unsubscribe' ) );

Foi apenas colocado ‘wp_loaded’ como exemplo, pois você pode se utilizar de outros ganchos (como o ‘wp’) e obter o mesmo resultado. O importante é definir especificamente o momento em que determinada ação deverá ser disparada e manter o propósito de funcionamento do plugin.

Dentro das instruções responsáveis por cancelar a inscrição do usuário verifique se o link requisitado pelo visitante do site é para um post único e se a variável escolhida está definida, assim você otimiza a execução dos processos apenas com valor válido e no momento propício:

function unsubscribe()
{
    if ( is_single() && isset( $_GET[ 'unsubscribe' ] ) ) {
        $comment_id = (int) $_GET[ 'unsubscribe' ];
        if ( $comment_id ) {

Confirmadas as condições é feito o processo inverso da subscrição, o campo karma recebe o valor zero. Em seguida defina uma mensagem de aviso para apresentar ao visitante informando que o cancelamento foi realizado com sucesso.

function unsubscribe()
{
        // …
            $c = get_comment( $comment_id );
            if ( $c->comment_karma ) {
                $comment = array(
                    'comment_ID'    => $comment_id,
                    'comment_karma' => false
                );
                wp_update_comment( $comment );
                $message = 'Você optou por não receber mais notificações de comentários desse post!';
            } else {
                $message = 'Você já fez o cancelamento de sua subscrição...';
            }

            global $post;
            $message = sprintf(
                '<h1>Notificação de comentários</h1>' .
                '<p>%s</p>' .
                '<p>Voltar ao post "<a href="%s" title="Voltar ao post">%s</a>".</p>',
                $message,
                get_permalink( $post->ID ),
                get_the_title( $post->ID )
            );
            wp_die( $message );
        }
    }
}

Recapitulando o uso dos códigos feitos até aqui, você pôde ver na prática:

  • Códigos organizados, bem estruturados;
  • Uso de orientação a objetos;
  • Ações e Filtros para manipulação de eventos e informações;
  • Separação do código das camadas de desenvolvimento (HTML, CSS, JavaScript, PHP) e locais de execução (cliente ou servidor);

Agora que você já sabe como instanciar um plugin, criar suas próprias instruções e integrá-las ao WordPress de modo seguro; é hora de estender a capacidade do CMS para diferentes tipos de conteúdo, modelos de organização e classificação das informações e trabalhar com estilos e scripts próprios na prática. Agora você está pronto para iniciar a construção do Slider personalizado.

Carousel Slider

O projeto consiste em criar um Slider para troca de imagens com seus respectivos links; tanto imagens, URL’s e ordem de exibição devem ser editáveis através do painel de controle. As imagens devem se ajustar ao tamanho proposto pelo plugin. Objetivos do plugin:

  • Gerenciar e permitir o recorte das imagens
  • Definir URL destino e ordem de exibição de cada uma
  • Agrupar as imagens em categorias específicas

A inserção do Slider no Tema se dará através de uma Template Tag personalizada. As Template Tags são funções oferecidas pelo WordPress para recuperar mais facilmente os dados gerenciados pelo sistema e então empregá-los dentro de um Tema; justamente por isso a denominação.

Mediante o uso da função ‘the_content’ responsável por exibir o conteúdo de um post, você pode observar o comportamento desse tipo de função. Quando aplicada corretamente dentro do Loop do WordPress a função recupera o conteúdo de valores globais, aplica os devidos filtros e exibe a informação dentro do tema; todo esse processo sem a necessidade de consultar o banco de dados e imprimir o conteúdo manualmente a cada post encontrado. Essa proposta reflete bem a proposta das Template Tags em facilitar a manipulação das informações com base na estrutura oferecida pelo sistema.

Template Tag Personalizada

Uma vez que toda função criada dentro de um arquivo de plugin é acessível em escopo global pelos Temas, você já tem toda liberdade para criar suas próprias Template Tags. Iniciando o desenvolvimento do plugin, defina a Template Tag responsável por exibir o Slider no Tema; permita a atribuição de parâmetros tornando o recurso ainda mais customizável. Como opção do slider, defina a quantidade de items a exibir.

function custom_slider( $count=3 ) {}

No entanto prefira o uso de parâmetros diversos seguindo o modelo que a grande maioria das Template Tags e funções do WordPress trabalham. Veja na aplicação de get_posts os modos distintos para definição de parâmetros:

$posts = get_posts( 'numberposts=10&post_type=attachment&post_mime_type=image' );

Tal emprego tem o mesmo efeito que a passagem de parâmetros em um array:

$args =  array( 
  'numberposts' => 10,
  'post_type' => 'attachment',
  'post_mime_type' => 'image'
);
$posts = get_posts( $args );

Com essa prática você permite a inserção de várias opções em único parâmetro, seja através de string ou de um array. Para incorporar esse mesmo comportamento a sua template tag faça uso da função wp_parse_args:

function custom_slider( $args=array() )
{
    $defaults = array(
        'count' => 3
    );
    $args = wp_parse_args( $args, $defaults );
    KDM_Custom_Slider::slider( $args );
}

Os parâmetros passados a sua Template Tag serão confrontados com as opções padrão e lhe retornarão o resultado dessa combinação; ou seja, se o valor da opção foi definido, ele irá sobrepor o valor padrão, do contrário o valor padrão se mantém. Desse modo a função que você acabou de criar para exibir o Slider pode ser utilizada com segurança tanto com ou sem passagem parâmetros.

Custom Post Types

A partir de uma instalação básica do WordPress você consegue observar a presença dos tipos de conteúdo inerentes a ferramenta: as páginas, os posts e os arquivos anexos dentro da Biblioteca de Mídia. O recurso em desenvolvimento requer a criação de um novo tipo para tornar mais prático e de rápido aprendizado o gerenciamento do novo conteúdo, uma vez que isso será feito no mesmo molde dos tipos existentes. Durante o gerenciamento dos posts perceba ainda a organização e classificação dos mesmos através das tags e categorias; o tipo de conteúdo a ser criado também deverá se utilizar desses mesmos conceitos.

Em princípio determine a função central do plugin responsável por centralizar os gatilhos a serem disparados. Como serão referenciados arquivos próprios de estilo e JavaScript, é muito interessante deixar armazenado o caminho absoluto do diretório onde o plugin esta armazenado.

add_action( 'plugins_loaded', array( 'KDM_Custom_Slider', 'init' ) );

class KDM_Custom_Slider
{
    static $url;
    static $cpt = 'slide';
    static $tax = 'slider';
    static $prefix = 'kdm_';

    function init()
    {
        self::$url = plugins_url( basename( dirname( __FILE__ ) ) ) . '/';

        add_action( 'init', array( 'KDM_Custom_Slider', 'register_cpt' ) );
    }
}

Através de variáveis estáticas estão sendo armazenados valores essenciais ao funcionamento do plugin: caminho absoluto do plugin, nome do tipo de conteúdo, nome da nova taxonomia e um prefixo para controle de campos personalizados. A partir do gancho ‘init’ você registrará o novo tipo de post e também a nova taxonomia.

function register_cpt()
{
    $attr = array(
        'label'     => 'Slides',
        'public'    => false,
        'show_ui'   => true,
        'supports'  => array( 'title', 'thumbnail', 'page-attributes' )
    );
    register_post_type( self::$cpt, $attr );

    $attr = array(
        'label'         => 'Sliders',
        'public'        => false,
        'show_ui'       => true,
        'hierarchical'  => true
    );
    register_taxonomy( self::$tax, self::$cpt, $attr );
}
Reconhecimento de novo tipo de conteúdo e taxonomia personalizados

Reconhecimento de novo tipo de conteúdo e taxonomia personalizados

Desse ponto em diante você trata cada imagem do slider como um ‘Slide’ que podem ser organizadas em ‘categorias’ denominadas ‘Sliders’; caso queira atribuir outros nomes modifique o valor do atributo label do código de exemplo acima. Como o tipo e a taxonomia criados não são públicos, o uso de flush_rewrite_rules logo após a efetivação dos registros é dispensável.

Custom Fields

O plugin em andamento necessita estabelecer uma URL para cada Slide, para isso você fará uso dos campos personalizados. O funcionamento desse recurso consiste na criação de uma metabox com o novo campo editável e o armazenamento do valor informado pelo gerente de conteúdo no banco de dados:

add_action( 'admin_init',   array( 'KDM_Custom_Slider', 'metabox' ) );
add_action( 'save_post',    array( 'KDM_Custom_Slider', 'metabox_save' ) );

Na inicialização do dashboard (ação ‘admin_init’) você estipula a inserção de uma nova caixa de informação com add_meta_box. Em seus parâmetros, esteja certo que a metabox está referenciada para o tipo de conteúdo criado, os Slides.

public static function metabox()
{
    add_meta_box( 'box_slide', 'Detalhes', array( 'KDM_Custom_Slider', 'metabox_edit' ), self::$cpt, 'normal', 'high' );
}

public static function metabox_edit( $post )
{
    $field = self::$prefix . 'url';
    $value = get_post_meta( $post->ID, $field, true );
    ?>
    <table>
        <tr>
            <th><label for="slide-url">URL</label></th>
            <td><input type="text" name="<?php echo $field; ?>" value="<?php echo $value; ?>" id="slide-url" /></td>
        </tr>
    </table>
    <?php
}

A função de callback deve conter o conteúdo da metabox. Foi então inserido um campo texto que exibe o valor armazenado do banco de dados, caso exista. O uso do prefixo está sendo usado conforme demonstrado nas boas práticas de desenvolvimento e a formatação do conteúdo em tabela define o mesmo padrão de formatação das demais metaboxes do WordPress.

Metabox próprio para inserção de meta valores de modo prático

Metabox próprio para inserção de meta valores de modo prático

Metadata API

Observe o uso de get_post_meta para recuperar o valor do campo personalizado da base de dados. Tal função pertence a API de meta-dados, pela qual você consegue gerenciar as informações das tabelas ‘meta’ do WordPress (postmeta, commentmeta e usermeta). Essas tabelas tratam de manipular informações referentes ao conteúdo da tabela principal a qual referencia; seja a tabela de posts, comentários ou usuários.

Feita a exibição do campo personalizado conforme demonstrado, crie agora a função responsável por salvar a informação desse campo cujo nome já fora definido no gancho ‘save_post’ criado anteriormente:

public static function metabox_save( $id )
{
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return $id;

    $field = self::$prefix . 'url';
    $old = get_post_meta( $id, $field, true );
    $new = ( isset( $_POST[ $field ] ) ) ? $_POST[ $field ] : '';

    if ( ( $new !== $old ) && $new )
        update_post_meta( $id, $field, $new );
    else if ( !$new && $old )
        delete_post_meta( $id, $field, $old );
}

Nesse momento você diz ao WordPress para cada vez que um post é salvo realizar suas instruções personalizadas. Se a ação de salvar não partiu do usuário, não é feito nenhum procedimento. Caso o usuário publicou, agendou ou salvou o rascunho do post em questão; são recuperados o valor do campo e do banco de dados para serem comparados e em seguida deixar registrado o valor correto para o Custom Field (se existir).

Gerenciamento personalizado de conteúdo

Acessando o Dashboard nesse momento você já oferece ao gerente de conteúdo as ferramentas necessárias para manipulação dos slides e suas taxonomias. No entanto perceba que durante a listagem dos resultados os dados exibidos são insuficientes para verificar se o conteúdo de cada Slide está correto ou precisa de alguma modificação.

Veja por exemplo a tela com a listagem de posts, por padrão são exibidas as colunas de título, autor, categorias, tags, quantidade de comentários e a data de sua publicação. Aprimorando a listagem de Slides, acrescente suporte às colunas URL, taxonomia (Slider) e ordem de exibição.

add_filter( 'manage_posts_columns', array( 'KDM_Custom_Slider', 'cols' ), 10, 2 );

public static function cols( $cols, $post_type )
{
    if ( $post_type == self::$cpt ) {
        $cols[ 'url' ]      = 'URL Destino';
        $cols[ 'slider' ]   = 'Slider';
        $cols[ 'order' ]    = 'Ordem';
    }
    return $cols;
}

Lembre-se de definir os ganchos dentro da função principal do plugin. Em seguida é preciso exibir a informação correspondente a cada nova coluna adicionada:

add_action( 'manage_' . self::$cpt . '_posts_custom_column', array( 'KDM_Custom_Slider', 'cols_content' ) );

public static function cols_content( $col )
{
    global $post;
    switch ( $col ) {
        case 'order':
            echo $post->menu_order;
            break;
        case 'slider':
            $tax = '';
            $terms = get_the_terms( $post->ID, self::$tax );
            foreach ( $terms as $t ) {
                if ( $tax ) $tax .= ', ';
                $tax .= $t->name;
            }
            echo $tax;
            break;
        default:
            echo get_post_meta( $post->ID, self::$prefix . $col, true );
            break;
    }
}

Com ‘manage_[cpt]_post_custom_column’ você já define que a função callback será executada apenas para o tipo de post em questão, no exemplo o próprio slide; e através da estrutura condicional de switch e case você verifica qual a coluna e informações a apresentar.

Uma outra prática interessante é permitir ao utilizador ordenar os resultados com base em alguma coluna específica. Estabeleça a coluna ordem de exibição para ser uma coluna ordenável no painel administrativo fazendo uso das seguintes instruções:

add_filter( 'request', array( 'KDM_Custom_Slider', 'orderby' ) );
add_filter( 'manage_edit-' . self::$cpt . '_sortable_columns', array( 'KDM_Custom_Slider', 'cols_sort' ) );

function cols_sort( $cols )
{
    $cols[ 'order' ] = 'ordem';
    return $cols;
}

function orderby( $vars )
{
    if ( isset( $vars[ 'orderby' ] ) && ( $vars[ 'orderby' ] == 'ordem' ) )
        $vars[ 'orderby' ] = 'menu_order';

    return $vars;
}
Gerenciamento personalizado de Custom Post Types

Gerenciamento personalizado de Custom Post Types

Imagens, Estilos e Scripts

Do lado gerenciável do plugin resta definir o modelo de gerenciamento das imagens dos Slides. Faça uso do recurso imagem destacada do WordPress que possibilita escolher uma imagem representativa para cada post. A escolha desse recurso ocorre em virtude de ser algo inerente ao CMS, cuja manipulação é feita mediante emprego de Templates Tags capazes de manipular as imagens de modo prático.

Inicialmente determine quais as dimensões das imagens e consequentemente do Slider com o uso de add_image_size. A função adicionará novos formatos aos já existentes no WordPress (tamanho miniatura, médio e grande). Para inserir novos formatos, insira dentro da função ‘init’ do plugin:

add_image_size( 'slide', 480, 320, true );

O formato já está adicionado. Aplique agora o filtro ‘intermediate_image_sizes’ para recortar apenas as imagens dos slides com essa dimensão.

add_filter( 'intermediate_image_sizes', array( 'KDM_Custom_Slider', 'image_sizes' ), 10, 3 );

public static function 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 ) ) {
        $post_type = get_post_type( $post->post_parent );
    }

    $sizes = array( 'thumbnail', 'medium', 'large' );
    if ( $post_type == self::$cpt )
        $sizes = array( 'slide' );

    return $sizes;
}

Esse filtro é disparado sempre que uma imagem é inserida ou removida do WordPress. Na primeira situação o ID do post é enviado juntamente com ela via $_POST; no outro caso ele está armazenado no valor de post_parent da imagem. De posse dessa informação é recuperado o tipo de post a qual a imagem pertence, caso seja do tipo Slide o único formato de recorte será o personalizado; quando não, mantém os formatos padrão.

Importante fazer a verificação na remoção da imagem porque é preciso apagar também os arquivos com a imagem redimensionada em tamanhos personalizados. Caso isso não seja feito as imagens manipuladas permanecem no servidor mesmo após você removê-las da biblioteca.

Exibição do conteúdo

A estrutura back-end do Slider está montada, resta exibir os itens cadastrados dentro do Tema através da Template Tag ‘custom_slider’ criada anteriormente. Acrescente uma nova opção que possibilite a escolha de uma taxonomia a fim de filtrar apenas os slides pertencentes a ela do seguinte modo:

function custom_slider( $args=array() )
{
    $defaults = array(
        'slider'=> '',
        'count' => 3
    );
    $args = wp_parse_args( $args, $defaults );
    KDM_Custom_Slider::slider( $args );
}

Perceba que a função serve apenas como um alias para o método da classe que de fato irá recuperar e exibir os resultados no Tema. Essa prática foi adotada para simplficar a chamada do recurso que deverá necessariamente ser referenciado em algum ou vários locais do Tema ativo para ser apresentado ao visitante do site.

custom_slider( 'count=5' ); // exibe os últimos cinco slides
custom_slider( array( 'slider' => 'principal' ) ); // exibe slides pertencentes a taxonomia 'principal'

Nesse modelo de interferência no conteúdo e código-fonte do Tema pode ser feito com tranquilidade pois assim é possível definir com liberdade quais as posições do layout que abrigarão o recurso. Recomenda-se no entanto que você verifique se o plugin está ativo antes de empregá-lo:

if ( function_exists( 'custom_slider' ) ) {
    custom_slider();
}

Dentro do método slider você precisará pesquisar os resultados de acordo com os parâmetros passados e em seguida apresentá-los em tela.

function slider( $args )
{
    $q = array(
        'post_type'     => self::$cpt,
        'numberposts'   => $args[ 'count' ],
        'orderby'       => 'menu_order',
        'order'         => 'ASC'
    );

    if ( $args[ 'slider' ] )
        $q[ self::$tax ] = $args[ 'slider' ];

    $slides = get_posts( $q );
    if ( is_array( $slides ) && count( $slides ) ) { ?>
    <div>
        <ul id="custom-slider">
            <?php
            foreach( $slides as $slide ) {
                if ( !has_post_thumbnail( $slide->ID ) ) continue;

                $thumb = get_the_post_thumbnail( $slide->ID, 'slide' );
                $url = get_post_meta( $slide->ID, self::$prefix . 'url', true );

                if ( $url )
                    $html = '<li><a href="' . $url . '" title="' . esc_attr( $slide->post_title ) . '">' . $thumb . '</a></li>';
                else
                    $html = "<li>{$thumb}</li>";

                echo $html;
            } ?>
        </ul>
    </div>
    <?php }
}

Através de get_posts e suas definições os slides são recuperados; confirmada a existência de resultados, estes são listados em formato de uma lista não ordenada do HTML. Note que a escolha do recurso Imagem destacada para manipulação da imagem do Slide permitiu o uso de has_post_thumbnail para verificar a existência de uma imagem para o slide e também de get_the_post_thumbnail para recuperar a imagem no formato desejado. Como foi dada a opção do preenchimento de um link para cada slide, caso ele tenha sido definido é também apresentado.

Owl Carousel Slider

A definição da estrutura HTML que exibirá as imagens (apresentada acima) pode ser alterada. A escolha feita por uma lista não ordenada, assim como a div container e demais tags são opcionais; porém, ao fazer as alterações, certifique-se de que o script funciona com a estrutura utilizada.

No exemplo, conforme foi antecipado no início da publicação, o script utilizado foi o Owl Carousel 2. Ele é compatível com diferentes browsers e responsivo. Se preferir você pode utilizar outro plugin JavaScript para realizar as transições; basta adequar a exibição dos slides a estrutura do novo script, bem como de seus códigos e dependências.

add_action( 'wp_enqueue_scripts', array( 'KDM_Custom_Slider', 'enqueue' ) );

function enqueue()
{
    if ( is_admin() ) return;

    wp_enqueue_script( 'cs-owl', self::$url . 'owlcarousel/owl.carousel.min.js', array( 'jquery' ), null, true );
    wp_enqueue_script( 'cs-script', self::$url . 'script.js', array(), null, true );

    wp_enqueue_style( 'cs-owl-base', self::$url . 'owlcarousel/owl.carousel.min.css', array(), null, 'screen' );
    wp_enqueue_style( 'cs-owl-theme', self::$url . 'owlcarousel/owl.theme.default.min.css', array(), null, 'screen' );
}

A inserção dos scripts e estilos ocorrem apenas fora do ambiente administrativo. Note a inserção de jQuery através do parâmetro de dependência de wp_enqueue_script em sua primeira chamada; afinal o recurso usado (Owl Carousel) precisa da jQuery para funcionar como previsto.

Os estilos inseridos são apenas de posicionamento a fim de obter o efeito esperado; os ajustes necessários para cada Tema é recomendado que se faça dentro dos arquivos do próprio Tema. Desse modo você terá um Slider funcionando em qualquer Tema sem grandes dificuldades!

Pra não esquecer

  • Template Tags aceitam parâmetros diferenciados
  • Manipulação de conteúdo personalizado e meta-valores
  • Tratamento de imagens otimizado
  • Uso de arquivos de estilo e script de modo seguro