Photo by @amartino20 / Unsplash.com

Building a command-line utility to search for WordPress content using .NET Core and System.Text.Json

Thanks for reading my blog! If you have any questions or need a second opinion with anything Microsoft Azure or Power Platform related, don't hesitate to contact me. I'm happy to provide my professional services through my company, North Advisors.

Recent weeks have been busy, and many things have demanded my attention. As a result I haven’t had too much time to build things, and I love to build things. So today, during a coffee break at work, I decided to spend 15 minutes to get something built. And it would need to be something I’d actually use.

Allow me to introduce – wpAPI_CLI, a simple and fast command-line utility to search for WordPress posts and their content.

Planning

I use Microsoft To Do to track ideas and topics I’d like to write about in the future. But after I’ve written an article and published it, I often cross it over in my To Do list and move on. So I needed a tool that quickly allows me to check against my published content if I’ve written about a specific topic.

In essence, my tool would work with a simple keyword:

wpAPI_CLI.exe <keyword>

WordPress exposes a REST API, and that REST API has a Search method. My tool would need to connect with this API, and execute a search using a keyword. The structure for the API call is:

/wp-json/wp/v2/posts?search=keyword&per_page=100

I added the &per_page=100 to get a reasonable amount of results. The default is 10.

Writing code

I just refreshed my laptop (more on that in a separate post a bit later), and had to re-install Visual Studio 2019. I created a new C# (and .NET Core) Console Project, and started hammering my code out. It’s pretty simple – but then again, so is my need.

First, as I’m calling a REST API, I need System.Net.Http, and for parsing the resulting JSON, I wanted to use the new System.Text.Json.

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Web;

I’ll then define a few variables in my Main() class:

string WP_HOST = "https://jussiroine.com";
string WP_API = "/wp-json/wp/v2/posts";
string WP_METHOD = "?search";
string WP_PARAMS = "&per_page=100";

I’ll pick up the keyword directly from the command-line. As I only had 15 minutes I decided to blindly trust the user (me) in inputting something usable:

string WP_KEYWORD = args[0];

Next, I’ll call the API and construct my query:

HttpClient client = new HttpClient();
var response = client.GetStringAsync(WP_HOST + WP_API + WP_METHOD + "=" + WP_KEYWORD + WP_PARAMS).Result;

And from this result, I’ll parse through all links:

var document = JsonDocument.Parse(response);
var root = document.RootElement;

var items = new List<string>();

And now items holds all the posts, which I’ll then need to parse into something usable:

int i = 0; 
foreach (var prop in root.EnumerateArray())
{
	i++; 
	// title - remove {rendered..}
	var rawTitle = JsonDocument.Parse(prop.GetProperty("title").ToString());
	var postTitle = rawTitle.RootElement.GetProperty("rendered").ToString();

	// strip HTML entities from title
	postTitle = HttpUtility.HtmlDecode(postTitle.ToString());
	postTitle = Regex.Replace(postTitle, "<.*?>", String.Empty);
	postTitle = Regex.Replace(postTitle, @"^\s+$[\r\n]*", string.Empty, RegexOptions.Multiline);

	// postLink
	var postLink = prop.GetProperty("link").ToString();

	Console.WriteLine("{0}", postLink);
}

And that’s it!

Trying it out

Time to try it out! I built this to an executable, and ran it with a few keywords to test:

Future betterments

For a future coffee break, I already came up with an interesting list of opportunities to work with:

  • Move the search logic (REST API query, essentially) to be hosted in Azure Functions
  • Local caching
  • Performance metrics – perhaps in Azure App Insights
  • Better command-line parameter handling
  • Highlight relevant line of text in content when it matches the keyword being search
  • Consider security a bit more

For now, I’m able to use this little tool and it’s already proving to be quite useful!