A l’heure où la vitesse de navigation est un des facteurs les plus importants pour nos sites et blogs alors que ceux-ci se remplissent de plus en plus de fonctionnalités pour nos visiteurs, toutes les méthodes sont bonnes pour gagner ces précieuses millisecondes.
Voici une petite astuce que je viens de trouver qui va donner un petit coup de boost à votre site WordPress, sans pour autant sacrifier une quelconque fonctionnalité.
Je ne sais pas pour vous, mais de mon côté le fichier functions.php de mon thème a plutôt tendance à devenir obèse au fil de mes personnalisations. Il suffit de jeter un œil à mon article sur la personnalisation de l’administration de WordPress pour voir les lignes de code faire des bébés. Il ne s’agit pas seulement du poids du fichier, mais surtout de toutes ces fonctions que devra lire WordPress à chaque chargement de page, même s’il n’en a pas besoin dans l’instant présent.
Mon idée consiste à diviser ce fichier functions.php en plusieurs parties : une partie commune à tout le site, une partie réservée à l’administration, et une uniquement pour le frontend. On peut même imaginer d’autres parties selon ce que vous avez mis dans votre fichier functions.php.
Mise à jour du 4 janvier 2014
J’ai modifié ma façon de faire, qui, je pense, est plus pertinente que ce qui est décrit dans l’article d’origine.
Différences :
- Diviser le code en 3 parties : ajax, admin, frontend.
- Utilisation de
include()
au lieu deget_template_part()
: aucun besoin de fallback, si un fichier manque c’est qu’on a plus important à se soucier qu’un fichier de fallback.
01020304050607080910111213141516
$templatepath = get_template_directory();
$stylesheetpath = get_stylesheet_directory();
if ( defined('DOING_AJAX') && DOING_AJAX && is_admin() ) {
include( $templatepath.'/inc/ajax.php' );
} elseif ( is_admin() ) {
include( $templatepath.'/inc/admin.php' );
} elseif ( !defined( 'XMLRPC_REQUEST' ) && !defined( 'DOING_CRON' ) ) {
include( $templatepath.'/inc/frontend.php' );
}
Remarques :
Dans un thème enfant il vous faudra utiliser $stylesheetpath
au lieu de $templatepath
.
Ne mettez pas de ?>
à la fin de vos fichiers, cela aura un impact positif sur la performance.
Rien ne vous empêche ensuite de diviser votre code en fonction de son utilité, par exemple, créer un fichier widgets.php afin d’y mettre tous vos widgets persos. Ce point ne jouera en rien sur la performance du site mais permet d’avoir un code plus clair et rangé, c’est un point positif pour la maintenance. Attention à ne pas faire trop de petits non plus, certains développeurs n’aiment pas les portées nombreuses.
Pour finir, un petit rappel sécurité. Au tout début de chacun de vos fichiers, pensez à mettre ceci :
12345
<?php
if( !defined( 'ABSPATH' ) )
die( 'Cheatin\' uh?' );
// Votre code ici
Cela aura pour effet de ne pas afficher un message d’erreur si quelqu’un tente d’accéder directement au fichier avec son navigateur, le message contient une information qui peut être utile à une personne malveillante.
Suite de l’article du 9 juin 2011
Structurer le code
La première chose à faire est d’étudier le code présent dans notre fichier functions.php pour voir ce qui est utile uniquement pour l’administration, uniquement pour le front-end, ou aux deux. Ce sera en fait la partie la plus difficile, surtout si on a ajouté du code sans trop savoir comment il fonctionne. Ensuite il suffira de séparer ces parties en se basant sur la condition is_admin(). Avant tout, je vous conseille de sauvegarder votre fichier original dans un coin.
Exemple :
1234567
// Code utile partout
if (is_admin()) {
// Code utile uniquement dans l'administration
} else {
// Code utile uniquement dans le front-end
}
Déjà, rien qu’en faisant ça, vous devriez sentir une différence dans le temps de chargement de vos pages.
NOTA : La page de login n’est pas considérée comme faisant partie de l’administration. Toutes les personnalisations concernant cette page devront se trouver dans la partie else
.
NOTA 2 : Les fenêtres « média », c’est à dire les fenêtres qui s’ouvrent lorsque l’on clique sur l’un des boutons situés au-dessus de l’éditeur visuel ou html (pour mettre une image à la une dans un article par exemple). Je ne sais pas si c’est valable pour toutes ces fenêtres « média », mais j’ai un plugin qui utilise une telle fenêtre pour insérer du contenu dans mes articles, et je me suis rendu compte que dans cette fenêtre is_admin()
me renvoie false. Plutôt étrange.
Diviser pour mieux régner
Allons encore plus loin et créons un fichier functions.php par partie, et utilisons seulement ceux dont nous avons besoin.
Pour cela nous allons utiliser une fonction apparue avec WordPress 3, très utile lors de la conception d’un thème WordPress, et nous allons légèrement détourner son utilisation. Il s’agit de get_template_part(). C’est tout simplement une sorte de require() php.
D’abord nous avons besoin de créer les fichiers. Nous avons déjà functions.php, qui servira pour le code commun à tout le site. Créez les fichiers functs-adminonly.php et functs-frontendonly.php qui serviront respectivement pour l’administration et le front-end.
Ensuite, copiez tout ce qui est à l’intérieur de la condition is_admin() et collez le dans functs-adminonly.php. Même chose pour le front-end : copiez tout ce qui est à l’intérieur du else et collez le dans functs-frontendonly.php. Pour finir, il suffit de remplacer le code dupliqué par des get_template_part() avec les paramètres adéquats dans functions.php.
NOTA : J’ai délibérément appelé les fichiers functs-XXXXX.php au lieu de functions-XXXXX.php. Si vous avez regardé la page du codex réservée à cette fonction (en lien plus haut), vous pouvez voir sous la partie « Examples » que la fonction va d’abord chercher le fichier functions-XXXXX.php, et si elle ne le trouve pas elle va chercher le fichier functions.php à la place, et l’inclure. Donc si votre functions-XXXXX.php disparait pour une raison ou pour une autre, functions.php va s’inclure dans lui-même à l’infini, et par la même occasion, déclarer des fonctions déjà existantes. Bref, le site sera en croix. En appelant nos fichiers functs-XXXXX.php on contourne ce problème puisque functs.php n’existe pas.
Si la fonction ne trouve aucun fichier, elle va générer une erreur et stopper le script php. Du coup, il n’est pas idiot de créer un fichier functs.php vide, et par la même occasion, mettre le code commun en premier dans functions.php, et le test is_admin() à la fin du fichier.
functions.php :
1234567
<?php
// Code commun à tout le site
if (is_admin())
get_template_part( 'functs', 'adminonly' );
else
get_template_part( 'functs', 'frontendonly' );
functs-adminonly.php :
123
<?php
// Code uniquement pour l'administration
?>
functs-frontendonly.php :
123
<?php
// Code uniquement pour le front-end
?>
[update]
Plutôt que de créer un fichier de fallback functs.php vide, pourquoi ne pas y ajouter une alerte qui nous préviendrait dans l’administration que quelque chose foire? Avec le hook suivant, nous aurons une alerte sur fond rouge en haut de toutes les pages de l’administration, dès lors qu’un des deux fichiers manquera à l’appel.
functs.php :
123
<?php
add_action( 'admin_notices', create_function( '' , "echo '<div class=\"error\"><p>Attention - L\'un des fichiers functs-xxxxx.php de votre thème n\'a pas été trouvé. Vérifiez les fichiers de votre thème.</p></div>';" ) );
?>
Mais il faut aussi vérifier que le ficher pour le front-end existe bien, car dans l’admin, on n’essaie pas de l’inclure, donc il ne fera pas de fallback vers functs.php.
functions.php :
1234567
if (is_admin()) {
get_template_part( 'functs', 'adminonly' );
if ( !file_exists(TEMPLATEPATH.'/functs-frontendonly.php') && file_exists(TEMPLATEPATH.'/functs-adminonly.php') ) {
get_template_part( 'functs' );
}
} else
get_template_part( 'functs', 'frontendonly' );
[update]
Astuce bonus : dans le fichier functions.php, utiliser des is_page(), is_single() ou autre, directement ne fonctionne pas (car au moment où le fichier est « lu », WordPress ne sait pas encore si nous nous trouvons dans une page, un article, ou autre). Il faut donc utiliser un hook :
12345
function single_setup() {
if (is_single())
get_template_part( 'functs', 'single' );
}
add_action( 'template_redirect', 'single_setup' );
Ce qui donne au final pour functions.php :
functions.php :
01020304050607080910111213
if (is_admin()) {
get_template_part( 'functs', 'adminonly' );
if ( (!file_exists(TEMPLATEPATH.'/functs-frontendonly.php') || !file_exists(TEMPLATEPATH.'/functs-single.php')) && file_exists(TEMPLATEPATH.'/functs-adminonly.php') ) {
get_template_part( 'functs' );
}
} else {
get_template_part( 'functs', 'frontendonly' );
function single_setup() {
if (is_single())
get_template_part( 'functs', 'single' );
}
add_action( 'template_redirect', 'single_setup' );
}
Conclusion
Voilà une méthode assez simple que j’ai testé ici-même, et je dois dire que j’ai vu une différence. Certes cela ne va pas diviser par deux vos temps de chargements mais le gain n’est pas du tout négligeable.
Points positifs :
- Le nombre de lignes de code lues a drastiquement diminué : nous évitons à WordPress de lire des fonctions qui ne lui sont pas utiles à un moment donné.
- Le poids des fichiers chargés : de 48ko pour le fichier functions.php, je suis passé à 6+30=36ko pour le front-end et 6+12=18ko pour l’administration (ok, la différence n’est pas énorme).
- La clarté du code : en séparant en plusieurs fichiers, je trouve qu’il est plus facile de se repérer.
Points négatifs :
- La première étape qui consiste à séparer son code en trois parties est la plus difficile. Le tout est de ne pas se planter à ce moment et de vérifier ensuite que tout fonctionne correctement.
- L’astuce ne sera efficace seulement si le fichier functions.php original est assez conséquent, sinon la différence sera imperceptible.
See ya!
Commentaires
Commentaire de billboc.
Salut !
Merci beaucoup pour cette excellente astuce que je n’avais pas encore croisé sur le net !
Je fais la même chose pour mes scripts mais je n’avais pas pensé le faire pour notre sympathique functions.php
bravo !
PS: Je découvre ton site en même temps que cet article et je suis sous le charme… J’adore !!! il est superbe !!!
Au plaisir de te lire !
=D
++
Billboc
Commentaire de Greg.
Salut.
Je suis comme toi, on fait souvent des include ou require en php, mais je n’avais encore jamais pensé à le faire pour functions.php. En plus, en ce moment je suis un peu dans une phase optimisation/sécurité, ceci explique peut-être cela :)
Effectivement, je n’ai pas encore vu cette astuce trainer sur le net, et maintenant je me dis « Mais pourquoi on n’y a pas pensé plus tôt!? » ^^
Merci pour ton commentaire et les compliments :)
Commentaire de Christophe de la Fab.
Oh oh oh, de bonnes idées à tester. Je suis sensible aux arguments vitesse et clarté du code. Je vais tenter.
Commentaire de Djib's.
Merci pour l’astuce.
il y a une petite erreur dans le code.
Ce n’est pas && mais && sinon on obtient l’erreur suivante:
Parse error: syntax error, unexpected ‘;’ in …
Mais j’ai toujours un probleme. Même après la correction de cette petite erreur, coté blog j’ai un grande page blanche (pas coté admin)
Commentaire de Abcmoteur.
Bonjour,
la différence se mesure en secondes ou moins ? Je très intéressé par votre méthode car je trouve toujours WP un poil trop long.
Que pensez-vous du chargement de mon blog (WP super cache activé) ? Je suis avec un hébergement mutualisé d’OVH.
Merci et très bon article que je n’ai pas hésité à relayer sur Twitter !
Commentaire de Greg.
Bonjour.
Le gain va dépendre de la taille de votre fichier functions.php : plus il sera fourni, plus le gain sera important. Ainsi il ne sera pas toujours utile d’utiliser cette astuce. De mémoire, je crois que j’ai gagné quelque chose comme une demi seconde (comme j’ai fait pas mal de changements dernièrement, je ne suis plus sûr de rien). A noter que je n’utilise aucun plugin de cache ;)
Je suis allé faire un tour sur votre site, et honnêtement, je trouve qu’il tourne très bien (en plus sur un mutualisé). Il dispose de pas mal de fonctionnalités qui habituellement ralentissent l’affichage d’une page, et pourtant je n’ai pas remarqué de blocage notable (et pourtant je navigue avec Firefox 5). Le plus important (à mon sens) étant que le contenu de la page s’affiche le plus tôt possible, le reste se chargeant ultérieurement. Cela passe bien sûr par tout un tas de choses, mais à priori ça me semble déjà très bien géré :)
Merci pour le commentaire et le tweet ;)
Commentaire de Abcmoteur.
Bonjour,
j’ai regardé le fichier fonction.php (qui se trouve dans le thème, c’est bien ça ?) et j’ai lu qu’il pesait environ 15 000 octets.
Est-ce beaucoup ?
Commentaire de Greg.
Bonjour.
Oui c’est bien celui là. 14ko à 15ko ce n’est pas énorme, le gain risque d’être léger, ça va dépendre si son contenu concerne la partie front-end ou l’administration.
Ce serait moi, la première question que je me poserais c’est « Est-ce que je m’y connais assez pour modifier ce fichier? ». Si oui, alors pourquoi pas, si non, ça ne vaut pas le coup de s’embêter pour si peu et de risquer un quelconque problème que je ne saurais peut-être pas réparer.
Commentaire de Abcmoteur.
Je vais rester comme cela, pas de prise de risque !
Merci.
Commentaire de Djib's.
Il y a une coquille ce n’est pas && mais && car sinon on obtient une erreur.
Même apres avoir corrigé cette coquille, j’obtiens une page blanche coté blog (pas coté admin)
Commentaire de Greg.
Salut.
En effet, pour le && il s’agissait d’une erreur d’interprétation de mon plugin de colorisation syntaxique (encore en bêta-test), le problème est réglé.
Concernant ta page blanche, tu as une erreur renvoyée par php ou seulement… du blanc? Peut-être qu’un court passage en mode debug à l’abri des yeux indiscrets pourrait aider. De mon côté je n’ai aucun problème avec cette astuce, peut-être que tes fonctions ne sont pas où elles devraient être (côté admin, côté front-end, pour les 2). Sans plus d’infos, je ne saurais t’aider :/
A+
PS : la page blanche est souvent le résultat d’un appel de fonction non définie, à vérifier.
Commentaire de Li-An.
Je me suis dit « super intéressant » et je me suis rendu compte que mon function.php ne faisait que 4ko. Bah oui, j’ai beaucoup de plugins d’installés :)