Lançámos hoje uma nova versão do nosso plugin de Contadores Sociais. Depois do grande sucesso das versões anteriores quisemos brindar, a par com o novo layout, com uma nova versão do nosso estimado plugin social. O Contadores Sociais é um plugin que lhe dará a possibilidade de colocar um widget no seu blog mostrando os contadores das suas redes sociais favoritas, como temos aqui nas Escolas. Esta nova versão do plugin proporciona melhoramentos ao nível da performance e do período de latência no acesso às API através da forma como as API são chamadas e guardadas em cache.

Além disso nessa nova versão incluimos um atualizador automático para o plugin, inaugurando o nosso novo repositório de plugins oficial da Escola WordPress, o que indica que novos plugins serão criados e atualizar esses plugins está ao alcance de um clique no seu blog WordPress.

contadores sociais

Poderá fazer o download gratuito do nosso plugin aqui: Plugin de Contadores Sociais

Como seria de esperar, deixamos aqui para si o nosso artigo para poder criar o seu próprio repositório alternativo de plugins para WordPress, seja para distribui-los mais facilmente ou para usar e distribuir atualizações dos seus plugins premium pagos.

CRIANDO UM REPOSITÓRIO DE PLUGINS

O sistema de atualização de plugins nativo do WordPress foi introduzido em 2007. Com este incremento, o WordPress passou a dotar de um sistema de atualizações automáticas, como muitos outros softwares o têm hoje em dia. A dashboard passou a mostrar notificações de novas versões tanto para a core como para plugins e temas alojados no diretório WordPress.org.

Para um plugin poder usufruir do sistema de notificações e atualizações automáticas que o WordPress providencia, necessita de estar alojado no diretório oficial de plugins do WordPress. Para se colocar lá um novo plugin, é necessário seguir algumas regras importantes tais como:

  • A licensa escolhida para o seu plugin deve ser GPL ou compatível (qualquer plugin tem de ser GPL na verdade, devido à licença usada pelo WordPress).
  • Deve ser open source (código-fonte aberto).
  • Deve haver uma política de gratuítidade para o seu plugin (a própria licensa GPL já o permite).

Essas três principais imposições excluiram muitos plugins do diretório, como por exemplo o famoso Gravity Forms, pois este para se obter é pago, no entanto a sua licensa GPL permite que você, após a compra, o redistribua e modifique gratuitamente. Um dos outros exemplos de exclusão foi o famoso plugin de traduções WPML. A ideia inicial foi de distribuir um plugin totalmente gratuito, cobrando apenas por traduções requesitadas à empresa que promovia o próprio plugin. Até aí não houve nenhum problema, no entanto o autor começou a cobrar pelo uso do plugin a todos os que faziam o download do plugin, através da introdução de uma chave-licensa comprada no site. Desta forma, não durou muito para que o plugin fosse excluido do diretório e o autor teve que criar um sistema de atualização próprio para “sobreviver” ao mercado. Muitos outros exemplos de exclusão como os plugins do WPMU e o Wygita Newsletter poderão estar para breve levando a que os autores criem novamente outros métodos de atualização automática que apenas criam entropia na interface do WordPress.

Como é possível ver, a maior parte dos plugins pagos usam o seu próprio sistema de atualizações automáticas à margem do sistema nativo do WordPress. Esse conceito, na minha opinião, é errado e é um modelo que não deve ser seguido pois um sistema de atualizações automáticas já existe nativamente e, imagine-se, é possível agregar-lhe outros diretórios externos para além do WordPress.org através de action Hooks, você sabia disso?

A primeira vez que tive conhecimento desta possibilidade foi quando, ao averiguar o código-fonte da função plugins_api() descobri que existiam vários filtros. Um particularmente saltou-me a atenção e é com esse que vamos trabalhar para criarmos o nosso próprio repositório de plugins para distribuirmos mais facilmente atualizações aos plugins que criamos, sem que estes estejam alojados no WordPress.org.

SISTEMA DE UPGRADE DE PLUGINS

Duas vezes por dia, o WordPress analisa no repositório se os plugins que tem instalados têm uma nova versão. A API do lado do repositório do WordPress.org analisa a informação e envia as informações de novos plugins instalados com as suas novas versões respetivamente. Por exemplo, a API do repositório de plugins http://api.wordpress.org/plugins/update-check/1.0/ poderia ser pesquisada com o seguinte pedido:

