How to Use the WordPress REST API with Python

WordPress powers around 39.5% of all websites.

It’s great, but if you’ve ever been in charge of a decent-sized blog, you know that keeping everything up to date is hard to do. Images break, links stop working, prices and product info get out of date, and so on.

Going through all of that content and updating it manually is a giant pain in the ass.

There are, however, ways you can speed it up. One of those ways is to use Python and the WordPress API. Every WP site has one, you just need to know how to use it.

In this article, I’ll show you the basics ( + code) so you can start to use it as well.

How to use the WordPress REST API with Python

The basics

To use the API, you’ll need login credentials. If you can get to the WordPress dashboard, you should already have them.

However, using your normal password to access the API isn’t very smart. You’ll have to put your credentials in your code, so it wouldn’t be very secure.

Instead, we’ll create a password for the sole purpose of using Python. To do this, go to your WP dashboard and click on ‘Users’ -> ‘Profile’.

If you scroll down, you’ll see a section called ‘Application Passwords’

Wordpress application password

Enter the name of your application and click ‘Add New Application Password’. This will generate a 24 character password that you can use for your Python script.

The good thing about application passwords is that you can revoke them easily when you don’t need them anymore. As an added security benefit, they can’t be used to get to the WP dashboard.

Even though application passwords are more secure, I recommend you generate a password right before you need to run the script and revoke the password when the work is done.

Setting up the API token

Now that we have our password, we can start working on our script. first, we need to import the necessary packages and create a token.

import requests
import base64

wordpress_user = "your username"
wordpress_password = "xxxx xxxx xxxx xxxx xxxx xxxx"
wordpress_credentials = wordpress_user + ":" + wordpress_password
wordpress_token = base64.b64encode(wordpress_credentials.encode())
wordpress_header = {'Authorization': 'Basic ' + wordpress_token.decode('utf-8')}

Once the token is set up, we can start to interact with our WordPress site.

Using the API to read posts on WordPress

