The WordPress REST API lets a script do most of what a person does in the dashboard: create, update, and publish posts and pages, upload media, and set categories and custom fields. It is built into WordPress and authenticates with an application password. Its main limits are page builder layouts and plugin fields that are not exposed to the API.
Some of the WordPress work we are proudest of involved almost no clicking. On a Phoenix law firm's site, a converter moved 552 blog posts into a new layout, and an auto-linker placed 1,004 internal links. Nobody opened 552 editor screens. A script talked to WordPress through its REST API and did each post the same way.
That is the case for automation in one example. People are good at deciding what a page should say. They are bad at applying the same change five hundred times without a mistake on number 340.
Here is what the API can do, where it stops, and how to use it without hurting a live site.
What is the WordPress REST API?
The WordPress REST API is a set of web addresses, built into every modern WordPress site, that let other software read and change the site's content as structured data. A script sends a request to an address such as /wp-json/wp/v2/posts and gets back posts as JSON, or sends JSON to create one.
It is the same interface the block editor uses. When you press Update in the dashboard, your browser sends a request much like the ones a script would send. Automation is doing that without the browser.
Reading public content needs no login. Changing anything does. The full reference is in the WordPress REST API handbook.
What can you automate with the WordPress REST API?
You can automate most routine content work with the WordPress REST API: creating and publishing posts and pages, editing existing ones in bulk, uploading images, assigning categories and tags, setting custom fields, and managing custom post types. Anything registered with the API can be read and written by a script.
| Task | Possible by script | Notes |
|---|---|---|
| Create and publish posts or pages | Yes | Including scheduling for a future date |
| Update hundreds of existing posts | Yes | Read, transform, write back |
| Upload images and set a featured image | Yes | Through the media endpoint |
| Categories, tags, authors | Yes | By ID |
| Custom post types | Yes | If registered with show_in_rest |
| Custom fields | Yes | If the field is registered for the API |
| SEO titles and descriptions | Sometimes | Depends on what the SEO plugin exposes |
| Page builder layouts | Often not | Many builders store layouts outside the standard content field |
| Theme and plugin settings | Rarely | Usually not exposed |
Our own uses follow that table. RankAZona, the Arizona business publication we make, runs on WordPress with custom post types and Python scripts working through the REST API. Our Content Engine picks a topic each morning, writes the article, converts it to the site's layout, sets its metadata, links it into related pages, and publishes. A human reviews the output, not the process. We describe that pipeline in how a daily publishing engine works.
How do you authenticate a script with WordPress?
Authenticate a script with an application password, a feature built into WordPress. It is a separate password generated from a user's profile screen, used only by software, and revocable without changing the person's real login. The script sends it with the username in a standard Basic authorization header over HTTPS.
Here is a complete update of one post from Node. The application password is a placeholder. A real one belongs in an environment variable, never in the code.
const site = 'https://example.com';
const user = 'editor-bot';
const appPassword = process.env.WP_APP_PASSWORD; // e.g. "abcd efgh ijkl mnop qrst uvwx"
const auth = Buffer.from(`${user}:${appPassword}`).toString('base64');
const res = await fetch(`${site}/wp-json/wp/v2/posts/123`, {
method: 'POST',
headers: {
Authorization: `Basic ${auth}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'Updated title',
content: '<p>Updated body.</p>',
status: 'publish',
}),
});
if (!res.ok) throw new Error(`Update failed: ${res.status}`);
const post = await res.json();
console.log(post.link);
Two habits matter here. Give the script its own user with the lowest role that can do the job, usually Editor and not Administrator. And keep the password out of the repository. We cover how in environment variables and secrets.
What are the limits of the WordPress REST API?
The limits of the WordPress REST API are the things WordPress does not store as standard content. Page builder layouts and some SEO plugin fields are the two we meet most. The API writes what has been registered with it, and anything a plugin keeps private stays out of reach.
Page builders are the hard one. One site we work on runs on a builder that stores pages in a format the API will not write to. We wrote a bridge plugin and a command-line tool so complete, styled pages could still be published from a script. That is a real cost, and it is worth knowing before choosing a builder. See page builders: the real pros and cons.
SEO fields are the subtle one. A title tag or meta description set by an SEO plugin is stored as post meta, and the standard post endpoint only accepts meta that has been registered for the API. Some plugins provide their own endpoints, some need a small snippet to expose the fields, and some need another route. Check before you promise anyone a bulk rewrite of titles.
How do you run a bulk change safely?
Run a bulk change safely by backing up first, testing on a handful of posts, making the script safe to run twice, and logging everything it touches. A script is exactly as careful as it was written to be, and it makes mistakes at the same speed it does everything else.
- Back up the database. See how to back up a website properly.
- Dry run. Have the script print what it would change without writing anything.
- Try three posts. Pick an ordinary one, a long one, and an odd one. Look at them in a browser.
- Make it idempotent. Running the script a second time should change nothing. Have it detect posts it has already converted and skip them.
- Go slowly. Pause between requests so the server and any firewall in front of it are not flooded.
- Log every write. Post ID, what changed, and the response.
- Clear caches and spot check. Then check again the next day.
Step four is what makes a long job recoverable. If the run stops at post 300, you start it again and it carries on.
When is automating WordPress not worth it?
Automating WordPress is not worth it for a change you will make once to a dozen pages. Writing and testing a script takes longer than doing that by hand. The break-even arrives when the same operation repeats across many pages, or happens on a schedule, or has to be done identically every time.
Our rough test: if a person would have to do the same thing more than a few dozen times, or will have to do it again next month, script it. Otherwise open the editor.
Frequently asked questions
Is the WordPress REST API enabled by default?
Yes. It has been part of WordPress core for years and is on unless a plugin or a security setting has restricted it. You can check by visiting /wp-json/ on the site, which should return a block of JSON describing the available routes.
Is it safe to leave the WordPress REST API turned on?
Yes, for a maintained site. Public endpoints only return what is already public, and changes require authentication. The block editor depends on the API, so disabling it entirely breaks editing. Protect it the way you protect the login: strong credentials and least privilege.
What programming language do you need for the REST API?
Any language that can send an HTTP request. We mostly use Python and Node. The API speaks JSON over HTTPS, so the choice comes down to what your team already knows and where the script will run.
Can the REST API schedule posts for later?
Yes. Send the post with a future date and a status of future, and WordPress publishes it at that time using its own scheduler. A script can queue a month of posts in one run.
Can the REST API change a post's URL?
Yes, through the slug field. Add a redirect from the old address when you do.
If there is a repetitive job on your WordPress site that someone dreads, tell us what it is. We will tell you if a script can do it.