COS WP Woo
Retour au blog

Remplacement d'ACF : champs personnalisés avec blocs et répéteurs Gutenberg

ACF Pro coûte jusqu'à 249 $/an, et après l'achat de WP Engine, l'avenir du plugin est en question. Je vais vous expliquer comment nous avons construit un remplacement complet : plus de 20 types de champs, répéteur, contenu flexible, blocs Gutenberg - avec stockage dans des tables personnalisées optimisées au lieu du wp_postmeta gonflé.

Il y a six mois, une vieille connaissance m'a appelé, directeur technique d'un distributeur industriel qui possède une boutique en ligne sur WooCommerce avec seize mille produits. Il avait l'air d'un homme qui venait de recevoir une facture pour des réparations de pare-chocs et qui découvrait en même temps que CASCO ne la couvrait pas. "Oleg", dit-il, "notre abonnement ACF Pro est épuisé, ils ont changé les prix, et maintenant pour notre volume de sites, ils demandent deux cent quarante-neuf dollars par an. J'ai aussi lu que WP Engine les avait achetés, et maintenant tout le monde se demande ce qui va se passer ensuite. Nous sommes complètement liés à eux - toutes les fiches de produits, toutes les caractéristiques, sélection par viscosité, plages de température. S'ils ferment ou cassent l'API, nous nous lèverons." Et cette phrase – « nous nous lèverons » – a retenu mon attention, car ce n’est pas la première fois que je l’entends. J'entends cela au moins une fois par mois de la part de différentes personnes, et derrière cela se cache le même problème, auquel peu de gens pensent jusqu'à ce qu'il leur frappe au front.

Le problème semble simple : dépendance à l'égard d'un plugin tiers pour les fonctionnalités critiques. ACF – Advanced Custom Fields – est devenu le standard de facto pour les champs personnalisés dans WordPress. Presque tous les magasins WooCommerce qui sont allés au-delà d’un simple « nom-prix-description » utilisent ACF ou ses analogues d’une manière ou d’une autre. Caractéristiques des produits, spécifications techniques, documentation, connexions entre les produits, conditions de livraison pour des articles spécifiques - tout cela réside dans des champs personnalisés. Et tout cela, en fait, est entre les mains d'un développeur tiers qui peut modifier les règles du jeu à tout moment. C’est exactement ce qui s’est passé.

Lorsque WP Engine a acquis ACF, une vague d'anxiété a traversé la communauté. Non pas parce que WP Engine est une mauvaise entreprise, mais parce que l’histoire de WordPress regorge d’exemples où le rachat d’un plugin par un acteur majeur a entraîné des conséquences inattendues. Parfois, un plugin cesse tout simplement de se développer. Parfois, les politiques de prix changent, obligeant les petites entreprises à rechercher des alternatives. Parfois, des modifications sont apportées qui rompent la compatibilité ascendante. Et vous êtes assis avec vos seize mille produits, qui comportent chacun vingt à trente champs personnalisés, et vous pensez : que devez-vous faire ? Se déplacer? Où? Sur quoi ? Ces questions ne sont pas abstraites ; Je les ai reçus sous forme d'appels directs de clients qui ont investi des années de travail dans leurs magasins WooCommerce.

Je me souviens comment, lors d'une conférence WordPress à Moscou, j'ai eu une conversation avec le propriétaire d'un réseau de centres de service automobile, qui disposait d'un catalogue de pièces détachées sur WooCommerce de douze mille articles. Il a déclaré que lors de la mise à jour d'ACF de la version 6.1 à 6.2, tous les champs conditionnels des fiches produits « sont tombés ». Les champs ont simplement cessé d'apparaître - parce que la mécanique interne de la logique conditionnelle a changé. Ils l'ont réparé en deux jours, mais pendant ces deux jours le site a travaillé avec des fiches produits incorrectes. Douze mille cartes avec des caractéristiques manquantes ne sont pas seulement un « inconvénient », c'est une perte directe de conversion. Et ce n’est pas la faute d’ACF : ils ont amélioré le produit. Mais la dépendance à l'égard du code tiers signifie que vous acceptez toutes les modifications, même celles pour lesquelles vous n'êtes pas prêt.

J'y ai pensé non pas en tant que théoricien, mais en tant que praticien. Sur notre projet principal - un grand distributeur de lubrifiants - la table wp_postmeta est passée à neuf cent trente-sept mégaoctets. Près d’un gigaoctet de métadonnées à elles seules. Seize mille huit cent quarante-quatre biens, chacun comportant des dizaines de champs. Viscosité, point d'éclair, point d'écoulement, approbations du fabricant, GOST, série, ligne, type de base - et je viens juste de commencer à les énumérer. Et tout cela est dans wp_postmeta, car c'est ainsi que fonctionne ACF. Chaque valeur correspond à une ligne distincte dans le tableau. Chaque répéteur comporte quelques lignes supplémentaires avec des méta-informations sur le nombre d'éléments. Et quand vous faites WP_Query avec une méta-requête sur trois ou quatre champs en même temps, la base de données se met à pleurer. Je n'exagère pas. J'ai vu des requêtes prendre huit secondes sur un serveur doté de lecteurs NVMe et de trente-deux gigaoctets de RAM.

