Desenvolvendo plugins para WordPress

Uma peça chave do sucesso do WordPress é justamente sua capacidade de aceitar plugins e widgets, além , é claro, dos milhares de programadores que desenvolvem os mais diversos plugins que fazem de tudo um pouco.

Algum tempo atrás fui abordado pelo Manoel Lemos do BlogBlogs para discutirmos uma missão, criar um plugin para o WordPress, baseado na API do site. Comecei entao minha saga atrás de como desenvolver um plugin. O material estava lá, espalhado em vários sites, mas estava lá.

Então agora com o sucesso do BBUinfo e na véspera de novos projetos, decidi tentar consolidar este conhecimento adquirido e focar ele no público brasileiro. Vou procurar mostrar o caminho das pedras de como começar e onde buscar os dados necessário para integrar seu código ao do WP.


O WP, como eu disse, foi desenhado com plugins em mente. Sua estrutura possui diversos componentes desenhados para que seu plugin se “encaixe” no ponto certo (attach points ou hooks) e na hora certa. Mas para isso é importante observar alguns passos, para melhor desenhar seu plugin.

Os passos a seguir são a minha recomendação de como desenvolver um plugin, e evitar maiores problemas e dificuldades. Para poder acompanhar melhor o código produzido, vou estar criando com vocês o meuPrimeiroPlugin, que será descrito passo a passo abaixo.

Passo 1: Planejamento

No desenvolvimento de qualquer sistema o primeiro passo deve sempre ser uma análise e planejamento do que será feito, com plugins, embora pequenos, isto se mantém.Como em sistemas é importante identificar neste momento o que se deseja fazer, qual o objetivo do plugin. Levantar entradas e saídas, dados externos e suas fontes, enfim, definir de forma geral o que o plugin faz, com que dados ele faz isso e como obter os dados necessários.Faça perguntas como:

  • Preciso de um banco de dados?
  • Preciso acessar dados externos por webservice ou uma API?
  • Vou mostrar algo visual para o usuário?
  • O que pretendo fazer?
  • Qual o nome darei ao plugin?(se você consegue definir o nome, sabe o que quer)

Um bom exercício para este momento é utilizar o padrão de arquivo readme do WP e já iniciar a escrita da descrição resumida e detalhada do plugin, pois este será seu guia. (você pode validar o arquivo aqui)

meuPrimeiroPlugin

Este plugin, desenhado para o aprendizado de como desenvolver plugins, executa ações básicas e didáticas, mas sem muito uso. Para mostrar todos os limites, o plugin fará as seguintes ações:

  1. Acrescentará ao final de cada comentário o texto: “O conteúdo deste comentário é de responsabilidade de: {AUTOR}”
  2. Criará uma tabela nova que irá armazenar uma contagem de visitas a cada post, e mostrará esta contagem logo ao final do POST.
  3. Substituir a palavra XXX por um link

Exemplos

  • Arquivo readme.txt
  • Meu brainstorm (idéias para o plugin):
    Brainstorm do MPP

Produtos desta etapa
Arquivo readme.txt, arquivo com “brainstorm” (tente um mindmap, como acima)

Passo 2: Projeto

Esta etapa segue os padrões de projetos de sistema, mas com algumas adições específicas do WordPress. Como base sugiro que use a linguagem UML para definir seu projeto e faça um diagrama de MER (base de dados).

Embora não seja obrigatório, a criação do plugin como um objeto, é recomendável e mais fácil de manter do que código estruturado, além claro de ser uma “prática recomendada” para o PHP5. Outra grande vantagem nesta orientação é que como os métodos são chamados de dentro do objeto a preocupação com “nomes coincidentes” é nula, sendo reduzida apenas ao nome do objeto que deve ser único.

Então defina o seu objeto com métodos que se identifiquem com as diversas ações que o plugin vai executar, por exemplo: adicionarAssinatura(), pegarDadosExternos(), salvarDados()…

Agora entra o ponto onde o WordPress traz toda sua mágica com os seus “hooks”, ou ganchos.

Ganchos do WordPress

Para facilitar que se ligue o plugin às ações doWP, são definidos ganchos em sua programação, ou seja, em pontos específicos do funcionamento do plugin, são disponibilizados pontos onde as funções podem se “pendurar”. Desta forma caso deseje criar um plugin, que deve executar determinada função no momento em que um comentário é salvo, você usaria o gancho “comment_post”.

Estes ganchos são divididos em 2, ações e filtros.

  • Ações são eventos disparados em momentos exatos durante a execução do WordPress.
  • Filtros são lançados no momento de gravação ou apresentação de um texto para que seja possível modificá-lo.

Outros Links: Todos Hooks de todas versões do WP

Para definir os ganchos você pode se perguntar “Em que momento devo fazer isso?” para cada ação e então verificar a lista de ganchos de ações e filtros para achar qual lhe atende.

meuPrimeiroPlugin
Neste caso podemos usar os seguintes pontos para anexar nossas funções:

  1. Instalar: ligada ao “register_activation_hook” que é executado na ativação de um plugin no menu
  2. Desinstalar: Estas funções foram bastante discutidas, mas ainda não existe um hook fixo.
  3. Inicializar: Esta deve ser executada logo no início, para isso temos o filtro “init”
  4. Aba de opções: para fazer a aba precisamos de dois pontos, a ação “admin_menu” e o “add_options_page”.
  5. Contar Visita: poderia ser melhor,mas o filtro “the_content” garante a contagem na hora mais certa.
  6. Inserir texto no comentário: Para isso o filtro “get_comment_text” é perfeito
  7. Substituir palavras: este é bem direto também, vamos usar o filtro “the_content”

Juntamente com este raciocínio, fiz o mapeamento da classe e do que seria necessário na base de dados:

