Sie sind auf Seite 1von 7

Desenvolvendo plugins para WordPress

by Rafael Dohms DohmsMarch 10, 2008 2008Pessoal/OffPessoal/Off-topic


Uma pea chave do sucesso do WordPress justamente sua capacidade de aceitar plugins e widgets, alm , claro, dos milhares de programadores que desenvolvem os mais diversos plugins que fazem de tudo um pouco.
2

Algum tempo atrs fui abordado pelo Manoel Lemos do BlogBlogs para discutirmos uma misso, criar um plugin para o WordPress, baseado na API do site. Comecei entao minha saga atrs de como desenvolver um plugin. O material estava l, espalhado em vrios sites, mas estava l. Ento agora com o sucesso do BBUinfo e na vspera de novos projetos, decidi tentar consolidar este conhecimento adquirido e focar ele no pblico brasileiro. Vou procurar mostrar o caminho das pedras de como comear e onde buscar os dados necessrio para integrar seu cdigo 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 so a minha recomendao de como desenvolver um plugin, e evitar maiores problemas e dificuldades. Para poder acompanhar melhor o cdigo produzido, vou estar criando com vocs o meuPrimeiroPlugin, que ser descrito passo a passo abaixo. Passo 1: Planejamento No desenvolvimento de qualquer sistema o primeiro passo deve sempre ser uma anlise e planejamento do que ser feito, com plugins, embora pequenos, isto se mantm.Como em sistemas importante identificar neste momento o que se deseja fazer, qual o objetivo do plugin. Levantar entradas e sadas, 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 necessrios.Faa perguntas como: Preciso de um banco de dados? Preciso acessar dados externos por webservice ou uma API? Vou mostrar algo visual para o usurio? O que pretendo fazer? Qual o nome darei ao plugin?(se voc consegue definir o nome, sabe o que quer)

Um bom exerccio para este momento utilizar o padro de arquivo readme do WP e j iniciar a escrita da descrio 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 aes bsicas e didticas, mas sem muito uso. Para mostrar todos os limites, o plugin far as seguintes aes: 1. Acrescentar ao final de cada comentrio o texto: O contedo deste comentrio 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 (idias para o plugin):

Produtos desta etapa Arquivo readme.txt, arquivo com brainstorm (tente um mindmap, como acima) Passo 2: Projeto Esta etapa segue os padres de projetos de sistema, mas com algumas adies especficas do WordPress. Como base sugiro que use a linguagem UML para definir seu projeto e faa um diagrama de MER (base de dados). Embora no seja obrigatrio, a criao do plugin como um objeto, recomendvel e mais fcil de manter do que cdigo estruturado, alm claro de ser uma prtica recomendada para o PHP5. Outra grande vantagem nesta orientao que como os mtodos so chamados de dentro do

http://blog.doh.ms/2008/03/10/desenvolvendo-plugins-para-wordpress/?lang=pt-br

objeto a preocupao com nomes coincidentes nula, sendo reduzida apenas ao nome do objeto que deve ser nico. Ento defina o seu objeto com mtodos que se identifiquem com as diversas aes que o plugin vai executar, por exemplo: adicionarAssinatura(), pegarDadosExternos(), salvarDados() Agora entra o ponto onde o WordPress traz toda sua mgica com os seus hooks, ou ganchos.

Ganchos do WordPress
Para facilitar que se ligue o plugin s aes doWP, so definidos ganchos em sua programao, ou seja, em pontos especficos do funcionamento do plugin, so disponibilizados pontos onde as funes podem se pendurar. Desta forma caso deseje criar um plugin, que deve executar determinada funo no momento em que um comentrio salvo, voc usaria o gancho comment_post. Estes ganchos so divididos em 2, aes e filtros. Aes so eventos disparados em momentos exatos durante a execuo do WordPress. Filtros so lanados no momento de gravao ou apresentao de um texto para que seja possvel modific-lo. Outros Links: Todos Hooks de todas verses do WP Para definir os ganchos voc pode se perguntar Em que momento devo fazer isso? para cada ao e ento verificar a lista de ganchos de aes e filtros para achar qual lhe atende.