Et si on regardait les choses différemment ? Non pas comme une tâche technique – remplacer un plugin par un autre – mais comme une décision stratégique quant à savoir à qui vous confiez vos données commerciales ? Lorsque j’ai travaillé avec des entreprises industrielles qui construisaient des systèmes ERP, aucune d’entre elles n’envisageait sérieusement l’option « déplaçons la logique clé dans un module tiers que nous ne contrôlons pas et pour lequel nous payons un abonnement annuel ». Ce serait absurde. Mais pour une raison quelconque, dans le monde WordPress, cela est considéré comme la norme. Une entreprise disposant d'un catalogue de vingt mille produits stocke toutes les caractéristiques, toutes les connexions, tous les paramètres techniques dans un plugin tiers. Et il paie pour ce privilège. Et risque de perdre l’accès à chaque mise à jour. Peut-être est-il temps d’arrêter de considérer cela comme la norme et de commencer à construire des infrastructures qui vous appartiennent ?

C'est pourquoi, lorsque nous avons conçu le module de champs personnalisés pour COS WP Woo, j'ai défini la tâche plus large que simplement « faire comme ACF, uniquement gratuitement ». La gratuité est un bonus intéressant, mais ce n’est pas l’objectif. Le but est de bien faire les choses. Assurez-vous que cela ne fera pas mal dans deux ans, lorsque la base aura triplé de taille. Et ce qui est encore plus important, c’est de ne pas vous retrouver dans une situation où les fonctionnalités clés de votre entreprise dépendent des décisions d’un fournisseur que vous ne contrôlez pas.

Pourquoi wp_postmeta est un piège architectural

Voyons pourquoi j'insiste tant sur le fait que stocker les champs personnalisés dans wp_postmeta est une mauvaise idée, en particulier pour les boutiques en ligne disposant d'un grand catalogue. WordPress a été créé comme plateforme de blogs. La table postmeta a été conçue pour stocker des informations supplémentaires sur les enregistrements - une paire clé-valeur pour chaque enregistrement. Cela fonctionne très bien lorsque vous avez une centaine d’articles et que chacun comporte trois ou quatre champs attachés. Mais lorsque vous avez seize mille produits et vingt-cinq champs pour chacun, vous obtenez quatre cent mille lignes uniquement pour les valeurs directes. Et s'il y a aussi des répéteurs avec trois éléments chacun, multipliez par trois. Plus les chaînes techniques qu'ACF utilise pour stocker les clés de champ, l'ordre des éléments dans le répéteur et les indicateurs. En conséquence, nous obtenons facilement un million à une ligne et demie dans une table.

Et c'est là que le plaisir commence. MySQL gère très bien un million de lignes, si vous indexez et interrogez correctement les données. Mais wp_postmeta a une structure spécifique : post_id, meta_key, meta_value. L'index est sur post_id et meta_key. Lorsque vous recherchez "tous les produits avec une viscosité = 5W-30 ET un point d'éclair supérieur à deux cents ET une approbation KAMAZ = oui", MySQL doit effectuer plusieurs JOINs de la table postmeta sur lui-même. Chaque méta-requête est un JOIN distinct. Trois conditions - trois JOINs de la même table de neuf cents mégaoctets. Et l’optimiseur de requêtes commence à faire des merveilles, mais pas les miracles auxquels vous vous attendez. Il essaie de trouver le plan d'exécution optimal, parcourt les options, choisit parfois une recherche complète dans la table - et vous obtenez une requête qui bloque le serveur.

Nous avons mesuré. Sur notre serveur de production avec cache Redis et MySQL optimisé, une requête avec trois méta-conditions sur un catalogue de seize mille produits prenait de trois à huit secondes sans cache. Avec Redis, c'est plus rapide, mais seulement lorsque le cache est chaud. Et le cache est invalidé à chaque mise à jour du produit. Et lorsque vous synchronisez avec 1C, qui met à jour les soldes et les prix une fois par heure, le cache est invalidé de manière cyclique. Cela s'avère être un cercle vicieux : vous installez Redis pour accélérer les méta-requêtes, mais la synchronisation tue le cache et les utilisateurs attendent à nouveau cinq à huit secondes sur la page de filtrage. Ce n'est pas un problème théorique, c'est la réalité quotidienne de toute boutique WooCommerce intégrée à un système comptable.

Lorsque nous avons conçu le module CF dans COS WP Woo, nous avons immédiatement imaginé une architecture de stockage différente. Trois tables personnalisées : wpaic_cf_field_groups pour les groupes de champs, wpaic_cf_fields pour les descriptions de champs et wpaic_cf_values ​​​​​​pour les valeurs. La table de valeurs est structurée différemment : elle connaît les types de données, les relations entre les champs et l'imbrication. Il ne stocke pas tout sous forme de texte dans meta_value, mais utilise des colonnes saisies. Les valeurs numériques sont stockées sous forme de nombres, les dates sous forme de dates, JSON sous forme de JSON. Cela permet à MySQL d'utiliser des index normaux et une optimisation normale. La même requête avec trois conditions qui prenait huit secondes dans postmeta est exécutée en deux cent à trois cents millisecondes sur des tables personnalisées. La différence est de vingt à trente fois. Et ce n'est pas un chiffre marketing, c'est une mesure basée sur des données réelles, sur un vrai serveur de production avec une charge réelle.

