Home » C# » Easy Integration of WordPress API in C# .Net

Easy Integration of WordPress API in C# .Net


In this post, we will see how to integrate WordPressPCL Nuget Package to connect and work with the WordPress website using REST APIs in C# .Net application. WordPress software is written in PHP and it is difficult for other programming developers to adopt additional skills and make changes in the code. The good thing is, .Net developers can make use of the WordPressPCL library in C# which acts as an interface to allow external applications to access the data and functionality of the WordPress CMS via REST API calls.

Table of Content
– Implementation of WordPress API Code
– WordPress CRUD Rest API Calls (Create, Read, Update, Delete)
Tag


Create Application Password for WordPress API

The first step is to create an Application Password which will be used in the code for authentication purposes.

  • Login into WordPress admin portal (https://www.YourDomain.com/wp-admin).
  • Go to User >> Profile page.
  • Generate the password by providing an Application Name.
create-wordpress-application-password


Implementation of WordPress API Code C#

Next, integrate the WordPressPCL library in the .Net application and write methods in a static class using C# code to call WordPress Rest APIs.

Integrate WordPressPCL Nuget Package

  • Create a new .Net application
  • Install WordPressPCL Nuget Package
wordpresspcl-nuget-package

or use the following command line in Console to install the package

Install-Package WordPressPCL -Version 2.0.0


WordPress API authentication C#

  • Create a common static class and methods that can perform WordPress API requests (CRUD operations).
public static class WordPress
{
} 

  • Add the following namespaces
using WordPressPCL;
using WordPressPCL.Models; 

  • Use WordPressClient‘ class to get authenticated and connect with the WordPress client.
    • Pass the default Rest API URL as a parameter in the constructor.
      e.g., https://YourDomain.com/wp-json
    • Pass your registered Application username & password for authentication.
      You can use either Basic or JWT Token (Bearer) for authentication
//Method 1) Basic Authentication
wpClient.Auth.UseBasicAuth("WpApiUserName", "JEs8 xxWpPasswordxx 98JW iKK3 98Jw");

//Or

//Method 2) JWT(Bearer) Authentication
wpClient.Auth.UseBearerAuth(JWTPlugin.JWTAuthByEnriqueChavez);
wpClient.Auth.RequestJWTokenAsync("username", "password");
var isValidToken = wpClient.Auth.IsValidJWTokenAsync;


CRUD Rest API C# Code for WordPress Post

Below is the full code for WP-Post which performs CRUD operation using WordPress Rest APIs

Create WP-Post C# Code


using WordPressPCL;
using WordPressPCL.Models;

namespace Data
{
    public static class WordPress
    {
        public static async Task CreateOrUpdatePost(DataObject dataObj)
        {
            // Get valid WordPress Client
            WordPressClient wpClient = new WordPressClient("https://YourDomain.com/wp-json/");

            //Basic Auth
            wpClient.Auth.UseBasicAuth("WpApiUserName", "JEs8 xxWpPasswordxx 98JW iKK3 98Jw");

            //Or, Bearer Auth using JWT tokens
            //wpClient.Auth.UseBearerAuth(JWTPlugin.JWTAuthByEnriqueChavez);
            //wpClient.Auth.RequestJWTokenAsync("username", "password");
            //var isValidToken = wpClient.Auth.IsValidJWTokenAsync;

            //Create and Set Post object
            var post = new Post
            {
                Title = new Title(dataObj.Title),
                Meta = new Description(dataObj.Description),
                Excerpt = new Excerpt(dataObj.Excerpt),
                Content = new Content(dataObj.Content),
                //slug should be in lower case with hypen(-) separator 
                Slug = dataObj.Slug
            };

            // Assign one or more Categories, if any
            if (dataObj.Categories.Count > 0)
            {
                post.Categories = dataObj.Categories;
            }

            // Assign one or more Tags, if any
            if (dataObj.Tags.Count > 0)
            {
                post.Tags = dataObj.Tags;
            }

            if (dataObj.PostId == 0)
            {
                // if you want to hide comment section
                post.CommentStatus = OpenStatus.Closed;
                // Set it to draft section if you want to review and then publish
                post.Status = Status.Draft;
                // Create and get new the post id
                dataObj.PostId = wpClient.Post.CreateAsync(post).Result.Id;

                // read Note section below - Why update the Post again?
                await wpClient.Posts.UpdateAsync(post);
            }
            else
            {
                // check the status of post (draft or publish) and then update
                if (IsPostDraftStatus(wpClient, dataObj.PostId))
                {
                    post.Status = Status.Draft;
                }

                await wpClient.Posts.UpdateAsync(post);
            }
        }

        private static bool IsPostDraftStatus(WordPressClient client, int postId)
        {
            var result = client.Posts.GetByIDAsync(postId, true, true).Result;

            if (result.Status == Status.Draft)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
} 

Note:
Why update the Post again?
Actually, it is not required but I encountered a problem when creating a bulk WP Post (more than 100) and noticed that many Post’s slug name is the same as the title name even though I gave different slug names. That’s the reason – calling the update method again. Implement if it is required.
Make sure to check the WP Post’s status before updating it next time. As per my scenario, I am creating Post and doing changes multiple times in the draft status via code and publishing it later.

Call CreateOrUpdatePost() static method from other class. The below code shows how to set the properties of a Post and generate content (from the database).


public async void PostTodaysContent()
{
	try
	{
		var dbContent = _context.NextPosts.Where(w => w.Name == "Today").FirstOrDefault();

		DataObject dataObj = new DataObject()
		{
			PostId = dbContent.PostId,
			Title = "Sample title",
			Description = "This is description",
			Content = GenerateContent(dbContent),
			Slug = dbContent.Slug // or "this-is-sample"
		};

		// Existing WP Category IDs
		dataObj.Categories = new() { 111, 112 };

		await WordPress.CreateOrUpdatePost(dataObj);

		if (dbContent.PostId == null || dbContent.PostId == 0)
		{
			dbContent.PostId = dataObj.PostId;
			_context.SaveChanges();
		}
	}
	catch (Exception ex)
	{

	}
} 

Suggestion:
If you are targeting standard Categories or Tags then better to create them manually in WP-Admin Portal and use its existing IDs in the code.
How to find Id? – Click on any Category or Tag and find the Id in the URL.
find-category-tag-id-wordpress
But you can generate them dynamically through code if that is the requirement, please see the Categories and Tags code section below.

Note:
It is a very rare situation but it is important to know that sometimes new WP-Post does not reflect in the WP-Admin portal immediately even though the API code generated and returned a new PostId. In my case, this issue occurred one time during the bulk process and it took 4 hours for a new post to get visible in the portal. If you got a new PostId via code then wait and don’t create the same (duplicate) post again, until you are sure it has not been created.

Generate HTML Content – Sample


private static string GenerateContent(NextPosts dbContent)
{
	// sample content
	StringBuilder sb = new StringBuilder();
	sb.Append("<h2> " + dbContent.Header + "</h2>");
	sb.Append("<div>");
	sb.Append(dbContent.Column2 + "<br>");
	sb.Append("<table>");
	sb.Append("<tr><td>" + dbContent.Column3 + "</td></tr>");
	sb.Append("</table>");
	sb.Append("</div>");

	return sb.ToString();
} 

Get WP-Post C# Code


// get all
var getAllPosts = await wpClient.Posts.GetAllAsync();
// get by id
var getPostbyid = await wpClient.Posts.GetByIDAsync(postId);

// Get Posts Count
var postsCount = await wpClient.Posts.GetCountAsync(); 

Delete WP-Post C# Code


// delete Post by id
bool isDeleted = wpClient.Posts.DeleteAsync(postId).Result;


WordPress Category CRUD REST API C# Code

CRUD operation API calls (create, read, update and delete) for Category.



Category category = new Category
{
	Name = "Sales",
	Slug = "new-sales",
	// If it is a sub-category then mention Parent(existing) category Id
	Parent = 111
};

// create
var wpc = wpClient.Categories.CreateAsync(category).Result;
int categoryId = wpc.Id; // e.g. 10

// update category by id
Category category = new Category
{
	Name = "Rename Sales",
	Id = 10,
};
await wpClient.Categories.UpdateAsync(category);

// get all categories
var getAllCategories = await wpClient.Categories.GetAllAsync();

// get category by id
var getCategoryById = await wpClient.Categories.GetByIDAsync(categoryId);

// delete Category by id
bool isDeleted = wpClient.Categories.DeleteAsync(categoryId).Result; 


WordPress Tag CRUD REST API C# Code

Code for consuming the Tag REST-APIs



Tag tag = new Tag
{
	Name = "books",
	Slug = "new-books",
};

// create
var wptag = wpClient.Tags.CreateAsync(tag).Result;
int tagId = wptag.Id; // e.g. 20

// update tag by id
Tag tag= new Tag
{
	Name = "Rename books",
	Id = 20,
};
await wpClient.Tags.UpdateAsync(tag);

// get all tags
var getAllTags = await wpClient.Tags.GetAllAsync();

// get tag by id
var getTagById = await wpClient.Tags.GetByIDAsync(tagId);

// delete tag by id
bool isDeleted = wpClient.Tags.DeleteAsync(tagId).Result; 


Getting WP-Post Comments Code

var comm = await wpClient.Comments.GetAllAsync();
var commById = await wpClient.Comments.GetByIDAsync(id);
var commByPostId = await wpClient.Comments.GetCommentsForPostAsync(postId, true, false); 


Note:
I run this code in a local environment and usually generate more than 50 (bulk) WP-Post using ‘foreach loop’. One time, I got a notification of duplicate ‘Page Indexing’ from Google Search Console
message – Duplicate, Google chose different canonical than user)
reason – Same post got created two times and the duplicate URL had “-2” at the end.
solution – as per my requirement i am handling it in two ways:
not using await in few lines of code even though it is async method
written a separate code that will compare sitemap URLs with stored slug names in the database, to make sure all bulk post is generated and there are no duplicates.

Suggestion:
As one or more post is getting generated through code, it is better to validate all ‘new & old’ URLs, periodically. Check this link – How to Read XML Sitemap and validate URLs (links exists or not)