Les tables personnalisées dans WordPress
Introduction
Même si WordPress propose une structure de tables assez flexible et des API pour en profiter intéressantes, il est parfois nécessaire pour le développeur de créer ses propres tables. Parfois pour les performances, parfois par méconnaissance des API, nous allons voir comment créer une table simple dans WordPress et surtout de manière propre et rapide.
La classe $wpdb
WordPres propose une classe globale qui permet de faire des requêtes SQL très facilement et surtout de façon sécurisée si on s’en donne la peine. Elle permet surtout d’êtrte le plus flexible avec une installation WordPress qui aurait, par exemple, modifié le prefixe de ses tables. Si le développeur n’utilise pas la classe wpdb, toutes ses requêtes ne fonctionneront pas !
Dans classe $wpdb on retrouve tous les noms des tables qui sont natives à WordPress comme la table des métas ou celle des posts. Elle stocke le nom des tables déjà préfixées, par exemple :
1 2 3 | global $wpdb; echo $wpdb->postmeta; |
Si vous utilisez ce bout de code, faites le uniquement en développement
.
Donc ce bout de code affiche le nom de la table postmeta de votre base et avec les préfixes que l’utilisateur aurait pu utiliser.
Cela permet de ne pas se soucier des préfixes de votre utilisateur et surtout que si un jour WordPress décide de changer le nom de la table en base que votre code continue à fonctionner sans problèmes et est maintenu entre les versions.
Et la sécurité ?
Faire des requêtes dans la base est assez problématique si vous le faites à partir d’informations entrées par votre utilisateur puisque certains sont mal intentionnés, et tentent de pirater votre site par cet intermédiaire. Si il tente de passer par le SQL cela s’appelle une attaque par injection SQL, il casse votre requête de base et en fait ce qu’il veut comme, par exemple, supprimer tous les utilisateurs ou toutes votre base etc…
Si votre plugin ou développement utilise des requêtes SQL personnalisées et que vous n’utilisez pas du tout la classe $wpdb, je vous encourage à le faire.
Prenons cet (horrible) exemple:
1 2 3 | global $wpdb; $wpdb->query( "SELECT * FROM wp_posts WHERE ID='$_GET['post_id']'" ); |
Nous sommes dans le cas où il est possible de se faire pirater son site, votre variable qui est dans $_GET peut être tout et n’importe quoi, ça peut être tout autant un ID de post mais aussi des caractères qui voudraient casser la requête actuelle pour aller faire autre chose dans votre base. Deuxième problème on marque directement le nom de la table dans la requête : ‘wp_posts’ ce qui peut ne pas fonctionner.
Voici la manière de le faire le plus proprement possible :
1 2 3 | global $wpdb; $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = '%d'", $_GET['post_id'] ) ); |
Dans cette requête j’utilise l’une des méthodes les plus importantes de la classe : prepare(). Elle permet de spécifier le type de données attendues dans les variables de notre requête. Par exemple ici j’ai mis ‘%d’ cela veut dire que j’attend un chiffre de la variable $_GET['post_id']. Si vous avez plusieurs variables à faire passer dans votre requête vous avez deux choix :
- Mettre l’un après l’autre les variables que vous souhaitez tester
- Donner un tableau à prepare là ou se trouve $_GET ['post_id'], et e mettant les données dans l’ordre de leur apparition.
Et les autres fonctions de wpdb ?
La classe wpdb permet de faire d’autres choses que get_results, par exemple si vous voulez récupérer une ligne entière, utilisez get_row. Si vous voulez récupérer une valeur unique utilisez get_var.
Dans tous les cas je vous invite à consulter la documentation de la classe wpdb du codex, bien d’autres choses vous y attendent.
Créer sa table
Etant donné que nous voulons créer une petite table personnalisée, il faut le faire le plus proprement possible et surtout en s’insérant le plus proprement dans l’installation de notre client. Comme dit plus tôt si votre client a utilisé une prefixe différent de celui que l’on trouve dans WordPress, il faut que vous puissiez utiliser cette donnée aussi !
Pour que tout se passe à merveille, la meilleure solution est de s’insérer dans WordPress et d’utiliser la classe $wpdb à votre avantage.
Déclarons dans la classe une nouvelle table ( attention cela ne la crée en aucun cas ) pour qu’elle puisse être utilisée dans nos requêtes.
1 2 3 | global $wpdb; $wpdb->ma_table_perso = $wpdb->prefix.'nom_de_ma_table_en_base'; |
Maintenant dès que vous aurez à faire une requête dans votre base, il vous suffira de faire $wpdb->ma_table_perso ! Comme ça vous ne vous souciez plus du tout du prefix ou autre.
Par contre il faut faire attention aux nom que vous donnez à votre propriété dans $wpdb, il ne faudrait pas écraser un nom existant, donc préfixez votre nom.
Cet exemple doit s’insérer dans le fichier principal d’un plugin, pour qu’il soit bien pris en compte par la suite.
Dans le cas d’un plugin, on veut créer une table perso lors de l’activation de celui-ci et ne plus la recréer si l’utilisateur le désactive puis le réactive. Voici la manière de procéder que j’utilise :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | register_activation_hook ( __FILE__, 'my_plugin_activate' ); function my_plugin_activate() { global $wpdb; if ( ! empty($wpdb->charset) ) $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset"; if ( ! empty($wpdb->collate) ) $charset_collate .= " COLLATE $wpdb->collate"; // Add one library admin function for next function require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); // Try to create the meta table return maybe_create_table( $wpdb->ma_table_perso, "CREATE TABLE $wpdb->ma_table_perso( `id` int(20) NOT NULL auto_increment, `object_id` INT( 20 ) NOT NULL, `user_id` INT( 20 ) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `object_ids` (`object_id`,`user_id`) ) $charset_collate;" ); } |
Dans ce cas, nous utilisons la classe $wpdb au mieux, nous vérifions bien le charset et le collate si besoin, nous utilisons notre variable de classe pour l’utiliser dans notre requête.
Avec la fonction maybe_create_table, nous ne créons la table que si elle n’existe pas encore, cela nous permet de ne pas générer d’erreurs lors de l’activation de notre plugin.
Avec ça, la table est créée proprement et ne posera pas de problèmes, vous pourrez ainsi utiliser autant de fois que vous le voudrez la classe avec cette variable
Les tables multi-site
Il s’avère que dans le cas d’un multisite avec la méthode citée ci-dessus la table n’est créée que pour le site principal, donc quand les requêtes seront effectuées, elle le seront sur la table du site principal !
Cela peut être utile si vous avez des données qui doivent être lues depuis les sous-sites sur le site principal et pas depuis sa table personnelle.
Si vous voulez que la table soit créée pour le site principal ainsi que sur les sous-sites, vous devez procéder de la manière suivante:
1 2 3 4 | global $wpdb; $wpdb->ma_table_perso = $wpdb->prefix.'nom_de_ma_table_en_base'; $wpdb->tables[] = 'ma_table_perso'; |
De cette manière, vous créerez aussi cette table lors de l’activation de votre plugin sur le sous-site.
Il ne faut pas perdre de vue que créer des tables dans WordPress reste quand même assez rare et je ne vous conseille pas de le faire, utilisez au maximum les possibilités des API de WordPress et de sa structure de base de données qui est assez flexible.
Si vous utilisez des tables personnalisées, faites le avec le plus grand soin et surtout pensez à la sécurité et à limiter les actions de vos utilisateurs. La plupart du temps ce sont les plugins et non WordPress lui même qui a des failles de sécurité. ![]()

ouèè un tuto sans failles et qui parle de sécu …
Merci et bravo
[...] Si vous souhaitez créer votre table dans WordPress, lisez les conseils de Nicolas Juen. [...]
Nicolas, ton précédent post est inaccessible.
message d’erreur :
l’image http://blog.nicolas-juen.fr/2011/10/27/utiliser-lapi-endpoint-pour-creer-une-regle-de-reecriture-durl-simple/#comment-36 ne peut être affichée car elle contient des erreurs.
Effectivement lors de l’affichage de l’article sous firefox j’ai une erreur.. bizarre !
Je ne sais pas si ça vient de mon .htaccess ou d’autre part mais je vais aller voir, rafraîchir la page semble régler le problème…
Je vais faire ma petite investigation ^^
Merci !
effectivement. Très étrange. ^^
Ce code est propre et bien sécurisé. Le tuto est vraiment bien conçu pour éviter d’utiliser la base de données n’importe comment dans WordPress. Merci pour l’info.