Il existe une autre nuance non évidente et rarement évoquée. La colonne meta_value dans wp_postmeta est de type LONGTEXT. Cela signifie que l'index de cette colonne est partiel, basé uniquement sur les premiers caractères. Lorsque vous effectuez une méta-requête avec l'opérateur égal, MySQL peut utiliser l'index. Mais lorsque vous avez besoin d'un LIKE ou d'une comparaison numérique, l'index est inutile car MySQL ne sait pas que meta_value stocke un nombre. Il est obligé de convertir la chaîne en nombre pour chaque ligne du tableau. Sur neuf cents mégaoctets de données, cela signifie une recherche complète. Et aucun paramètre MySQL n'aidera - le problème réside dans l'architecture de stockage elle-même, et non dans la configuration du serveur. Nous avons testé cela en utilisant EXPLAIN sur des requêtes réelles - MySQL a honnêtement montré le type : ALL, c'est-à-dire une analyse complète de la table.

Mais voici le problème. Un stockage rapide n’est que la base. L’utilisateur de l’administrateur WordPress ne se soucie pas de l’endroit où se trouvent physiquement ses données. Il est important pour lui que l'interface fonctionne de manière pratique, que les champs soient créés facilement, que les répéteurs ne présentent pas de problèmes et que Gutenberg affiche normalement le contenu personnalisé. Et nous arrivons ici à ce qui constitue réellement la valeur fondamentale d'ACF : non pas le stockage de données, mais l'interface de gestion. Et ici, nous devions non seulement répéter ce qu’ACF avait fait, mais faire un pas en avant.

Vingt types de champs et une interface qui ne nécessite aucune instruction

Lorsque j'ai analysé la manière dont nos clients utilisent ACF, j'ai dressé une liste des types de champs rencontrés le plus souvent. Champ de texte, zone de texte, numéro, e-mail, URL : ce sont les éléments de base dont vous ne pouvez pas vous passer. Select, checkbox, radio sont également standard. Mais ensuite des choses plus intéressantes commencent : les relations entre les objets, une galerie d'images, la date et l'heure, le sélecteur de couleurs, l'éditeur WYSIWYG, les pièces jointes, les commutateurs vrai/faux, Google Maps (même si ce dernier, pour être honnête, n'est nécessaire que par quelques-uns). Et ce sont ces types « avancés » qui font des champs personnalisés un outil vraiment puissant.

Nous avons implémenté plus d'une vingtaine de types de champs dans le module CF pour COS WP Woo. Je ne transformerai pas l'article en une documentation technique et énumérerai chacun d'entre eux, mais je souhaite en souligner quelques-uns que je considère comme essentiels pour les magasins WooCommerce et que nous avons implémentés d'une manière fondamentalement différente de celle d'ACF.

CfRelationshipField - relations entre objets. C'est ce qu'utilisent presque tous nos clients, et ce qu'ACF ne fonctionne pas idéalement sur de gros catalogues, c'est un euphémisme. Lorsque vous avez seize mille produits et que vous devez en sélectionner des produits associés, la recherche AJAX dans ACF commence à ralentir. Vous saisissez trois lettres, attendez une seconde ou deux, les résultats arrivent, mais vous n'êtes pas sûr d'avoir trouvé tous les produits correspondants, car ACF limite la sortie. Notre implémentation de CfRelationshipField utilise la recherche et la pagination indexées. Vous commencez à saisir le nom du produit - et les résultats apparaissent instantanément, même sur un catalogue de vingt mille articles. Parce que la recherche n'est pas effectuée par méta_valeur via LIKE, mais par des index de texte intégral normaux. Et les résultats sont paginés - vous pouvez faire défiler toutes les correspondances, plutôt que d'espérer que le produit dont vous avez besoin figure parmi les vingt premiers.

CfGalleryField - galerie d'images. Un autre point sensible. Dans ACF, la galerie fonctionne via le chargeur multimédia WordPress standard, et c'est... tolérable. Mais lorsque vous devez télécharger dix photos d'un produit, les trier dans le bon ordre, en recadrer une, en remplacer une autre, le processus se transforme en une séquence de clics sur les fenêtres modales. J'ai ouvert la médiathèque, sélectionné un fichier, l'ai fermé, réalisé que je devais le découper - je l'ai rouvert, j'ai trouvé le fichier, j'ai ouvert l'éditeur, je l'ai recadré, je l'ai enregistré, je l'ai fermé. Notre CfGalleryField est intégré directement dans la métabox : téléchargement de fichiers par glisser-déposer directement dans la zone de champ, tri par glisser-déposer, recadrage des images sans quitter l'éditeur de produit. Cela semble peu de chose, mais lorsqu'un gestionnaire de contenu traite cinquante produits par jour, chaque clic enregistré est multiplié par cinquante. En une semaine, une heure et demie de temps pur s'accumule. Dans un mois - une journée de travail entière. Je n’aime pas compter l’efficacité en minutes, mais quand la différence est si évidente, les chiffres parlent d’eux-mêmes.

Et maintenant, parlons de ce qui distingue le travail professionnel avec des champs personnalisés du travail amateur : Répéteur et contenu flexible. Deux types de champs qu’ACF a longtemps gardés derrière un mur payant, et qui déterminent essentiellement si vous pouvez ou non construire un annuaire sérieux avec une structure de données complexe sur WordPress.

