Coder un thème WordPress : bonnes pratiques

Un thème WordPress bien codé peut alléger la charge du serveur et augmenter la rapidité de chargement des pages.
Par ailleurs, vous gagnerez en facilité de maintenance en rationalisant l’organisation de votre thème.

Restez léger, codez proprement, utilisez le cache WordPress, allégez votre header.php, utilisez un sous domaine en CDN.
Exemple de fichier functions.php.

Codez et voyagez léger

  • De facon générale, le minimum de PHP dans vos fichiers de theme. Le fichier functions.php (à placer dans le même répertoire que vos fichiers de thème single.php, index.php, etc.) est fait pour contenir les fonctions PHP qui serviront dans le thème. En particulier :
    • Pas d’interrogation RSS dans les thèmes
    • Pas de requêtes MySQL lourdes dans les thèmes
    • Le minimum de lignes PHP : si vous venez d’ajouter plus de 3 lignes de PHP à la suite dans votre thème, vous feriez mieux d’en faire une fonction.
  • Autant que possible, essayez de spécifiez les dimensions des images dans vos balises <img>. C’est systématique pour les images statiques (images de sidebar); en revanche pour les images dynamiques (dans les billets), c’est moins important.
  • Pensez à compresser/minifier vos fichiers CSS et JS. Utilisez un compresseur de Javascript pour créer des versions “pack” de vos fichiers Javascript. Utilisez votre éditeur favori pour formatez vos CSS “en ligne”
  • Utilisez des noms de classes courts dans vos fichiers CSS, surtout pour les classes répétitives. #h au lieu de #header n’économisera pas grand chose, mais .ost au lieu de .odd_strong_title peut avoir un impact (on gagne quelques % sur la longueur du fichier HTML)

Coder proprement, et dans le style WordPress

Dans votre template :

<?php faire_quelque_chose('var=val&var2=val2'); ?>

Dans le fichier functions.php :

<?php
function faire_quelque_chose($args = '') {
  $defaults = array(
    'var' => 'valeur par defaut',
    'var2' => 'valeur par defaut',
    'echo' => 1,
    );
  $args = wp_parse_args($args,$defaults);
  extract($args,EXTR_SKIP);
  // vous pouvez maintenant utiliser les variables $var et $var2
  // $output =  "resultat de la fonction: $var est var et var2 est $var2";
  // ajouter un filtre avant de retourner est une bonne pratique, qui permet d'ajouter une couche plugin a vos fonctions de theme
  $output = apply_filters('faire_quelque_chose',$output);
  if($echo) echo $output;
  else return $output;
  }

Utiliser le cache WordPress

Rien de plus simple, et ca peut vous économiser beaucoup de charge :

Sans cache :

function afficher_quelque_chose() {
  $output = "une opération longue et compliquée";
  echo $output;
  }
function faire_qqchose_post($post_id) {
  $value = "operation compliquée avec des get_post et plein de choses compliquées";
  return $value;
  }

Avec cache :

function afficher_quelque_chose() {
  if(!$output = wp_cache_get('afficher_quelque_chose')) {
    $output = "une opération longue et compliquée";
    wp_cache_add('afficher_quelque_chose',$output);
    }
  echo $output;
  }

function faire_qqchose_post($post_id) {
  if(!$value = wp_cache_get("faire_qqchose_$post_id")) {
    $value = "operation compliquée avec des get_post et plein de choses compliquées";
    wp_cache_add("faire_qqchose_$post_id",$value);
  }
  return $value;
  }

Le cache ne sera effectif que si vous avez le plugin WP Super Cache activé en mode HalfOn ou On.


Garder un header.php léger : ajout dynamique du style et des scripts

Voici un exemple de début de fichier header.php, sur un site de mes clients, un site particulièrement chargé en trafic et très intégré :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
<head profile="http://gmpg.org/xfn/11">
<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
<title><?php wp_title(); ?></title>
<!--wp_head-->
<?php wp_head(); ?><!--//wp_head-->
</head>

Compliqué, n’est ce pas ? Il y a pourtant plus de 10 scripts JS et 5 feuilles de style sur ce site.
Une fois tout installé, voici un exemple de header généré :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" class="fr-FR">
<head profile="http://gmpg.org/xfn/11">
<!-- les deux lignes suivantes sont ajoutés par PHP Speedy, il s'agit du JavaScript et du CSS compressé -->
<link type="text/css" href="http://lesite.com/wp-content/plugins/php_speedy_wp/cache/_cmp_cssstylesheet_aaaabe17ccfd921696e24d48176f17b6.php" rel="stylesheet" />
<script type="text/javascript" src="http://lesite.com/wp-content/plugins/php_speedy_wp/cache/_cmp_javascript_57b933498ac7eff7b75fe9dd997b5cb0.php"></script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>titre généré</title>
<!--wp_head-->
<!-- tout ce qui suit est rajouté de facon dynamique -->
<!-- rajoute par le theme -->
<link href="/favicon.ico" rel="shortcut icon" />
<script type="text/javascript">if(top!=self) {top.location=self.location;}</script>
<!--[if IE]><link rel="stylesheet" href="http://lesite.com/wp-content/themes/lesite/ie.css" type="text/css" media="screen, projection" /><![endif]-->
<!-- les lignes qui suivent sont rajoutés en standard par WordPress -->
<link rel="alternate" type="application/rss+xml" title="Jeux Géographiques RSS Feed" href="http://lesite.com/feed/" />
<link rel="alternate" type="application/atom+xml" title="Jeux Géographiques Atom Feed" href="http://lesite.com/feed/atom/" />
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://lesite.com/xmlrpc.php?rsd" />
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://lesite.com/wp-includes/wlwmanifest.xml" />
<meta name="generator" content="WordPress 2.7" />
<meta name="description" content="Description." />
<meta name="keywords" content="keywords" />
<!--//wp_head-->
</head>

