Tout savoir sur WordPress

Importer vos données Prismic vers WordPress

Prismic.io est un CMS moderne plein de promesses. Un de mes clients a souhaité revenir sur WordPress et avait donc besoin d’importer les données de l’un vers l’autre. Je partage mon script d’import avec vous aujourd’hui.

Avant de commencer, je précise que je n’ai pas fait ce script sous forme plugin WordPress, car je n’ai pas eu le temps de faire les choses à fond, et il y a une particularité à Prismic, c’est que la structure des données varie en fonction des sites. Du coup l’export de mon site ne ressemblera peut-être pas entièrement à l’export du votre. J’ai donc opté pour un simple script PHP facile à modifier. Il est loin d’être parfait mais il a le mérite de marcher.

L’export Prismic

Lorsque l’on exporte nos données Prismic, on obtient un joli JSON :

json

J’ai menti, en réalité il est compressé et sur une seule ligne. Pour le rendre lisible je vous conseille d’installer Pretty JSON via Package Control si vous êtes sur Sublime text.  Ensuite un coup de CMD+Alt+J vous permettra de mettre en beauté tout cela.

Et là premier souci : le fichier est enregistré en UTF-8 avec BOM. Pour faire simple : c’est la merde, les parsers JSON aiment pas cet encodage.

Je ne comprend pas trop pourquoi les créateurs ont trouvé que c’était une bonne idée mais on va pouvoir facilement convertir depuis Sublime Text en cliquant en bas à droite sur l’encodage puis en choisissant UTF-8.

encodage

Si l’encodage utilisé n’apparait pas en bas, ouvrez les préférences de Sublime et ajoutez cette ligne :

"show_encoding": true,

Script d’import

Voyons maintenant mon script d’import. Vous pouvez le télécharger sur Bitbucket ici :

Télécharger le script d'import

le dossier est à placer à la racine de votre site. Comme je vous le disais c’est une base que vous pourrez utiliser et adapter à vos besoins. Ca ne marchera peut être pas directement, en fonction de la configuration de votre site Prismic.

Pensez bien à faire des sauvegardes de votre base de données avant toute tentative d’import.

le fichier index.php contient en fait une fonction ajax qui se lancera pour chaque article à importer. De cette manière on évite d’avoir un timeout PHP : un import = un lancement de script PHP.

La boucle se relance chaque fois qu’Ajax a terminé sa requête, et a eu son retour. La seule chose à changer ici est la variable maxLoop qui doit correspondre au nombre d’entrées dans le Json (pointez le nomdre d’id via sublime en cherchant « id »).

nota : la boucle Ajax aurait pu être améliorée en utilisant les promises JS.

Passons maintenant au plus important : le fichier ajax.php :

Etape 1 : les vérifications

Voici la liste des actions effectuées dans un premier temps :

  1. Charger le coeur de WordPress (à nu, sans qu’il termine sur un affichage)
  2. Charger la classe de gestion d’images de WP (on va en avoir besoin)
  3. Définir un dossier pour accueillir les images (j’ai choisi arbitrairement wp-content/uploads/import/)
  4. Créer le dossier s’il n’existe pas déjà
  5. Lire l’export json (que j’ai appelé datas.json dans mon cas)
  6. Vérifier qu’il n’y a pas d’erreur json
  7. Récupérer le numéro d’entrée à importer (c’est ajax qui l’envoie : d’abord l’entrée 1, puis 2, 3 … une à la fois)
  8. Cas spécifique : ne pas importer les articles de certaines catégories
  9. Vérifier que l’article n’existe pas déjà dans WordPress (en comparant le titre)

Jusque là on a surtout fait des vérifications, et de la récupération de données brutes. Quelques explications avant de continuer :

Ecriture d’objets à caractère spécial

Constatez la façon bizarre d’écrire parfois les objets :

<?php 

// BON
$post_title = $entry->data->{'article.title'}->value[0]->text;

// PAS BON
$post_title = $entry->data->article.title->value[0]->text;

Prismic utilise des points dans le nom de ses objets, et PHP n’aime pas ça, il faut donc empaqueter les notations spécifiques dans des accolades. C’est du PHP natif, mais ça peu faire bizarre de le voir écrit de cette manière quand on n’a pas l’habitude.

