Simple Page Builder
WordPress Developer Assessment
by Ahmed Zekry · github.com/ahmedzekry1/simple-page-builder-plugin
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/ahmedzekry1/simple-page-builder-plugin/archive/refs/heads/main.zipSimple Page Builder is a WordPress plugin that exposes a secure REST API endpoint for bulk page creation, protected by API keys, secrets, and optional JWT bearer tokens. It includes API key management, rate limiting, full request logging, and webhook notifications when pages are created.
Author: Ahmed Zekry
Assessment: WebOps WordPress Developer Assessment
Quick Start
- Install the plugin by copying
simple-page-builderintowp-content/plugins/and activating Simple Page Builder in Plugins. - In the WordPress admin, go to Page Builder → API Keys, generate a new key, and copy the API Key and Secret Key (shown once).
- (Optional, recommended) Obtain a JWT access token by calling
POST /wp-json/pagebuilder/v1/tokenwith your API key and secret, or by using the includedpostman_collection.jsonin Postman. - Create pages via the API using
POST /wp-json/pagebuilder/v1/create-pageswith either:- Headers:
X-API-Key,X-API-Secret, or - Header:
Authorization: Bearer YOUR_JWT_TOKEN
- Headers:
- Verify results in WordPress under Pages, and review activity in Page Builder → API Activity Log and Created Pages.
Features
- Secure REST API endpoint:
POST /wp-json/pagebuilder/v1/create-pages - API key + secret authentication (no basic auth)
- API key management UI (generate, list, revoke)
- Optional per-key expiration, request counting, and last-used tracking
- Per-key rate limiting (requests per hour)
- Detailed API activity log with CSV export
- Table of pages created through the API
- Webhook notifications (with HMAC-SHA256 signature) when pages are created
- Global settings for rate limits, key expiration, webhook URL, and API enable/disable
- Built using WordPress best practices (WP REST API, nonces, capabilities, esc_* functions)
Installation
- Copy the
simple-page-builderdirectory into your WordPresswp-content/plugins/directory. - In the WordPress admin, go to Plugins → Installed Plugins.
- Activate Simple Page Builder.
- Go to the top-level Page Builder menu in the admin sidebar to manage API keys, view logs, configure settings, and read the API documentation.
Database Tables
The plugin creates the following tables on activation:
wp_spb_api_keys— Stores hashed API keys and secrets, metadata, status, expiration, usage counts.wp_spb_api_logs— Logs every API request (successful and failed), including key preview, endpoint, status, IP, and response time.wp_spb_pages— Records WordPress pages created via the API, including URL and originating API key name.wp_spb_webhook_logs— Logs webhook delivery attempts, status, response codes, and errors.
API Authentication
You can authenticate in two ways:
- API key headers (simple):
X-API-Key: Your API key (plain value)X-API-Secret: Your API secret (plain value)
- JWT bearer token (recommended for production clients):
Authorization: Bearer <token>
The plugin never stores the plain keys. Instead it stores SHA-256 hashes of both the key and the secret, plus a short non-sensitive preview for admin display.
API keys can be:
- Generated in the WordPress admin (Page Builder → API Keys tab)
- Optionally configured with an explicit expiration date
- Revoked at any time by an administrator
All key usage (including failed auth attempts) is logged in wp_spb_api_logs.
In addition, you can exchange an API key + secret for a short-lived JWT access token via:
-
Method:
POST -
URL:
https://your-site.com/wp-json/pagebuilder/v1/token -
Body (JSON):
{ "api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET" }
REST Endpoint
- Method:
POST - URL:
https://your-site.com/wp-json/pagebuilder/v1/create-pages - Headers (API key auth):
Content-Type: application/jsonX-API-Key: YOUR_API_KEYX-API-Secret: YOUR_API_SECRET
- Headers (JWT auth):
Content-Type: application/jsonAuthorization: Bearer YOUR_JWT_TOKEN
Request Body
{
"pages": [
{
"title": "About Us",
"content": "About page content",
"slug": "about-us",
"status": "publish"
},
{
"title": "Contact",
"content": "Contact page content",
"slug": "contact",
"status": "draft"
}
]
}
Fields:
title(string, required) — Page title.content(string, optional) — HTML content for the page.slug(string, optional) — URL slug; if omitted, WordPress generates one from the title.status(string, optional) — One ofpublish,draft,pending,private. Defaults topublish.
Successful Response
HTTP 201 with JSON body:
{
"request_id": "req_abc123xyz",
"status": "success",
"total_pages": 2,
"pages": [
{
"id": 123,
"title": "About Us",
"url": "https://your-site.com/about-us"
},
{
"id": 124,
"title": "Contact",
"url": "https://your-site.com/contact"
}
],
"errors": [],
"webhook": {
"enabled": true,
"attempts": 1,
"status": "success",
"last_response_code": 200
}
}
On partial failure (some pages fail, some succeed), total_pages counts the successfully created pages and details about failed items appear in errors.
Error Responses
The API returns appropriate HTTP status codes and error codes, for example:
401 spb_auth_missing— Missing API key or secret401 spb_auth_invalid— Invalid API key401 spb_auth_invalid_secret— Invalid API secret403 spb_auth_revoked— Revoked or inactive key403 spb_auth_expired— Expired key400 spb_invalid_payload— Malformed request body400 spb_no_pages_created— No pages could be created429 spb_rate_limited— Rate limit exceeded for this key503 spb_api_disabled— API globally disabled in settings
Rate Limiting
The plugin enforces a configurable per-key rate limit in requests per hour.
- Default limit:
100requests per hour per key (can be changed in the Settings tab). - Rate limiting is based on the count of successful API log entries for the key in the last 60 minutes.
Set the limit to 0 to disable rate limiting.
Webhook Notifications
If a default webhook URL is configured in the Settings tab, the plugin will send a POST request after pages are created.
Webhook Request
- Method:
POST - URL:
WEBHOOK_URLfrom settings - Headers:
Content-Type: application/jsonX-Webhook-Signature: <HMAC-SHA256 signature>
Webhook Payload
{
"event": "pages_created",
"timestamp": "2025-10-07T14:30:00Z",
"request_id": "req_abc123xyz",
"api_key_name": "Production Server",
"total_pages": 3,
"pages": [
{ "id": 123, "title": "About Us", "url": "https://your-site.com/about-us" },
{ "id": 124, "title": "Contact", "url": "https://your-site.com/contact" },
{ "id": 125, "title": "FAQ", "url": "https://your-site.com/faq" }
]
}
Webhook Security
The plugin computes an HMAC-SHA256 signature of the JSON payload using the configured webhook secret and sends it in the X-Webhook-Signature header.
Example verification (PHP):
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $body, 'YOUR_WEBHOOK_SECRET');
if (!hash_equals($expected, $signature)) {
http_response_code(400);
exit('Invalid signature');
}
Webhook delivery uses wp_remote_post() with:
- 10 second timeout
- Up to 3 attempts total (initial + 2 retries with exponential backoff)
- Each attempt logged to
wp_spb_webhook_logs(status, response code, error message)
Page creation is never rolled back if the webhook fails; failures only affect the webhook logs.
Admin Interface Overview
Under the top-level Page Builder menu you will find the following tabs:
-
API Keys
- Generate new API keys (name + optional expiration date)
- View existing keys: name, key preview, status, created, expires, last used, request count
- Revoke keys instantly
-
API Activity Log
- View recent API requests with status, endpoint, IP, response time, and message
- Export logs as CSV
-
Created Pages
- View pages created via the API with title, URL, created date, and API key name
-
Settings
- Enable/disable API access globally
- Configure rate limit (requests/hour/key)
- Configure default API key expiration (30/60/90 days or never)
- Set default webhook URL and webhook secret
-
API Documentation
- Summary of endpoint, headers, and request/response format
- Ready-to-use cURL example with placeholders for API key and secret
- Webhook description and signature verification notes
Example cURL Request
curl -X POST \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-API-Secret: YOUR_API_SECRET" \
"https://your-site.com/wp-json/pagebuilder/v1/create-pages" \
-d '{
"pages": [
{ "title": "About Us", "content": "About page content", "slug": "about-us" },
{ "title": "Contact", "content": "Contact page content", "slug": "contact", "status": "draft" }
]
}'