Diagrama de classe do plugin

Diagrama de classe do MPP

MER do Banco

MER do MPP

Produtos desta etapa: diagrama de classe do seu plugin, um MER do banco de dados e uma lista de possíveis pontos de inserção (ganchos).

Passo 3: Desenvolvendo

Com o caminho a sua frente devidamente mapeado, agora podemos nos aprofundar no código, além de conhecer algumas possibilidades que o WP traz embutidas em si mesmo.

O ideal é que seu plugin caiba dentro de um arquivo só, mas caso isso não seja possível, recomenda-se que todos arquivos sejam jogados dentro de uma pasta com o mesmo nome do plugin. O nome do plugin também pode (recomenda-se) ser o nome de seu arquivo principal, isso irá lhe facilitar usar funções “on activation” disparadas na ativação do plugin. Portanto teremos a seguinte estrutura para nosso exemplo:

Pasta do MPP

A primeira coisa que deve aparecer em nosso arquivo meuPrimeiroPlugin.php é o cabeçalho. Este cabeçalho é usado pelo WP para mostrar os dados de seu plugin na página de administração de plugins, então é muito importante manter estes dados corretos, o cabeçalho segue o padrão abaixo:

/*
Plugin Name: Nome do Plugin
Plugin URI: http://Endereço_da_pagina
Description: Descrição simples e curta do plugin
Version: A versão atual do plugin, ex.: 1.0
Author: Nome do Autor do Plugin
Author URI: http://Endereço_do_site_do_autor
*/

Após isso podemos começar a definir a classe. A definição segue o padrão normal de um objeto em PHP (4 ou 5). Aqui vamos seguir uma orientação PHP5 por sua enorme vantagem e pelo “fim” do PHP

O site do WP possui muito material sobre padrões de codificação, e eu recomendo uma leitura, mas são padrões bem estabelecidos que muitos programadores já devem usar normalmente.

Como vimos no passo anterior montamos um diagrama de classe e nesse diagrama já identificamos as funções que precisamos desenvolver em nosso plugin, portanto a seguir vou seguir passo a passo deste arquivos criando e explicando cada uma destas funções, e no final comentarei sobre os ganchos que serão colocados fora do escopo do objeto e porque.

Função Inicializar

Esta função serve para centralizar todas as ações que devem ser sempre tomadas para integrar o plugin com o WP, sejam elas ações de adição/remoção de filtros/ações ou instanciação de objetos, cópias de variáveis globais, enfim, todas ações que serão executadas sempre que o WP carregar.

public static  function inicializar(){
global $wpdb;

//Definir ganchos
add_filter("get_comment_text", array("meuPrimeiroPlugin","exonerarComentarios"));
add_filter("the_content", array("meuPrimeiroPlugin","contarVisita"));
add_filter("the_content", array("meuPrimeiroPlugin","processarSubstituicao"));
add_action('admin_menu', array('meuPrimeiroPlugin','adicionarMenu'));

//Mapear objetos WP
meuPrimeiroPlugin::$wpdb = $wpdb;

//Outros mapeamentos
meuPrimeiroPlugin::$info['plugin_fpath'] = dirname(__FILE__);

}

Como podemos ver, no caso do meuPrimeiroPlugin, estamos cadastrando as outras funções com seus devidos filtros, ou seja, os ganchos que irão executá-las e copiando o objeto $wpdb para dentro do nosso script, podendo agora ser referenciado como: meuPrimeiroPlugin::$wpdb que é melhor que ficar sempre usando “global” no início da função. Além disso aproveita-se para obter a localização do plugin, usando a constante __FILE__ do PHP que define o caminho até o arquivo onde esta.

$wpdb
Este objeto sempre presente no WordPress é responsável pela sua conexão com a base de dados, ele pode executar queries, buscar dados, e realizar diversas funções relacionadas a base de dados. Veja aqui a lista de métodos [aqui]

Função Instalar

Esta função é mapeada para ser executada no momento que o plugin é ativado na aba de plugins do WordPress. Como nosso plugin utiliza dados que serão salvos e lidos de bases de dados é necessário que elas sejam criadas antes de seu uso, o momento de ativação é excelente para isso, porém o plugin pode ser ativado e desativado diversas vezes (quando se faz upgrade do WordPress por exemplo) e não podemos simplesmente criar a tabela sempre, por isso observe o comando para criar apenas caso não exista.

	public static function instalar(){

if ( is_null(meuPrimeiroPlugin::$wpdb) ) meuPrimeiroPlugin::inicializar();

//Criar base de dados
$sqlContador = "CREATE  TABLE IF NOT EXISTS `".meuPrimeiroPlugin::$wpdb->prefix."mpp_post_visitas` (
`id_post` INT NOT NULL ,
`visitas` INT NULL ,
PRIMARY KEY (`id_post`) )";

