Using WordPress API’s with PowerShell

This blog uses WordPress. Why WordPress? Well, it was the most prevalent platform when I started this blog back in 2016 and it was more powerful and extensible than Blogger which I had used previously. Anyway, that’s rather irrelevant for this post which about accessing WordPress APIs with PowerShell.

What I was trying to achieve was to automate the process of retrieving statistics on views and visitors to my blog.

After some investigation I learned that there are two separate APIs for WordPress.

Reading through the documentation for each it became apparent that only the v1.1 API had an endpoint that would return views and visitor statistics. Also, the two APIs differed in their implementations for authentication and use. My blog is hosted by a hosting provider, and I authenticate directly to my WordPress environment. This does also impact how authentication is performed. For completeness and to document it for any future requirements I may have, this post will detail authenticating and querying both the v1.1 and v2 APIs.

v2 WordPress API’s with PowerShell

To access the v2 WordPress API’s you will first need to configure your WordPress User Account Profile with an Application Password. From your WordPress Admin Console select Users => Your User Account => Add New Application Password. It does not matter what you name the Application Password. This is just a friendly display-name in the console. Record the generated password for use in your PowerShell automation script.

Example Authentication and API call

The snippet below shows how to use the Application Password generated above for your WordPress Account with Basic Authentication to call v2 WordPress APIs.

Update $userID for your WordPress User Account Alias, the $userPassword with the Application Password generated above and in the Invoke-RestMethod API query update the URL for your WordPress site.

$userID = 'yourWordpressAccountAlias'
$userPassword = 'ABCD wTUZ pIST 9jEo 99LV 1234'
$Bytes = [System.Text.Encoding]::utf8.GetBytes("$($userID):$($userPassword)")
$encodedAuth = [Convert]::ToBase64String($Bytes)
$header = @{Authorization = "Basic $($encodedAuth)" }

Invoke-RestMethod -method get -uri "https://yourwordpressURL/wp-json/wp/v2/posts" -headers $header

The example above calls the /wp-json/wp/v2/posts API and returns WordPress Posts. Other v2 APIs that can be queried are listed here.

v1.1 WordPress API’s with PowerShell

The v1.1 WordPress API’s leverage the WordPress centralized store and with JetPack installed on my WordPress site that data is then available via WordPress and the v1.1 API’s.

As I want to automate the process of obtaining the statistics, I needed to use an authentication mechanism that could be automated. There are a few options leveraging OAuth but the one that fitted my scenario was to obtain an authorization code as a one-time flow. That is then used to obtain an access token that can be stored and reused as required.

First you need to register an Application with the WordPress Developer Portal. Login to the WordPress Developer Portal using your WordPress account and select Create New Application.

Enter the details for your WordPress site. Here is an example for mine, then select Create.

With the application registration complete you can then select Manage Application for your new application registration and retrieve the Client ID and Client Secret. Record these for use in the automation script.

Authorize the Application Registration

Before we can use the API, we need to authorize the application using our WordPress account. I used the authorization code flow for this, as it meant I could do it interactively once then get an access token and store that for future calls. Update the following snippet with the clientID from your newly registered WordPress application and the URL from your WordPress site. It must be the same as you registered with the application registration. Running the snippet below will generate the URL and put it in the clipboard. Paste it into your browser. You will then be prompted to authenticate with your WordPress account and authorize your application.

$clientID = 'myClientID'
$replyURL = 'https://myWordPressURL.com'
$url = "https://public-api.wordpress.com/oauth2/authorize?client_id=$($clientID)&redirect_uri=$($replyURL)&scope=global%20stats&response_type=code"

$url | clip 

If you are not authenticated, you will be prompted too including MFA in order to authorize your application. For Stats via JetPack a second authorization screen is triggered.

After successful authorization you will be directed to your WordPress site. Look at the URL in the browser address bar and you will see the Authorization Code after you site URL. Copy the code.

The following script will take your Client ID, Client Secret, Blog URL and the AuthCode and get an Access Token.

Function Get-WordPressAccessToken {
    [CmdletBinding()] 
    param( 
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 
        $clientID, 
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        $blogURL, 
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 
        $clientSecret, 
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        $authCode
    )

    try { 
        $result = Invoke-RestMethod https://public-api.wordpress.com/oauth2/token `
            -Method Post -ContentType "application/x-www-form-urlencoded" `
            -Body @{
            client_id     = $clientId
            client_secret = $clientSecret
            redirect_uri  = $blogURL
            grant_type    = "authorization_code"
            code          = $authCode
        } -ErrorAction STOP 
        return $result
    }
    catch {
        $_
    }
}

$clientID = 'yourAppClientID'
$clientSecret = 'yourAppClientSecret'
$authCode = 'code_from_browser_authorization'
$replyURL = 'https://myWordPressURL.com'

$accessToken = Get-WordPressAccessToken -ClientID $clientID -blogURL $replyURL -clientSecret $clientSecret -authCode $authCode

Using the WordPress Access Token

Now we have authorized our application and obtained an Access Token we can query the v1.1 API. Here is a function to get WordPress statistics. It just needs to be passed the siteID of the WordPress blog site and the access token retrieved above. If you don’t know your blog siteID update the following URL with your blog URL rather than mine and paste it into your browser and locate “site_ID” in the returned page

https://public-api.wordpress.com/rest/v1.1/sites/BLOG.DARRENJROBINSON.COM/posts/?number=2&pretty=true

Add your site_ID into the $wpBlogID variable at the bottom of the script below.

Function Get-WordPressStats { 
    [Cmdletbinding()] 
    param( 
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] 
        [string] $siteID, 
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] 
        [string] $accessToken
        )

    $stats = Invoke-RestMethod https://public-api.wordpress.com/rest/v1.1/sites/$siteID/stats -Method Get `
        -Headers @{"Authorization" = "Bearer $accessToken" } | Select-object -ExpandProperty Stats 
    return $stats
}

$wpBlogID = '123514446'
Get-WordPressStats -siteID $wpBlogID -accessToken $accessToken.access_token

Statistics from your blog will be returned. Using this as an example other API endpoints on the v1.1 API can be queried and interacted with. You will need to change the Scope(s) in the authorization application request. Valid scopes are listed on this page.

Using WordPress API’s with PowerShell Script Examples on Gist

The formatting of code snippets in WordPress can get awkward so here is a Gist of the script examples.

Summary

Depending on the automation you are looking to achieve with WordPress there are two separate APIs that can be leveraged. Basic Authentication to the v2 API is the simplest. Using a registered application and an authorization code flow with the v1.1 APIs allows for an access token to be acquired which can be stored and used indefinitely. An access token acquired using this method will not expire.