Role Importer
WordPress plugin: REST endpoint that upserts structured content into a CPT with ACF fields and image uploads
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/alexskybrain/wp-role-importer/archive/refs/heads/main.zipA WordPress plugin that accepts role content as JSON over a REST endpoint and upserts it into a custom post type with ACF fields, including uploading and attaching images.
It was written to let an external pipeline publish and re-publish structured content into WordPress without anyone touching the admin, while keeping the endpoint closed to everyone who does not hold the key.
What it does
- Registers the
marketing_rolecustom post type. - Exposes a REST endpoint that creates a post or updates the existing one with the same slug, so the pipeline can be re-run safely.
- Accepts image uploads and stores the resulting attachment IDs in the ACF field group, instead of hot-linking external files.
- Adds a meta box for a per-post SEO schema block and prints it in
wp_head.
Requirements
- WordPress 6.0+
- PHP 7.4+
- Advanced Custom Fields for the field group. The plugin checks
function_exists('update_field')before writing, so it degrades instead of fataling when ACF is absent.
Installation
- Copy the plugin folder into
wp-content/plugins/and activate it. - Set the shared key in the
role_importer_api_keyoption. - Send requests with that key in the
x-role-importer-keyheader.
REST API
Namespace role-importer/v1.
POST /wp-json/role-importer/v1/marketing-role upsert a role from JSON
POST /wp-json/role-importer/v1/upload upload an image, returns the attachment ID
GET /wp-json/role-importer/v1/marketing-role/ID read back a stored role
Authentication
Every route uses a permission_callback. The callback reads the x-role-importer-key header and compares it with the stored option using hash_equals(), so the comparison does not leak the key through timing. The endpoint answers 403 when no key is configured at all, rather than defaulting to open.
The key lives in an option and is never committed to the repository.
Notes on implementation
- Titles, slugs and file names go through
sanitize_text_field(),sanitize_title()andsanitize_file_name(). - Uploads are handled by
media_handle_upload(), so WordPress generates the sizes and metadata as it would for a normal upload. - The upsert matches on slug, which keeps the pipeline idempotent.
License
MIT — see LICENSE.