Pensieri sparsi sul template engine di WordPress

E’ risaputo oramai che se devo scegliere tra WordPress e MovableType, normalmente, prediligo la seconda soluzione. Tuttavia, nei casi in cui l’integrazione e la semplicità di personalizzazione del codice sorgente è essenziale, WordPress è per me una scelta quasi obbligata dato che la mia conoscenza di PERL è lontana anni luce dalla padronanza del PHP.

Ieri, per varie ragioni che al momento è precoce documentare, ho deciso di configurare una nuova installazione di WordPress.

Questa volta, rispetto alle altre, c’era una grado di difficoltà maggiore: ho deciso di darci sotto con la personalizzazione dei template… non l’avessi mai fatto!

Lasciatemelo dire: il codice del template engine di WordPress (ma non solo lui) avrebbe bisogno di una bella spolverata!

Reduce dalle pulizie invernali su MovableType mi sono attivato per ridurre un po’ il codice duplicato anche nel blog basato su WordPress, prima della sua pubblicazione online.

Presto mi sono accorto che:

  1. Le variabili PHP inserite in un qualsiasi template non sono accessibili da un altro template, neanche se incluso nel precedente. Secondo l’approccio attuale di WordPress dovrei usare una variabile global (argh!)
  2. Anche in pagine dove è previsto un solo post, come single.php, i post vengono rappresentati come array di elementi.

    <?php if (have_posts()) : while (have_posts()) : the_post(); ?>
    
    // per poter utilizzare in seguito
    
    <?php echo the_title() ?>
    <?php echo get_permalink() ?>
    <?php the_content('Continue Reading &raquo;'); ?>
    

    In Movable Type una situazione simile semplicemente non esiste. Ogni pagina il cui scope è un post ha automaticamente accesso a tutte le variabili dei post, comodamente richiamabili con i tag messi a disposizione

    <mt:EntryTitle />
    <mt:EntryPermalink />
    <mt:EntryBody />
    

    Non mi soffermo poi sulla incoerenza di alcune nomenclature. Fermo restando che trovo i “tag” di WordPress abbastanza intuitivi, non mi è chiaro perché io chiamo the_title(), the_content() e ad un certo punto mi trovo get_permalink().

  3. La quantità di codice PHP presente per azioni dove potrebbe essere evitato è impressionante.

    Si veda ad esempio la seguente porzione di codice per mostrare i possibili status dei commenti:

    <p class="centered">
    <?php if (('open' == $post-> comment_status) && ('open' == $post->ping_status)) {
    // Both Comments and Pings are open ?>
    You can <a href="#respond">leave a response</a>, or <a href="<?php trackback_url(); ?>" rel="trackback">trackback</a> from your own site.
    
    <?php } elseif (!('open' == $post-> comment_status) && ('open' == $post->ping_status)) {
    // Only Pings are Open ?>
    Responses are currently closed, but you can <a href="<?php trackback_url(); ?> " rel="trackback">trackback</a> from your own site.
    
    <?php } elseif (('open' == $post-> comment_status) && !('open' == $post->ping_status)) {
    // Comments are open, Pings are not ?>
    You can skip to the end and leave a response. Pinging is currently not allowed.
    
    <?php } elseif (!('open' == $post-> comment_status) && !('open' == $post->ping_status)) {
    // Neither Comments, nor Pings are open ?>
    Both comments and pings are currently closed.
    
    <?php } ?>
    </p>
    

    Qualcosa più tag oriented sarebbe auspicabile. Un occhio alla concorrenza rivela EntryIfCommentsOpen, EntryIfAllowComments e EntryIfAllowPings.

Non so voi, personalmente sento molto la mancanza di una struttura più orientata agli oggetti che consenta di ottenere un oggetto Post ed invocare su di esso i metodi necessari (tag).

Personalmente ritengo che un progetto come WordPress avrebbe molto da guadagnare in termini di fluidità del codice da un approccio più object oriented.

Tra i vari pensieri sparsi, mi chiedo quando e se è previsto l’abbandono del supporto a PHP 4, una delle principali cause (a mio avviso) dell’arretratezza del codice di WordPress.

Ricordo ancora l’intervento di Matt, in occasione dell’annuncio che ha decretato il termine del supporto di PHP 4, fissato per il 31 Dicembre. Matt non mi sembrò così entusiasta, o meglio, non mancarono le critiche rivolte al team di sviluppo di PHP.

Prima di concludere questi pensieri sparsi, vi lascio con una semplice classe (compatibile solo con PHP 5) scritta ieri in un paio di minuti per sopperire al problema del punto 1.

Si chiama TemplateConfig e, sostanzialmente, non è altro che un oggetto singleton che si preoccupa di tenere traccia di arbitrarie configurazioni che desiderate utilizzare nei vari template. Mi rendo conto che non è particolarmente amichevole per i non addetti ai lavori, magari qualcuno potrebbe prenderne spunto per un plugin. Inoltre, andrebbe leggermente migliorata per eseguire la validazione dell’input.

```php
<?php

class TemplateConfig {

  protected $_properties = array();
  protected static $_instance;

  public static function getInstance() {
    if (self::$_instance === null) {
      self::$_instance = new self;
    }
    return self::$_instance;
  }

  public function __get($name) {
    if (isset($this->_properties[$name])) {
      return $this->_properties[$name];
    } else {
      return null;
    }
  }

  public function __set($name, $value) {
    $this->_properties[$name] = $value;
    return $this;
  }
}
```

Inserite la definizione della classe all’interno del file functions.php presente nella cartella del vostro template, in wp-content/themes/NOME_DEL_VOSTRO_THEME. Se il file non c’è, createlo. Verrà caricato in automatico da WordPress e consentirà di avere accesso alla libreria nei vostri template.

Ecco un esempio di utilizzo.

Immaginate di voler mostrare una piccola intro, scritta nel file header.php, solo in alcune pagine del blog. Normalmente questo non sarebbe possibile senza avere accesso a qualche funzione particolare.

Ci vuole una variabile, vero/falso, che dica a WordPress: stampa l’intro, non stampare l’intro. All’inizio delle pagine dove volete mostrare la intro, ad esempio 404.php e index.php, prima del richiamo di wp_header(); inserite la variabile interruttore.

```php
<?php
  // recupero l'istanza singleton dell'oggetto
  $instance = TemplateConfig::getInstance();
  // setto la variabile
  $instance->intro = true;

  // o più semplicemente
  TemplateConfig::getInstance()->intro = true;
?>
```

Ora aprite il file header.php ed utilizzate un controllo sulla variabile per stampare o meno la intro.

```php
<?php if (TemplateConfig::getInstance()->intro): ?>
  <p>Questa è una intro da visualizzare solo in alcune pagine.</p>
<?php endif; ?>
```

Per semplificare ulteriormente la vita ai non addetti ai lavori potrebbe essere utile aggiungere due tag più user friendly che consentano di scrivere qualcosa tipo:

```php
<?php set_template_var('intro', false); ?>
```

e recuperare il valore con

```php
<?php get_template_var('intro', false); ?>
```

nascondendo completamente l’uso della classe e dell’istanza singleton.