Répéteur et Contenu Flexible : quand les simples champs ne suffisent pas

Tu sais ce qui est drôle ? Lorsque je montre aux nouveaux clients une liste de types de champs, ils disent généralement : « Eh bien, nous n'avons besoin que de texte et de sélection, le reste est inutile. » Et après trois mois de travail, ils utilisent relation, galerie, répéteur et contenu flexible, et demandent : « Y a-t-il un type de champ pour… » Les besoins grandissent avec la compréhension des possibilités. Et par conséquent, il était fondamentalement important pour nous d'implémenter la vingtaine de types à la fois, et de ne pas les ajouter progressivement. Car lorsque le client se rend compte qu’il a besoin d’un répéteur, mais qu’il n’y en a pas, il retourne chez ACF. Et puis il est quasiment impossible de le restituer. Les premières impressions comptent, et si le premier jour d'utilisation une personne ne trouve pas le type de champ souhaité, c'est tout, il n'y aura pas de seconde chance.

Honnêtement, le répéteur est la fonctionnalité pour laquelle la plupart des gens achètent ACF Pro. La version gratuite d'ACF ne l'inclut pas, et c'est la principale raison pour laquelle quarante-neuf dollars par an sont dépensés en abonnement. Qu’est-ce que le répéteur dans le contexte de WooCommerce ? Imaginez une fiche produit : l'huile moteur. Il dispose des agréments des constructeurs automobiles : BMW Longlife-01, Mercedes-Benz MB 229.5, Volkswagen VW 502.00. Chaque tolérance est plus qu'une simple ligne de texte. Il s'agit d'un objet avec un nom, un numéro, un statut (valide ou obsolète) et un lien vers un document de confirmation. Et une huile peut avoir de deux à quinze tolérances de ce type. Comment stocker cela sans répéteur ? Vous pouvez bien sûr tout regrouper dans un seul champ de texte séparé par des virgules. Mais alors vous ne pourrez pas filtrer correctement par tolérances, vous ne pourrez pas les afficher sous une forme structurée, vous ne pourrez pas vérifier leur validité. Ou vous pouvez créer quinze champs distincts « Tolérance 1 », « Tolérance 2 »... « Tolérance 15 » - mais c'est moche et rigide.

Repeater résout ce problème avec élégance. Vous créez un groupe de sous-champs - « Nom de l'approbation », « Numéro », « Statut », « Document » - et indiquez que ce groupe est répétable. Dans l'éditeur de produits, le gestionnaire de contenu voit le bouton « Ajouter une autorisation », clique dessus et un nouveau bloc avec quatre champs apparaît. Je l'ai rempli, j'ai cliqué à nouveau - le deuxième bloc est apparu. Vous devez modifier l'ordre - faites glisser et déposez avec la souris. Besoin de supprimer - cliquez sur la croix. Tout est intuitif, tout fonctionne. Le gestionnaire n'a pas besoin de connaître quoi que ce soit sur la base de données, le JSON ou les champs méta : il clique simplement sur « Ajouter » et remplit le formulaire.

Notre CfRepeaterField dans COS WP Woo va au-delà du répéteur ACF standard de plusieurs manières importantes. Dans ACF, les données du répéteur sont stockées dans postmeta sous la forme d'un ensemble de champs méta distincts : _tolerances_0_name, _tolerances_0_number, _tolerances_1_name, _tolerances_1_number, etc. Plus un champ distinct _tolerances, qui stocke le nombre d'éléments. Pour un produit avec dix tolérances et quatre sous-champs, cela représente quarante et une entrées postméta pour un seul répéteur. Quarante et une lignes dans un tableau qui pèse déjà près d'un gigaoctet. Et si vous avez trois répéteurs sur un produit - un pour les homologations, un pour les caractéristiques techniques, un pour la documentation - vous obtenez facilement cent vingt lignes en postmeta pour un produit. Multipliez par seize mille produits et vous obtiendrez près de deux millions de lignes rien qu'avec les répéteurs. Notre implémentation stocke les données du répéteur sous forme de document JSON dans un champ d'une table saisie. Les dix tolérances avec tous les sous-champs - une entrée au lieu de quarante et un. Dans le même temps, la recherche et le filtrage fonctionnent via les fonctions MySQL JSON, qui dans la version 8.0 et supérieure sont assez rapides et prennent en charge l'indexation.

Mais le répéteur n'est qu'une petite chose. Le vrai pouvoir commence avec le contenu flexible. Imaginez que vous deviez créer non seulement un ensemble répétable de champs identiques, mais également un constructeur à partir de différents blocs. Sur une page de marque, par exemple, il peut y avoir : un bloc de texte avec une description, un bloc avec des caractéristiques sous forme de tableau, un bloc avec une galerie de produits, un bloc avec un avis vidéo, un bloc avec des avis revendeurs. Chacun de ces blocs a sa propre structure de champs - le bloc de texte n'a qu'un éditeur WYSIWYG, la galerie a un ensemble d'images avec légendes, le tableau des caractéristiques a un répéteur avec des paires paramètre-valeur. Et l'utilisateur devrait pouvoir ajouter n'importe quel bloc dans n'importe quel ordre - comme un constructeur Lego. Il s'agit d'un contenu flexible.