Il n’y a aucune raison de charger plus que ca le fichier header.php.

Pour ajouter dynamiquement les fichiers JS et CSS, utilisez les fonctions wp_enqueue_style et wp_enqueue_script
Usage :

wp_enqueue_script($handle,$src,$dependances,$version,$in_footer); // $in_footer pour WP 2.8+
wp_enqueue_style($handle,$src,$dependances,$version,$media);

En voir plus dans le fichier exemple


Utiliser un sous domaine pour servir les fichiers

En raison des limites des requêtes HTTP (principalement, 4 fichiers servis par sous domaine simultanément), vous gagnerez de la rapidité en servant vos fichiers CSS, JS et images à partir d’un sous domaine.
Une solution simple est de configurer un sous domaine qui pointe à la même adresse que votre site principal.
Exemple: www.malaiac.net et medias.malaiac.net pointent vers le même répertoire.

Vous pouvez ensuite modifier les adresses de certains de vos fichiers (par exemple, les images), ou bien filtrer tout les JS et CSS :

Dans functions.php :

// a modifier avec votre sous domaine ou CDN
//define('CDN_ADDRESS','http://medias.malaiac.net');
function get_cdn_address() {
  if(!defined('CDN_ADDRESS')) return get_option('home');
  return CDN_ADDRESS;
}

function add_cdn_address($bloginfo,$output = '', $show= '') {
  if(!in_array($output,array('stylesheet_url','stylesheet_directory','template_directory','template_url'))) return $bloginfo;
  $bloginfo = str_replace(get_option('home'),get_cdn_address(),$bloginfo);
  return $bloginfo;
}
add_filter('bloginfo_url','add_cdn_address',10,2);
/** attention à modifier :
 * get_bloginfo('template_directory');
 * en :
 * get_bloginfo('template_directory','display');
 * pour que le filtre soit appellé
 **/

/**
 * Pour afficher une image dans votre thème, utilisez :
 * 
 **/

Utilisez Ajax pour charger les éléments lourds

Certains éléments n’ont aucun intérêt pour le référencement, et prennent beaucoup de temps à charger.
Exemple : les mosaiques de gravatars des derniers commentaires ; une image lourde qui sert d’illustration.

Vous pouvez charger ces éléments en Ajax, exemple :

<div id="contenulourd"></div>
<script type="text/javascript">
jQuery(document).ready(function() {
	jQuery.ajax({
		type: 'POST',
		url: '<?php get_bloginfo('template_directory','display') ?>/ajax.php',
		data: {action: 'contenulourd'},
		success: function(response) {
			jQuery('#contenulourd').html(response);
			},
	});
	}
});
</script>

Dans votre répertoire de thème, ajoutez un fichier ajax.php :

<?php
header("text/html; charset=UTF-8");
// si vous avez besoin de charger WordPress
//include('../../../wp-load.php');

if($_POST['action'] == 'contenulourd') {
  echo "<div>plein de contenu avec des <img> bien chargées et des <p>contenus bien lourds</p>";
  }
}

Une base de fichiers functions.php

// si vous avez un fichier de traduction, à nommer fr_FR.mo
load_theme_textdomain('theme');

function theme_init() {
  // setlocale permet de préciser la langue et le charset à utiliser si besoin
  // setlocale(LC_ALL, 'fr_FR@euro', 'fr_FR', 'fra_fra');

  // ajout JS et CSS
  $template_dir = get_bloginfo('template_directory','display');
  wp_enqueue_style('style_css',$template_dir.'/style.css',array(),false,'screen,projection');
  wp_enqueue_style('print_css',$template_dir.'/print.css',array(),false,'print');

  // ce script se chargera en pied de page
  wp_enqueue_script('theme_js_footer',$template_dir.'/functions.js',array('jquery'),false,1);

  // ajout d'un script avec des chaines de traduction :
  wp_enqueue_script('theme_js',$template_dir.'/functions.js',array('jquery'));
  wp_localize_script('theme_js','themeL10n',array(
    'no' => __('No','theme'),
    'thanks' => __('Thanks','theme'),
    ));
  // ces chaines seront disponibles dans le javascript avec : themeL10n.thanks

  }
// pour WP2.8+
add_action('wp_enqueue_scripts', 'theme_init');
// pour WP < 2.8, dans ce cas, rajouter if(is_admin()) return; au début de la fonction
add_action('init','theme_init',8); //

// cette fonction se lance entre <head> et </head>
function theme_wp_head() {
  if(is_admin()) return;
  // exemple de ligne
  echo '	';
  }
add_action('wp_head','theme_wp_head',8);

// cette fonction peut servir à filter les headers 301 et 404 (redirections, héritages, etc.)
function theme_header($header) {
  if($header == 'HTTP/1.1 301 Moved Permanently') {
    // faire qqchose
  }
  elseif($header == 'HTTP/1.1 404 Not Found') {
    // faire qqchose
  }
  return $header;
  }
add_filter('status_header','theme_header');

Rejoindre la conversation

5 commentaires

  1. Merci pour ces bonnes pratiques. Juste une question concernant l’apply_filters: je pensais qu’un apply_filters() sans add_filter() sur le hook en question ne faisait rien…Que fait cet apply_filter ici ?
    merci de la précision !

  2. My developer is trying to persuade me to move to .net from PHP.
    I have always disliked the idea because of the expenses.
    But he’s tryiong none the less. I’ve been using
    WordPress on numerous websites for about a
    year and am worried about switching to another platform. I have heard good things about blogengine.
    net. Is there a way I can transfer all my wordpress
    content into it? Any help would be really appreciated!

Laisser un commentaire