Article 57G78 Posting to wordpress.com in code

Posting to wordpress.com in code

by
jonskeet
from Jon Skeet's coding blog on (#57G78)
History

I started blogging back in 2005, shortly before attending the only MVP summit I've managed to go to. I hosted the blog on msmvps.com, back when that was a thing.

In 2014 I migrated to wordpress.com, in the hope that this would make everything nice and simple: it's a managed service, dedicated to blogging, so I shouldn't have to worry about anything but the writing. It's not been quite that simple.

I don't know when I started writing blog posts in Markdown instead of using Windows Live Writer to create the HTML for me, but it's definitely my preferred way of writing. It's the format I use all over the place, it makes posting code easy... it's just the right format" (for me).

Almost all my problems with wordpress.com have fallen into one of two categories:

  • Markdown on WordPress (via JetPack, I believe) not quite working as I expect it to.
  • The editor on wordpress.com being actively hostile to Markdown users

In the first category, there are two problems. First, there's my general annoyance at line breaks being relevant outside code. I like writing paragraphs including line breaks, so that the text is nicely in roughly 80-100 character lines. Unfortunately both WordPress and GitHub decide to format such paragraphs as multiple short lines, instead of flowing a single paragraph. I don't know why the decision was made to format things this way, and I can see some situations in which it's beneficial (e.g. a diff of adding a single word" showing as just that diff rather than all the lines in the paragraph changing) but I mostly dislike it.

The second annoyance is that angle brackets in code (either code fences or just in backticks) behave unpredictably in WordPress, in a way that I don't remember seeing anywhere else. The most common cause of having to update a post is to fix some generics in C# code, mangling to Markdown to escape the angle brackets. One of these days I may try to document this so that I can get it right in future posts, but it's certainly a frustration.

I don't expect to be able to do anything about either of these aspects. I could potentially run posts through some sort of preprocessor, but I suspect tha unwrapping paragraphs but not code blocks could get fiddly pretty fast. I can live with it.

The second category of annoyance - editing on wordpress.com - is what this post is mostly about.

I strongly suspect that most bloggers want a reasonably-WYSIWYG experience, and they definitely don't want to see their post in its raw, unformatted version (usually HTML, but Markdown for me). For as long as I can remember, there have been two modes in the wordpress.com editor: visual and text. In some cases just going into the visual editor would cause the Markdown to be converted into HTML which would then show up in the text editor... it's been fiddly to keep it as text. My habit is to keep a copy of the post as text (originally just in StackEdit but now in GitHub) and copy the whole thing into WordPress any time I wanted to edit anything. That way I don't really care what WordPress does with it.

However, wordpress.com have now made even that workflow even harder - they've moved to a blocks" editor in the easy-to-get-to UI, and you can only get to the text editor via the admin UI.

I figured enough was enough. If I've got the posts as text locally (then stored on GitHub), there's no need to go to the wordpress.com UI for anything other than comments. Time to crack open the API.

What no .NET package?

