Insérer des valeurs d'une autre base de données dans un champ "select" d'ACF grâce à WPDB
Imaginons que vous ayez sur une base de données un CMS ou une gestion de stock et que, pour une raison ou une autre, vous souhaitiez insérer, de temps en temps, des informations dans votre blog WordPress, sans développer une synchronisation complexe.
Par exemple, lier certaines catégories de produits dans les deux systèmes.
L'interface souhaitée était un champ dans l'admin, avec une liste déroulante reprenant toutes les catégories produits du système de gestion de stock.
Préparer le champ ACF, de type select
L'erreur à ne surtout pas faire est de saisir à la main dans la liste de choix les catégories du système de stock. Il se passe quoi quand on rajoute une catégorie ou qu'on en supprime une ?
Voici donc la définition de base de ce champ, en php (vous pouvez aussi vous en tenir à l'interface graphique, l'essentiel c'est de récupérer l'id du champ).
[pastacode lang="php" manual="array(%0A%09%09%09'key'%20%3D%3E%20'field_62d495e8zb111'%2C%0A%09%09%09'label'%20%3D%3E%20__('Dolibar%20product%20category'%2C%20'mytextdomain')%2C%0A%09%09%09'name'%20%3D%3E%20'dolibar_product_cat'%2C%0A%09%09%09'type'%20%3D%3E%20'select'%2C%0A%09%09%09'instructions'%20%3D%3E%20''%2C%0A%09%09%09'required'%20%3D%3E%200%2C%0A%09%09%09'conditional_logic'%20%3D%3E%200%2C%0A%09%09%09'wrapper'%20%3D%3E%20array(%0A%09%09%09%09'width'%20%3D%3E%20''%2C%0A%09%09%09%09'class'%20%3D%3E%20''%2C%0A%09%09%09%09'id'%20%3D%3E%20''%2C%0A%09%09%09)%2C%0A%09%09%09'choices'%20%3D%3E%20array(%20)%2C%0A%09%09%09'default_value'%20%3D%3E%200%2C%0A%09%09%09'allow_null'%20%3D%3E%200%2C%0A%09%09%09'multiple'%20%3D%3E%200%2C%0A%09%09%09'ui'%20%3D%3E%200%2C%0A%09%09%09'return_format'%20%3D%3E%20'value'%2C%0A%09%09%09'ajax'%20%3D%3E%200%2C%0A%09%09%09'placeholder'%20%3D%3E%20''%2C%0A%09%09)%2C" message="" highlight="" provider="manual"/]Au passage, vous pouvez noter que l'étiquette est en format __(
, pour permettre la traduction en cas de site multilingue ou simplement d'utilisateur qui veut afficher son admin dans une autre langue. Ça prend trois minutes à mettre en place, et c'est bien utile.
Ce qui est important, c'est que choices est vide.
Ajouter un filtre au champ ACF pour remplir la liste des choix
La liste des choix, c'est un tableau (une array) avec un identifiant et la valeur affichée dans la liste. Ici, on va construire une fonction qui permet de d'aller chercher les valeurs dans l'autre base de données.
Les filtres ACF fonctionnent tous de la même façon : une fonction dont le paramètre unique est $field
(le champ), où on modifie un des éléments, ici les choix : $field['choices']
et qui renvoie, à la fin l'objet $field
complet.
Je prends donc la liste de mes catégories Dolibar (on voit ensuite comment faire) et on la parcourt pour générer les valeurs de choices, sans oublier de rajouter une valeur "nulle" pour ne pas stocker de catégorie.
Et on ajoute le filtre acf/load_field/
(on peut utiliser la clé, comme moi, ou le nom, dolibar_product_cat
, et dans ce cas, le filtre serait :
Se connecter à l'autre base de données
Bien sûr, on pourrait le faire "à la main", de façon classique.
Mais il y a une autre méthode, beaucoup plus simple, qui va aussi énormément faciliter la vie. Utiliser le pouvoir de $wpdb !
Vous savez, la classe magique qui permet de faire des $wpdb->get_results, $wpdb->prepare, etc.
Si on n'a besoin de la base de données externe que pour une seule fonction, on peut le faire à l'intérieur de la précédente fonction, mais quand on commence à jouer avec ce genre de choses, il y a des chances qu'on ait besoin de l'utiliser plusieurs fois.
Créer une variable globale qui représente la seconde connexion, new wpdb
[pastacode lang="php" manual="function%20dolibar_connect(%20)%7B%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20global%20%24dolibar_db%20%3B%20%0A%0A%20%20%20%20%20%20%20%20%24dolibar_db%20%3D%20new%20wpdb('user'%2C%20'password'%2C%20'db_name'%2C%20'db_host'%20)%3B%0A%0A%20%20%20%20%7D%0A%7D%0A%20%20%20%20%0A%20%20%20%20add_action('admin_init'%2C'dolibar_connect'%20)%20%3B" message="" highlight="" provider="manual"/]Et voilà, à partir de maintenant, votre connexion sera disponible où vous voulez, quand vous voulez dans l'admin.
Pour les identifiants de connexion, vous pouvez les écrire en dur dans la fonction ou, mieux, créer une page d'option dans votre plugin pour que l'utilisateur les saisisse, plus facile en cas de modification.
Il reste à aller chercher les valeurs pour les injecter dans la liste de choix.
Faire une sélection sur la seconde base de données
Il suffit d'utiliser $dolibar_db
.
Ma fonction dolibar_product_cat_choices devient :
[pastacode lang="php" manual="function%20dolibar_product_cat_choices(%24field)%20%7B%0A%0Aglobal%20%24dolibar_db%20%3B%20%0A%0A%24product_cats%20%3D%20%24dolibar_db-%3Eget_results(%22Select%20row_id%2C%20label%20from%20llx_categorie%20WHERE%20type%20%3D%200%20ORDER%20BY%20label%20%22)%20%3B%0A%0A%09if%20(%20%24product_cats%20)%20%7B%0A%0A%09%09%24field%5B'choices'%5D%5B0%5D%20%3D%20__('None'%2C%20'textdomain')%20%3B%0A%0A%09%09foreach(%20%24product_cats%20as%20%24k%3D%3E%24v%20)%20%7B%0A%09%09%09%24field%5B'choices'%5D%5B%24v-%3Erow_id%5D%20%3D%20%5B%24v-%3Elabel%5D%0A%09%09%7D%0A%0A%09%7D%0A%09return%20%24field%20%3B%0A%7D%0A%0Aadd_filter('acf%2Fload_field%2Fkey%3Dfield_62d495e8zb111'%2C%20'dolibar_product_cat_choices')%3B" message="" highlight="" provider="manual"/]la méthode get_results
renvoie par défaut un objet pour chaque ligne, d'où le $v->row_id
et le $v->label
.
Simplissime, non ?
En pratique, comment faire ?
Vous pouvez vous contenter de définir le champ ACF dans l'admin. Par contre, le filtre et le reste doivent aller dans un plugin (ne faites pas l'erreur de les mettre dans le fichier functions.php du thème).
Il n'est pas compliqué de faire un plugin, et ça vous évite de casser votre site si vous changez de thème.
Évidemment, vous devez pouvoir vous connecter à la base de données. Sinon il faudra passer par une API.
Et la sécurité dans tout ça ?
D'une façon où d'une autre, on va stocker en clair un mot de passe, dans la base de données ou dans le fichier. Pas moyen de faire autrement.
Le risque qu'un hack se propage à la seconde base de données reste, amha, très faible, mais, dans le doute, vous pouvez toujours créer pour cette base un utilisateur spécifique dont les privilèges sont restreints : SELECT et éventuellement SHOW VIEW.
Car je vous conseille de ne faire que cela. Ne changez pas les données sur l'autre base de données, sauf cas exceptionnel. Les données ne doivent être modifiées qu'à un seul endroit, par leur système maître, et si possible via des fonctions, pas des entrées directes en base.