Here With Me

Le blog technique d'Amaury Balmer qui parle de technologies open-source, mais surtout de WordPress !

11 points importants lors de la réalisation d’un plugin WordPress

| 5 Commentaires

Afin de bien comprendre, nous allons illustrer chacun des 11 points avec un exemple.

Pour cela, nous allons comparer le plugin "Seo Http error manager" au plugin "Http Error Codes Manager" que j'ai codéveloppé avec Thomas pour l'occasion.

Cela nous permettra de bien voir les choses, qu'il faut faire, qu'il ne faut pas faire, et nous donnera un bon contraste.

Précision: Lorsque je parle de l'API, il s'agit de la section développeur du Codex, et du PHPxRef.

Quand je parle du bon plugin, il s'agit de "Http Error Codes Manager", tandis que le mauvais plugin est "Seo Http error manager".

 

1. Évitez les variables globales, préférez-les constantes

Nous ne sommes pas ici pour débattre sur l'utilisation et la présence des variables globales dans le langage PHP, mais autant que possible, s'il est possible de s'en passer, faites-le !

Par exemple:

// ---------------------------------------------
// Constantes
// ---------------------------------------------
$TAGERROR        = "code_errorcode_worpress_seo"; // ne pas editer
$TAGURL            = "url_errorcode_worpress_seo"; // ne pas editer
$DEFAULTURL    = "http://www.-seo.com/redirection-par-defaut.php"; // editable a vos risques et peril

C'est typiquement une mauvaise utilisation des variables globales. Si vous souhaitez définir une constante, utilisez la fonction "define()" tout simplement...

Il n'y a pas de comparaison avec le bon plugin pour ce point, car l'utilisation de variables globales ou constantes est simplement inutile.

 

2. Consultez l'API avant d'écrire des requêtes SQL

L'API de WordPress est plus vaste qu'on peut l'imaginer. Consultez-la toujours avant d'écrire une requête SQL.

2.1 Dans le premier cas, nous souhaitons récupérer une valeur méta d'un article:

Voilà la mauvaise méthode:

