Danny Brown

A Blog on Code and Occasionally Other Things

Using Python to Publish a Post with Embedded Images to WordPress

Danny BrownJuly 29, 2021

I found myself in a position of needing to publish to WordPress programmatically recently, but despite using WordPress for years, I’d never delved into its API before now. There are a few outdated Python modules out there, but none worked out of the box for me, so I figured I’d go straight to the API with my own code. Ultimately the hardest part of this (for me) was figuring out the right way to authenticate, so I’ll start with that.

Application Password

The non-code part of this (ew, yuck) involves downloading the WordPress plugin Application Passwords:

Then go into the Users section, select a account with administrative privileges, and scroll all the way to the bottom of the page, where you will find the Application Passwords section:

Here you can generate a new password, which you should definitely note in a secure location, as you’ll never be able to access it again (though you can revoke and regenerate it):

So now you have two things:

  1. A username
  2. An application password

Finally, Python Code: Authentication and Basic Post

Authenticating took me some time to figure out (other approaches just weren’t working for me), but with the application password, you should be good to go with this code:

import requests
from datetime import datetime

auth = ("username", "application_password_you_generated")
url = "http://yourwebsite.com/wp-json/wp/v2/posts"

post_data = {
    "date" : str(datetime.now().date()),
    "title" : "This is a sample title",
    "content" : "HTML is fine here (but is hard to post on the web).", 
    "status" : "publish", 
} 

r = requests.post(url, auth=auth, json=post_data) 
print(r.status_code) # should be 201 with a successful post

Embedding an Image in Your Post

You’ll need to make a separate post request to upload images. Here’s a function to help:

import requests
import json

def add_a_wordpress_image(img_name):
    """ Takes an image name, posts to WP, returns image url. """

    auth = ("username", "application_password_you_generated")
    url = "http://yourwebsite.com/wp-json/wp/v2/media"

    # Define the image
    media = {
        "file": open(f"path/to/image/file/{img_name}.png", "rb"),
        "caption": img_name,
        "description": img_name
    }
        
    # Post the image to WP
    image = requests.post(url, auth=auth, files=media)   # ! files=, not json= !

    # Extract and return the image URL from returned data
    return str(json.loads(image.content)["source_url"])

The above function returns the URL of the uploaded image. To use it in a post, simply put an img tag in your HTML with the src attribute pointing at the returned URL.

Last Thing: Automating Categories

It’s nice to have a category on one’s WordPress posts, but adding them to a post requires the category ID. Here’s a function that takes a category name, checks to see if it exists, and then creates it if not. In either case, it returns the category ID to use in a post.

import requests
import json

def lookup_or_create_wp_category(name):
    """ Takes a category name, looks up or creates category, returns ID """

    auth = ("username", "application_password_you_generated")
    url = "http://yourwebsite.com/wp-json/wp/v2/categories?per_page=100"
    # Note that you'll need to figure out pagination 
    # (or just use an API search, which is probably better)
    # if you have more than 100 categories on your site. 
    # I'm nowhere close so I didn't concern myself!

    # Get list of categories
    r = requests.get(url, auth=auth)
    cats = list(json.loads(r.content))

    # Find the category with the name we are searching using a generator
    cat = next((item for item in cats if item["name"] == name), None)
    
    # Return its ID if it exists (it will be None if not)
    if cat:
        return cat["id"]
    
    # Otherwise, add the category
    category = {
        "name" : name,
        "description" : name
    }
    r = requests.post(url, auth=auth, json=category)
    return str(json.loads(r.content)["id"])

And here’s how you might use it to add a category to a new post:

import requests

cat_id = lookup_or_create_wp_category("category name")
post_data = {
    "date" : str(datetime.now().date()),
    "title" : "This is a sample title",
    "content" : "HTML is fine here (but is hard to post on the web).", 
    "status" : "publish", 
    "categories" : [cat_id, ],
} 
requests.post(url, auth=auth, json=post_data)

As always, I hope this is helpful to future travelers.

Posted In code | Python | tech | WordPress
Tagged Python | Requests | WordPress | WordPress API

Post navigation

PreviousTallahassee Neighborhood Latitude/Longitude List
NextSecuring Your S3 Bucket Using the Serverless Framework

Danny Brown

A Dev Blog with Some Tangents

About

Categories

  • code
    • APIs
    • Bash
    • CSS
    • Django
    • HTML
    • JavaScript
    • Python
    • S3
    • Selenium
    • Serverless
    • TypeScript
  • games
  • music
    • concert reviews
    • synthesizers
  • opinion
  • sports
  • tech
    • Bitbucket
    • Git
    • GitHub
    • MS Teams
    • WordPress
  • theater

Recent Posts

  • Open Pull Requests from the Terminal (One of My Favorite Dotfiles Scripts)
  • Dotfiles Script for a New TypeScript/Node Project
  • So I Told You to Go See a Broadway Play? Tips for Theater in New York
  • Build a Simple Microsoft Teams Bot Easily, No SDK Required
  • Creating a GUI for Conway’s Game of Life Using Pygame and Numpy

External Links

  • GitHub
  • LinkedIn

Recent Posts

  • Open Pull Requests from the Terminal (One of My Favorite Dotfiles Scripts)
  • Dotfiles Script for a New TypeScript/Node Project
  • So I Told You to Go See a Broadway Play? Tips for Theater in New York
  • Build a Simple Microsoft Teams Bot Easily, No SDK Required
  • Creating a GUI for Conway’s Game of Life Using Pygame and Numpy

Categories

  • code
    • APIs
    • Bash
    • CSS
    • Django
    • HTML
    • JavaScript
    • Python
    • S3
    • Selenium
    • Serverless
    • TypeScript
  • games
  • music
    • concert reviews
    • synthesizers
  • opinion
  • sports
  • tech
    • Bitbucket
    • Git
    • GitHub
    • MS Teams
    • WordPress
  • theater
Copyright © 2025. Danny Brown
Powered By WordPress and Meritorious