<?php

// Enviamos informação em forma de array serializado
// para que a API responda corretamente

$request = array(
  'plugins' => array(
    'plugin-exemplo/plugin-exemplo.php' => array(
      'Name' => 'Plugin Exemplo',
      'PluginURI' => 'http://www.escolawp.com/',
      'Version' => '1.0',
      'Description' => 'Este plugin é um plugin exemplo que não supostamente está alojado no WordPress.org',
      'Author' => 'Escola WordPress',
      'Network' => false,
      'Title' => 'Plugin Exemplo',
    ),
  ),
  'active' => array(
    0 => 'plugin-exemplo/plugin-exemplo.php',
  ),

);

?>

A API do repositório de plugin poderia responder com nova informação:

<?php

// Suposta resposta do api.wordpress.org com uma nova versão do plugin

$response = array(
  'plugin-exemplo/plugin-exemplo.php' => array(
    'id' => 123456,
    'slug' => 'plugin-exemplo',
    'new_version' => '1.1',
    'url' => 'http://wordpress.org/extend/plugins/plugin-exemplo/',
    'package' => 'http://downloads.wordpress.org/plugin/plugin-exemplo.zip'
  ),

);
?>

Em cada 12 horas o seu blog WordPress faz a verificação por novas atualizações e guarda essa informação num transient denominado ‘update_plugins’, que contém a seguinte informação:

  1. ‘last_checked’: o tempo em timestamp da última verificação feita
  2. ‘checked’: a lista de plugins a versão atualmente instalada
  3. ‘response’: a resposta do repositório com a informação das novas versões

Assim, toda a vez que o seu blog verifica por atualizações é desta forma que você é notificado de novas versões.

CRIAR UM REPOSITÓRIO ALTERNATIVO

Como deve se ter apercebido na secção anterior, o sistema de atualizações é bastante fácil de ser modificado por forma a poder incorporar uma nova API a apontar para um repositório mantido por nós. Para isso iremos criar um pequeno plugin que vocês poderá incorporar na sua instalação local para testar o seu novo repositório.

Uma nota explicativa: antes do blog guardar os dados no transient ‘update_plugins’, o filtro ‘pre_set_site_transient_update_plugins’ é accionado. É neste momento que o nosso novo plugin irá verificar por novas atualizações no nosso novo repositório e juntar a essa informação.

<?php

/*
Plugin Name: Plugin Exemplo - Repositório Alternativo
Plugin URI: http://www.escolawp.com/
Description: Este plugin liga a uma API de atualização alternativa
Version: 1.0
Author: Escola WordPress
Author URI: http://www.escolawp.com/
*/ 

define( 'PLUGIN_EXEMPLO_ALT_API', 'http://api.exemplo.com/plugin-api/' );

// Executa a função que irá procurar por atualizações na nossa API
add_filter( 'pre_set_site_transient_update_plugins', 'plugin_exemplo_api_check' );

// Executa a função que irá buscar a informações detalhada do plugin à nossa API
add_filter( 'plugins_api', 'plugin_exemplo_api_information', 10, 3 );

/**
 * Verifica por novas atualizações na nossa API
 * @since 1.0
 */
function plugin_exemplo_api_check( $transient ) {

	// Verifica se o transient já foi atualizado
	// Caso esteja vazio, não há nada a fazer
	if( empty( $transient->checked ) )
		return $transient;

	// O identificador do plugin na API é o seu nome
	// ou seja o diretorio/nome-do-ficheiro.php
	$plugin = plugin_basename( __FILE__ );

	// Vamos construir a informação necessária para
	// chamar o nosso API
	$info = array(
		'action' => 'update-check',
		'plugin_name' => $plugin,
		'version' => $transient->checked[ $plugin ]
	);

	// Envia o pedido de verificação por atualizações à nossa API
	// Usamos a função nativa wp_remote_post() passando-lhe a URL
	// da nossa API e dois parametros:
	// Os argumentos que vão no corpo da mensagem e
	// o pedido timeout de 15 segundos
	$request = wp_remote_post( PLUGIN_EXEMPLO_ALT_API, array( 'body' => $args, 'timeout' => 15 ) );

	// Vamos ver se o pedido foi recebido e devolvido, ou seja, o código
	// HTTP seja 200 e que não haja nenhum erro gerado
	if( is_wp_error( $request ) || wp_remote_retrieve_response_code( $request ) != 200 ) {
		// O pedido falhou e por isso vamos retornar falso
		return false;

	}

	// Como não houve erro, vamos enviar a resposta do pedido em forma
	// objecto, através da função nativa do PHP unserialize()
	// A função do WordPress wp_remote_retrieve_body() retorna apenas o
	// corpo do pedido.
	return @unserialize( wp_remote_retrieve_body( $request ) );

}

