Créer un article WordPress grâce à l’API REST

WordPress API

Mis à jour le 5 janvier 2023

Authentification API WordPress

Pour utiliser l’API de WordPress, il faut un login et un mot de passe. Le login correspond à l’identifiant que vous utilisez pour vous connecter au backoffice de votre site. Le mot de passe par contre est différent.

Pour créer un mot de passe pour accéder à l’API de WordPress, allez dans le menu « Comptes » puis « Profil ». Vers le bas de la page trouvez la section « Mots de passe d’application » (votre site doit être en HTTPS sinon vous ne pourrez pas générer de mot de passe).

Entrez n’importe quel nom dans le champ texte puis cliquez sur « Ajouter un nouveau mot de passe d’application ».
Une fois fait, vous devrez copier le mot de passe généré juste en dessous.

WordPress mot de passe API

Pour commencer, j’ai simplement créé une classe qui contient les informations nécessaires pour faire appel à l’API.

public class WordPressApiClient
{
	private const string Login = "monidentifiant";
	private const string Password = "monmotdepassewordpress";
	private readonly Uri baseUrl = new Uri("https://monsite.com/wp-json/wp/v2/");
}

Installez le package « Newtonsoft.Json » dans votre projet via le Gestionnaire de package, car nous allons l’utiliser par la suite.

Créer une image de mise en avant pour l’article

Avant de créer un article, si vous souhaitez intégrer une image de mise en avant, il faut d’abord la créer.
La documentation officielle de l’API de WordPress n’est malheureusement pas très explicite. Normalement pour créer un média, il y a 2 façons possibles :

  1. En passant le fichier directement dans le body de la requête
  2. En envoyant un objet dans la requête avec plusieurs champs comme le titre ou le texte alternatif de l’image.

Cette dernière méthode ne semble pas fonctionner correctement nous allons donc utiliser la première, puis faire un update de l’image après l’avoir créée pour mettre à jour les champs qui nous intéressent.

Voici la documentation pour créer un media.

La méthode que j’utilise pour créer une image à partir d’un chemin sur le disque :

public async Task<BaseItem> CreateMedia(string filePath)
{
	using (var client = new HttpClient())
	{
		client.BaseAddress = baseUrl;
		client.DefaultRequestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{Login}:{Password}"))}");

		using (FileStream fs = File.OpenRead(filePath))
		{
			using StreamContent content = new(fs);
			string contentType = Path.GetExtension(filePath)?.ToLower() == ".png" ? "image/png" : "image/jpeg";
			content.Headers.TryAddWithoutValidation("Content-Disposition", $"attachment; filename=\"{Path.GetFileName(filePath)}\"");
			content.Headers.TryAddWithoutValidation("Content-Type", contentType);

			var response = await client.PostAsync("media", content);
			var responseString = await response.Content.ReadAsStringAsync();
			return JsonConvert.DeserializeObject<BaseItem>(responseString);
		}
	}
}

Comme vous pouvez le voir, le body de la requête contient directement le fichier. L’API requiert aussi les header Content-Disposition et Content-Type pour fonctionner.

La classe BaseItem contient seulement les informations de base, vous pouvez la compléter avec les autres champs présents dans la documentation.

public class BaseItem
{
	[JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore)]
	public int Id { get; set; }

	[JsonProperty("date", DefaultValueHandling = DefaultValueHandling.Ignore)]
	public DateTime Date { get; set; }

	[JsonProperty("date_gmt", DefaultValueHandling = DefaultValueHandling.Ignore)]
	public DateTime DateGmt { get; set; }
}

N’oubliez pas d’ajouter la référence au package Newtonsoft.Json pour utiliser l’attribut JsonProperty.

Mettre à jour l’image

Une fois l’image créée on peut la mettre à jour pour spécifier les champs titre et texte alternatif par exemple.

Le paramètre mediaId est l’id de l’image créée par la méthode CreateMedia.