function wordpress_seo_http_error_code_manager_GetPostMeta_FromKeyAndPostId($TagKey,$Id,$Max=1)
{
    // Les global issues de wordpress
    global $wpdb,$table_prefix;
    //
    // On force le debug
    $Print_debug=0;
    $ArrMsgAll=array();
    $ArrMsgCount=0;
    // ———————————-
    // On isole la liste
    $SQL="SELECT meta_id,meta_value FROM `".$table_prefix."postmeta` where meta_key='".$TagKey."' AND post_id='".$Id."' limit ".$Max." " ;
    $search_counter = 0;
    $A_meta = $wpdb->get_results($SQL);
    if($A_meta){return $A_meta[0]->meta_value;}
    else{if($Print_debug==1){echo "
DEBUG :

No results.


";}} return ""; // vide ! }

Cette fonction est inutile. Il existe déjà une fonction dans l'API de WordPress:

get_post_meta( $post_id, $meta_name, $single );

Nous venons d'économiser 18 lignes et 10 minutes. Et nous profitons par la même occasion de toute la sécurité et l'expérience des développeurs de WordPress avec une pérennité garantie bien entendu.

2.2 Deuxième cas, nous décidons d'insérer ou de mettre à jour la valeur méta d'un article

Voilà la mauvaise méthode:

function wordpress_seo_http_error_code_manager_SetUserMeta($TagKey="error",$NewVal,$Id=0)
{
    // Les global issues de wordpress
    global $wpdb,$table_prefix;
    //
    // On force le debug
    $Print_debug=0;
    $SQL="DELETE FROM `".$table_prefix."postmeta` where meta_key='".$TagKey."' AND post_id='".$Id."' " ;
    $wpdb->get_results($SQL);
    $SQL="INSERT INTO `".$table_prefix."postmeta` set meta_key='".$TagKey."', meta_value='".addslashes($NewVal)."' , post_id='".$Id."' " ;
    if($Print_debug==1){echo "DEBUG : 
$SQL
";} $wpdb->get_results($SQL); }

Encore une fois, cette fonction est inutile. Il suffit d'utiliser 2 fonctions de l'API WordPress:

delete_post_meta( $post_id, $key); // Supprimer une méta de la base de données
add_post_meta( $post_id, $key, $value); // Ajouter une méta à la base de données

Ces 2 exemples sont très parlants...

Les intérêts sautent aux yeux: Gain de temps, pérénnité, sécurité et lisibilité du code

 

3. N'utilisez plus la variable dépréciée "$table_prefix"

Depuis WordPress 2.1, la variable globale "$table_prefix" est dépréciée.

Cela ne veut pas dire qu'elle ne fonctionne plus, mais pour garantir la compatibilité et des prochaines versions de WordPress, vous ne devez plus l'utiliser.

A la place, il faut utiliser "$wpdb->prefix".

PS: N'oubliez de rappeler la variable globale "$wpdb" au début de la fonction.

Exemple:

function test() {
    global $wpdb;
    $prefixdeWP = $wpdb->prefix;
}

 

4. Evitez les noms de variables et de fonctions à rallonges et utiliser les classes (même pour PHP4)

S'il vous plait... évitez les noms de fonctions et de variables à rallonges...

  1. c'est illisible
  2. ça augmente sensiblement la consommation mémoire de PHP

Exemple de nom de fonction trop long:

wordpress_seo_http_error_code_manager_GetPostMeta_FromKeyAndPostId()
wordpress_seo_http_error_code_manager_SetUserMeta()

Priviligiez l'utilisation des classes !

Même si l'implémentation des classes dans PHP4 est limitée, elles sont tout à fait utilisables et possèdent un grand avantage:

Seul le nom de la classe doit être unique !

Les fonctions contenues dans la classe peuvent avoir le nom que l'on souhaite sans problème de doublons. De quoi mettre des noms courts et concis.

Exemple:

Class HttpErrorCodesManager {
    // Displays two fields for 1. the error code and 2. the url to redirect the visitor to
    function printFields() {
    ...
    }
    function redirect() {
    ...
    }
}

Je n'ai plus besoin de savoir si une fonction "redirect()" existe déjà dans WordPress ou un autre plugin vu qu'elle est située dans ma classe.

Simple, mais efficace.

 

5. Développez vos en anglais et internationalisés !

Oui, je sais la France est un beau pays, mais la France c'est petit... tout-petit... ne vous limitez pas aux utilisateurs francophones de WordPress !

Développez vos plugins en anglais...

Plusieurs raisons à cela, il existe plus de personnes lisant l'anglais que le français... très pratique pour la traduction de votre plugin dans plusieurs langues et aussi pour la lisibilité de votre code. Un développeur étranger sera plus à même de vous aider dans un code anglais, qu'un code français...

Conclusion, évitez d'entrer du texte en dur :

Plugin Seo, WordPress-seo.com : Imposer un code d'erreur.
Nous vous remercions de ne pas cree d'erreur 302 vers http://www.wordpress-seo.com
Action :
URL (301 ou 302 ):

Mais écrivez en anglais et internationalisez vos textes:

echo '
',"\n", '
' .__("Force a code error for this post", 'hecm'). '',"\n", '

',"\n", '

',"\n", '
',"\n";

Je ne fais pas de rappel sur les fonctions d'internationalisation, vu que j'ai écrit un article dessus, il y a peu de temps.

6. Utilisez correctement les Hooks de WordPress

Il existe 2 types de Hook dans WordPress, les actions et les filtres. (voir codex)

Ils sont listés sur le codex, on peut également les retrouver à l'adresse suivante: http://wphooks.flatearth.org/

Dans le cas présent, nous allons utiliser l'action présente lors de la publication d'un article. Il s'agit de "publish_post" et comme on peut le voir dans le codex, cette action prend en paramètre l'ID de l'article.

Point que le mauvais plugin n'a pas pris en compte:

function wordpress_seo_http_error_code_manager_save()  {
     global $TAGERROR,$TAGURL,$DEFAULTURL;

     wordpress_seo_http_error_code_manager_SetUserMeta($TAGERROR,$_POST['wordpressseoerrorcode_err'],$_POST['ID']);
     wordpress_seo_http_error_code_manager_SetUserMeta($TAGURL,$_POST['wordpressseoerrorcode_url'],$_POST['ID']);
}

Car il récupère l'ID de l'article depuis l'information $_POST['id'] sans aucun contrôle, ce qui peut poser des problèmes de sécurité.

La bonne méthode est la suivante:

function saveFields($post_id) {
    if( isset($_POST['redirect_code']) || isset($_POST['redirect_url']) ) {
        delete_post_meta($post_id, 'redirect_url');
        delete_post_meta($post_id, 'redirect_code');        
        add_post_meta($post_id, 'redirect_code', (int) $_POST['redirect_code']);        
        add_post_meta($post_id, 'redirect_url', clean_url($_POST['redirect_url']));        
    }
    return;
}

Nous passons en paramètre l'ID de l'article, et comme nous savons que cette valeur provient de WordPress, elle est sécurisée et valide.

7. Faites le moins de requêtes

Un point bien souvent négligé dans les plugins WordPress est le nombre de requêtes effectuées...

Il faut bien comprendre que le nombre de requêtes influe directement sur les performances de votre blog, moins il y en a, plus l'affichage est rapide (sauf exception)

Exemple d'une mauvaise gestion des requêtes:

$Tag_url=$DEFAULTURL;
$Tag_error=wordpress_seo_http_error_code_manager_GetPostMeta_FromKeyAndPostId($TAGERROR,$wp_query->post->ID);
$Tag_urlt=wordpress_seo_http_error_code_manager_GetPostMeta_FromKeyAndPostId($TAGURL,$wp_query->post->ID);
if(strlen($Tag_urlt)>0) {$Tag_url=$Tag_urlt;}
switch($Tag_error)
{
    case 3: 
    header("HTTP/1.1 404 Not Found");
    die("404 File not found!"); 
    exit(); 
    break;
    case 2: 
    header("HTTP/1.1 302 Found", false, 302);
    header("Location: ".$Tag_url."");
    exit();
    break;
    case 1: 
    header('HTTP/1.1 301 Moved Permanently', false, 301); 
    header('Location: '.$Tag_url.''); 
    exit(); 
    break;
    case 0: default:     break;
}

On voit que le plugin effectue toujours 2 requêtes. (ligne 2 et 3)

Or dans le cas numéro 3, on s'aperçoit que le résultat de la deuxième requête n'est pas utilisé. Voilà une requête de trop...

Voilà la même fonction revue et corrigée:

$code = (int) get_post_meta($wp_query->post->ID, 'redirect_code', true);            
if ( $code === 3 ) {
    header('HTTP/1.1 404 Not Found');
    die(__('404 File not found!', 'hecm'));
} elseif ( $code === 2 || $code === 3 ) {
    $url = get_post_meta($wp_query->post->ID, 'redirect_url',  true);
    if ( $code === 2  && !empty(trim($url)) ) {
        wp_redirect($url, 302);
    } 
    if ( $code === 3  && !empty(trim($url)) ) {
        wp_redirect($url, 301);
    }
}

La deuxième requête est effectuée uniquement au besoin et non systématiquement.

Voilà une utilisation intelligente et économique des requêtes.

 

8. Sécurisez votre plugin avec l'API WordPress

Le plugin ne se prête pas vraiment au jeu de la sécurisation des plugins mais sachez qu'il existe un excellent tutoriel en anglais sur la sécurisation des plugins WordPress.

On peut tout de même aborder 2 points.

1. Utiliser les fonctions de l'API vous évite de faire un effort sur la sécurité

2. "castez" vos données au maximum.

Par exemple, si le résultat attendu est un nombre entier, utiliser (int) comme dans l'exemple ci-dessous:

$code = (int) get_post_meta($wp_query->post->ID, 'redirect_code', true);

Si la donnée n'est pas un entier, mais une chaine de caractère ou autres, elle deviendra le chiffre 0.

9. Ne négligez pas la qualité du code HTML !

Oui je sais... c'est plus rapide d'écrire "<br>" que "<br />" mais peu importe... prenez le pari de respecter les normes du W3C et d'assurer à votre plugin une parfaite compatibilité avec tous les navigateurs existants.

Code HTML à bannir:

URL (301 ou 302 ): 

Version conforme au W3C:

URL (301 ou 302 ): 

Ca n'est pas si compliqué ;)

10. L'API de WordPress : Encore et toujours...

l'API de WordPress contient un grand nombre de fonctions très utiles, par exemple, la redirection en PHP.

Selon l'environnement où l'on travaille, l'utilisation de la fonction headers() peut-être différente.

Ne vous compliquez pas la vie !!

La fonction "wp_redirect( $url, $code_http )" gère tout cela de façon transparente pour vous.

Exemple du mauvais plugin:

header("HTTP/1.1 302 Found", false, 302);
header("Location: ".$Tag_url."");

2 lignes et compatibilité plus que douteuse.

La même chose avec l'API WordPress:

wp_redirect($url, 302);

Autre exemple, nous souhaitons enregistrer une adresse internet dans la base de données.

Problématique : Comment savoir que le texte entré correspond bien à une adresse internet ?

On pourrait imaginer une fonction avec des pregs et diverses astuces...

Encore une fois, allez au plus simple...

WordPress possède une fonction "clean_url( $url )" qui s'assure que le texte entré correspond bien à une adresse internet.

11. Ne cherchez pas à profiter des erreurs de vos utilisateurs

Comme on peut le voir dans le mauvais plugin, si un utilisateur oublie de rentrer une adresse internet alors qu'il a sélectionné une redirection, ce dernier est automatiquement renvoyé à l'adresse suivante:

$DEFAULTURL = "http://www.wordpress-seo.com/redirection-par-defaut.php"; // editable a vos risques et peril

Honnêtement, dans une telle situation à part vouloir augmenter son nombre de visiteurs, quel est l'intérêt d'une telle redirection ?

Pourquoi ne pas simplement annuler la redirection si l'utilisateur oublie d'entrer une adresse internet ?

Il y a vraiment des développeurs peu scrupuleux...

Conclusion

Vous pouvez retrouver les 2 plugins au format PHPs içi:

À noter que développer un plugin correctement correspond à environ 50% de lignes de code en moins, ce qui n'est pas négligeable.

Vos réactions sont comme toujours, les bienvenues...

5 Commentaires

  1. Merci Rod pour les fautes ;)

  2. Héhé, bien vu tout ça :P

    (et merci pour la pub en passant)

    Par contre, l’URL exacte vers le plugin est : Http Error Codes Manager

Répondre à xwwx Annuler la réponse.

Champs Requis *.