CfFlexibleContentField dans notre module implémente exactement ce scénario. Vous définissez un ensemble de « mises en page » - chacune avec ses propres champs. Et dans l'éditeur, le gestionnaire de contenu sélectionne la mise en page souhaitée, l'ajoute à la page et remplit les champs. Peut-être en ajouter un autre identique ou différent. Peut faire glisser des blocs et changer l'ordre. Le résultat est une structure de page entièrement personnalisée, assemblée à partir de composants prêts à l'emploi, sans une seule ligne de code. Et je pense que le contenu flexible est ce qui transforme WordPress d'une plate-forme de blogs en un système de gestion de contenu à part entière de niveau entreprise. Car sans cela, chaque page non standard nécessite l'intervention du développeur, mais le gestionnaire de contenu peut s'en occuper lui-même. Pour les entreprises B2B, cela est d'une importance cruciale : pages de marque, catalogues de produits par secteur, sections techniques - tout cela doit être mis à jour régulièrement, et il n'est tout simplement pas rentable d'attirer un programmeur à chaque fois.

Et nous arrivons ici à un sujet qui a été une véritable révélation pour moi : l'intégration des champs personnalisés avec Gutenberg. Quand j’ai commencé ce projet, j’étais sceptique. Je pensais que Gutenberg était maladroit et redondant pour WooCommerce. Mais j'avais tort, et voici pourquoi.

Blocs Gutenberg et générateurs de règles visuelles

Savez-vous ce qui m'a le plus irrité chez ACF ? Le fait que les champs personnalisés vivent séparément du contenu. Vous ouvrez l'éditeur de produit, en haut il y a Gutenberg avec une description, et quelque part en dessous, sous les cinq écrans défilants, il y a des métaboxes ACF avec des champs personnalisés. Deux univers distincts qui ne se connaissent pas. Le gestionnaire de contenu est obligé de faire défiler l'écran d'avant en arrière, de se rappeler de quoi il est responsable et d'espérer qu'il n'a pas manqué un champ obligatoire quelque part dans les métaboxes inférieures. Ce n'est pas un problème d'architecture, c'est un problème d'expérience utilisateur. Et pour un gestionnaire de contenu qui travaille avec une cinquantaine de produits par jour, cette expérience détermine sa productivité.

J'ai vu des projets dans lesquels les gens inventent leurs propres champs répétables au niveau du thème - via JavaScript et AJAX dans l'administrateur. Cela a fonctionné, mais chaque mise à jour de WordPress ou WooCommerce s'est transformée en loterie. Le répéteur auto-écrit pourrait tomber en panne en raison d'un changement dans jQuery, d'un nouveau format de métabox ou d'une mise à jour de l'éditeur TinyMCE. Et à chaque fois, le développeur a passé des heures à réparer ce qui devrait, en toute bonne foi, être la fonctionnalité standard de la plateforme. Les champs personnalisés avec des blocs répétables ne sont pas un luxe, ils constituent l'infrastructure de base de tout annuaire sérieux. Et le fait que WordPress ne l’inclut toujours pas dans son noyau est l’une des principales raisons pour lesquelles il existe toute une industrie de plugins autour des champs personnalisés.

Lorsque nous avons conçu le module CF, je me suis fixé un objectif : chaque groupe de champs personnalisés doit automatiquement recevoir une vue en bloc dans Gutenberg. Non pas « peut être configuré via un plugin séparé », non « nécessite un développement supplémentaire », mais automatiquement. J'ai créé un groupe de champs et le bloc correspondant est immédiatement apparu dans Gutenberg. Ceci est implémenté via le composant CfBlocks, qui enregistre dynamiquement les blocs Gutenberg en fonction de la configuration des groupes de champs. Techniquement, cela fonctionne comme ceci : lors de la sauvegarde d'un groupe de champs, le code PHP génère un enregistrement de bloc via register_block_type(), et le composant React restitue le formulaire de saisie directement dans l'éditeur.

À quoi cela ressemble-t-il en pratique ? Disons que vous avez créé un groupe de champs « Caractéristiques techniques de l'huile » avec les champs suivants : viscosité, point d'éclair, point d'écoulement, tolérances du fabricant, domaine d'application. Après avoir enregistré le groupe, le bloc Oil Spécifications apparaît dans la bibliothèque de blocs Gutenberg. Le gestionnaire de contenu peut l'insérer directement dans le contenu du produit, à côté de la description, entre les paragraphes – n'importe où. Et les champs sont affichés dans le contexte du contenu, plutôt que dans une métabox distincte en bas de la page. Cela change fondamentalement le flux de travail. Au lieu de « remplissez la description en haut, puis faites défiler vers le bas et remplissez les caractéristiques », vous obtenez un seul flux - une description, puis un bloc avec des caractéristiques, puis une autre description, puis un bloc avec des tolérances. Tout est au même endroit, dans le bon ordre.