/**
 * Retira a informação detalhada do nosso plugin da API
 * @since 1.0
 */
function plugin_exemplo_api_information( $false, $action, $args ) {

	$plugin = plugin_basename( __FILE__ );

	// Vamos verificar se o pedido de informações é relativo a este plugin
	// testando o seu identificador
	if ( $args->slug != $plugin )
		return false;

	// Vamos construir a informação necessária para
	// chamar o nosso API
	$info = array(
		'action' => 'plugin-information',
		'plugin_name' => $plugin,
	);

	$request = wp_remote_post( PLUGIN_EXEMPLO_ALT_API, array( 'body' => $args, 'timeout' => 15 ) );

	if( is_wp_error( $request ) || wp_remote_retrieve_response_code( $request ) != 200 ) {
		// O pedido falhou e por isso vamos retornar falso
		return false;

	}

	return @unserialize( wp_remote_retrieve_body( $request ) );

}

O nosso plugin já se encontra criado, no entanto necessitamos de criar a nossa própria API que irá fornecer as informações ao plugin sempre que pedido. Tenha em nota que esta API é um esboço, um exemplo do que você necessita de criar para poder ter um repositório próprio. Tudo o resto fica para sua criação. Como referência podemos deixar aqui alguns exemplos:

  • Ter um espaço no servidor publico onde são colocados os ficheiros ZIP e a informação de cada plugin introduzida num array
  • Criar um servidor SVN onde seja possível fazer checkout dos próprios plugins, juntando uma rotina que cria um ficheiro ZIP com a última versão tag do plugin
  • Alojar os plugins em repositórios privados do GitHub e criar uma rotina no nosso servidor que acede à API do GitHub extraindo as informações e o próprio ficheiro ZIP do repositório

Vamos por exemplo criar uma API chamada ‘http://api.exemplo.com/plugin-api/’. Esta API muito básica irá gerir apenas dois pedidos, os suficientes para você ter um plugin completamente funcional:

  • Pesquisar por novas versões do plugin através do parametro action=update-check
  • Mostrar a informação detalhada do nosso plugin

Segue o código da nossa API:

<?php

// Vamos limpar e guardar os valores pedidos
$action = strip_tags( $_REQUEST['action'] );
$plugin_name = strip_tags( $_REQUEST['plugin_name'] );

// Vamos criar um novo objeto standard através da classe nativa stdClass
$response = new stdClass;

// Através do switch roteamos os pedidos de acordo com a ação pedida
switch ( $action ) {

	// É pedido à API a existência de uma nova versão
	case 'update-check' :
		$response->slug = $plugin_name;
		$response->new_version = '2.0';
		$response->requires = '3.4';
		$response->tested = '3.4.1';
		$response->url = 'http://www.exemplo.com/meus-plugins/plugin-exemplo';
		$response->package = 'http://downloads.exemplo.com/plugin-exemplo.zip';
		break;

	// É pedido à API que envie informações detalhadas do plugin
	case 'plugin-information' :
		$response->slug = $plugin_name;
		$response->plugin_name = $plugin_name;
		$response->version = '2.0';
		$response->new_version = '2.0';
		$response->author = '<a href="http://www.escolawp.com/">Escola WP</a>';
		$response->homepage = 'http://www.exemplo.com/meus-plugins/plugin-exemplo';
		$response->download_link = 'http://downloads.exemplo.com/plugin-exemplo.zip';
		$response-sections = array(
			'description' => 'Esta é uma pequena descrição',
			'changelog' => 'Esta versão 2.0 é bem melhor!',
			'installation' => 'Para instalar apenas terá que clicar em Atualizar',
			'screenshots' => 'Como estes paineis aceitam HTML, algumas imagens poderiam aparecer aqui',
			'faq' => 'Algumas dúvidas mais frequentes',
		),
		$response->requires = '3.4';
		$response->tested = '3.4.1';
		$response->downloaded = '1234';
		$response->last_updated = '2012-07-30';
		$response->rating = 85;
		$response->num_ratings = 123;
		break;

	default :
		// Se o pedido de ação não se enquadrar enviamos informação
		// de não encontrado por forma a proteger a API de ameaças
		// externas.
		header( "HTTP/1.0 404 Not Found" );
		header( "Status: 404 Not Found" );

}