meuPrimeiroPlugin
Neste caso podemos usar os seguintes pontos para anexar nossas funes: 1. Instalar: ligada ao register_activation_hook register_activation_hook que executado na ativao de um plugin no menu 2. Desinstalar: Estas funes foram bastante discutidas, mas ainda no existe um hook fixo. 3. Inicializar: Esta deve ser executada logo no incio, para isso temos o filtro init init 4. Aba de opes: para fazer a aba precisamos de dois pontos, a ao admin_menu e o add_options_page add_options_page. 5. Contar Visita: poderia ser melhor,mas o filtro the_content the_content garante a contagem na hora mais certa. 6. Inserir texto no comentrio: Para isso o filtro get_comment_text get_comment_text perfeito 7. Substituir palavras: este bem direto tambm, vamos usar o filtro the_content the_content Juntamente com este raciocnio, fiz o mapeamento da classe e do que seria necessrio na base de dados: Diagrama de classe do plugin

MER do Banco

http://blog.doh.ms/2008/03/10/desenvolvendo-plugins-para-wordpress/?lang=pt-br

Produtos desta etapa: diagrama de classe do seu plugin, um MER do banco de dados e uma lista de possveis pontos de insero (ganchos). Passo 3: Desenvolvendo Com o caminho a sua frente devidamente mapeado, agora podemos nos aprofundar no cdigo, alm 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 no seja possvel, recomenda-se que todos arquivos sejam jogados dentro de uma pasta com o mesmo nome do plugin. O nome do plugin tambm pode (recomenda-se) ser o nome de seu arquivo principal, isso ir lhe facilitar usar funes on activation disparadas na ativao do plugin. Portanto teremos a seguinte estrutura para nosso exemplo:

A primeira coisa que deve aparecer em nosso arquivo meuPrimeiroPlugin.php o cabealho. Este cabealho usado pelo WP para mostrar os dados de seu plugin na pgina de administrao de plugins, ento muito importante manter estes dados corretos, o cabealho segue o padro abaixo: 1 2 3 4 5 6 7 8 /* Plugin Name: Nome do Plugin Plugin URI: http://Endereo_da_pagina Description: Descrio simples e curta do plugin Version: A verso atual do plugin, ex.: 1.0 Author: Nome do Autor do Plugin Author URI: http://Endereo_do_site_do_autor */

Aps isso podemos comear a definir a classe. A definio segue o padro normal de um objeto em PHP (4 ou 5). Aqui vamos seguir uma orientao PHP5 por sua enorme vantagem e pelo fim do PHP O site do WP possui muito material sobre padres de codificao, e eu recomendo uma leitura, mas so padres 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 funes que precisamos desenvolver em nosso plugin, portanto a seguir vou seguir passo a passo deste arquivos criando e explicando cada uma destas funes, e no final comentarei sobre os ganchos que sero colocados fora do escopo do objeto e porque. Funo Inicializar Esta funo serve para centralizar todas as aes que devem ser sempre tomadas para integrar o plugin com o WP, sejam elas aes de adio/remoo de filtros/aes ou instanciao de objetos, cpias de variveis globais, enfim, todas aes que sero executadas sempre que o WP carregar. 1 2 3 4 5 6 7 8 9 public static global $wpdb; function inicializar(){

//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'));

http://blog.doh.ms/2008/03/10/desenvolvendo-plugins-para-wordpress/?lang=pt-br

10 11 12 13 14 15 16

//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 funes com seus devidos filtros, ou seja, os ganchos que iro 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 incio da funo. Alm disso aproveita-se para obter a localizao do plugin, usando a constante __FILE__ do PHP que define o caminho at o arquivo onde esta. $wpdb Este objeto sempre presente no WordPress responsvel pela sua conexo com a base de dados, ele pode executar queries, buscar dados, e realizar diversas funes relacionadas a base de dados. Veja aqui a lista de mtodos [aqui] Funo Instalar Esta funo mapeada para ser executada no momento que o plugin ativado na aba de plugins do WordPress. Como nosso plugin utiliza dados que sero salvos e lidos de bases de dados necessrio que elas sejam criadas antes de seu uso, o momento de ativao excelente para isso, porm o plugin pode ser ativado e desativado diversas vezes (quando se faz upgrade do WordPress por exemplo) e no podemos simplesmente criar a tabela sempre, por isso observe o comando para criar apenas caso no exista. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 opes add_option("mpp_texto_exonerar","O contedo deste comentrio de responsabilidade de: "); }

Neste caso, de forma puramente didtica, criei uma opo para armazenar o texto que ser inserido nos comentrios. Esta opo foi criada apenas para mostrar como elas podem ser utilizadas. Estas opes so gravadas na tabela de opes do prprio WordPress e acessadas com estes mtodos: add_option, update_option, delete_option, get_option. Note que no nicio da funo chamo a funo de inicializao, isso importante pois no ato em que a funo de instalao chamada o gancho init ainda no foi chamado e por isso no temos nossa conexo com o banco por exemplo. Isto causaria erros na ativao do plugin. Dica: Se voc receber um aviso cannot redeclare class na ativao do plugin, 9 em 10 vezes o erro no esta na declarao do plugin e sim omitido pelo WordPress, em sua funo 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: 1 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();

Funo Desinstalar Esta funo no possui um hook para ser executada de forma automtica, mas uma funo que recebeu muita ateno nos ltimos tempos em diversas discusses pela internet. Nossa aba de opes deve implementar uma chamada a esta funo, mas em breve o WordPress deve implementar um hook para ela.

http://blog.doh.ms/2008/03/10/desenvolvendo-plugins-para-wordpress/?lang=pt-br

Sua funo bem direta e simples, remover tudo que foi criado pela funo de instalao. Por isso no possvel ligar ela ao ato de desativar o plugin, pois o usurio perderia suas preferncias a cada vez que fizesse upgrade do WordPress ( recomendado que se desative os plugins para tal). 1 2 3 4 5 6 7 8 9 10 11 12 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 opes delete_option("mpp_texto_exonerar"); }