public async Task<MediaItem> UpdateMedia(string altText, string title, int mediaId)
{
	using (var client = new HttpClient())
	{
		client.BaseAddress = baseUrl;
		client.DefaultRequestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{Login}:{Password}"))}");

		var values = new Dictionary<string, string>
		{
			{ "title", title },
			{ "alt_text", altText }
		};

		var response = await client.PutAsync("media/" + mediaId.ToString(), new FormUrlEncodedContent(values));
		var responseString = await response.Content.ReadAsStringAsync();
		return JsonConvert.DeserializeObject<MediaItem>(responseString);
	}
}

Si vous obtenez une erreur « 406 Not Acceptable » lors de l’appel à client.PutAsync, cela signifie que le serveur rejette la requête. Pour débloquer la situation, vous devez regarder dans les paramètres de votre hébergement s’il y a des sécurités activées. Si vous avez accès à l’interface cPanel par exemple, allez dans la section « Sécurité » puis cliquez sur « ModSecurity », afin de le désactiver pour votre domaine.

modsecurity

Créer un article avec l’API – Exemple

Pour créer un article on utilise l’API createPost. Dans la méthode ci-dessous j’ai mis seulement les paramètres qui me paraissaient importants mais vous pouvez bien entendu en ajouter en fonction de ce que l’API propose.

Encore une fois, le paramètre featuredImageId est l’id de l’image créée par la méthode CreateMedia.

public async Task<CreatePostResponse> CreatePost(string title, string content, string status, int featuredImageId, IEnumerable<string> categoriesId = null)
{
	using (var client = new HttpClient())
	{
		client.BaseAddress = baseUrl;
		client.DefaultRequestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{Login}:{Password}"))}");

		var values = new Dictionary<string, string>
		{
			{ "title", title },
			{ "status", status },
			{ "content", content },
			{ "featured_media", featuredImageId.ToString() }
		};

		if (categoriesId?.Any() == true)
		{
			values.Add("categories", string.Join(",", categoriesId));
		}

		var response = await client.PostAsync("posts", new FormUrlEncodedContent(values));
		var responseString = await response.Content.ReadAsStringAsync();
		return JsonConvert.DeserializeObject<CreatePostResponse>(responseString);
	}
}

Voici le code qui fait appel à toutes les méthodes vues jusqu’ici.

var media = await wpApiClient.CreateMedia(@"C:\Temp\Sans titre.png");
await wpApiClient.UpdateMedia("Image test", "Image test", media.Id);
var title = "Article créé via l'API";
var content = "<h3>Mon titre</h3><p>Mon premier paragraphe créé via l'API</p>";
var status = "draft";
var post = await wpApiClient.CreatePost(title, content, status, media.Id);

Après exécution, voilà le résultat !

article WordPress via API

Sympa non ?

Librairie WordPresPCL

C’est bien beau, mais il n’y avait pas une librairie existante pour faire tout ça ? Eh bien si, vous trouverez dans le gestionnaire de package une librairie qui s’appelle WordPressPCL qui est plutôt complète. voici ce qu’elle supporte à l’heure où j’écris ces lignes :

WordPresPCL méthodes REST supportées

Son utilisation est facile, voici le code qui fait exactement la même chose que le précédent, sans avoir besoin de la classe WordPressApiClient.

var client = new WordPressClient("https://monsite.com/wp-json/");
client.Auth.UseBasicAuth("monidentifiant", "monmotdepassewordpress");

var filePath = @"C:\Temp\Sans titre.png";
var media = await client.Media.CreateAsync(filePath, Path.GetFileName(filePath));
media.Title = new Title("Image test");
media.AltText = "Image test";
await client.Media.UpdateAsync(media);

var title = "Article créé via l'API";
var content = "<h3>Mon titre</h3><p>Mon premier paragraphe créé via l'API</p>";
var status = "draft";
var post = await client.Posts.CreateAsync(new Post
{
    Title = new Title(title),
    Content = new Content(content),
    FeaturedMedia = media.Id,
    Status = Status.Draft
});

Cette libraire a l’avantage d’exposer tous les champs de l’API, vous n’avez plus besoin de le faire vous-même.

Si vous souhaitez aller plus loin et intégrer les champs meta de Yoast SEO lors de la création de votre article, j’ai créé un post pour le faire.

Laisser un commentaire

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