Bien entendu, nous avons également conservé l'approche classique avec les métaboxes. Tous les utilisateurs ne sont pas prêts pour Gutenberg et tous les scripts ne nécessitent pas une représentation en bloc. Il existe des entreprises où l’éditeur WordPress est réglé en mode classique, et changer les habitudes des gens n’est pas notre métier. Si vous êtes habitué aux métaboxes, s'il vous plaît, elles fonctionnent exactement de la même manière que dans ACF. Mais la possibilité de passer aux blocs existe et cela ne nécessite aucun effort supplémentaire. C’est une question de préparation de l’équipe et non de limitations techniques.

Parlons maintenant des concepteurs visuels - l'une des choses dont je suis le plus fier dans ce module. CfLocationRulesBuilder est un constructeur visuel qui détermine exactement où vos champs personnalisés seront affichés. Dans ACF, cela fonctionne via des listes déroulantes : "Afficher ce groupe de champs si le type d'enregistrement est produit ET la catégorie de produit est masla." Abandons, petit texte, logique ET/OU non évidente qui déroute même les utilisateurs expérimentés. Notre constructeur est une interface visuelle construite en React, où les règles sont représentées sous forme de cartes. Vous voyez littéralement la logique : ce bloc de conditions est connecté via AND et à un autre bloc via OR. Vous faites glisser les cartes, modifiez les conditions et vous comprenez immédiatement ce qui va se passer. J'ai montré cela à plusieurs gestionnaires de contenu qui avaient peur de toucher aux paramètres ACF depuis des mois - ils l'ont compris en cinq minutes. Pas de documentation, pas de formation.

CfConditionalLogicBuilder va encore plus loin. Il s'agit d'une logique conditionnelle au niveau d'un champ individuel : afficher ou masquer un champ en fonction des valeurs des autres champs. Par exemple, si le type d'huile est « moteur », affichez le champ « tolérances moteur ». Si le type est « hydraulique », afficher le champ « Classe ISO ». Si le fabricant « Shell » est sélectionné, affichez le champ supplémentaire « Shell line ». Pourquoi est-ce nécessaire ? Ensuite, les fiches produits pour l’huile moteur et l’huile hydraulique sont deux fiches différentes avec un ensemble de champs différent. Et au lieu de montrer au gestionnaire les trente champs à la fois (dont la moitié ne sont pas applicables), la logique conditionnelle affiche uniquement les champs pertinents. Moins de champs - moins d'erreurs - une complétion plus rapide. ACF l'a, mais il est implémenté sous la forme d'une simple liste de conditions sans retour visuel. Notre constructeur montre visuellement les connexions entre les champs - vous voyez quels champs dépendent de lesquels, où quelle logique est appliquée. Et surtout, vous pouvez tester les conditions directement dans le designer, sans passer par l'éditeur produit.

Je me demande depuis longtemps si ces constructeurs visuels valent mon temps. Le code n’est que cela : il peut s’agir simplement d’un fichier de configuration ou d’une API logicielle. Mais ensuite je me suis rappelé combien de fois des clients m'ont appelé pour me demander « pourquoi ce champ n'apparaît-il pas dans telle ou telle catégorie ? - et la réponse était toujours la même : les règles de localisation étaient mal configurées car l'interface de configuration était incompréhensible. Le concepteur visuel ne résout pas tous les problèmes du monde, mais il résout celui-ci en particulier : les gens arrêtent de faire des erreurs lors de la configuration et ils arrêtent de m'appeler. Et cela, croyez-moi, vaut les semaines de développement que nous avons consacrées à ces composants.

Couche de compatibilité et écosystème : pourquoi ce n'est pas juste un plugin de plus

Lorsque nous avons commencé à concevoir le module CF, j'ai immédiatement réalisé que quatre-vingt-dix pour cent des utilisateurs potentiels étaient des personnes qui utilisaient déjà ACF. Et ils ne sont pas prêts à simplement « reprendre et changer ». Ils ont des modèles de thème qui appellent get_field() et the_field(). Ils disposent de plugins qui s'intègrent à ACF via son API. Ils ont un code personnalisé dans Functions.php qui utilise des hooks ACF. Se déplacer sans couche de compatibilité signifie : réécrire toute l'interface du site, tous les modèles, toutes les intégrations. Pour un site de seize mille produits, cela signifie des mois de travail et un risque énorme de casser quelque chose. Ce n’est pas un risque qu’une entreprise intelligente prendrait, même si le nouvel outil est objectivement meilleur.

Par conséquent, nous avons implémenté register_cf_compat() - une couche de compatibilité qui intercepte toutes les fonctions ACF standard et les achemine vers notre module. Les fonctions get_field(), the_field(), get_sub_field(), have_rows() fonctionnent toutes. Vous pouvez désactiver ACF, activer notre module et vos modèles continueront à fonctionner sans changer une seule ligne de code. La couche de compatibilité fonctionne au niveau des fonctions wrapper. Lorsque votre modèle appelle get_field avec une clé de champ et un ID de publication, notre wrapper détermine à quel groupe de champs appartient le champ, accède à la table wpaic_cf_values ​​​​au lieu de postmeta et renvoie la valeur dans le même format que celui renvoyé par ACF. Pour les répéteurs, la logique est plus compliquée : have_rows() initialise l'itérateur interne, the_row() déplace le pointeur, get_sub_field() récupère la valeur de la ligne actuelle. Toutes ces mécaniques sont reproduites exactement parce que nous les comprenons : un endroit cassé dans le template et le client revient pour toujours à ACF.