$sqlPalavras = "CREATE  TABLE IF NOT EXISTS `".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao` (
`idmpp_substituicao` INT NOT NULL AUTO_INCREMENT ,
`orig_palavra` VARCHAR(255) NULL ,
`subst_palavra` VARCHAR(255) NULL ,
PRIMARY KEY (`idmpp_substituicao`) )";
meuPrimeiroPlugin::$wpdb->query($sqlContador);
meuPrimeiroPlugin::$wpdb->query($sqlPalavras);

//Criar opções
add_option("mpp_texto_exonerar","O conteúdo deste comentário é de responsabilidade de: ");
}

Neste caso, de forma puramente didática, criei uma opção para armazenar o texto que será inserido nos comentários. Esta opção foi criada apenas para mostrar como elas podem ser utilizadas. Estas opções são gravadas na tabela de opções do próprio WordPress e acessadas com estes métodos: add_option, update_option, delete_option, get_option.

Note que no ínicio da função chamo a função de inicialização, isso é importante pois no ato em que a função de instalação é chamada o gancho “init” ainda não foi chamado e por isso não temos nossa conexão com o banco por exemplo. Isto causaria erros na ativação do plugin.

Dica:
Se você receber um aviso “cannot redeclare class” na ativação do plugin, 9 em 10 vezes o erro não esta na declaração do plugin e sim omitido pelo WordPress, em sua função de captura de erros, que infelizmente possui algumas falhas, como essa.

Para ver o erro verdadeiro vá até o arquivo wp-admin/plugin.php e comente as linhas 14 e 15, mostradas abaixo:

wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), 'plugins.php?error=true&plugin=' . $plugin)); // we'll override this later if the plugin can be included without fatal error
ob_start();

Função Desinstalar

Esta função não possui um hook para ser executada de forma automática, mas é uma função que recebeu muita atenção nos últimos tempos em diversas discussões pela internet. Nossa aba de opções deve implementar uma chamada a esta função, mas em breve o WordPress deve implementar um hook para ela.

Sua função é bem direta e simples, remover tudo que foi criado pela função de instalação. Por isso não é possível ligar ela ao ato de “desativar” o plugin, pois o usuário perderia suas preferências a cada vez que fizesse upgrade do WordPress (é recomendado que se desative os plugins para tal).

	public static function desinstalar(){

//Remover bases de dados
$sqlContador = "DROP TABLE `".meuPrimeiroPlugin::$wpdb->prefix."mpp_post_visitas`";
$sqlPalavras = "DROP TABLE `".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao`";

meuPrimeiroPlugin::$wpdb->query($sqlContador);
meuPrimeiroPlugin::$wpdb->query($sqlPalavras);

//Remover opções
delete_option("mpp_texto_exonerar");
}

Como podemos ver apenas é feito um DROP nas tabelas e a remoção da opção que foi criada na própria tabela do WordPress.

Função adicionarMenu

Esta função indica ao WordPress que ao montar o menu da administração ele deve inserir uma nova aba que aponta para uma função de nosso plugin.

	public static function adicionarMenu(){
add_options_page('meuPrimeiroPlugin - Gerenciamento','meuPrimeiroPlugin',10,__FILE__,array("meuPrimeiroPlugin","abaOpcoes"));
}

A sintaxe deste comando é a seguinte:

add_menu_page(titulo_da_pagina, titulo_do_menu, nivel_de_acesso, arquivo, [função]);

O nível de acesso diz respeito as permissões do usuário, o arquivo é o arquivo de nosso plugin (__FILE__) e a função é a função de nossa classe em formato de call_user_func

Função abaOpcoes

Esta função é a que setamos no exemplo anterior para ser executada quando o usuário clicar na nossa aba do menu. Neste caso fiz uma implementação simplificada, onde uma mesma função mostra o menu e executa as operações de salvar e atualizar as opções.

Para salvar as opções fazemos inserções usando novamente o $wpdb->query(). Esta operação é executada sempre que o array de POST (dados enviados pelo form) possuir algum conteúdo.