Let’s start with the most straightforward action: reading content. You can do this in your browser if you want. You just need to go to the API URL (e.g: https://robingeuens.com/wp-json/wp/v2/posts). If you want to do this with Python, however, this is the code:

def read_wordpress_posts():
 api_url = 'https://robingeuens.com/wp-json/wp/v2/posts'

 response = requests.get(api_url)
 response_json = response.json()

 print(response_json)

Here’s what we’re doing:

api_url = This is the URL we need to get all our posts from.
response = we’re making a GET request to the previously defined api_url.
response_json = we turn our response into something we can read.

This gives us a bunch of JSON data to work with. It’ll look something like this:

{'id': 347, 'date': '2021-05-09T02:42:48', 'date_gmt': '2021-05-09T00:42:48', 'guid': {'rendered': 'https://robingeuens.com/?p=347'}, 'modified': '2021-05-09T02:42:50', 'modified_gmt': '2021-05-09T00:42:50', 'slug': 'think-outside-the-box', 'status': 'publish', 'type': 'post', 'link': 'https://robingeuens.com/blog/think-outside-the-box', 'title': {'rendered': 'Why Trying to Think Outside The Box is a Waste of....

There’s one problem, however. If you have a large site, the API returns a maximum of 100 posts per page. This is to ensure the server doesn’t time out trying to process large requests.

If you want to get all the posts from your site, add parameters to your API URL to go to the next page. For example, if we want to get 100 posts per page, and we want to get page two, the API URL would look something like this: https://robingeuens.com/wp-json/wp/v2/posts?page=2&per_page=100

Now, increasing the pagination count manually is impractical, so you’ll want to automate that. To do that, we’ll first need to figure out how many pages are available. This is pretty easy, as WordPress sends this info along in the request header.

def get_total_pagecount():
 api_url = 'https://robingeuens.com/wp-json/wp/v2/posts?page=1&per_page=100'

 response = requests.get(api_url)
 pages_count = response.headers['X-WP-TotalPages']

 return int(pages_count)

By doing a simple GET request and looking at the header, you can get the total amount of pages available. We can then create a loop that goes through all of them one by one, gets all the content, and adds it to a list. For example:

def read_wordpress_post_with_pagination():
 total_pages = get_total_pagecount()
 current_page = 1
 all_page_items_json = []

 while current_page <= total_pages:
	 api_url = f"https://robingeuens.com/wp-json/wp/v2/posts?page={current_page}&per_page=100"
	 page_items = requests.get(api_url)
	 page_items_json = page_items.json()
	 all_page_items_json.extend(page_items_json)
	 current_page = current_page + 1

 return all_page_items_json

Once you have the content, you can start to manipulate it and do fun stuff with it.

Using the API to create a post in WordPress

Just retrieving a bunch of content is pretty boring, so let’s create a post instead. To do this, we need to send over a couple of things.

def create_wordpress_post():

 api_url = 'https://robingeuens.com/wp-json/wp/v2/posts'
 data = {
 'title' : 'Example wordpress post',
 'status': 'publish',
 'slug' : 'example-post',
 'content': 'This is the content of the post'
 }

 response = requests.post(api_url,headers=wordpress_header, json=data)

 print(response)

api_url = again, this is the URL we need to send our data to.
data = This contains all the arguments that you want to send to WordPress. The list of things you can send is pretty long, so I recommend you give the API reference a read. For this example, we’re just creating a simple post.
response = we’re doing a POST request and sending over what URL we need to go to, our WordPress credentials, and the data of the post.

Once it’s done, check out your site and the post should be live (if you set the status to ‘publish’).

Wordpress API example post

This, of course, is a very basic example. In reality, it opens the door for you to play around and create WordPress content in different ways. For example, you could create a template of your content and use a CSV to fill out different variables automatically.

Using the API to update a post in WordPress

Updating a blog post is very similar to creating a new one. the only difference is that you need to add the post ID to the API URL.

If you’re not sure where to find the post ID, you can either ping the API again, or you can go to the WP dashboard and edit the post you want to update. You’ll see the post ID in the URL. For example: https://robingeuens.com/wp-admin/post.php?post=380&action=edit

You can then use the same code we used to create a post and update the content.

def update_wordpress_post():

 api_url = 'https://robingeuens.com/wp-json/wp/v2/posts/'
 post_id = '380'

 data = {
 'title' : 'Updated example wordpress post',
 'status': 'publish',
 'slug' : 'example-post-update',
 'content': 'This is the updated content of the post'
 }

 response = requests.post(api_url + post_id,headers=wordpress_header, json=data)

 print(response)

Once you run this code, check your site and the post should be updated.

Wordpress API example update


There is one major problem with updating content, though. If you’re using the Gutenberg editor and you use the API to get content, it doesn’t send over any data related to the blocks you’re using in the editor.

If you get the content, change it, and send it back again, WordPress loses track of which blocks you used throughout your post. It will revert back to the classic editor and if you try to automatically convert it to blocks, you run the risk of everything being made a custom HTML block.

This might be fine if you just have a bunch of text, but if you use custom blocks like we do at Piktochart, this method becomes useless. Here’s what I mean.

WordPress uses block data to tell the editor what kind of block you’re using. You can see this if you’re looking at revisions:

Wordpress api editor blocks

Or you can export an XML of all your posts. The XML file contains all the block data as well. for example:

<!-- wp:paragraph -->

<p>Simple, however, doesn't mean easy. Finding a project that combined all 3 things turned out to be more difficult than I thought.</p>

<!-- /wp:paragraph -->

Without this data, WP doesn’t know what blocks to use and it’ll revert to the standard ones like paragraphs.

That’s why I recommend you export an XML of all the posts or pages on your site and work with that. You have access to the block data, and if you use the API to send an update, WordPress will use that block data to figure out what type of block it is.

This way you can use the API, and you can still properly edit in the editor if you need to.

Using the API to delete a post in WordPress

Deleting a post is easy peasy. You just need the API URL and post id and you’re good to go.

def delete_wordpress_post():
 api_url = 'https://robingeuens.com/wp-json/wp/v2/posts/'
 post_id = '380'

 response = requests.delete(api_url + post_id, headers=wordpress_header)

 print(response)

Nothing more to it, to be honest.

Putting it all together

This post went through some of the basic ways of interacting with the API. However, it is only the beginning. You can start combining them, adding steps in between, or use another API to enhance a process.

Here are a couple of things you could do with the API:

  • Create a template of your content and use a CSV to fill in the variables
  • Create a report by getting all the blog URLs and adding Google Analytics data for all of them
  • Get all the content, look for any outdated links, and use a CSV to change them to a different link
  • Get all the content, check with Google search console & Google analytics, and delete all posts that don’t get more than 1 visitor a day
  • Get the content, scan for any broken internal links, and use a machine-learning algorithm to suggest a different URL. Then use the update function to update all the broken internal links
  • Get the content and automatically post the title and URL to social media
  • Get the content, scan for headings, and automatically add jump links to them. Then, add a table of contents right above the first H2

Once you try it out for yourself you’ll understand how powerful the API is. You’ll also start saving a lot of time by automating menial tasks.