Mais je veux être honnête : une compatibilité à 100% est une utopie. Si votre code utilise directement les classes internes d'ACF, ou si vous êtes lié à des hooks spécifiques qui ne figurent pas dans la documentation, il peut y avoir des nuances. Nous avons abordé l'API publique, qui est décrite dans la documentation et qui est utilisée dans quatre-vingt-quinze pour cent des cas. Les cinq autres sont des espèces exotiques qui doivent être analysées individuellement. Pour la grande majorité des sites, la migration ressemble à ceci : installé COS WP Woo, activé le module CF, importé des groupes de champs depuis ACF, désactivé ACF, vérifié - ça marche.

La migration des données est un processus distinct. La couche de compatibilité permet à votre site de fonctionner immédiatement, mais les données sont toujours physiquement en postmeta. Pour obtenir des avantages en termes de performances, nous devons transférer les données de postmeta vers nos tables personnalisées. Il s'agit d'une opération distincte effectuée par un processus en arrière-plan via le planificateur d'actions - sans arrêter le site, sans temps d'arrêt. Pour seize mille produits, la migration prend environ vingt à trente minutes. Après la migration, vous bénéficiez à la fois de la compatibilité avec l’ancien code et des performances du nouveau stockage. Et les anciennes données de postmeta peuvent être laissées en sauvegarde ou supprimées lorsque vous êtes sûr que tout fonctionne correctement.

Qu'en est-il de l'API REST ? C’est une question que se posent les développeurs, et elle est tout à fait légitime. Dans les projets modernes, le frontend est de plus en plus séparé du backend - architecture sans tête, applications mobiles, intégration avec des systèmes externes. L'accès aux champs personnalisés via API n'est pas un luxe, mais une nécessité. ACF Pro fournit une API REST, mais avec des mises en garde : vous devez activer explicitement la prise en charge de l'API pour chaque groupe de champs, le format de réponse n'est pas toujours prévisible et pour les répéteurs, les données se présentent sous une forme plate, que vous devez assembler indépendamment dans une structure. Notre module fournit une API REST complète dès le départ. Un contrôleur avec CRUD complet pour les groupes de champs et de valeurs. Les valeurs des champs sont disponibles au format imbriqué : le répéteur est renvoyé sous forme de tableau d'objets, le contenu flexible est renvoyé sous forme de tableau de blocs indiquant le type de mise en page. Aucune collecte manuelle de données côté client. Le format est prévisible, documenté et ne change pas entre les versions.

Neuf services exécutent le module en coulisses. CfFieldGroupService gère les groupes de champs. CfFieldService - champs individuels et leurs configurations. CfFieldValueService - lecture et écriture de valeurs. CfRelationshipService - connexions entre objets. Six pages React dans le panneau d'administration donnent un contrôle total : liste des groupes de champs, éditeur de groupe, concepteur de règles de mise en page, concepteur de logique conditionnelle, migration depuis ACF, paramètres du module. Tout est construit sur des composants WordPress standard, donc l'interface semble native et n'entre pas en conflit avec d'autres plugins.

Je sais que beaucoup diront : « Pourquoi faire tout ça s'il y a des Carbon Fields, des Pods, des Meta Box ? » C'est une bonne question, et j'y répondrai directement. Carbon Fields est un excellent plugin gratuit, mais il n'a pas d'interface visuelle pour créer des champs dans le panneau d'administration, tout se fait via du code. C'est normal pour un développeur, mais une impasse pour un gestionnaire de contenu. Pods est un framework puissant, mais il est excessif pour la plupart des tâches et présente une courbe d'apprentissage abrupte qui intimide même les utilisateurs WordPress expérimentés. Meta Box est bon, mais payant pour des fonctions avancées, et est encore une fois lié à son propre écosystème d'une douzaine d'addons. Chacun d’eux résout une partie du problème, mais aucun ne résout celui que j’ai décrit au début : la dépendance à l’égard d’un fournisseur tiers pour les fonctionnalités critiques.

Mais le plus important c'est qu'aucun de ces plugins n'est intégré à votre recherche, votre 1C, votre module B2B. Le module CF dans COS WP Woo fait partie de l'écosystème. Il fonctionne avec le module d'intégration 1C, qui mappe les attributs du produit de 1C : Trade Management aux champs personnalisés. Il fonctionne avec un module de recherche qui indexe les champs personnalisés pour la recherche en texte intégral via Typesense. Il fonctionne avec le module B2B, qui utilise des champs personnalisés pour configurer les droits d'accès des groupes. Lorsqu'un gestionnaire ajoute un nouveau permis au répéteur, notre module écrit des données dans wpaic_cf_values, met à jour l'index de recherche Typesense via les hooks du module de recherche et vérifie si le permis fait référence à KAMAZ ou MAZ, ajoute automatiquement le produit à la catégorie « Pour les équipements russes ». Une action du gestionnaire donne lieu à trois résultats dans des systèmes différents.

