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 Loïc Hélias.
Merci, je vais essayer de mettre ça en place dès que possible.
Je vous fais un feedback dès que j’en ai le temps.
Commentaire de Gpenverne.
« Diviser pour mieux régner »
Le fait de diviser un gros fichier en plusieurs parties peut nuire au cache d’opcode, non ?
Commentaire de Greg.
Salut Gpenverne.
Grâce à toi je découvre qu’il existe un cache d’opcode :D (je ne me dis pas développeur je rappelle).
A mon avis, si on ne fait que séparer le code administration / front-end, ce cache ne devrait pas bouger, puisqu’un visiteur appellera à chaque fois la partie nécessaire pour le front-end, qui sera inchangée.
Maintenant si un include( ) nuis à ce cache, alors oui, diviser ce fichier nuira à ce cache, mais j’en doute puisque chaque page d’un thème WordPress est constitué de plusieurs include( ) -get_header( ) / get_footer( )- donc…
Tout ce que je peux dire c’est que cela m’a permis un petit gain non négligeable dans le temps de chargement :)
Commentaire de Li-An.
Je lis ailleurs que la balise <?php ne doit pas être fermée pour functions.php.
Commentaire de Gpenverne.
Où le lis tu ? :)
Commentaire de Li-An.
http://wordpress.bbxdesign.com/
De plus, un coup d’oeil rapide dans le functions.php de Twenty Ten et Twenty Eleven confirme ce fait.
Commentaire de Greg.
En effet je ne vois pas de fermeture de <?php dans le functions.php de twentyten et twentyeleven. Il ne reste plus qu’à en savoir la raison :)
Commentaire de Li-An.
Ça m’intéresserait bien aussi :)
Commentaire de Yannick Altuna.
Merci pour cette astuce puissante, il est vraie qu’après avoir plongé dans le « wordpress’world », lorsqu’on entend « code propre » « optimisation » etc ça nous évoques un certain plaisir, même si ça nous est pas utile sur le moment (vous vous reconnaissez? ^^).
Bref, question avant que je mette ça en oeuvre :
Et pour le code utile des deux côtés? Admin et frontend?
Je pense particulièrement au déclaration des custom-post-type, doit on les placer dans le backend? le frontend? ou sur les deux?
Cordialement,
Yannick
Commentaire de Greg.
Bonjour Yannick.
Les 2 mon capitaine! La réponse était caché en ligne 2 :
12
Commentaire de Yannick Altuna.
Merci merci,
Je pense que même avec peu de ligne je vais le mettre sur tout mes sites wordpress, j’aime bien les choses bien classé, et c’est une bonne habitude à prendre ^^.
Cordialement, Yannick
Commentaire de Greg.
A noter qu’on peut le faire plus simplement avec
include_once()
aussi.L’utilisation de
get_template_part()
c’était plus pour le plaisir de légèrement détourner l’utilisation première de cette fonction ^^Commentaire de Hervé.
Bonjour,
J’ai bien appliqué cette méthode sans soucis jusqu’à présent.
mais maintenant je souhaiterai affiner avec un affichage différent pour le super administrateur.
J’ai essayé avec !is_super_admin, l’username du super admin ou les rôles mais cela ne fonctionne pas dans le répertoire \mu*plugins\
Une idée ?
Commentaire de Greg.
Bonjour Hervé.
Perso je n’ai pas encore eu à tester le dossier /mu-plugins/ ni à cibler le super admin ou son administration dédiée, mais je tenterais ça :
–
current_user_can('manage_network')
ouis_super_admin( $user_id )
pour cibler le Super Admin (il n’a pas de rôle dédié, c’est un Admin avec des super pouvoirs x) ), à noter que $user_id est facultatif dans is_super_admin() et est l’ID d’un user (pas son nom),– à mon avis ça ne marchera pas mais tu peux tester avec
if ( defined(WP_NETWORK_ADMIN) && WP_NETWORK_ADMIN ) { ... }
pour tester si on est dans l’administration network (je pense que la définition de la constante arrive trop tard).– dernier recours pour savoir si on est dans l’administration du réseau : utiliser l’url et rechercher « /wp-admin/network/ » avec un is_admin() supplémentaire par sécurité.
Je pense vraiment qu’une méthode simple existe mais je ne la connais pas, comme je disais j’ai assez peu travaillé avec un multisite. Ça demanderait quelques recherches.
Nota : perso, dans un plugin je n’utilise pas get_template_part() mais plutôt include_once()
A+
Commentaire de Hervé.
Bonsoir,
Merci pour cette réponse rapide.
Comme tu l’a deviné, cela ne fonctionne pas. Soit j’ai des pb de droits, erreur ou pas de différence entre les 2 admins.
Juste pour précisions, car j’ai du mal m’exprimer, je cherche à avoir un affichage différent pour l’admin ou super admin mais dans l’interface de base et non pas dans l’interface réseau
A+
j’ai posté ailleurs, je te tiens au courant si solution !
Commentaire de Willy.
Salut, merci encore pour l’astuce, je m’étais juré de la tester mais n’était jamais passé à l’acte.
Grâce à toi mon code est beaucoup plus clair maintenant !
Cependant j’ai juste un petit souci que je n’arrive pas à élucider.
Avant (à l’époque où je n’avais qu’un simple fichier functions.php) toutes les variable que j’y déclarait étaient globales. Mais maintenant, les variables que je déclare dans functs-adminonly.php ne sont plus accessibles…
Y aurait-il un moyen de les rendre globales ?
ps : je suis sûr que ça doit être super simple mais je galère comme un gland…
Merci d’avance !