Como podemos ver apenas feito um DROP nas tabelas e a remoo da opo que foi criada na prpria tabela do WordPress. Funo adicionarMenu Esta funo indica ao WordPress que ao montar o menu da administrao ele deve inserir uma nova aba que aponta para uma funo de nosso plugin. 1 2 3 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, [funo]);


O nvel de acesso diz respeito as permisses do usurio, o arquivo o arquivo de nosso plugin (__FILE__) e a funo a funo de nossa classe em formato de call_user_func Funo abaOpcoes Esta funo a que setamos no exemplo anterior para ser executada quando o usurio clicar na nossa aba do menu. menu Neste caso fiz uma implementao simplificada, onde uma mesma funo mostra o menu e executa as operaes de salvar e atualizar as opes. Para salvar as opes fazemos inseres usando novamente o $wpdb->query(). Esta operao executada sempre que o array de POST (dados enviados pelo form) possuir algum contedo. Para mostrar o formulrio utilizei uma implementao simplificada de templates, onde tenho um arquivo .tpl externo com o layout do menu e chaves especiais ({PALAVRAS},{STATS}) que so substitudas pelo contedo que quero gerar. Voc pode usar outra tcnica e at usar cdigo espageti com HTML no meio de seu plugin, depende da sua facilidade e organizao. Para gerar o contedo dinmico, fao diversas queries no banco buscando os dados que so necessrios. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public static function abaOpcoes(){ //Predefinidos $templateVars['{UPDATED}'] = ""; $templateVars['{ERROS}'] = ""; //Executar operaes 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 funes do WP $admTplObj = new FileReader(meuPrimeiroPlugin::$info ['plugin_fpath']."/admin_tpl.htm"); $admTpl = $admTplObj->read($admTplObj->_length); //pegar palavras

http://blog.doh.ms/2008/03/10/desenvolvendo-plugins-para-wordpress/?lang=pt-br

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

$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 variveis 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 preferncia de se utilizar ela ao invs de utilizar funes como fopen ou similares. importante lembrar que o WordPress possui diversas classes disponveis em suas pastas, pastas e uma boa idia ver se existe alguma para executar a operao que voc procura. Funo contarVisita Como foi dito esta funo convocada pelo gancho the_content sempre que o contedo de um post for resgatado do banco para exibio. Ento para fazer uma simples contagem de visualizaes de um post, sem entrar em muitos detalhes, filtros por IP nem nada do tipo, apenas fazemos uma insero no banco, em nossa tabela de contagem. 1 2 3 4 5 6 7 8 9 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 funo recebe um parmetro que chamei de $post_texto. Sempre que uma funo usa o gancho the_content ela receber o contedo do post como parmetro. parmetro Ao final da funo este contedo, alterado ou no, deve ser retornado com uma chamada return, return caso contrrio o blog no exibir o contedo 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 atualizao do mesmo, caso contrrio cria o novo registro. Ela bem til para no ser necessrio fazer um select para decidir se devemos usar um INSERT ou UPDATE. Funo processarSubstituicao Esta funo, tambm ligada ao the_content efetua a troca das palavras que cadastrarmos, por outras que forem escolhidas. interessante notar que podemos ter vrias funes ligadas a um mesmo gancho e elas sero executadas na ordem que os ganchos so designados, por isso a importncia ressaltada na funo anterior, onde o parmetro deve ser retornado no final. Para fazer a substituio usei um mtodo simples tambm, busquei no banco os pares (palavra original => nova palavra) e montei um array de traduo. Usando a funo strtr do PHP eu passo este array e o texto do post e a funo se encarrega de fazer a troca e me devolver o texto alterado. 1 2 3 4 5 6 7 8 9 10 11 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);

