Taxonomy Sync Engine – REST API Category and Tag Sync for WordPress

December 19, 2025 · Pawan

A WordPress plugin that creates and assigns categories and tags through the REST API with append mode, automatic term creation, and strict permission checks.

Taxonomy Sync Engine – REST API Category and Tag Sync for WordPress

A lightweight WordPress plugin that lets you assign and create tags and categories for posts via the REST API — with automatic term creation, append mode, and granular error reporting.

Features

  • Set categories and tags on any public post type via a single REST call
  • Resolve categories by ID, slug, or slug + custom name
  • Auto-create missing tags (and categories, if the user has manage_categories)
  • Append mode — add terms without overwriting existing ones
  • Structured response with existing, created, and errors arrays
  • Per-request term cap (50) to prevent bulk abuse
  • Full capability enforcement — no privilege escalation

Installation

  1. Download taxonomy-sync-engine.php.
  2. Upload it to your site's /wp-content/plugins/taxonomy-sync-engine/ directory, or zip it and install via Plugins → Add New → Upload Plugin.
  3. Activate the plugin from the Plugins screen.
  4. The REST endpoint is immediately available — no configuration required.

Authentication

All requests must be authenticated. The plugin uses WordPress's built-in REST authentication. The recommended approaches are:

Application Passwords (built into WordPress 5.6+)

Authorization: Basic base64(username:application_password)

Cookie authentication (for requests made from within WordPress, e.g. admin-ajax or the block editor). Include a valid nonce:

X-WP-Nonce: <nonce>

Unauthenticated requests will receive a 401 Unauthorized response.

API Reference

Endpoint

POST /wp-json/tse/v1/update-post-terms

Content-Type: application/json

Parameters

ParameterTypeRequiredDefaultDescription
post_idintegerID of the post to update. Must be a public, non-trashed post.
categoriesarray of objects[]Categories to assign. Each object may contain id, slug, and/or name. See details below.
tagsarray of strings[]Tag names to assign. Missing tags are created automatically.
appendbooleanfalseWhen true, terms are added to existing ones. When false, existing terms are replaced.

Maximum 50 items per categories or tags array per request.

categories item schema

Each entry in the categories array is an object. The plugin resolves it in this priority order:

FieldTypeDescription
idintegerResolve by exact term ID. If provided, slug and name are ignored.
slugstringResolve by slug. If not found, a new category is created (requires manage_categories).
namestringHuman-readable name used only when creating a new category. Ignored if the category already exists.

If only slug is given and the category doesn't exist, the name defaults to a slug-derived value (e.g. "machine-learning""Machine Learning").

Response

Success — 200 OK (all terms applied without errors)

Partial success — 207 Multi-Status (some terms applied, some failed — check errors)

{ "post_id": 42, "post_title": "Hello World", "post_status": "publish", "categories": { "set": [3, 7], // Term IDs now assigned to the post "existing": [ // Terms that already existed before the request { "id": 3, "name": "News", "slug": "news" } ], "created": [ // Terms created by this request { "id": 7, "name": "Machine Learning", "slug": "machine-learning" } ] }, "tags": { "set": [12, 15], "existing": [ { "id": 12, "name": "WordPress" } ], "created": [ { "id": 15, "name": "REST API" } ] }, "errors": [] }

Error — 400 / 401 / 403 / 404 (invalid request or insufficient permissions)

{ "code": "rest_forbidden", "message": "You do not have permission to edit this post.", "data": { "status": 403 } }

Error Handling

Non-fatal errors (e.g. one bad category ID among several valid ones) are collected in the errors array and return a 207 status. The rest of the request is still applied.

Fatal errors (missing post_id, bad authentication, insufficient capabilities) return a standard WP REST error object with an appropriate HTTP status code.

Examples

1. Set categories by slug

curl -X POST https://yoursite.com/wp-json/tse/v1/update-post-terms \ -H "Content-Type: application/json" \ -H "Authorization: Basic <base64-credentials>" \ -d '{ "post_id": 42, "categories": [ { "slug": "news" }, { "slug": "technology" } ] }'

2. Set categories by ID

curl -X POST https://yoursite.com/wp-json/tse/v1/update-post-terms \ -H "Content-Type: application/json" \ -H "Authorization: Basic <base64-credentials>" \ -d '{ "post_id": 42, "categories": [ { "id": 3 }, { "id": 7 } ] }'

3. Set categories with a custom name

Useful when you want to create a category and control its display name precisely:

curl -X POST https://yoursite.com/wp-json/tse/v1/update-post-terms \ -H "Content-Type: application/json" \ -H "Authorization: Basic <base64-credentials>" \ -d '{ "post_id": 42, "categories": [ { "slug": "ai-ml", "name": "AI & Machine Learning" } ] }'

4. Set tags

Missing tags are created automatically. No special permissions are required for tag creation.

curl -X POST https://yoursite.com/wp-json/tse/v1/update-post-terms \ -H "Content-Type: application/json" \ -H "Authorization: Basic <base64-credentials>" \ -d '{ "post_id": 42, "tags": ["WordPress", "REST API", "Headless CMS"] }'

5. Append instead of replace

By default the plugin replaces all existing terms. Pass "append": true to add to them instead:

curl -X POST https://yoursite.com/wp-json/tse/v1/update-post-terms \ -H "Content-Type: application/json" \ -H "Authorization: Basic <base64-credentials>" \ -d '{ "post_id": 42, "tags": ["New Tag"], "append": true }'

6. Categories and tags together

curl -X POST https://yoursite.com/wp-json/tse/v1/update-post-terms \ -H "Content-Type: application/json" \ -H "Authorization: Basic <base64-credentials>" \ -d '{ "post_id": 42, "categories": [ { "slug": "news" }, { "slug": "open-source", "name": "Open Source" } ], "tags": ["WordPress", "Plugin", "REST API"], "append": false }'

Permissions

ActionRequired Capability
Call the endpointedit_post on the specific post
Assign existing categoriesedit_post on the specific post
Create new categoriesmanage_categories
Assign / create tagsedit_post on the specific post

If a user has edit_post but not manage_categories, the request will still succeed for existing categories and tags — the missing-category entries will appear in the errors array and be skipped.

Limits

LimitValue
Max categories per request50
Max tags per request50
Supported post typesAll public post types (excludes attachment, nav_menu_item, etc.)

Author: Pawan
Contributors: paw1xd
License: GPLv2
Current Version: 1.0

GitHub
X
instagram