Para mostrar o formulário utilizei uma implementação simplificada de templates, onde tenho um arquivo .tpl externo com o layout do menu e chaves especiais ({PALAVRAS},{STATS}…) que são substituídas pelo conteúdo que quero gerar. Você pode usar outra técnica e até usar código espageti com HTML no meio de seu plugin, depende da sua facilidade e organização. Para gerar o conteúdo dinâmico, faço diversas queries no banco buscando os dados que são necessários.

    public static function abaOpcoes(){

//Predefinidos
$templateVars['{UPDATED}'] = "";
$templateVars['{ERROS}'] = "";

//Executar operações definidas
if (count($_POST) > 0){
$ins = meuPrimeiroPlugin::$wpdb->query("INSERT INTO ".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao
(idmpp_substituicao,orig_palavra,subst_palavra)
VALUES
(NULL,'".$_POST['orig']."','".$_POST['subst']."')
");
$templateVars['{UPDATED}'] = '<div id="message" class="updated fade"><p><strong>';
if ($ins){
$templateVars['{UPDATED}'] .= "Dados atualizados!";
}else{
$templateVars['{UPDATED}'] .= "Erro ao atualizar dados!";
}
$templateVars['{UPDATED}'] .= "</strong></p></div>";
}

//Ler arquivo de template usando funções do WP
$admTplObj = new FileReader(meuPrimeiroPlugin::$info['plugin_fpath']."/admin_tpl.htm");
$admTpl = $admTplObj->read($admTplObj->_length);

//pegar palavras
$resultados = meuPrimeiroPlugin::$wpdb->get_results( "SELECT orig_palavra,subst_palavra FROM ".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao" );
foreach($resultados as $res){
$palavras .= "<li><b>".$res->orig_palavra." -></b> ".$res->subst_palavra."</li>";
}
$templateVars['{PALAVRAS}'] = $palavras;

//pegar estatisticas
$resultados = meuPrimeiroPlugin::$wpdb->get_results( "SELECT post_title,visitas FROM ".meuPrimeiroPlugin::$wpdb->prefix."mpp_post_visitas
LEFT JOIN ".meuPrimeiroPlugin::$wpdb->prefix."posts AS posts ON mpp_post_visitas.id_post = posts.ID" );
foreach ($resultados as $res){
$stats .= "<dt>".$res->post_title."</dt>";
$stats .= "<dd>".$res->visitas." Visitas</dd>";
}
$templateVars['{STATS}'] = $stats;

//Substituir variáveis no template
$admTpl = strtr($admTpl,$templateVars);

echo $admTpl;

}

Observe o uso da classe FileReader para leitura do arquivo .tpl. Esta classe é nativa do WordPress portanto a preferência de se utilizar ela ao invés de utilizar funções como fopen ou similares. É importante lembrar que o WordPress possui diversas classes disponíveis em suas pastas, e é uma boa idéia ver se existe alguma para executar a operação que você procura.

Função contarVisita

Como foi dito esta função é convocada pelo gancho “the_content” sempre que o conteúdo de um post for resgatado do banco para exibição. Então para fazer uma simples contagem de visualizações de um post, sem entrar em muitos detalhes, filtros por IP nem nada do tipo, apenas fazemos uma inserção no banco, em nossa tabela de contagem.


public static function contarVisita($post_texto){
global $post;

$sql = "INSERT INTO ".meuPrimeiroPlugin::$wpdb->prefix."mpp_post_visitas (id_post,visitas) VALUES ('".$post->ID."',1)
ON DUPLICATE KEY UPDATE visitas=visitas+1";
meuPrimeiroPlugin::$wpdb->query($sql);

return $post_texto;
}

Note neste caso que a função recebe um parâmetro que chamei de $post_texto. Sempre que uma função usa o gancho “the_content” ela receberá o conteúdo do post como parâmetro. Ao final da função este conteúdo, alterado ou não, deve ser retornado com uma chamada return, caso contrário o blog não exibirá o conteúdo do post.

Para o comando de SQL caso interesse usei o ON DUPLICATE KEY UPDATE, que verifica se já existe um registro para o post e faz a atualização do mesmo, caso contrário cria o novo registro. Ela é bem útil para não ser necessário fazer um select para decidir se devemos usar um INSERT ou UPDATE.

Função processarSubstituicao

Esta função, também ligada ao “the_content” efetua a troca das palavras que cadastrarmos, por outras que forem escolhidas. É interessante notar que podemos ter várias funções ligadas a um mesmo gancho e elas serão executadas na ordem que os ganchos são designados, por isso a importância ressaltada na função anterior, onde o parâmetro deve ser retornado no final.

Para fazer a substituição usei um método simples também, busquei no banco os pares (palavra original => nova palavra) e montei um array de “tradução”. Usando a função strtr do PHP eu passo este array e o texto do post e a função se encarrega de fazer a troca e me devolver o texto alterado.

public static function processarSubstituicao($post_texto){

//Montar array de palavras para substituirmos
$resultados = meuPrimeiroPlugin::$wpdb->get_results("SELECT orig_palavra,subst_palavra FROM ".meuPrimeiroPlugin::$wpdb->prefix."mpp_substituicao");

foreach($resultados as $res){
$aTraducao[$res->orig_palavra] = $res->subst_palavra;
}

$post_text = strtr($post_texto,$aTraducao);

return $post_texto;
} 

Função exonerarComentarios

Finalmente esta função será a responsável por incluir um texto ao final do comentário para nos exonerar das palavras do seu autor. Para isto usamos o gancho get_comment_text que é similar ao get_content acima, mas se refere ao comentário.

    public static function exonerarComentarios($cmt_texto){
global $comment;

$anexo = "<br><br><b><i>".get_option('mpp_texto_exonerar').$comment->comment_author."</i></b>";

$cmt_texto .= $anexo;

return $cmt_texto;
}

Como antes, recebemos o texto como parâmetro e devemos retornar ele ao final para evitar quebrar outros plugins ou ocultar comentários .

Nota: Quando desenvolvi meu primeiro plugin de WordPress, usei o gancho get_comment_ID e não fiz o retorno do meu parâmetro ao final. Resultado, todos plugins executados após este quebravam, pois não recebiam um ID e sim uma string vazia.

Usando o contexto global, a variável $comment é um objeto que representa todos os dados do comentário atual, por isso como pode ser visto acima, posso acessar o nome do autor, para agregá-lo à mensagem, que foi buscada da tabela de opções pela chamada get_option. Ao final tudo isso é concatenado ao texto no comentário que segue em frente para outros plugins, ou é simplesmente mostrado.

Código remanescente

Para inicializar nosso plugin o código abaixo é inserido solto em nosso arquivo, para que seja executado diretamente quando o arquivo for incluso, já que tudo que esta no escopo da classe não é executado sem sua instanciação.

$mppPluginFile = substr(strrchr(dirname(__FILE__),DIRECTORY_SEPARATOR),1).DIRECTORY_SEPARATOR.basename(__FILE__);
/** Funcao de instalacao */
register_activation_hook($mppPluginFile,array('meuPrimeiroPlugin','instalar'));
/** Funcao de inicializacao */
add_filter('init', array('meuPrimeiroPlugin','inicializar'));

Nestes ganchos determinamos a execução da função instalar na ativação do plugin e da init na inicialização do WordPress. Para o gancho de ativação definimos a variável $mppPluginFile que determina a pasta onde o plugin esta, e para isso o plugin deve estar em uma sub-pasta de plugin e não na raiz. Com esta combinação de funções e as constantes DIRECTORY_SEPARATOR (barra invertida ou não), e o __FILE__, saimos com algo como “mpp/meuprimeiroplugin.php” ou seja, pasta e arquivo necessários para a detecção de ativação.

Divulgando seu plugin

Para divulgar seu plugin o primeiro e mais importante passo é adicionar ele no repositório do WordPress. Isso é uma excelente ferramenta, pois além de fornecer um repositório SVN que pode lehe ajudar a melhor controlar seu desenvolvimento ele permite que o usuário de seu plugin possa ser notificado de novas versões diretamente na página de plugins.

Divulgue o seu plugin no repositório oficial do WordPress: http://wordpress.org/extend/plugins/ usando o link http://wordpress.org/extend/plugins/add/. A única exigência é que o plugin deve ser licenciado como GPL (detalhes)

Conclusão

Espero que com este artigo (que atrasou mais do que devia) muitos usuários de WordPress e desenvolvedores da comunidade possam embarcar no desenvolvimento de novos plugins e que todos tenham uma noção do poder que o blog oferece permitindo tamanha integração de forma tão simplificada e acessível.

O plugin criado neste exemplo esta 100% funcional e pode até ser usado, mas use-o para aprender e vá muito mais longe. Abaixo deixo os links para download caso lhes interesse.

Com o atraso do artigo estamos na beira do WordPress 2.5, mas tudo indica que além da carinha nova da administração, não haverá impactos no processo descrito acima, e inclusive este exemplo já funciona na nova versão e foi testado aqui com ela.

Download o meuPrimeiroPlugin

não esqueçam: se quiserem agradecer, contribuam com uma graninha ou um presente da lista ao lado….

64 thoughts on “Desenvolvendo plugins para WordPress

  1. Caramba Rafael, de PRIMEIRÍSSIMA QUALIDADE seu material.

    Meus parabéns, tenho certeza que será muito útil para quem está começando a desenvolver plugins para o WP.

    Dá só uma olhadinha aqui embaixo dos comentários que tá dando erro.

    WordPress database error: [Unknown table 'wp_posts' in on clause]
    SELECT p.ID, p.post_title FROM wp_posts AS p INNER JOIN wp_post2lang p2l ON wp_posts.ID = p2l.post_id INNER JOIN wp_languages l ON p2l.language_id = l.language_id WHERE p.post_date ’2008-03-10 10:40:10′ AND p.post_type = ‘post’ AND p.post_status = ‘publish’ AND p.ID != 147 AND l.language_id IN (1) ORDER BY p.post_date ASC LIMIT 1

  2. Rafael,

    Obrigado.

    Sobre o erro, sim é o Gengo que ainda não esta compativel e nao tive tempo de arrumar, mas felizmente o erro é só visual, não afeta o funcionamento do blog, por isso nao pus urgencie nele, com o WP 2.5 isso deve se resolver.

    Abraço.

  3. Oi Rafael, existe alguma diferença para plugins WordPress 2.5 em relação as instruções que você dá aqui?

    Acredito que estas instruções também funcionaram em plugins para WordPress 2.5, mas com todas as funcionalidades que a versão 2.5 dispoe?

    Isto é a 2.5 tem novos padrões para desenvolver plugins?

    Desde já agradeço sua atenção,

    Sardano

  4. Sardano,

    Não olhei com cuidado as novidades ainda, mas todos plugins que fiz estão funcionando normalmente como era esperado. Então o tutorial vale sim para a versão 2.5 e os padrões são os mesmo até o momento.

    Na versão 2.5 temos novidades sim, uma delas é a ShortCode API que permite tags como [gallery] dentro do post que são depois substituidas por algo, vou ver se escrevo sobre isso depois.

    Abraço!

  5. Ola Rafael,

    Muito bom viu.. estou usando seu tutorial para criar um plugin aqui no meu trabalho… Ainda estou começando a mexer.
    Só um detalhe, você esqueceu de por o gancho register_deactivation_hook chamando a função de desinstalar…

    Parabens
    []s
    Humberto

  6. Humberto,

    Na verdade este gancho não pode ser usado para desinstalação, pois no ato do upgrade do WP cada plugin é desativado, entao imagine qu voce perderia suas configurações cada vez que o plugin for desativado. Eu falo sobre isso na função desinstalar.

    Abraço!

  7. olá grande rafael!
    gostei muito do seu post, estou a apenas 2 semanas estudando programação (principalmente OO) e mesmo assim tive uma compreenção clara do seu artigo, ótima didática.

    gostaria de saber se em vez de declararmos os métodos dentro de uma classe poderiamos criar uma interface ou uma classe abstrata e estender o plug-in?

    seria possível aplicar uma arquitetura MVC para um plug-in wordpress?

  8. Obrigado pelos elogios.

    Bem, você pode criar a estrutura que desejar, portanto que mapeie os filtros para as funções de um classe.
    No meu plugin BlogblogsUserInfo, eu uso uma pseudo-camada de templates improvisada inclusive, então cair em algo MVC é possível sim.

    Você pode usar interfaces e classes abstratas, mas terá de ter uma classe que implemente ou extenda estas, não existe uma classe plugin do próprio WP que possa ser estendida.

    Abraço!

  9. Olá, Rafael!

    Parabéns pelo ótimo tutorial. Pela primeira vez em quase 3 anos mexendo com o WordPress precisarei desenvolver pequenos hacks ou até mesmo plugins. Seu tutorial foi muito bem estruturado e explicado.

    Sucesso com o blog!

  10. Parabéns, estou começando hoje a aprender e está sendo muito bom.

    Abaixei e instalei como está para testar no meu 2.7 e notei que:
    * no admin não exibia as visitas por posts (este resolvi adicionando um ” AS mpp_post_visitas” que faltou na linha 136
    * um warning sobre um segundo parâmetro da linha 185 não ser array ocorre se não houver nenhuma palavra cadastrada para substituição

    foi ótimo!

    obrigado e abraço!

  11. Fala ae cara beleza?

    O seu artigo está de 100%, mas estou com algumas dúvidas aqui.

    Estou escrevendo um plugin ou melhor dizendo, tentando, que funcione da seguinte forma:
    após um novo cadastro no WordPress o plugin seria disparado, este por sua vez, pegaria o email cadastrado pelo visitante e enviaria um email usando a classe PHPMailer para um email de assinatura de uma lsta de discussão.

    Estava navegnado pelos hooks para tentar identificar qual seria o melhor gancho para isso, achei o register_form ou o user_register

    Mas minha dúda alem de saber como identificar o melhor hook para os diversos casos, como pegar o email previamente cadastrado?

    depois vou aperfeiçoar o plugin, fazendo uma aba no admin do WP para que seja possível informar quel o email que irá receber o registro e tal.

    Pode ma ajudar a sanar minhas dúvidas?

    abraços.

  12. Gerson,

    Procure no código fonte onde o hook é disparado e veja quais objetos estao disponiveis, ou veja se existe uma funçao que busque estes dados.
    Nem sempre é facil, mas já é um caminho para começar.

  13. Fala Rafael, blz?

    Cara, consegui fazer o plugin, ainda que basico, seguinda a propria documentação do WP…

    tentei usar o add_filter da forma como estava aqui na suas explicações e deu vários erros..

    mudei para add_filter(“filtro”, “função/metodo”);

    e funcionou sem o uso de array e tal….

    mas é isso. com tempo vou melhorar ele e posto aqui as dificuldades e o que foi aprendido..

    compartilhar.

    abraços.

  14. Gerson,

    O array é apenas usado se vc for chamar uma método de um objeto, se for chamar uma função é só botar o nome. Verifique “callbacks” no manual do PHP.

    • é terrível cara… se a pessoa não programa utilizando o conceito de MVC, o código fica tão ruim que inviabiliza qualquer futura alteração….

      • Desculpe Felipe, mas MVC não é o unico padrão existente no escopo de programação de sistemas, plugins do WP podem não ser a coisa mais organizada do mundo, mas podem usar muitos outros padrões.

  15. Fala rafael tudo bom ?
    muito seu material sobre desenvolvimento de plugins!!
    bem ve se vc pode me ajudar com uma coisa,(sei que nao tem haver com o post entao pode apagar se preferir) eu criei 3 cartegorias, sendo que a primeira e a mãe(nao contem post) e as duas restantes sao filhas (contem post), crie a pagina cartegory.php pra quando clicar na categoria mãe, apresentar as informacoes sobre os posts, mas gostaria de apresentar o resultado ordenado por categoria e nao em ordem cronologica, utilizei a seguinte funcao :
    query_posts(”{$query_string}&orderby=category”) antes do have_post(). mas nao obtive sucesso =(
    vc teria alguma dica pra resolver esse meu problema?
    http://www.periclessantana.com.br/arq/query.jpg esse e o link do print do codigo, caso vc ou alguem queira da uma ajuda.
    Agradeço desde ja
    [ ]‘s
    Cordialmente Romulo

  16. Muito bom o tuto. Tive a necessidade de fazer um plugin para wordpress sem qualquer experiência nisso. Baseado no seu guia eu consegui realizar. Em breve vou disponibilizar o plugin no site do wordpress, espero ajudar a comunidade. É um plugin de pesquisa (parecido com o wp-surveys), porém mais flexível.
    Um abraço a todos.

  17. Boa Tarde Rafael,

    Excelente tutorial, ajudou muito no desenvolvinmento do meu primeiro plugin!

    Vê se você pode me dar mais uma ajuda: eu preciso exibir o resultado da busca que o plugin faz na base de dados em uma página que eu o usuário criar (já vi que os plugins que usam este recurso fazem isso usando o nome do plugin entre colchetes dentro da página, ex.: [contactform] / [newsletter] ), vocÊ sabe me dizer como posso fazer isso?

    Grato,

    Andre

    • Isso aí vc faz com os shortcodes.

      no functions.php vc cria:
      add_shortcode('contactform',funcao_formcontato);
      function funcao_formcontato() {
      $atalho = 'Ei! Este texto vai substituir um atalho!';
      return $atalho;
      }

      Essa é a forma mais básica. Onde vc inserir [contactform], o WP vai substituir por "Ei! Este texto vai substituir um atalho!".

  18. Andre,

    Isso é o recurso mais usado mesmo, a nao ser que vá mostrar o reslutado em um widget.
    Para fazer isso é simples, use o hook de post_content, acho que é esse, verifique, e use um comando str_replace substituindo o texto nos colchetes pelo conteudo da sua busca.

    Abraço

  19. Olá Rafael,

    Favor desconsiderar o email que lhe enviei! Achei a solução neste mesmo artigo seu, trocando o loop de while para foreach e o script funcionou perfeitamente!

    Continuarei acompanhando seu blog, que traz um excelente trabalho!

    Abçs

    Andre

  20. Parabéns pelo texto …
    Simplesmente surpeendente a organização, conteúdo e empenho.
    Sucesso..

  21. Obrigado pelo tutorial. Aquela televisão/monitor de 22′ que vc quer, está indisponível no site, portanto terei que achar outra coisa.

    Abraço.

  22. Gostei do artigo, mas uma coisa que eu quero aprender eu acabei não aprendendo, como eu faço para que meu plug-in seja carregado no lugar do conteúdo do site?

    Pois eu quero integrar o conteúdo que o plug-in gera no WordPress, pretendo fazer um site de downloads integrado com o blog, já está até pronto, mas aparece o meu conteúdo (do plug-in) e logo abaixo o conteúdo da homepage do do próprio WordPress.

    Bom, é isso, eu quero desativar o conteúdo principal a partir de um IF, mas não sei como fazer isso.

    Obrigado pelo artigo, me ajudou muito, mas ainda falta este "detalhe" pra mim terminar.

    • Se eu entendi bem, você quer que o conteúdo do seu plugin seja exibido na página principal ao invés do próprio conteúdo do WP. É isso?
      Se for isso é fácil!
      Vá em Settings > Reading (acho que é essa a opção).
      Lá tem uma opção para você alterar a página principal e a página de posts.
      Basta selecionar para página principal a página com o conteúdo do seu plugin.

  23. Gostei do artigo, mas uma coisa que eu quero aprender eu acabei não aprendendo, como eu faço para que meu plug-in seja carregado no lugar do conteúdo do site?
    Pois eu quero integrar o conteúdo que o plug-in fera no WordPress, pretendo fazer um site de downloads integrado com o blog, já está até pronto, mas aparece o meu conteúdo (do plug-in) e logo abaixo o conteúdo da homepage do do próprio WordPress.
    Bom, é isso, eu quero desativar o conteúdo principal a partir de um IF, mas não sei como fazer isso.

    Obrigado pelo artigo, me ajudou muito, mas ainda falta este “detalhe” pra mim terminar.

  24. Pronto!!! Não é mais necessário, eu desativei no tema!
    Já que meu plug-in só funciona junto com o tema, crie umas variáveis para eles interagirem entre sí e deu certo!!!
    Muito obrigado pelo post e parabéns!!! ;-)

  25. Caro Rafael:
    Já lhe enviei uma mensagem pelo seu Blog, mas como o computador pendurou, não sei se recebeu a mesma.
    Vamos ao que interessa, instalei o “meuprimeiroplugin” sem problemas, mas quando vou Menu de Administrador e clico em “Opções / meuprimeiroplugin” recebo o seguinte erro:

    “Fatal error: Class ‘FileReader’ not found in /home/ruimacd1/public_html/wordpress/wp-content/plugins/meuprimeiroplugin/meuprimeiroplugin.php on line 125″

    Pode-me ajudar com o presente erro?

    Já agora, tenho um PlugIn que queria desenvolver, gostava de saber se está interessado em fazê-lo, eu Pago! Se estiver interessado ou souber de alguém que está interessado por favor contactem-me através do meu email.

    Rui Macdonald

  26. Ok! Já funciona!

    No meuprimeiroplugin.php logo depois dos cometários iniciais inclui:

    include(ABSPATH . ‘wp-includes/streams.php’);

    E passou funcionar.

    Segundo li, é devido à Class FileReader não ser standard agora no WordPress.

    Fiquem Bem!

    Rui Macdonald

  27. Cara, muito bom mesmo, simplesmente nunca vi um tutorial tão completo, explicativo e com inovações como este.
    Atenção especial para o ‘ON DUPLICATE KEY UPDATE’, que particularmente não conhecia e é de grande importância no desenvolvimento.

    Parabéns!

  28. No caso do erro relatado pelo Rui McDonald, e depois dado solução por ele mesmo, no meu caso não funciona pois não existe o arquivo stream.php no WPMU. O que fazer?

  29. Olá Rafael,

    Olha eu aí de novo! O meu plugin cria tabelas próprias na rotina de instalação e elimina essas tabelas na rotina de desinstalação, então quando o plugin tiver uma atualização as tabelas serão apagadas e recriadas? Ou o wordpress reconhece que é uma atualização e não executa a rotina de desinstalação?

    Estou querendo lançar minha primeira atualização, mas estou com receio devido a essa questão.

    Grato,

    André

  30. "O ideal é que seu plugin caiba dentro de um arquivo só"
    Eu discorto 200% disso que foi dito….

    Peguei um sistema wordpress com um plugin X instalado precisando de modificação. Me deparei com o código mais porco que já vi na minha vida!

    Nota mental: "Nunca mais aceitar trabalhos que envolvam desenvolver algo pra wordpress"…

      • Novamente,

        Este post foi escrito a mais de 3 anos quando o sistema de plugins do WP era infelizmente horrivel e muitas vezes impossivel de se trabalhar. Neste caso a arquitetura nao se beneficiava de OO e era muito mais facil gerenciar seu plugin em um arquivo só.

        Isso não é mais o caso, mas MVC é apenas um padrão de projeto, existem muitos outros mais adequados, de acordo com o tamanho e complexidade do seu plugin. MVC seria muito para plugins simples, mas pode sim ser a solução para plugins mais complexos que realmente alterem vastamente o funcionamento do site em WP.

        Obrigado

  31. Rafael muito bom o teu post, mas queria pedir para ti dar uma atualizada nele com relação a classe FileReader, pelo que pesquisei ela não existe mais e como eu sou novato no assunto não tenho base para resolver esse problema, poderias me ajudar a resolver esse problema para mim poder testar o plugin?

    Abraços
    Adonai

  32. Cara, estou vendo os preguiçosos de plantão ai em cima reclamando e descordando, a verdade é uma só, o seu trabalho já está ótimo só pela vontade de compartilhar algo útil e muito bem explicado, quando procuramos no Google programação para plugins WordPress, tudo que encontramos são alguns amebas ensinando a subir um plugin para escrever na tela o famoso "Olá Mundo" que não serve pra nada rsrs, deixo aqui os meus parabéns pela iniciativa, independente da linguajem qualidade ou funcionalidade, só podemos aprender com quem compartilha, então continue, pessoas como eu sempre irão ser gratas.

  33. Boas dicas para desenvolvimento de plugins! Já consegui fazer um plugin básico com essas informações. Parabéns.

  34. Olá Pessoal, tudo bem ?

    Estamos precisando de programadores para fazer plugins wordpress para nossa empresa, interessados, favor entrar em contato blog"arroba"andersonferro.com.br

    Abraço,

    Anderson Ferro

  35. Tive o mesmo problema com o a classe FileReader e consegui resolver.

    Primeiro é preciso o include antes da classe meuPrimeiroPlugin ser definica.
    include($_SERVER['DOCUMENT_ROOT'] . "/wp-includes/pomo/streams.php");

    Veja abaixo como fica o código corrigido e comentado.

    //Ler arquivo de template usando funções do WP
    # A classe FileReader não existe, substitui pela classe POMO_FileReader.
    //$admTplObj = new FileReader(meuPrimeiroPlugin::$info['plugin_fpath']."/admin_tpl.htm");
    //$admTpl = $admTplObj->read($admTplObj->_length);
    # Aqui uso a classe POMO_FileReader em vez da classe FileReader. Precisei fazer algumas
    # mudancas no codigo para usar esta classe.
    $admTplObj = new POMO_FileReader(meuPrimeiroPlugin::$info['plugin_fpath']."/admin_tpl.htm");
    $admTpl = $admTplObj->read_all();

    Qualquer dúvida podem me contactar no site: http://www.jorgerodrigues.com.br

    Espero ter ajudado.

  36. Olá!

    estou procurando um plugin para cadastramento de usuario na plataforma wordpress com as seguintes funções:

    - plugin parecido com o PassExpire, mas que dê diversas opções de tempo de acesso para cada usuario ou grupo cadastrado ( 5, 10, 15, 20, 30, 60, 120, 250, 365)
    - o plugin tem que bloquear o acesso multiplo
    Prevent Multiple People Logging Into a Single Account
    ( impedir que varias pessoas usem o mesmo login senha )
    - quando o usuário logar, recebe um aviso ( editavel ) que a sua senha vai expirar em determinado tempo (uma janela pop-up aparecesse ao usuario toda vez que ele efetuasse login no site, informando o tempo (em dias) que lhe resta tipo:

    "bom dia Sr João
    seu login de acesso para este site expira em 15 dias…" )

    - no painel de controle deste plugin, o administrador pode visualizar quantos usuarios estão cadastrados, seus repectivos nomes, emails, data do 1º acesso e tempo em dias quando a senha de acesso de cada um vai expirar exemplo:

    nº d usuarios nomes email data do 1º acesso senha expira em
    001 josé picanço jose@uni.com 15/06/2012 20 dias
    002 alana maciel aln@box.com 20/03/2012 60 dias
    003 carlos aver cal@der.com 13/01/2012 30 dias
    total: 03

    opcional:
    - o plugin deve registrar até 4 endereços de IPS diferentes para cada usuario (pessoas q podem acessar d diferentes equipamentos: do trabalho, de casa, da escola etc…) , passando disso, deve enviar uma mensagem automatica, alertando que o login e senha do usuario é d uso pessoal e individual e q nao pode ser compartilhado, com risco de bloquear o acesso ao site.

  37. Ola Rafael,

    Obrigada pelo tutorial.
    Até agora nao sei que funciona pois estou empacada nos:
    register_activation_hook($mppPluginFile,array('meuPrimeiroPlugin','instalar'));
    e/** Funcao de inicializacao */
    add_filter('init', array('meuPrimeiroPlugin','inicializar'));

    Apesar de que coloquei o nome do desejado plugin 'naira_converter'

    Também seguindo as instruçoes do WordPress tutorial me deparo com o mesmo problema.

    Estou entrando pela primeira vez nesta tentativa e adoraria poder resolver.
    Vou continuar pesquisando no Google, etc..

    Obrigada
    Naira

    • Oi Rafael,

      Desculpe ter lhe incomodado com o comentario acima.
      A questao já está resolvida.
      No browser diz que é um 'undefined call function" mas dentro do WP o funcionamento está ótimo.

      Obrigada

      abraço

      Naira

  38. Cara, obrigado por todo tempo despreendido nesse artigo! Não li ainda mas me parece excelente e já lhe agradeço.

    Grande abraço, parabéns pela humildade em ensinar.

  39. Legal parabéns ! eu só não compreendi por que você usou meuPrimeiroPlugin::$wpdb !

    mas muito bom parabéns !

    • Flavio, em que sentido?

      No caso este artigo é bem velho e precisa ser re-visto, mas naquela epoca a solução para ter o $wpdb era sempre usar 'global' que eu nao recomendo, desta forma o que fiz foi armazenar ele numa variável e fazer da minha classe um Registry, tendo sempre uma fonte unica para usar o $wpdb.

  40. Olá ainda estou lendo mais achei um link quebrado no $wpdb para nós visualizarmos as suas funções etc… Abraços… por enquanto estou supreendido mt bom!

  41. Oi, Vc pode criar um pluglin para transportadora???
    Que eu crio uma tabela de peso e preço, por região.

    Meu telefone 41-3209-9793 – Paulo

Comments are closed.

4ª Edição da PHP Magazine, e artigo sobre AJAX

Finalmente saiu a 4ª edição da PHP Magazine, prometida para agosto de 2007. Pelo que aparenta o projeto ganhou novo gás, lançando esta edição e anunciando que muitas mudanças estão por vir.

Nesta edição sai também meu artigo PHP e AJAX I: conhecendo o AJAX, que descreve o AJAX, como aprender e realiza um exemplo simples de como criar uma aplicação em AJAX sem o uso de nenhum framework. Este material é complemento da minha palestra, dada no PHP Conference 2007: PHP e AJAX: do Request ao Framework, e em breve deve abrir caminho para o segundo artigo da série que entrará em maiores detalhes sobre frameworks e uso avançado de AJAX.

Então visitem o site da PHP magazine e façam agora o download. Dentre os outros artigos temos “Gerando planilhas em Excel com PHP-GTK” escrito pelo Pablo Dall’Oglio (cuju livro devo publicar uma análise aqui no blog) e “Ataque de sobrecarga utilizando utilizando SMTP Injection. O que é, como é e como se prevenir” por Ricardo Striquer Soares.

One thought on “4ª Edição da PHP Magazine, e artigo sobre AJAX

Comments are closed.