Ordenando posts por page view no WordPress

O WordPress não salva as visualizações (page views) dos posts no banco de dados ou qualquer outra forma, então não há como ordenar os posts pelo número de page views. Mas se você use o Google Analytics para mensurar as estatísticas de acesso do seu blog/site, é possível fazer uma integração simples que permite a ordenação, ou qualquer outra manipulação dos posts que você queira fazer, baseada em page views.

Antes de mais nada, para facilitar a integração, estamos usando algumas classes do Zend Framework. Você pode baixar os arquivos necessários no site oficial do framework: http://framework.zend.com/download/gdata.

Enfim, vamos ao código!

Ah! Importante: estou considerando que tudo isso acontece dentro do functions.php do seu tema, se você usar outro arquivo (um plugin, por exemplo), fique atento às bibliotecas externas — Zend — e caminhos, ok?

Para não sobrecarregar o servidor com chamadas constantes para os serviços do Google e nem depender de algum tipo de gatilho manual, incluí a função que carrega os dados de visualização em uma tarefa do WP Cron.

add_action('ck_ga_hourly', 'ck_ga_pageviews');

function ck_ga_cron()
{
  if ( ! wp_next_scheduled('ck_ga_hourly'))
  {
    wp_schedule_event(time(), 'hourly', 'ck_ga_hourly');
  }
}

add_action('wp', 'chefs_ga_cron');

No trecho abaixo é que, realmente, a mágica acontece. Ah! Um detalhe importante, estou considerando que você fez o download da Google’s Data API do site do Zend Framework e incluiu o conteúdo da pasta library no diretório do seu tema.

Você verá que é necessário configurar 4 variáveis importantes: o e-mail da sua conta no Google Analytics, a senha da sua conta, o nome da sua aplicação (de acordo com a documentação do Google, deve seguir o seguinte padrão companyName-applicationName-versionID) e, finalmente, o ID do perfil do Analytics (você consegue esse dado nas Configurações do Perfil, dentro do GA).

function ck_ga_pageviews()
{
  $path = dirname(__FILE__);
  set_include_path(get_include_path().PATH_SEPARATOR.$path);

  require_once 'Zend/Loader.php';
  Zend_Loader::loadClass('Zend_Gdata');
  Zend_Loader::loadClass('Zend_Gdata_Analytics');
  Zend_Loader::loadClass('Zend_Gdata_Query');
  Zend_Loader::loadClass('Zend_Gdata_ClientLogin');

  try
  {
    $email = ''; // E-mail da sua conta no GA
    $password = ''; // Senha da sua conta no GA
    $service_name = Zend_Gdata_Analytics::AUTH_SERVICE_NAME;
    $application = 'minha-app-v1_0'; // Nome da sua aplicação
    $profile = '12345678'; // ID do perfil no GA

    $client = Zend_Gdata_ClientLogin::getHttpClient(
        $email, 
        $password, 
        $service_name, 
        null, 
        $application);
    $service = new Zend_Gdata_Analytics($client);

    // No loop abaixo estamos usando os parâmetros padrão da função
    // get_posts do WordPress, mas você pode definir um outro tipo
    // de post específico, ou status, ou qualquer outro critério.
    // Dê uma olhada na documentação do WordPress e veja todas os
    // parâmetros possíveis.
    foreach (get_posts() as $post)
    {
      $path = parse_url(get_permalink($post->ID), PHP_URL_PATH);
      $query = $service->newDataQuery()
          ->setProfileId($profile)
          ->addMetric(Zend_Gdata_Analytics_DataQuery::METRIC_PAGEVIEWS)
          ->setFilter(Zend_Gdata_Analytics_DataQuery::DIMENSION_PAGE_PATH.'=='.$path)
          ->setStartDate('2010-01-01') // Apenas uma data no passado
          ->setEndDate(date('Y-m-d'))
          ->setMaxResults(1);

      $result = $service->getDataFeed($query);
      if (count($result) > 0)
      {
        $row = $result->current();
        $pageviews = $row->getValue(Zend_Gdata_Analytics_DataQuery::METRIC_PAGEVIEWS);
        update_post_meta($post->ID, '_pageviews', $pageviews);
      }
      else if ( ! get_post_meta($post->ID, '_pageviews', true))
      {
        update_post_meta($post->ID, '_pageviews', 0);
      }
    }
  } catch (Exception $e) {
    // Nada de importante para se fazer...
  }
}

Links úteis:

Qualquer dúvida ou problema, use os comentários.

Peso por extenso

Estou compartilhando um trecho de código bem simples que eu escrevi para retornar um dado peso por extenso.

Minha função usa o S.I. (Sistema Internacional de Medidas), mas você pode facilmente alterar o código e adaptá-lo para outro sistema de medidas. Também é bem simples traduzi-lo para outra linguagem de programação.