Ignorer des catégories

Ensuite j’ai un cas spécifique demandé par mon client : les articles d’une catégorie particulière ne devaient pas être importées dans le nouveau site, j’ai donc lancé une vérification et quitte le script prématurément si c’est la catégorie concernée, en laissant un message qui viendra s’afficher dans index.php

<?php
// Do not import from specific category
$forbidden_cats = array('CAT 1', 'CAT 2', 'CAT 5');

if(isset($entry->tags[0]) and in_array($entry->tags[0], $forbidden_cats)):
  	echo "Article <span style='color:lightsalmon'>ignoré (catégorie à exclure)</span> <em>$post_title</em><br>";
  	die();
endif;

D’ailleurs dans Prismic il n’y a pas de catégories ET de mots clés, tout est un Tag, qui deviendront alors des catégories dans WordPress en toute logique.

Eviter les doublons

Pour éviter d’importer un article qui aurait déjà été importé, je controle si un article du même titre existe déjà en base, via la fonction WordPress get_posts :

<?php
// Check if post doesn't already exists (check title)
$post_title = $entry->data->{'article.title'}->value[0]->text;

if(count(get_posts(array('title' => $post_title)))):
  	echo "Article <span style='color:tomato'>existant</span> <em>$post_title</em><br>";
  	die();
endif;

Alors attention : ici j’évite simplement les doublons. Mais si vous souhaitez pouvoir quand même mettre à jour l’article, il faudra procéder un peu différemment.

Etape 2 : l’import

On continue les étapes :

  1. Créer un article vide en brouillon (vous allez voir pourquoi)
  2. Importer l’image à la Une
  3. Formatter la date
  4. Préparer l’extrait
  5. Préparation du contenu (textes et images)
  6. Import des images
  7. Assigner les catégories
  8. Importer le contenu de l’article
  9. Cas spécifique : Ajouter les metas

Et voilà ! Bon tout cela mérite quelques explications supplémentaires !

Pourquoi déjà, pour commencer, je crée un article vide en brouillon ? Car cela me permet d’obtenir un ID d’article que je vais utiliser sur les images pour les lier à celui-ci :

  • l’image à la Une en a besoin pour être assignée à cet article
  • Pour les autres images dans le contenu, c’est aussi utile. Quand vous allez dans la bibliothèque de média vous verrez l’indication « cette image est utilisée dans tel article« .

C’est beaucoup plus propre comme ça. WordPress fait la même chose : quand vous commencez un nouvel article, il crée immédiatement un brouillon.

Pour créer cet article j’utilise la fonction WordPress wp_insert_post.

L’image à la une

J’ai crée une fonction import_pic qui va s’occuper du nécessaire pour les images (à la une ou non), à savoir télécharger l’image à partir de l’url fournie par prismic et l’importer dans la bibliothèque de média, en créant au passage les meta données qui la concerne et en générant les tailles d’images intermédiaires.

J’en profite dans cette fonction pour « nettoyer » le nom d’image car prismic y ajoute un identifiant unique à rallonge pas très sexy.

Pour l’image à la Une, une fois qu’elle est importée en médiathèque, je la définie en tant qu’image à la Une via la fonction set_post_thumbnail et l’id de l’article.

Les textes prismic sont bruts

Prismic a eu l’excellente idée de stocker le texte brut, c’est à dire sans sa mise en forme. Et au lieu de stocker une version HTML, ils ont simplement crée des objets indiquant  le type de mise en forme (gras, italique, lien) et la position du caractère de départ, et d’arrivée (putain ! les mecs quoi !).

brut

Du coup il y a une belle moulinette qui va régénérer la chaine HTML à partir de ces informations. J’utilise au passage des fonctions comme mb_substr , le mb voulant dire multibyte, qui permet de travailler sans problème sur un encodage utf8 :

un accent est encodé sur 2 bytes, et du coup ça fausse le comptage d’une chaine de caractère si vous utilisez un strlen normal. J’ai mis un peu de temps à me rappeler de cela, et j’avais des décalages de mise en forme du texte. Attention pour le moment l’algorithme n’est pas parfait (il ne prend pas en compte s’il y a du gras dans un lien par exemple), mais suffisant.