http://blog.doh.ms/2008/03/10/desenvolvendo-plugins-para-wordpress/?lang=pt-br

12 13

return $post_texto; }

Funo exonerarComentarios Finalmente esta funo ser a responsvel por incluir um texto ao final do comentrio 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 comentrio. 1 2 3 4 5 6 7 8 9 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 parmetro e devemos retornar ele ao final para evitar quebrar outros plugins ou ocultar comentrios . Nota: Quando desenvolvi meu primeiro plugin de WordPress, usei o gancho get_comment_ID e no fiz o retorno do meu parmetro ao final. Resultado, todos plugins executados aps este quebravam, pois no recebiam um ID e sim uma string vazia. Usando o contexto global, a varivel $comment um objeto que representa todos os dados do comentrio atual, por isso como pode ser visto acima, posso acessar o nome do autor, para agreg -lo mensagem, que foi buscada da tabela de opes pela chamada get_option. Ao final tudo isso concatenado ao texto no comentrio que segue em frente para outros plugins, ou simplesmente mostrado. Cdigo remanescente Para inicializar nosso plugin o cdigo 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 no executado sem sua instanciao. 1 2 3 4 5 $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 execuo da funo instalar na ativao do plugin e da init na inicializao do WordPress. Para o gancho de ativao definimos a varivel $mppPluginFile que determina a pasta onde o plugin esta, e para isso o plugin deve estar em uma sub-pasta de plugin e no na raiz. Com esta combinao de funes e as constantes DIRECTORY_SEPARATOR (barra invertida ou no), e o __FILE__, saimos com algo como mpp/meuprimeiroplugin.php ou seja, pasta e arquivo necessrios para a deteco de ativao. Divulgando seu plugin Para divulgar seu plugin o primeiro e mais importante passo adicionar ele no repositrio do WordPress. Isso uma excelente ferramenta, pois alm de fornecer um repositrio SVN que pode lehe ajudar a melhor controlar seu desenvolvimento ele permite que o usurio de seu plugin possa ser notificado de novas verses diretamente na pgina de plugins. Divulgue o seu plugin no repositrio oficial do WordPress: http://wordpress.org/extend/plugins/ usando o link http://wordpress.org/extend/plugins/add/. A nica exigncia que o plugin deve ser licenciado como GPL (detalhes) Concluso Espero que com este artigo (que atrasou mais do que devia) muitos usurios de WordPress e desenvolvedores da comunidade possam embarcar no desenvolvimento de novos plugins e que todos tenham uma noo do poder que o blog oferece permitindo tamanha integrao de forma to simplificada e acessvel. 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 alm da carinha nova da administrao, no haver impactos no processo descrito acima, e inclusive este exemplo j funciona na nova verso e foi testado aqui com ela. Download o meuPrimeiroPlugin

http://blog.doh.ms/2008/03/10/desenvolvendo-plugins-para-wordpress/?lang=pt-br