function weight($weight)
{
  $weight = (float) $weight;
  $int = intval($weight);
  $dec = $weight - $int;
  $text = '';
  if ($int > 0)
  {
    $text .= $int . ' ' . ($int > 1 ? 'quilogramas' : 'quilograma');
  }
  if ($dec > 0)
  {
    if ($int > 0)
    {
      $text .= ' e ';
    }
    $dec = round($dec * 1000);
    $text .= $dec . ' ' . ($dec > 1 ? 'gramas' : 'grama');
  }
  return $text;
}

Exemplos de uso:

echo weight(20.2307);
echo weight(1);
echo weight(3);
echo weight(1.001);

Model instances with Active Record on CodeIgniter

Recently we developed at CodeKings a customized CMS to meet specific needs for a client. One of the requirements of this project was that we had to use the CodeIgniter MVC framework. Early in the programming, we feel the need to access methods of model’s objects to navigate the hierarchy of classes. Thus, in a control, for example, we could do this:

$this->load->model('User_model');
$user = $this->User_model->get_by_email('john@example.com');
$group = $user->get_group();
echo $group->name; // Prints the name of the group the user belongs.

The problem is that in CodeIgniter, after calling the get method of Active Record class the value returned when generating query results is an array of StdClass’ instances (or an empty array on failure). In our case, it would be better to have a list of User_model. So, at first, we wrote the following helper (data_helper) to assist our work:
Continue reading “Model instances with Active Record on CodeIgniter”

Running Magento on Mac OS X

I recently formatted my MacBook and I chose to use PHP that comes with the operating system. This version comes with a few libraries installed, then you need to make some customizations.

First you must enable the PHP module in Apache, there are several tutorials talking about it on the web. A quick Google search brings some good results over this. So I will not talk about it here.

Once installed the PHP module in Apache and properly configured, you must compile some libraries from source.

First of all, you should make sure that you have Developer Tools installed. These software usually comes at an additional installation disc, along with your computer.

MySQL should be installed too. You can grab its installer from the official site.
Continue reading “Running Magento on Mac OS X”

Mac OS X and Java 1.6, keyboard input

Few months ago, after I updated (via Apple’s software update) my Java from 1.5 to 1.6, some applications started to have a strange behavior: the input by keyboard simply didn’t work as expected. Some keys, like return and shift, does work, but all letters and numbers not.

Only in the past week I’ve discovered why. The problem wasn’t with the Java version, like I thought, but with the keyboard layout. As I’m brazilian, I’m using the US International layout by Rainer Brockerhoff. Googling about this issue, I found that some custom keyboard layout doesn’t work correctly with recent Java versions.

Now I’m using the Mac’s native layout for Brazil. The bad thing is that I have to make the accentuation using option + some key. e.g., option + e to make the acute accent (´).

Zend Framework: Cannot save a row unless it is connected

Recently I was working on developing an application in PHP using Zend Framework, and when I tried to do an action that used the database in an previously serialized object that extends the class Zend_Db_Table_Row_Abstract – stored in a session, for example – an exception was thrown with the following message:

Cannot save a row unless it is connected

A small snippet of code that represents the problem:

$namespace = new Zend_Session_Namespace('signinData');
$user = $namespace->user;
$user->save();

Continue reading “Zend Framework: Cannot save a row unless it is connected”

Recursive chmod

Sometimes you need to change the access control to files matching some requirement. E.g. today I needed grant execute access to the owner of all PHP scripts running under Apache HTTP Server, in a specific directory.

Continue reading “Recursive chmod”

Checking if a form was sent via POST method

Since I started programming with PHP I’ve used several ways to check if a form was sent via the POST method. This is useful when the same method of control (or the same script, if you’re using structured programming or not using the MVC model) handle the form presentation and also its submission.

I used three ways, in chronological order, to do this: Continue reading “Checking if a form was sent via POST method”

Retrieving an hierarchical tree recursively with PL/PgSQL

From PostgreSQL 8.4 you can write WITH queries using the optional RECURSIVE modifier to make a query refer to its own output.

Ok, but if I’m using a previous version of PostgreSQL? What can I do? I had this same question and, after some research, I found a solution based on functions.

Below I’ll explain how the functions works. Continue reading “Retrieving an hierarchical tree recursively with PL/PgSQL”

PHP strtr alternative for an UTF-8 enviroment

The PHP strtr function replaces characters in a list by characters in a second list. The expected behaviour for that function in any enviroment is the following:

$from = '12345';
$to = 'ABCDE';
$str = 'I have 2 monkeys and just 1 dog';
echo strtr($str, $from, $to); // Prints 'I have B monkeys and just A dog';

But when using an UTF-8 encoded script, some unexpected character replacement can happen, because the strtr function always expect a string where the characters takes 1 byte each. But in the case of UTF-8, each char holds 2 bytes. So the split truncates.
Continue reading “PHP strtr alternative for an UTF-8 enviroment”