Donc dans la boucle je vérifie aussi :

  • Si c’est un texte, j’applique la mise en forme expliquée ci-dessus
  • Si c’est une image, je vais l’importer dans la médiathèque et l’assigner à cet article, puis générer le html correspondant
  • Si c’est un embed, j’intègre son html

Attention il se peut que chez vous d’autres types de mise en page soient déclarés dans le json, il faudra alors ajouter un peu de code pour le traiter.

Import du contenu

Il est temps d’importer le contenu ! On réunit toutes les informations préalablement préparées et on met à jour l’article grâce à l’id. On n’oublie pas de passer l’article en « publié ».

<?php

$datas = array(
	"ID" => $post_id,
	"post_status" => "publish",
	"post_date" => $date,
	"post_date_gmt" => $date,
	"post_title" => $post_title,
	"post_name" => $entry->slug,
	"post_excerpt" => $excerpt,
	"post_content" => $content,
);

// Insert Post
wp_update_post($datas);

Et on valide avec wp_update_post($datas);

Si vous avez besoin de faire une correlation avec des catégories, créez d’abord les catégories dans votre WordPress, puis récupérez les identifiants de celles-ci.

Vous pouvez trouver cet id depuis l’admin en regardant l’url d’une catégorie :

category-id-wp

Dans mon exemple la catégorie à un id de 213.

Le code correpondant se trouve entre $datas et le wp_update_post.

Post Metas

Si vous le souhaitez, vous pouvez également enregistrer des données supplémentaires via les post metas (si vous utilisez le nom d’un champ ACF, vous remplirez alors le champ ACF, et ça, c’est cool !)

Dans le script j’ajoute une meta afin de conserver l’identifiant de l’article sous prismic. Cela ne me sert pas à grand chose mais c’est « au cas où » :

<?php
add_post_meta($post_id, "old_id", $entry->id, true);

Résultat

Et voici l’import qui est prêt ! Positionnez votre json dans le dossier prismic-to-wp/ , qui lui même est à la racine de votre site. Lancez la page via votresite.ext/prismic-to-wp/ ! Vous avez fait une sauvegarde préalable ? Cliquez sur le gros bouton and let the magic happen !

import-prismic-wp

C’est beau non ! Tout ce petit monde qui s’agite tout seul ! Alors comme je disais, c’est pas encore super optimisé et donc lent (je suis à peu près sûr que si Julio lit le code il fait un ulcère direct) : encore plus lent en local si vous avez une connexion Internet de campagnard comme c’est mon cas (puisque le script télécharge les images). Mais bon, ça marche plutôt bien !

Conclusion

Même si vous n’avez pas prévu d’importer quoi que ce soit depuis prismic, cet article pourra vous en apprendre davantage sur la création de données via le code de WordPress, en utilisant habilement les fonctions du coeur mises à votre disposition.

Vous pourriez très bien utiliser cette base pour importer n’importe quel autre type de fichier JSON ! Sinon j’ai également fait un article sur WP All Import, qui peut marcher dans la plupart des cas.

J’espère que ce petit tutoriel vous a plu ! En tous cas grâce à ce code j’ai pu importer plus de 650 articles de Prismic vers WordPress pour mon client, et sans encombre (si vous avez déjà fait des imports vous savez que ce n’est pas forcément facile, surtout avec l’outil proposé par défaut dans WordPress).

Si vous voulez participer à l’amélioration de ce script, je vous invite à forker le repertoire bitbucket !

 

Cet article a été mis à jour il y a 176 jours

Article écrit par Maxime BJ

Développeur, bloggeur et formateur Web spécialisé WordPress. 31 ans. Grenoblois. Co-fondateur de WPChef, l’organisme de formation WordPress.

Organisateur de WPInAlps, le meetup WordPress Grenoblois. Vous pouvez me rencontrer lors d’événements tels que WordCamp Paris et Europe. Traducteur Français de l’extension Advanced Custom Fields. Également développeur d’applications web avec MeteorJs. Je m’occupe un site pour apprendre l’informatique aux débutants gratuitement.

J’aime les jeux vidéo, la rando, la bouffe bien grasse et les voyages.

1 Commentaire

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

f5e6dfec0c2cdd0a808fd0cf535253b1ppppppppp