Je ne dis pas qu'ACF est un mauvais produit. Il est génial. Il a établi la norme en matière de champs personnalisés dans WordPress, et nous lui en sommes très reconnaissants. Mais le monde a changé. WordPress est devenu une plateforme pour le commerce électronique sérieux, pour les portails B2B et pour l'intégration avec les systèmes ERP. Et les exigences en matière de champs personnalisés ont tellement augmenté que l'approche « tout dans postmeta, tout via méta-requêtes » a tout simplement cessé d'évoluer. Ce n'est pas la faute d'ACF, c'est l'évolution des tâches. J'utilise souvent l'analogie du transport. L’ACF est une berline fiable qui roule bien en ville. Mais lorsque vous devez transporter vingt tonnes de marchandises de Tcheliabinsk à Moscou, vous prenez un camion. Non pas parce que la berline est mauvaise, mais parce que la tâche est différente.

Quant au coût, comptons honnêtement. ACF Pro coûte entre quarante-neuf et deux cent quarante-neuf dollars par an, selon le nombre de sites. Sur cinq ans - de deux cent quarante-cinq à mille deux cent quarante-cinq dollars uniquement pour les champs personnalisés. Ajoutez à cela les extensions WooCommerce nécessaires au filtrage par champs méta, à la tarification B2B basée sur les champs méta, à l'indexation de recherche des champs méta - et le coût total de possession augmente de trois à quatre fois. COS WP Woo inclut tout cela dans une seule licence. Champs personnalisés, recherche, B2B, 1C - tout fonctionne ensemble, tout est pris en charge par une seule équipe, tout est mis à jour de manière synchrone. Pas besoin de vérifier la compatibilité de cinq plugins à chaque mise à jour. Il n’est pas nécessaire d’écrire des hooks pour relier un plugin à un autre. Il n’est pas nécessaire de prier pour que la mise à jour d’ACF ne rompe pas l’intégration avec le plugin de recherche.

Mais je ne veux pas que cet article ressemble à un argumentaire de vente. Par conséquent, je serai honnête sur ce que notre module ne fait pas encore. Nous n'avons pas de plugin séparé pour le frontend qui générerait des formulaires basés sur des champs personnalisés - nous avons notre module de formulaires pour cela. Nous n'avons pas de blocs pour Elementor ou WPBakery - nous nous appuyons sur Gutenberg, et si votre site est entièrement construit sur Elementor, l'intégration se fera via des shortcodes plutôt que des widgets natifs. Et notre couche de compatibilité avec ACF ne couvre pas à cent pour cent - j'ai déjà parlé de scénarios exotiques. C’est une position honnête, et je préfère être ouvert sur les limitations plutôt que de traiter plus tard avec des utilisateurs déçus.

C'est ce qui me semble le plus important. Lorsque vous choisissez un outil pour stocker et gérer vos données commerciales (et les champs de produits personnalisés sont vos données commerciales), vous devez penser à un horizon de cinq à dix ans. ACF existera-t-elle encore dans cinq ans ? Très probablement oui. Mais est-ce que ça coûtera le même prix ? Supportera-t-il la même architecture ? WP Engine ira-t-il dans la direction dont votre entreprise a besoin ? Personne ne le sait. Et quand vous avez seize mille produits et que la table postméta pèse un gigaoctet, chaque mauvaise réponse à ces questions coûte très cher. Je choisis la prévisibilité : un outil que je contrôle, qui stocke les données efficacement, qui est intégré à mon écosystème et qui ne dépend pas des décisions stratégiques d'un fournisseur tiers.

Il y a une pensée que je veux laisser pour la fin. Nous vivons à une époque où les données constituent le principal atout des entreprises. Les caractéristiques de vos produits, leurs connexions, leurs paramètres techniques ne sont pas de simples champs dans une base de données. Il s’agit de connaissances que votre entreprise a accumulées au fil des années. Viscosité de chaque huile, compatibilité avec chaque type de moteur, recommandations pour chaque secteur d'activité, derrière chaque champ renseigné se cachent des heures de travail technique. Et ces connaissances sont stockées dans un outil que vous ne contrôlez pas, dans un format qui n'est pas optimal pour vos tâches, dans un tableau qui pèse presque un gigaoctet et ralentit à chaque requête. Peut-être est-il temps de réfléchir à la manière de stocker correctement ces connaissances ? Il est temps de choisir un outil qui respecte vos données autant que vous respectez vos clients.

Et si vous êtes actuellement assis devant l'écran avec une lettre ouverte sur le renouvellement de votre abonnement ACF Pro et que vous pensez « et si je ne renouvelle pas ? – essayez de vous poser trois questions. Combien coûte votre dépendance à l’égard d’ACF en argent – ​​non seulement l’abonnement, mais aussi le temps nécessaire pour prendre en charge les intégrations ? Combien pèse votre table postmeta et comment cela affecte-t-il la vitesse du site ? Et avez-vous un plan B au cas où ACF modifierait l’API ou la politique de tarification ? Si au moins une des réponses ne vous convient pas, alors il est temps de réfléchir à des changements.

Essayez COS WP Woo - quatorze jours gratuits. Installez, activez le module de champs personnalisés, importez un groupe depuis ACF, travaillez avec lui pendant une semaine. Ressentez la différence de vitesse de requête, essayez le générateur de règles visuelles, voyez comment fonctionne le répéteur dans un bloc Gutenberg. Et puis décidez - de vos propres mains, en utilisant vos propres données, sans promesses marketing. Parce que le meilleur argument est votre propre expérience.