WordPress is a pretty common blogging platform, let's face it. I was entirely unsurprised to find out that there's a REST API for it, allowing you to post to it. (The fact that I'd been using StackEdit to post for ages was further evidence of that.) It also wasn't surprising that it used OAuth2 for authentication, given OAuth's prevalance.

What was surprising was my inability to find any .NET packages to let me write a C# console application to call the API with really minimal code. I couldn't even find any simple do the OAuth dance for me" libraries that would work in a console application rather than in a web app. RestSharp looked promising, as the home page says Basic, OAuth 1, OAuth 2, JWT, NTLM are supported" - but the authentication docs could do with some love, and looking at the source code suggested there was nothing that would start a local web server just to receive the OAuth code that could then be exchanged for a full auth token. (I know very little about OAuth2, but just enough to be aware of what's missing when I browse through some library code.) WordPressPCL also looked promising - but requires JWT authentication, which is available via a plugin. I don't want to upgrade from a personal wordpress.com account to a business account just for the sake of installing a single plugin. (I'm aware it could have other benefits, but...)

So, I have a few options:

  • Upgrade to a business account, install the JWT plugin, and try to use WordPressPCL
  • Move off wordpress.com entirely, run WordPress myself (or find another site like wordpress.com, I suppose) and make the JWT plugin available, and again use WordPressPCL
  • Implement the OAuth2 dance myself
Self-hosting WordPress

I did toy with the idea of running WordPress myself. I have a Google Kubernetes Engine cluster already, that I use to host nodatime.org and some other sites. I figured that by now, installing WordPress on a Kubernetes cluster would be pretty simple. It turns out there's a Bitnami Helm chart for it, so I decided to give that a go.

First I had to install Helm - I've heard of it, but never used it before. My first attempt to use it, via a shell script, failed... but with Chocolatey, it installed okay.

Installing WordPress was a breeze - until it didn't actually work, because my Kubernetes cluster doesn't have enough spare resources. It is a small cluster, certainly - it's not doing anything commercial, and I'm paying for it out of my own pocket, so I try to keep the budget relatively low. Apparently too low.

I investigated how much it might cost to increase the capacity of my cluster so I could run WordPress myself, and when it ended up being more expensive than the business account on wordpress.com (even before the time cost of maintaining the site), I figured I'd stop going down that particular rabbit hole.

Implementing OAuth2

In the end, I really shouldn't have been so scared of implementing the OAuth2 dance myself. It's not too bad, particularly when I'm happy to do a few manual steps each time I need a new token, rather than automating everything.

First I had to create an application" on wordpress.com. That's really just a registration for a client_secret and client_id, along with approved redirect URIs for the OAuth dance. I knew I'd be running a server locally for the browser to redirect to, so I allowed http://127.0.0.1:8080/auth as a redirect URI, and created the app appropriately.

The basic flow is:

  • Start a local web server to receive a redirect response from the WordPress server
  • Visit a carefully-constructed URL on WordPress in the browser
  • Authorize the request in the browser
  • The WordPress response indicates a redirect to the local server, that includes a code
  • The local server then exchanges that code for a token by making another HTTP request to the WordPress server
  • The local server displays the access token so I can copy and paste it for use elsewhere

In a normal application the user never needs to see the access token of course - all of this happens behind the scenes. However, doing that within my eventual console application which calls the WordPress API to create or update posts" would be rather more hassle than copy/paste and hard-coding the access token. Is this code secure, if it ever gets stolen? Absolutely not. Am I okay with the level of risk here? Yup.

So, what's the simplest way of starting an HTTP server in a standalone app? (I don't need this to integrate with anything else.) You could obviously create a new empty ASP.NET Core application and find the right place to handle the request... but personally I reached for the .NET Functions Framework. I'm clearly biased as the author of the framework, but I was thrilled to see how easy it was to use for a real task. The solution is literally a single C# file and a project file, created with dotnet new gcf-http. The C# file contains a single class (Function) with a single method (HandleAsync). The C# file is 50 lines of code in total.

Mind you, it still took over an hour to get a working token that was able to create a WordPress post. Was this due to intricacies of URL encoding in forms? No, despite my investigations taking me in that direction. Was it due to needing to base64 encode the token when making a request? No, despite many attempts along those lines too.

I made two mistakes:

  • In my exchange-code-for-token server, I populated the redirect_uri field in the exchange request with "http://127.0.0.1/auth" instead of "http://127.0.0.1:8080/auth"
  • In the test-the-token application, I specified a scheme of "Basic" instead of "Bearer" in AuthenticationHeaderValue

So just typos, basically. Incredibly frustrating, but I got there.

As an intriguing thought, now I've got a function that can do the OAuth dance, there's nothing to stop me deploying that as a real Google Cloud Function so I could get an OAuth access token at any time just by visiting a URL without running anything locally. I'd just need a bit of configuration - which ASP.NET Core makes easy, of course. No need to do that just yet.

Posting to WordPress

At this point, I have a test application that can create a WordPress post (as Markdown, importantly). It can update the post as well.

The next step is to work out what I want my blogging flow to be in the future. Given that I'm storing the blog content in GitHub, I could potentially trigger the code from a GitHub action - but I'm not sure that's a particularly useful flow. For now, I'm going to go with explicitly running an app when I want to create/update a post".

Now updating a post requires knowing the post ID - which I can get within the WordPress UI, but I also get when creating the post in the first place. But I'd need somewhere to store it. I could create a separate file with metadata for posts, but this is all starting to sound pretty complex.

Instead, my current solution is to have a little metadata header" before the main post. The application can read that, and process it appropriately. It can also update it with the post ID when it first creates the post on wordpress.com. That also avoids me having to specify things like a title on the command line. At the time of writing this, this post has a header like this:

title: Posting to wordpress.com in codecategories: C#, General---

After running my application for the first time, I expect it to be something like this:

postId: 12345title: Posting to wordpress.com in codecategories: C#, General---

The presence of the postId field will trigger the app to use update" instead of create" next time I ask it to process this file.

Will it work? I'll find out in just a few minutes. This code hasn't been run at all yet. Yes, I could write some tests for it. No, I'm not actually going to write the tests. I think it'll be just as quick to iterate on it by trial and error. (It's not terribly complicated code.)

Conclusion

If you can see this post, I have a new process for posting to my blog. I will absolutely not create this post manually - if the code never works, you'll never see this text.

Is this a process that other people would want to use? Maybe, maybe not. I'm not expecting to open source it. But it's a useful example of how it really doesn't take that much effort to automate away some annoyance... and I was able to enjoy using my own Functions Framework for realsies, which is a bonus :)

Time to post!

External Content
Source RSS or Atom Feed
Feed Location http://codeblog.jonskeet.uk/feed/
Feed Title Jon Skeet's coding blog
Feed Link https://codeblog.jonskeet.uk/
Reply 0 comments