// Enviamos o resultado serializado
echo serialize( $response );
?>

Este pequeno script gera a informação suficiente para vocês poder usar o sistema de atualizações nativo do WordPress no seu plugin.

REPOSITÓRIO COM PLUGINS PREMIUM

Como o factor chave aqui é informar o WordPress dos seus clientes da localização da nova versão, você poderá apenas fazê-lo caso durante o pedido a chave-licensa do seu cliente seja válida. É tão simples quanto isto. Alterando no código, podemos ter uma versão do plugin que vais buscar a chave-licensa guardada numa opção na tabela do WordPress enviando-a conjuntamente com o pedido de atualização:

// Vamos buscar a chave de licensa à opção
$license_key = get_option( 'plugin_exemplo_license_key' );

// Vamos construir a informação necessária para
// chamar o nosso API
$info = array(
	'action' => 'update-check',
	'plugin_name' => $plugin,
	'version' => $transient->checked[ $plugin ],
	'license_key' => $license_key,
);

Do lado da API vamos testar se a licensa é válida. Na informação do pedido de detalhes você poderá incluir um texto a avisar seus clientes que estes não pussuem uma chave-licensa válida e por isso não poderão atualizar, incluindo instrucções de como obter uma nova chave:

[...]
case 'update-check' :
[...]
$response->url = 'http://www.exemplo.com/meus-plugins/plugin-exemplo';

// Vamos avaliar se a chave de licensa enviada é válida através
// de uma função hipotética:
if ( chave_licensa_valida( strip_tags( $_REQUEST['license_key'] ) ) )
	// Se for válida enviamos o link para download do pacote
	$response->package = 'http://downloads.exemplo.com/plugin-exemplo.zip';

[...]
case 'plugin-information' :
[...]
// Vamos avaliar se a chave de licensa enviada é válida através
// de uma função hipotética:
if ( chave_licensa_valida( strip_tags( $_REQUEST['license_key'] ) ) ) {
	// Se for válida enviamos o link para download
	$response->download_link = 'http://downloads.exemplo.com/plugin-exemplo.zip';

} else {
	// Caso contrário vamos acrescentar aos paineis a informação
	// de que a chave não está válida
	$response-sections['description'] = '<h3>A sua chave de licensa não é válida!</h3>' . $response-sections['description'];

}
[...]

Desta forma você poderá habilitar as atualizações do seu plugin apenas aos clientes que tenham uma chave válida.

PRECAUÇÕES DE UM REPOSITÓRIO PRÓPRIO

A flexibilidade que a API de plugins do WordPress trás, possibilita-nos criar todo o tipo de customizações, incluindo alterar configurações tão profundas como as atualizações automáticas do WordPress. Desta forma, você deverá ter em precaução vários fatores, incluindo:

  • O seu repositório deverá estar sempre acessível por parte dos usuários que usam os seus plugins
  • A informação pessoal dos seus usuários é privada! Você não deve tentar enviar nomes de usuários nem passwords durante as comunicações. Isso poderá ser considerado crime!
  • Quando montar a sua API troque apenas informação relevante. Por exemplo, mantenha uma tabela com o número de downloads, como nós fazemos aqui no nosso repositório da Escola WordPress, mas nunca tente coletar informação que não seja relevante.

Não se esqueça que seu plugin é sempre de código aberto e sendo assim qualquer um poderá ler seu código e se se descobrir informações, seu prestigio estará severamente em causa.

Para os usuários normais, tenha sempre em atenção escolher repositórios oficiais ou com credibilidade, desta forma garante que a sua informação estará segura.

DOWNLOAD DO CÓDIGO DE EXEMPLO

Poderá fazer o download do código de exemplo, clicando no link em baixo.

{filelink=5}

Até breve!