Latest commit

History

256 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🧙‍♂️ PostWizardREST

JavaCode StyleLicense: MPL 2.0Status: Archived

A high-performance, secure RESTful API for WordPress content management, built with modern Java Enterprise architectural patterns.

PostWizardREST provides a robust complement to the default WordPress REST API, offering performance improvements in specific automation-heavy and enterprise deployment scenarios, enhanced security features, and advanced content management capabilities.

⚠️ Project Status

Archived / Discontinued

PostWizardREST is no longer actively maintained, and the associated service is no longer available.

This repository is preserved for reference and educational purposes only.
No support, updates, security patches, or guarantees are provided.


Historical note

All documentation below reflects the system’s design, features, and API as they existed during active development. It is preserved for architectural reference and educational purposes.


Why was PostWizardREST created?

PostWizardREST was designed as an integration hub and server-side extension for projects such as PostWizardX3, handling taxonomy creation, post management, and media-related workflows outside of WordPress’ runtime.

While the WordPress REST API is suitable for many use cases, it is intentionally constrained by WordPress’ execution model, plugin ecosystem, and PHP-based request lifecycle. PostWizardREST explored an alternative approach: offloading critical content management workflows to a dedicated Java-based service, while remaining fully compatible with the WordPress database and ecosystem.

This design was motivated by the need for greater control over execution, security boundaries, and data modeling, particularly in high-volume or automation-heavy scenarios.

By decoupling these responsibilities from WordPress, the project aimed to leverage established Enterprise Java capabilities, resulting in:

  • Direct database access, avoiding repeated WordPress bootstrap and plugin execution overhead
  • Scheduled and batch jobs with proper locking, retries, and concurrency control
  • Application-server–managed threading and resource pools, instead of request-bound execution
  • A REST API decoupled from WordPress’ PHP execution model, enabling reliable integration with external automation systems
  • Documentation-driven API design with explicit contracts
  • Structured metadata handling with cascading and relational consistency
  • Type-safe APIs to reduce common runtime and data-shape errors
  • Explicit control over database connections, transactions, and isolation levels
  • Extensibility by default, without reliance on WordPress hooks or filters
  • Reduced attack surface, by minimizing public exposure of WordPress endpoints commonly targeted by automated attacks against WordPress installations
  • Observability and audit logging, enabling detection of abnormal behavior and performance bottlenecks
  • Developer-friendly modeling of taxonomies and custom fields for Java-based teams
  • A WordPress domain abstraction, designed with future integration into Jakarta EE or Spring ecosystems in mind, including message-driven and batch-oriented enterprise workflows
  • Compatibility with existing WordPress plugins, including Yoast SEO and CompressX
  • JWT-based authentication, role-based access control, and request validation
  • Consistent response formats and structured error handling
  • Integration testing, CI/CD readiness, and container-friendly deployment

In short, PostWizardREST was not intended to replace WordPress, but to isolate automation-heavy, security-sensitive, or high-throughput operations into a system better suited for those concerns, while still using WordPress as the content source of truth.

✨ Features

Core Features

  • Full CRUD operations for WordPress posts
  • Advanced taxonomy management (categories, tags, custom taxonomies)
  • Extensible metadata system
  • Batch processing using Jakarta Concurrency
  • Scheduled and automated content tasks

Security Features

  • JWT-based authentication
  • Secure HS256 key generation using SecureRandom
  • Role-based access control (RBAC)
  • Request validation and sanitization
  • Audit logging
  • Probe and automated scan detection

Operational

  • Jenkins - CI/CD pipeline integration

Logging

The application implements a structured, file-based logging system designed for observability, auditing, and troubleshooting in automation-heavy environments.

  • Log Levels
    Controlled via the PWLOG_LEVEL environment variable:

    • DEBUG → full trace logging (Level.ALL)
    • Any other value → defaults to INFO
  • Log Output & Organization

    • Logs are written to a PWLogs directory in the application working directory
    • Each logger writes to a dedicated file named after its class
    • Logs are appended by default (configurable)
  • Key Capabilities

    • Method entry/exit logging with parameter tracking
    • Automatic caller method detection
    • REST request logging (request path and client IP) for critical endpoints
    • Log file rotation using sequence-based file handlers
  • Format

    • Human-readable output via Java SimpleFormatter
    • Includes timestamp, log level, and source class/method

To enable debug logging:

export PWLOG_LEVEL="DEBUG"

🛠️ Tech Stack

Core Technologies

  • Java (JDK 21)
  • Jakarta EE 10 (platform API, provided by the application server)
  • Hibernate ORM 7
  • MariaDB 10.6+
  • JWT (JJWT)

Key Dependencies

  • MariaDB JDBC Driver
  • Apache Commons Lang 3
  • JSpecify
  • Jersey Client
  • Jakarta JSON Processing (JSON-P)

Development & Testing

  • Maven
  • JUnit (unit and integration testing)
  • Arquillian (container-based integration testing)
  • ShrinkWrap Resolver (test deployment assembly)
  • SpotBugs (static analysis)
  • fmt-maven-plugin (code formatting)
  • Maven WAR Plugin

📋 Prerequisites

Development

  • JDK 21
  • Maven 3.8+
  • MariaDB 10.6+ or MySQL 8.0+
  • Docker (optional)

Application Servers

  • Primary: OpenLiberty 23.0.0.3+
  • Other Jakarta EE 10 compatible servers: WildFly 27+, GlassFish 7.x, supported Payara releases

Note: Some server-specific configuration may be required for non-OpenLiberty deployments.

Getting Started

  1. Clone the repository

    git clone https://github.com/Urbine/PostWizardREST.git
    cd PostWizardREST
  2. Configure database access in:

    • src/main/liberty/config/server.xml
    • src/main/resources/META-INF/persistence.xml
  3. Build the project

    mvn -DskipTests package

    Note: The -DskipTests option is used to skip the tests during the build process. At that time in the project's lifecycle, the test suite was executed manually before every commit, so that the pipeline could take care of the remote deployment. Improving that used to be a milestone in the roadmap

  4. Deploy the generated WAR to a Jakarta EE 10–compatible application server.

API Documentation

API Overview (OpenAPI-Style)

Authentication

MethodEndpointDescriptionAuth
GET/v1/auth/loginAuthenticate user and issue JWT tokenBasic

Posts

MethodEndpointDescriptionAuth
GET/v1/posts/{postId}Retrieve a single postJWT
GET/v1/posts/meta/{postId}Retrieve metadata for a postJWT
GET/v1/posts/meta/dumpRetrieve metadata for all postsJWT
GET/v1/posts/dump?type={postType}Retrieve posts by typeJWT
POST/v1/posts/{postId}Update post contentJWT
POST/v1/posts/batchBatch update multiple postsJWT
POST/v1/posts/meta/{postId}Update post metadataJWT
POST/v1/posts/meta/batchBatch update post metadataJWT
GET/v1/posts/randomfeatured?limit={int}Randomize featured posts (e.g. videos)JWT

Taxonomies

MethodEndpointDescriptionAuth
POST/v1/taxonomies/checkLink or unlink taxonomy terms to a postJWT
POST/v1/taxonomies/addCreate taxonomy termsJWT
DELETE/v1/taxonomies/removeRemove taxonomy termsJWT

Conventions

  • Auth:

    • Basic → used only for token issuance
    • JWT → required for all protected endpoints
  • Content-Type: application/json

  • Responses: Consistent JSON structure with structured error payloads

  • Batch endpoints: Accept arrays of objects


API in Depth

🔐 Authentication

JWT-based authentication with Basic Auth used only to obtain the initial token.

Login (Get JWT)
GET /v1/auth/loginAuthorization: Basic base64(username:password)Content-Type: application/json
# Local cURL example:
curl -X GET "http://localhost:9080/PostWizardREST/v1/auth/login" \
-H "Authorization: Basic $(echo -n 'username:password'| base64)" \
-H "Content-Type: application/json"

Response

{
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"type": "bearer",
"expiration": "2025-10-06T16:33:01+07:00"
}

Usage

Authorization: Bearer <jwt>

Tokens are valid for 1 hour and must be refreshed after expiration.


📝 Posts

Read
  • GET /v1/posts/{postId} — Get post
  • GET /v1/posts/meta/{postId} — Get post metadata
  • GET /v1/posts/meta/dump — Get all post metadata
  • GET /v1/posts/dump?type={postType} — Get posts by type (post, attachment, all)

Update
POST /v1/posts/{postId}Content-Type: application/json
{
"title": "Updated Post Title",
"content": "Updated post content..."
}

Metadata Update
POST /v1/posts/meta/{postId}?autothumb={bool}&retries={int}&timeout={sec}Content-Type: application/json
{
"thumbURL": "http://example.com/thumb.jpg",
"yoastFocusKw": "java",
"yoastMetaDesc": "Yoast-compatible meta description"
}

Batch Operations
  • POST /v1/posts/batch — Batch post updates
  • POST /v1/posts/meta/batch — Batch metadata updates
[
{ "postID": 1, "title": "First Post" },
{ "postID": 2, "status": "publish" }
]

Featured Content
GET /v1/posts/randomfeatured?limit={int}

Randomizes featured posts (e.g. videos).


🏷️ Taxonomies

Link / Unlink Terms
POST /v1/taxonomies/check?id={postId}&link={bool}&unlink={bool}Content-Type: application/json
{
"name": "Technology",
"slug": "tech",
"taxonomy": {
"taxonomy_name": "category",
"taxonomy_description": "This is a new category."
}
}

Add Terms
POST /v1/taxonomies/add?clean={bool}Content-Type: application/json
{
"name": "Java 21",
"slug": "java-21",
"taxonomy": { "taxonomy_name": "post_tag" }
}

Remove Terms
DELETE /v1/taxonomies/removeContent-Type: application/json
{
"name": "Obsolete Term",
"taxonomy": { "taxonomy_name": "category" }
}

Project Structure

src/main/java/net/ygbstudio/postwizard/
├── auth/ # Authentication & authorization
├── dao/ # Data access layer
├── dto/ # Data transfer objects
├── entities/ # JPA entities
├── exceptions/ # Custom exceptions
├── filters/ # HTTP filters
├── mappers/ # Exception mappers
├── models/ # Domain models
├── rest/ # REST endpoints
├── services/ # Business logic
├── tasks/ # Scheduled tasks
└── utils/ # Utilities

Code Formatting

Uses fmt-maven-plugin, based on the Google Java Style Guide.

mvn fmt:format

📄 License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).

⚠️ Disclaimer

This project is provided as-is, without warranty of any kind, express or implied.

The author assumes no responsibility for security issues, data loss, or misuse. Users are solely responsible for compliance with applicable laws, platform terms of service, and content regulations when using or adapting this code.

About

A high-performance RESTful backend service for WordPress-based publishing systems, providing centralized content persistence, validation, and automation-oriented workflows.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

256 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🧙‍♂️ PostWizardREST

JavaCode StyleLicense: MPL 2.0Status: Archived

A high-performance, secure RESTful API for WordPress content management, built with modern Java Enterprise architectural patterns.

PostWizardREST provides a robust complement to the default WordPress REST API, offering performance improvements in specific automation-heavy and enterprise deployment scenarios, enhanced security features, and advanced content management capabilities.

⚠️ Project Status

Archived / Discontinued

PostWizardREST is no longer actively maintained, and the associated service is no longer available.

This repository is preserved for reference and educational purposes only.
No support, updates, security patches, or guarantees are provided.


Historical note

All documentation below reflects the system’s design, features, and API as they existed during active development. It is preserved for architectural reference and educational purposes.


Why was PostWizardREST created?

PostWizardREST was designed as an integration hub and server-side extension for projects such as PostWizardX3, handling taxonomy creation, post management, and media-related workflows outside of WordPress’ runtime.

While the WordPress REST API is suitable for many use cases, it is intentionally constrained by WordPress’ execution model, plugin ecosystem, and PHP-based request lifecycle. PostWizardREST explored an alternative approach: offloading critical content management workflows to a dedicated Java-based service, while remaining fully compatible with the WordPress database and ecosystem.

This design was motivated by the need for greater control over execution, security boundaries, and data modeling, particularly in high-volume or automation-heavy scenarios.

By decoupling these responsibilities from WordPress, the project aimed to leverage established Enterprise Java capabilities, resulting in:

  • Direct database access, avoiding repeated WordPress bootstrap and plugin execution overhead
  • Scheduled and batch jobs with proper locking, retries, and concurrency control
  • Application-server–managed threading and resource pools, instead of request-bound execution
  • A REST API decoupled from WordPress’ PHP execution model, enabling reliable integration with external automation systems
  • Documentation-driven API design with explicit contracts
  • Structured metadata handling with cascading and relational consistency
  • Type-safe APIs to reduce common runtime and data-shape errors
  • Explicit control over database connections, transactions, and isolation levels
  • Extensibility by default, without reliance on WordPress hooks or filters
  • Reduced attack surface, by minimizing public exposure of WordPress endpoints commonly targeted by automated attacks against WordPress installations
  • Observability and audit logging, enabling detection of abnormal behavior and performance bottlenecks
  • Developer-friendly modeling of taxonomies and custom fields for Java-based teams
  • A WordPress domain abstraction, designed with future integration into Jakarta EE or Spring ecosystems in mind, including message-driven and batch-oriented enterprise workflows
  • Compatibility with existing WordPress plugins, including Yoast SEO and CompressX
  • JWT-based authentication, role-based access control, and request validation
  • Consistent response formats and structured error handling
  • Integration testing, CI/CD readiness, and container-friendly deployment

In short, PostWizardREST was not intended to replace WordPress, but to isolate automation-heavy, security-sensitive, or high-throughput operations into a system better suited for those concerns, while still using WordPress as the content source of truth.

✨ Features

Core Features

  • Full CRUD operations for WordPress posts
  • Advanced taxonomy management (categories, tags, custom taxonomies)
  • Extensible metadata system
  • Batch processing using Jakarta Concurrency
  • Scheduled and automated content tasks

Security Features

  • JWT-based authentication
  • Secure HS256 key generation using SecureRandom
  • Role-based access control (RBAC)
  • Request validation and sanitization
  • Audit logging
  • Probe and automated scan detection

Operational

  • Jenkins - CI/CD pipeline integration

Logging

The application implements a structured, file-based logging system designed for observability, auditing, and troubleshooting in automation-heavy environments.

  • Log Levels
    Controlled via the PWLOG_LEVEL environment variable:

    • DEBUG → full trace logging (Level.ALL)
    • Any other value → defaults to INFO
  • Log Output & Organization

    • Logs are written to a PWLogs directory in the application working directory
    • Each logger writes to a dedicated file named after its class
    • Logs are appended by default (configurable)
  • Key Capabilities

    • Method entry/exit logging with parameter tracking
    • Automatic caller method detection
    • REST request logging (request path and client IP) for critical endpoints
    • Log file rotation using sequence-based file handlers
  • Format

    • Human-readable output via Java SimpleFormatter
    • Includes timestamp, log level, and source class/method

To enable debug logging:

export PWLOG_LEVEL="DEBUG"

🛠️ Tech Stack

Core Technologies

  • Java (JDK 21)
  • Jakarta EE 10 (platform API, provided by the application server)
  • Hibernate ORM 7
  • MariaDB 10.6+
  • JWT (JJWT)

Key Dependencies

  • MariaDB JDBC Driver
  • Apache Commons Lang 3
  • JSpecify
  • Jersey Client
  • Jakarta JSON Processing (JSON-P)

Development & Testing

  • Maven
  • JUnit (unit and integration testing)
  • Arquillian (container-based integration testing)
  • ShrinkWrap Resolver (test deployment assembly)
  • SpotBugs (static analysis)
  • fmt-maven-plugin (code formatting)
  • Maven WAR Plugin

📋 Prerequisites

Development

  • JDK 21
  • Maven 3.8+
  • MariaDB 10.6+ or MySQL 8.0+
  • Docker (optional)

Application Servers

  • Primary: OpenLiberty 23.0.0.3+
  • Other Jakarta EE 10 compatible servers: WildFly 27+, GlassFish 7.x, supported Payara releases

Note: Some server-specific configuration may be required for non-OpenLiberty deployments.

Getting Started

  1. Clone the repository

    git clone https://github.com/Urbine/PostWizardREST.git
    cd PostWizardREST
  2. Configure database access in:

    • src/main/liberty/config/server.xml
    • src/main/resources/META-INF/persistence.xml
  3. Build the project

    mvn -DskipTests package

    Note: The -DskipTests option is used to skip the tests during the build process. At that time in the project's lifecycle, the test suite was executed manually before every commit, so that the pipeline could take care of the remote deployment. Improving that used to be a milestone in the roadmap

  4. Deploy the generated WAR to a Jakarta EE 10–compatible application server.

API Documentation

API Overview (OpenAPI-Style)

Authentication

MethodEndpointDescriptionAuth
GET/v1/auth/loginAuthenticate user and issue JWT tokenBasic

Posts

MethodEndpointDescriptionAuth
GET/v1/posts/{postId}Retrieve a single postJWT
GET/v1/posts/meta/{postId}Retrieve metadata for a postJWT
GET/v1/posts/meta/dumpRetrieve metadata for all postsJWT
GET/v1/posts/dump?type={postType}Retrieve posts by typeJWT
POST/v1/posts/{postId}Update post contentJWT
POST/v1/posts/batchBatch update multiple postsJWT
POST/v1/posts/meta/{postId}Update post metadataJWT
POST/v1/posts/meta/batchBatch update post metadataJWT
GET/v1/posts/randomfeatured?limit={int}Randomize featured posts (e.g. videos)JWT

Taxonomies

MethodEndpointDescriptionAuth
POST/v1/taxonomies/checkLink or unlink taxonomy terms to a postJWT
POST/v1/taxonomies/addCreate taxonomy termsJWT
DELETE/v1/taxonomies/removeRemove taxonomy termsJWT

Conventions

  • Auth:

    • Basic → used only for token issuance
    • JWT → required for all protected endpoints
  • Content-Type: application/json

  • Responses: Consistent JSON structure with structured error payloads

  • Batch endpoints: Accept arrays of objects


API in Depth

🔐 Authentication

JWT-based authentication with Basic Auth used only to obtain the initial token.

Login (Get JWT)
GET /v1/auth/loginAuthorization: Basic base64(username:password)Content-Type: application/json
# Local cURL example:
curl -X GET "http://localhost:9080/PostWizardREST/v1/auth/login" \
-H "Authorization: Basic $(echo -n 'username:password'| base64)" \
-H "Content-Type: application/json"

Response

{
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"type": "bearer",
"expiration": "2025-10-06T16:33:01+07:00"
}

Usage

Authorization: Bearer <jwt>

Tokens are valid for 1 hour and must be refreshed after expiration.


📝 Posts

Read
  • GET /v1/posts/{postId} — Get post
  • GET /v1/posts/meta/{postId} — Get post metadata
  • GET /v1/posts/meta/dump — Get all post metadata
  • GET /v1/posts/dump?type={postType} — Get posts by type (post, attachment, all)

Update
POST /v1/posts/{postId}Content-Type: application/json
{
"title": "Updated Post Title",
"content": "Updated post content..."
}

Metadata Update
POST /v1/posts/meta/{postId}?autothumb={bool}&retries={int}&timeout={sec}Content-Type: application/json
{
"thumbURL": "http://example.com/thumb.jpg",
"yoastFocusKw": "java",
"yoastMetaDesc": "Yoast-compatible meta description"
}

Batch Operations
  • POST /v1/posts/batch — Batch post updates
  • POST /v1/posts/meta/batch — Batch metadata updates
[
{ "postID": 1, "title": "First Post" },
{ "postID": 2, "status": "publish" }
]

Featured Content
GET /v1/posts/randomfeatured?limit={int}

Randomizes featured posts (e.g. videos).


🏷️ Taxonomies

Link / Unlink Terms
POST /v1/taxonomies/check?id={postId}&link={bool}&unlink={bool}Content-Type: application/json
{
"name": "Technology",
"slug": "tech",
"taxonomy": {
"taxonomy_name": "category",
"taxonomy_description": "This is a new category."
}
}

Add Terms
POST /v1/taxonomies/add?clean={bool}Content-Type: application/json
{
"name": "Java 21",
"slug": "java-21",
"taxonomy": { "taxonomy_name": "post_tag" }
}

Remove Terms
DELETE /v1/taxonomies/removeContent-Type: application/json
{
"name": "Obsolete Term",
"taxonomy": { "taxonomy_name": "category" }
}

Project Structure

src/main/java/net/ygbstudio/postwizard/
├── auth/ # Authentication & authorization
├── dao/ # Data access layer
├── dto/ # Data transfer objects
├── entities/ # JPA entities
├── exceptions/ # Custom exceptions
├── filters/ # HTTP filters
├── mappers/ # Exception mappers
├── models/ # Domain models
├── rest/ # REST endpoints
├── services/ # Business logic
├── tasks/ # Scheduled tasks
└── utils/ # Utilities

Code Formatting

Uses fmt-maven-plugin, based on the Google Java Style Guide.

mvn fmt:format

📄 License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).

⚠️ Disclaimer

This project is provided as-is, without warranty of any kind, express or implied.

The author assumes no responsibility for security issues, data loss, or misuse. Users are solely responsible for compliance with applicable laws, platform terms of service, and content regulations when using or adapting this code.

About

A high-performance RESTful backend service for WordPress-based publishing systems, providing centralized content persistence, validation, and automation-oriented workflows.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

256 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🧙‍♂️ PostWizardREST

JavaCode StyleLicense: MPL 2.0Status: Archived

A high-performance, secure RESTful API for WordPress content management, built with modern Java Enterprise architectural patterns.

PostWizardREST provides a robust complement to the default WordPress REST API, offering performance improvements in specific automation-heavy and enterprise deployment scenarios, enhanced security features, and advanced content management capabilities.

⚠️ Project Status

Archived / Discontinued

PostWizardREST is no longer actively maintained, and the associated service is no longer available.

This repository is preserved for reference and educational purposes only.
No support, updates, security patches, or guarantees are provided.


Historical note

All documentation below reflects the system’s design, features, and API as they existed during active development. It is preserved for architectural reference and educational purposes.


Why was PostWizardREST created?

PostWizardREST was designed as an integration hub and server-side extension for projects such as PostWizardX3, handling taxonomy creation, post management, and media-related workflows outside of WordPress’ runtime.

While the WordPress REST API is suitable for many use cases, it is intentionally constrained by WordPress’ execution model, plugin ecosystem, and PHP-based request lifecycle. PostWizardREST explored an alternative approach: offloading critical content management workflows to a dedicated Java-based service, while remaining fully compatible with the WordPress database and ecosystem.

This design was motivated by the need for greater control over execution, security boundaries, and data modeling, particularly in high-volume or automation-heavy scenarios.

By decoupling these responsibilities from WordPress, the project aimed to leverage established Enterprise Java capabilities, resulting in:

  • Direct database access, avoiding repeated WordPress bootstrap and plugin execution overhead
  • Scheduled and batch jobs with proper locking, retries, and concurrency control
  • Application-server–managed threading and resource pools, instead of request-bound execution
  • A REST API decoupled from WordPress’ PHP execution model, enabling reliable integration with external automation systems
  • Documentation-driven API design with explicit contracts
  • Structured metadata handling with cascading and relational consistency
  • Type-safe APIs to reduce common runtime and data-shape errors
  • Explicit control over database connections, transactions, and isolation levels
  • Extensibility by default, without reliance on WordPress hooks or filters
  • Reduced attack surface, by minimizing public exposure of WordPress endpoints commonly targeted by automated attacks against WordPress installations
  • Observability and audit logging, enabling detection of abnormal behavior and performance bottlenecks
  • Developer-friendly modeling of taxonomies and custom fields for Java-based teams
  • A WordPress domain abstraction, designed with future integration into Jakarta EE or Spring ecosystems in mind, including message-driven and batch-oriented enterprise workflows
  • Compatibility with existing WordPress plugins, including Yoast SEO and CompressX
  • JWT-based authentication, role-based access control, and request validation
  • Consistent response formats and structured error handling
  • Integration testing, CI/CD readiness, and container-friendly deployment

In short, PostWizardREST was not intended to replace WordPress, but to isolate automation-heavy, security-sensitive, or high-throughput operations into a system better suited for those concerns, while still using WordPress as the content source of truth.

✨ Features

Core Features

  • Full CRUD operations for WordPress posts
  • Advanced taxonomy management (categories, tags, custom taxonomies)
  • Extensible metadata system
  • Batch processing using Jakarta Concurrency
  • Scheduled and automated content tasks

Security Features

  • JWT-based authentication
  • Secure HS256 key generation using SecureRandom
  • Role-based access control (RBAC)
  • Request validation and sanitization
  • Audit logging
  • Probe and automated scan detection

Operational

  • Jenkins - CI/CD pipeline integration

Logging

The application implements a structured, file-based logging system designed for observability, auditing, and troubleshooting in automation-heavy environments.

  • Log Levels
    Controlled via the PWLOG_LEVEL environment variable:

    • DEBUG → full trace logging (Level.ALL)
    • Any other value → defaults to INFO
  • Log Output & Organization

    • Logs are written to a PWLogs directory in the application working directory
    • Each logger writes to a dedicated file named after its class
    • Logs are appended by default (configurable)
  • Key Capabilities

    • Method entry/exit logging with parameter tracking
    • Automatic caller method detection
    • REST request logging (request path and client IP) for critical endpoints
    • Log file rotation using sequence-based file handlers
  • Format

    • Human-readable output via Java SimpleFormatter
    • Includes timestamp, log level, and source class/method

To enable debug logging:

export PWLOG_LEVEL="DEBUG"

🛠️ Tech Stack

Core Technologies

  • Java (JDK 21)
  • Jakarta EE 10 (platform API, provided by the application server)
  • Hibernate ORM 7
  • MariaDB 10.6+
  • JWT (JJWT)

Key Dependencies

  • MariaDB JDBC Driver
  • Apache Commons Lang 3
  • JSpecify
  • Jersey Client
  • Jakarta JSON Processing (JSON-P)

Development & Testing

  • Maven
  • JUnit (unit and integration testing)
  • Arquillian (container-based integration testing)
  • ShrinkWrap Resolver (test deployment assembly)
  • SpotBugs (static analysis)
  • fmt-maven-plugin (code formatting)
  • Maven WAR Plugin

📋 Prerequisites

Development

  • JDK 21
  • Maven 3.8+
  • MariaDB 10.6+ or MySQL 8.0+
  • Docker (optional)

Application Servers

  • Primary: OpenLiberty 23.0.0.3+
  • Other Jakarta EE 10 compatible servers: WildFly 27+, GlassFish 7.x, supported Payara releases

Note: Some server-specific configuration may be required for non-OpenLiberty deployments.

Getting Started

  1. Clone the repository

    git clone https://github.com/Urbine/PostWizardREST.git
    cd PostWizardREST
  2. Configure database access in:

    • src/main/liberty/config/server.xml
    • src/main/resources/META-INF/persistence.xml
  3. Build the project

    mvn -DskipTests package

    Note: The -DskipTests option is used to skip the tests during the build process. At that time in the project's lifecycle, the test suite was executed manually before every commit, so that the pipeline could take care of the remote deployment. Improving that used to be a milestone in the roadmap

  4. Deploy the generated WAR to a Jakarta EE 10–compatible application server.

API Documentation

API Overview (OpenAPI-Style)

Authentication

MethodEndpointDescriptionAuth
GET/v1/auth/loginAuthenticate user and issue JWT tokenBasic

Posts

MethodEndpointDescriptionAuth
GET/v1/posts/{postId}Retrieve a single postJWT
GET/v1/posts/meta/{postId}Retrieve metadata for a postJWT
GET/v1/posts/meta/dumpRetrieve metadata for all postsJWT
GET/v1/posts/dump?type={postType}Retrieve posts by typeJWT
POST/v1/posts/{postId}Update post contentJWT
POST/v1/posts/batchBatch update multiple postsJWT
POST/v1/posts/meta/{postId}Update post metadataJWT
POST/v1/posts/meta/batchBatch update post metadataJWT
GET/v1/posts/randomfeatured?limit={int}Randomize featured posts (e.g. videos)JWT

Taxonomies

MethodEndpointDescriptionAuth
POST/v1/taxonomies/checkLink or unlink taxonomy terms to a postJWT
POST/v1/taxonomies/addCreate taxonomy termsJWT
DELETE/v1/taxonomies/removeRemove taxonomy termsJWT

Conventions

  • Auth:

    • Basic → used only for token issuance
    • JWT → required for all protected endpoints
  • Content-Type: application/json

  • Responses: Consistent JSON structure with structured error payloads

  • Batch endpoints: Accept arrays of objects


API in Depth

🔐 Authentication

JWT-based authentication with Basic Auth used only to obtain the initial token.

Login (Get JWT)
GET /v1/auth/loginAuthorization: Basic base64(username:password)Content-Type: application/json
# Local cURL example:
curl -X GET "http://localhost:9080/PostWizardREST/v1/auth/login" \
-H "Authorization: Basic $(echo -n 'username:password'| base64)" \
-H "Content-Type: application/json"

Response

{
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"type": "bearer",
"expiration": "2025-10-06T16:33:01+07:00"
}

Usage

Authorization: Bearer <jwt>

Tokens are valid for 1 hour and must be refreshed after expiration.


📝 Posts

Read
  • GET /v1/posts/{postId} — Get post
  • GET /v1/posts/meta/{postId} — Get post metadata
  • GET /v1/posts/meta/dump — Get all post metadata
  • GET /v1/posts/dump?type={postType} — Get posts by type (post, attachment, all)

Update
POST /v1/posts/{postId}Content-Type: application/json
{
"title": "Updated Post Title",
"content": "Updated post content..."
}

Metadata Update
POST /v1/posts/meta/{postId}?autothumb={bool}&retries={int}&timeout={sec}Content-Type: application/json
{
"thumbURL": "http://example.com/thumb.jpg",
"yoastFocusKw": "java",
"yoastMetaDesc": "Yoast-compatible meta description"
}

Batch Operations
  • POST /v1/posts/batch — Batch post updates
  • POST /v1/posts/meta/batch — Batch metadata updates
[
{ "postID": 1, "title": "First Post" },
{ "postID": 2, "status": "publish" }
]

Featured Content
GET /v1/posts/randomfeatured?limit={int}

Randomizes featured posts (e.g. videos).


🏷️ Taxonomies

Link / Unlink Terms
POST /v1/taxonomies/check?id={postId}&link={bool}&unlink={bool}Content-Type: application/json
{
"name": "Technology",
"slug": "tech",
"taxonomy": {
"taxonomy_name": "category",
"taxonomy_description": "This is a new category."
}
}

Add Terms
POST /v1/taxonomies/add?clean={bool}Content-Type: application/json
{
"name": "Java 21",
"slug": "java-21",
"taxonomy": { "taxonomy_name": "post_tag" }
}

Remove Terms
DELETE /v1/taxonomies/removeContent-Type: application/json
{
"name": "Obsolete Term",
"taxonomy": { "taxonomy_name": "category" }
}

Project Structure

src/main/java/net/ygbstudio/postwizard/
├── auth/ # Authentication & authorization
├── dao/ # Data access layer
├── dto/ # Data transfer objects
├── entities/ # JPA entities
├── exceptions/ # Custom exceptions
├── filters/ # HTTP filters
├── mappers/ # Exception mappers
├── models/ # Domain models
├── rest/ # REST endpoints
├── services/ # Business logic
├── tasks/ # Scheduled tasks
└── utils/ # Utilities

Code Formatting

Uses fmt-maven-plugin, based on the Google Java Style Guide.

mvn fmt:format

📄 License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).

⚠️ Disclaimer

This project is provided as-is, without warranty of any kind, express or implied.

The author assumes no responsibility for security issues, data loss, or misuse. Users are solely responsible for compliance with applicable laws, platform terms of service, and content regulations when using or adapting this code.

About

A high-performance RESTful backend service for WordPress-based publishing systems, providing centralized content persistence, validation, and automation-oriented workflows.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

256 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🧙‍♂️ PostWizardREST

JavaCode StyleLicense: MPL 2.0Status: Archived

A high-performance, secure RESTful API for WordPress content management, built with modern Java Enterprise architectural patterns.

PostWizardREST provides a robust complement to the default WordPress REST API, offering performance improvements in specific automation-heavy and enterprise deployment scenarios, enhanced security features, and advanced content management capabilities.

⚠️ Project Status

Archived / Discontinued

PostWizardREST is no longer actively maintained, and the associated service is no longer available.

This repository is preserved for reference and educational purposes only.
No support, updates, security patches, or guarantees are provided.


Historical note

All documentation below reflects the system’s design, features, and API as they existed during active development. It is preserved for architectural reference and educational purposes.


Why was PostWizardREST created?

PostWizardREST was designed as an integration hub and server-side extension for projects such as PostWizardX3, handling taxonomy creation, post management, and media-related workflows outside of WordPress’ runtime.

While the WordPress REST API is suitable for many use cases, it is intentionally constrained by WordPress’ execution model, plugin ecosystem, and PHP-based request lifecycle. PostWizardREST explored an alternative approach: offloading critical content management workflows to a dedicated Java-based service, while remaining fully compatible with the WordPress database and ecosystem.

This design was motivated by the need for greater control over execution, security boundaries, and data modeling, particularly in high-volume or automation-heavy scenarios.

By decoupling these responsibilities from WordPress, the project aimed to leverage established Enterprise Java capabilities, resulting in:

  • Direct database access, avoiding repeated WordPress bootstrap and plugin execution overhead
  • Scheduled and batch jobs with proper locking, retries, and concurrency control
  • Application-server–managed threading and resource pools, instead of request-bound execution
  • A REST API decoupled from WordPress’ PHP execution model, enabling reliable integration with external automation systems
  • Documentation-driven API design with explicit contracts
  • Structured metadata handling with cascading and relational consistency
  • Type-safe APIs to reduce common runtime and data-shape errors
  • Explicit control over database connections, transactions, and isolation levels
  • Extensibility by default, without reliance on WordPress hooks or filters
  • Reduced attack surface, by minimizing public exposure of WordPress endpoints commonly targeted by automated attacks against WordPress installations
  • Observability and audit logging, enabling detection of abnormal behavior and performance bottlenecks
  • Developer-friendly modeling of taxonomies and custom fields for Java-based teams
  • A WordPress domain abstraction, designed with future integration into Jakarta EE or Spring ecosystems in mind, including message-driven and batch-oriented enterprise workflows
  • Compatibility with existing WordPress plugins, including Yoast SEO and CompressX
  • JWT-based authentication, role-based access control, and request validation
  • Consistent response formats and structured error handling
  • Integration testing, CI/CD readiness, and container-friendly deployment

In short, PostWizardREST was not intended to replace WordPress, but to isolate automation-heavy, security-sensitive, or high-throughput operations into a system better suited for those concerns, while still using WordPress as the content source of truth.

✨ Features

Core Features

  • Full CRUD operations for WordPress posts
  • Advanced taxonomy management (categories, tags, custom taxonomies)
  • Extensible metadata system
  • Batch processing using Jakarta Concurrency
  • Scheduled and automated content tasks

Security Features

  • JWT-based authentication
  • Secure HS256 key generation using SecureRandom
  • Role-based access control (RBAC)
  • Request validation and sanitization
  • Audit logging
  • Probe and automated scan detection

Operational

  • Jenkins - CI/CD pipeline integration

Logging

The application implements a structured, file-based logging system designed for observability, auditing, and troubleshooting in automation-heavy environments.

  • Log Levels
    Controlled via the PWLOG_LEVEL environment variable:

    • DEBUG → full trace logging (Level.ALL)
    • Any other value → defaults to INFO
  • Log Output & Organization

    • Logs are written to a PWLogs directory in the application working directory
    • Each logger writes to a dedicated file named after its class
    • Logs are appended by default (configurable)
  • Key Capabilities

    • Method entry/exit logging with parameter tracking
    • Automatic caller method detection
    • REST request logging (request path and client IP) for critical endpoints
    • Log file rotation using sequence-based file handlers
  • Format

    • Human-readable output via Java SimpleFormatter
    • Includes timestamp, log level, and source class/method

To enable debug logging:

export PWLOG_LEVEL="DEBUG"

🛠️ Tech Stack

Core Technologies

  • Java (JDK 21)
  • Jakarta EE 10 (platform API, provided by the application server)
  • Hibernate ORM 7
  • MariaDB 10.6+
  • JWT (JJWT)

Key Dependencies

  • MariaDB JDBC Driver
  • Apache Commons Lang 3
  • JSpecify
  • Jersey Client
  • Jakarta JSON Processing (JSON-P)

Development & Testing

  • Maven
  • JUnit (unit and integration testing)
  • Arquillian (container-based integration testing)
  • ShrinkWrap Resolver (test deployment assembly)
  • SpotBugs (static analysis)
  • fmt-maven-plugin (code formatting)
  • Maven WAR Plugin

📋 Prerequisites

Development

  • JDK 21
  • Maven 3.8+
  • MariaDB 10.6+ or MySQL 8.0+
  • Docker (optional)

Application Servers

  • Primary: OpenLiberty 23.0.0.3+
  • Other Jakarta EE 10 compatible servers: WildFly 27+, GlassFish 7.x, supported Payara releases

Note: Some server-specific configuration may be required for non-OpenLiberty deployments.

Getting Started

  1. Clone the repository

    git clone https://github.com/Urbine/PostWizardREST.git
    cd PostWizardREST
  2. Configure database access in:

    • src/main/liberty/config/server.xml
    • src/main/resources/META-INF/persistence.xml
  3. Build the project

    mvn -DskipTests package

    Note: The -DskipTests option is used to skip the tests during the build process. At that time in the project's lifecycle, the test suite was executed manually before every commit, so that the pipeline could take care of the remote deployment. Improving that used to be a milestone in the roadmap

  4. Deploy the generated WAR to a Jakarta EE 10–compatible application server.

API Documentation

API Overview (OpenAPI-Style)

Authentication

MethodEndpointDescriptionAuth
GET/v1/auth/loginAuthenticate user and issue JWT tokenBasic

Posts

MethodEndpointDescriptionAuth
GET/v1/posts/{postId}Retrieve a single postJWT
GET/v1/posts/meta/{postId}Retrieve metadata for a postJWT
GET/v1/posts/meta/dumpRetrieve metadata for all postsJWT
GET/v1/posts/dump?type={postType}Retrieve posts by typeJWT
POST/v1/posts/{postId}Update post contentJWT
POST/v1/posts/batchBatch update multiple postsJWT
POST/v1/posts/meta/{postId}Update post metadataJWT
POST/v1/posts/meta/batchBatch update post metadataJWT
GET/v1/posts/randomfeatured?limit={int}Randomize featured posts (e.g. videos)JWT

Taxonomies

MethodEndpointDescriptionAuth
POST/v1/taxonomies/checkLink or unlink taxonomy terms to a postJWT
POST/v1/taxonomies/addCreate taxonomy termsJWT
DELETE/v1/taxonomies/removeRemove taxonomy termsJWT

Conventions

  • Auth:

    • Basic → used only for token issuance
    • JWT → required for all protected endpoints
  • Content-Type: application/json

  • Responses: Consistent JSON structure with structured error payloads

  • Batch endpoints: Accept arrays of objects


API in Depth

🔐 Authentication

JWT-based authentication with Basic Auth used only to obtain the initial token.

Login (Get JWT)
GET /v1/auth/loginAuthorization: Basic base64(username:password)Content-Type: application/json
# Local cURL example:
curl -X GET "http://localhost:9080/PostWizardREST/v1/auth/login" \
-H "Authorization: Basic $(echo -n 'username:password'| base64)" \
-H "Content-Type: application/json"

Response

{
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"type": "bearer",
"expiration": "2025-10-06T16:33:01+07:00"
}

Usage

Authorization: Bearer <jwt>

Tokens are valid for 1 hour and must be refreshed after expiration.


📝 Posts

Read
  • GET /v1/posts/{postId} — Get post
  • GET /v1/posts/meta/{postId} — Get post metadata
  • GET /v1/posts/meta/dump — Get all post metadata
  • GET /v1/posts/dump?type={postType} — Get posts by type (post, attachment, all)

Update
POST /v1/posts/{postId}Content-Type: application/json
{
"title": "Updated Post Title",
"content": "Updated post content..."
}

Metadata Update
POST /v1/posts/meta/{postId}?autothumb={bool}&retries={int}&timeout={sec}Content-Type: application/json
{
"thumbURL": "http://example.com/thumb.jpg",
"yoastFocusKw": "java",
"yoastMetaDesc": "Yoast-compatible meta description"
}

Batch Operations
  • POST /v1/posts/batch — Batch post updates
  • POST /v1/posts/meta/batch — Batch metadata updates
[
{ "postID": 1, "title": "First Post" },
{ "postID": 2, "status": "publish" }
]

Featured Content
GET /v1/posts/randomfeatured?limit={int}

Randomizes featured posts (e.g. videos).


🏷️ Taxonomies

Link / Unlink Terms
POST /v1/taxonomies/check?id={postId}&link={bool}&unlink={bool}Content-Type: application/json
{
"name": "Technology",
"slug": "tech",
"taxonomy": {
"taxonomy_name": "category",
"taxonomy_description": "This is a new category."
}
}

Add Terms
POST /v1/taxonomies/add?clean={bool}Content-Type: application/json
{
"name": "Java 21",
"slug": "java-21",
"taxonomy": { "taxonomy_name": "post_tag" }
}

Remove Terms
DELETE /v1/taxonomies/removeContent-Type: application/json
{
"name": "Obsolete Term",
"taxonomy": { "taxonomy_name": "category" }
}

Project Structure

src/main/java/net/ygbstudio/postwizard/
├── auth/ # Authentication & authorization
├── dao/ # Data access layer
├── dto/ # Data transfer objects
├── entities/ # JPA entities
├── exceptions/ # Custom exceptions
├── filters/ # HTTP filters
├── mappers/ # Exception mappers
├── models/ # Domain models
├── rest/ # REST endpoints
├── services/ # Business logic
├── tasks/ # Scheduled tasks
└── utils/ # Utilities

Code Formatting

Uses fmt-maven-plugin, based on the Google Java Style Guide.

mvn fmt:format

📄 License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).

⚠️ Disclaimer

This project is provided as-is, without warranty of any kind, express or implied.

The author assumes no responsibility for security issues, data loss, or misuse. Users are solely responsible for compliance with applicable laws, platform terms of service, and content regulations when using or adapting this code.

About

A high-performance RESTful backend service for WordPress-based publishing systems, providing centralized content persistence, validation, and automation-oriented workflows.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

256 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🧙‍♂️ PostWizardREST

JavaCode StyleLicense: MPL 2.0Status: Archived

A high-performance, secure RESTful API for WordPress content management, built with modern Java Enterprise architectural patterns.

PostWizardREST provides a robust complement to the default WordPress REST API, offering performance improvements in specific automation-heavy and enterprise deployment scenarios, enhanced security features, and advanced content management capabilities.

⚠️ Project Status

Archived / Discontinued

PostWizardREST is no longer actively maintained, and the associated service is no longer available.

This repository is preserved for reference and educational purposes only.
No support, updates, security patches, or guarantees are provided.


Historical note

All documentation below reflects the system’s design, features, and API as they existed during active development. It is preserved for architectural reference and educational purposes.


Why was PostWizardREST created?

PostWizardREST was designed as an integration hub and server-side extension for projects such as PostWizardX3, handling taxonomy creation, post management, and media-related workflows outside of WordPress’ runtime.

While the WordPress REST API is suitable for many use cases, it is intentionally constrained by WordPress’ execution model, plugin ecosystem, and PHP-based request lifecycle. PostWizardREST explored an alternative approach: offloading critical content management workflows to a dedicated Java-based service, while remaining fully compatible with the WordPress database and ecosystem.

This design was motivated by the need for greater control over execution, security boundaries, and data modeling, particularly in high-volume or automation-heavy scenarios.

By decoupling these responsibilities from WordPress, the project aimed to leverage established Enterprise Java capabilities, resulting in:

  • Direct database access, avoiding repeated WordPress bootstrap and plugin execution overhead
  • Scheduled and batch jobs with proper locking, retries, and concurrency control
  • Application-server–managed threading and resource pools, instead of request-bound execution
  • A REST API decoupled from WordPress’ PHP execution model, enabling reliable integration with external automation systems
  • Documentation-driven API design with explicit contracts
  • Structured metadata handling with cascading and relational consistency
  • Type-safe APIs to reduce common runtime and data-shape errors
  • Explicit control over database connections, transactions, and isolation levels
  • Extensibility by default, without reliance on WordPress hooks or filters
  • Reduced attack surface, by minimizing public exposure of WordPress endpoints commonly targeted by automated attacks against WordPress installations
  • Observability and audit logging, enabling detection of abnormal behavior and performance bottlenecks
  • Developer-friendly modeling of taxonomies and custom fields for Java-based teams
  • A WordPress domain abstraction, designed with future integration into Jakarta EE or Spring ecosystems in mind, including message-driven and batch-oriented enterprise workflows
  • Compatibility with existing WordPress plugins, including Yoast SEO and CompressX
  • JWT-based authentication, role-based access control, and request validation
  • Consistent response formats and structured error handling
  • Integration testing, CI/CD readiness, and container-friendly deployment

In short, PostWizardREST was not intended to replace WordPress, but to isolate automation-heavy, security-sensitive, or high-throughput operations into a system better suited for those concerns, while still using WordPress as the content source of truth.

✨ Features

Core Features

  • Full CRUD operations for WordPress posts
  • Advanced taxonomy management (categories, tags, custom taxonomies)
  • Extensible metadata system
  • Batch processing using Jakarta Concurrency
  • Scheduled and automated content tasks

Security Features

  • JWT-based authentication
  • Secure HS256 key generation using SecureRandom
  • Role-based access control (RBAC)
  • Request validation and sanitization
  • Audit logging
  • Probe and automated scan detection

Operational

  • Jenkins - CI/CD pipeline integration

Logging

The application implements a structured, file-based logging system designed for observability, auditing, and troubleshooting in automation-heavy environments.

  • Log Levels
    Controlled via the PWLOG_LEVEL environment variable:

    • DEBUG → full trace logging (Level.ALL)
    • Any other value → defaults to INFO
  • Log Output & Organization

    • Logs are written to a PWLogs directory in the application working directory
    • Each logger writes to a dedicated file named after its class
    • Logs are appended by default (configurable)
  • Key Capabilities

    • Method entry/exit logging with parameter tracking
    • Automatic caller method detection
    • REST request logging (request path and client IP) for critical endpoints
    • Log file rotation using sequence-based file handlers
  • Format

    • Human-readable output via Java SimpleFormatter
    • Includes timestamp, log level, and source class/method

To enable debug logging:

export PWLOG_LEVEL="DEBUG"

🛠️ Tech Stack

Core Technologies

  • Java (JDK 21)
  • Jakarta EE 10 (platform API, provided by the application server)
  • Hibernate ORM 7
  • MariaDB 10.6+
  • JWT (JJWT)

Key Dependencies

  • MariaDB JDBC Driver
  • Apache Commons Lang 3
  • JSpecify
  • Jersey Client
  • Jakarta JSON Processing (JSON-P)

Development & Testing

  • Maven
  • JUnit (unit and integration testing)
  • Arquillian (container-based integration testing)
  • ShrinkWrap Resolver (test deployment assembly)
  • SpotBugs (static analysis)
  • fmt-maven-plugin (code formatting)
  • Maven WAR Plugin

📋 Prerequisites

Development

  • JDK 21
  • Maven 3.8+
  • MariaDB 10.6+ or MySQL 8.0+
  • Docker (optional)

Application Servers

  • Primary: OpenLiberty 23.0.0.3+
  • Other Jakarta EE 10 compatible servers: WildFly 27+, GlassFish 7.x, supported Payara releases

Note: Some server-specific configuration may be required for non-OpenLiberty deployments.

Getting Started

  1. Clone the repository

    git clone https://github.com/Urbine/PostWizardREST.git
    cd PostWizardREST
  2. Configure database access in:

    • src/main/liberty/config/server.xml
    • src/main/resources/META-INF/persistence.xml
  3. Build the project

    mvn -DskipTests package

    Note: The -DskipTests option is used to skip the tests during the build process. At that time in the project's lifecycle, the test suite was executed manually before every commit, so that the pipeline could take care of the remote deployment. Improving that used to be a milestone in the roadmap

  4. Deploy the generated WAR to a Jakarta EE 10–compatible application server.

API Documentation

API Overview (OpenAPI-Style)

Authentication

MethodEndpointDescriptionAuth
GET/v1/auth/loginAuthenticate user and issue JWT tokenBasic

Posts

MethodEndpointDescriptionAuth
GET/v1/posts/{postId}Retrieve a single postJWT
GET/v1/posts/meta/{postId}Retrieve metadata for a postJWT
GET/v1/posts/meta/dumpRetrieve metadata for all postsJWT
GET/v1/posts/dump?type={postType}Retrieve posts by typeJWT
POST/v1/posts/{postId}Update post contentJWT
POST/v1/posts/batchBatch update multiple postsJWT
POST/v1/posts/meta/{postId}Update post metadataJWT
POST/v1/posts/meta/batchBatch update post metadataJWT
GET/v1/posts/randomfeatured?limit={int}Randomize featured posts (e.g. videos)JWT

Taxonomies

MethodEndpointDescriptionAuth
POST/v1/taxonomies/checkLink or unlink taxonomy terms to a postJWT
POST/v1/taxonomies/addCreate taxonomy termsJWT
DELETE/v1/taxonomies/removeRemove taxonomy termsJWT

Conventions

  • Auth:

    • Basic → used only for token issuance
    • JWT → required for all protected endpoints
  • Content-Type: application/json

  • Responses: Consistent JSON structure with structured error payloads

  • Batch endpoints: Accept arrays of objects


API in Depth

🔐 Authentication

JWT-based authentication with Basic Auth used only to obtain the initial token.

Login (Get JWT)
GET /v1/auth/loginAuthorization: Basic base64(username:password)Content-Type: application/json
# Local cURL example:
curl -X GET "http://localhost:9080/PostWizardREST/v1/auth/login" \
-H "Authorization: Basic $(echo -n 'username:password'| base64)" \
-H "Content-Type: application/json"

Response

{
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"type": "bearer",
"expiration": "2025-10-06T16:33:01+07:00"
}

Usage

Authorization: Bearer <jwt>

Tokens are valid for 1 hour and must be refreshed after expiration.


📝 Posts

Read
  • GET /v1/posts/{postId} — Get post
  • GET /v1/posts/meta/{postId} — Get post metadata
  • GET /v1/posts/meta/dump — Get all post metadata
  • GET /v1/posts/dump?type={postType} — Get posts by type (post, attachment, all)

Update
POST /v1/posts/{postId}Content-Type: application/json
{
"title": "Updated Post Title",
"content": "Updated post content..."
}

Metadata Update
POST /v1/posts/meta/{postId}?autothumb={bool}&retries={int}&timeout={sec}Content-Type: application/json
{
"thumbURL": "http://example.com/thumb.jpg",
"yoastFocusKw": "java",
"yoastMetaDesc": "Yoast-compatible meta description"
}

Batch Operations
  • POST /v1/posts/batch — Batch post updates
  • POST /v1/posts/meta/batch — Batch metadata updates
[
{ "postID": 1, "title": "First Post" },
{ "postID": 2, "status": "publish" }
]

Featured Content
GET /v1/posts/randomfeatured?limit={int}

Randomizes featured posts (e.g. videos).


🏷️ Taxonomies

Link / Unlink Terms
POST /v1/taxonomies/check?id={postId}&link={bool}&unlink={bool}Content-Type: application/json
{
"name": "Technology",
"slug": "tech",
"taxonomy": {
"taxonomy_name": "category",
"taxonomy_description": "This is a new category."
}
}

Add Terms
POST /v1/taxonomies/add?clean={bool}Content-Type: application/json
{
"name": "Java 21",
"slug": "java-21",
"taxonomy": { "taxonomy_name": "post_tag" }
}

Remove Terms
DELETE /v1/taxonomies/removeContent-Type: application/json
{
"name": "Obsolete Term",
"taxonomy": { "taxonomy_name": "category" }
}

Project Structure

src/main/java/net/ygbstudio/postwizard/
├── auth/ # Authentication & authorization
├── dao/ # Data access layer
├── dto/ # Data transfer objects
├── entities/ # JPA entities
├── exceptions/ # Custom exceptions
├── filters/ # HTTP filters
├── mappers/ # Exception mappers
├── models/ # Domain models
├── rest/ # REST endpoints
├── services/ # Business logic
├── tasks/ # Scheduled tasks
└── utils/ # Utilities

Code Formatting

Uses fmt-maven-plugin, based on the Google Java Style Guide.

mvn fmt:format

📄 License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).

⚠️ Disclaimer

This project is provided as-is, without warranty of any kind, express or implied.

The author assumes no responsibility for security issues, data loss, or misuse. Users are solely responsible for compliance with applicable laws, platform terms of service, and content regulations when using or adapting this code.

About

A high-performance RESTful backend service for WordPress-based publishing systems, providing centralized content persistence, validation, and automation-oriented workflows.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

256 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🧙‍♂️ PostWizardREST

JavaCode StyleLicense: MPL 2.0Status: Archived

A high-performance, secure RESTful API for WordPress content management, built with modern Java Enterprise architectural patterns.

PostWizardREST provides a robust complement to the default WordPress REST API, offering performance improvements in specific automation-heavy and enterprise deployment scenarios, enhanced security features, and advanced content management capabilities.

⚠️ Project Status

Archived / Discontinued

PostWizardREST is no longer actively maintained, and the associated service is no longer available.

This repository is preserved for reference and educational purposes only.
No support, updates, security patches, or guarantees are provided.


Historical note

All documentation below reflects the system’s design, features, and API as they existed during active development. It is preserved for architectural reference and educational purposes.


Why was PostWizardREST created?

PostWizardREST was designed as an integration hub and server-side extension for projects such as PostWizardX3, handling taxonomy creation, post management, and media-related workflows outside of WordPress’ runtime.

While the WordPress REST API is suitable for many use cases, it is intentionally constrained by WordPress’ execution model, plugin ecosystem, and PHP-based request lifecycle. PostWizardREST explored an alternative approach: offloading critical content management workflows to a dedicated Java-based service, while remaining fully compatible with the WordPress database and ecosystem.

This design was motivated by the need for greater control over execution, security boundaries, and data modeling, particularly in high-volume or automation-heavy scenarios.

By decoupling these responsibilities from WordPress, the project aimed to leverage established Enterprise Java capabilities, resulting in:

  • Direct database access, avoiding repeated WordPress bootstrap and plugin execution overhead
  • Scheduled and batch jobs with proper locking, retries, and concurrency control
  • Application-server–managed threading and resource pools, instead of request-bound execution
  • A REST API decoupled from WordPress’ PHP execution model, enabling reliable integration with external automation systems
  • Documentation-driven API design with explicit contracts
  • Structured metadata handling with cascading and relational consistency
  • Type-safe APIs to reduce common runtime and data-shape errors
  • Explicit control over database connections, transactions, and isolation levels
  • Extensibility by default, without reliance on WordPress hooks or filters
  • Reduced attack surface, by minimizing public exposure of WordPress endpoints commonly targeted by automated attacks against WordPress installations
  • Observability and audit logging, enabling detection of abnormal behavior and performance bottlenecks
  • Developer-friendly modeling of taxonomies and custom fields for Java-based teams
  • A WordPress domain abstraction, designed with future integration into Jakarta EE or Spring ecosystems in mind, including message-driven and batch-oriented enterprise workflows
  • Compatibility with existing WordPress plugins, including Yoast SEO and CompressX
  • JWT-based authentication, role-based access control, and request validation
  • Consistent response formats and structured error handling
  • Integration testing, CI/CD readiness, and container-friendly deployment

In short, PostWizardREST was not intended to replace WordPress, but to isolate automation-heavy, security-sensitive, or high-throughput operations into a system better suited for those concerns, while still using WordPress as the content source of truth.

✨ Features

Core Features

  • Full CRUD operations for WordPress posts
  • Advanced taxonomy management (categories, tags, custom taxonomies)
  • Extensible metadata system
  • Batch processing using Jakarta Concurrency
  • Scheduled and automated content tasks

Security Features

  • JWT-based authentication
  • Secure HS256 key generation using SecureRandom
  • Role-based access control (RBAC)
  • Request validation and sanitization
  • Audit logging
  • Probe and automated scan detection

Operational

  • Jenkins - CI/CD pipeline integration

Logging

The application implements a structured, file-based logging system designed for observability, auditing, and troubleshooting in automation-heavy environments.

  • Log Levels
    Controlled via the PWLOG_LEVEL environment variable:

    • DEBUG → full trace logging (Level.ALL)
    • Any other value → defaults to INFO
  • Log Output & Organization

    • Logs are written to a PWLogs directory in the application working directory
    • Each logger writes to a dedicated file named after its class
    • Logs are appended by default (configurable)
  • Key Capabilities

    • Method entry/exit logging with parameter tracking
    • Automatic caller method detection
    • REST request logging (request path and client IP) for critical endpoints
    • Log file rotation using sequence-based file handlers
  • Format

    • Human-readable output via Java SimpleFormatter
    • Includes timestamp, log level, and source class/method

To enable debug logging:

export PWLOG_LEVEL="DEBUG"

🛠️ Tech Stack

Core Technologies

  • Java (JDK 21)
  • Jakarta EE 10 (platform API, provided by the application server)
  • Hibernate ORM 7
  • MariaDB 10.6+
  • JWT (JJWT)

Key Dependencies

  • MariaDB JDBC Driver
  • Apache Commons Lang 3
  • JSpecify
  • Jersey Client
  • Jakarta JSON Processing (JSON-P)

Development & Testing

  • Maven
  • JUnit (unit and integration testing)
  • Arquillian (container-based integration testing)
  • ShrinkWrap Resolver (test deployment assembly)
  • SpotBugs (static analysis)
  • fmt-maven-plugin (code formatting)
  • Maven WAR Plugin

📋 Prerequisites

Development

  • JDK 21
  • Maven 3.8+
  • MariaDB 10.6+ or MySQL 8.0+
  • Docker (optional)

Application Servers

  • Primary: OpenLiberty 23.0.0.3+
  • Other Jakarta EE 10 compatible servers: WildFly 27+, GlassFish 7.x, supported Payara releases

Note: Some server-specific configuration may be required for non-OpenLiberty deployments.

Getting Started

  1. Clone the repository

    git clone https://github.com/Urbine/PostWizardREST.git
    cd PostWizardREST
  2. Configure database access in:

    • src/main/liberty/config/server.xml
    • src/main/resources/META-INF/persistence.xml
  3. Build the project

    mvn -DskipTests package

    Note: The -DskipTests option is used to skip the tests during the build process. At that time in the project's lifecycle, the test suite was executed manually before every commit, so that the pipeline could take care of the remote deployment. Improving that used to be a milestone in the roadmap

  4. Deploy the generated WAR to a Jakarta EE 10–compatible application server.

API Documentation

API Overview (OpenAPI-Style)

Authentication

MethodEndpointDescriptionAuth
GET/v1/auth/loginAuthenticate user and issue JWT tokenBasic

Posts

MethodEndpointDescriptionAuth
GET/v1/posts/{postId}Retrieve a single postJWT
GET/v1/posts/meta/{postId}Retrieve metadata for a postJWT
GET/v1/posts/meta/dumpRetrieve metadata for all postsJWT
GET/v1/posts/dump?type={postType}Retrieve posts by typeJWT
POST/v1/posts/{postId}Update post contentJWT
POST/v1/posts/batchBatch update multiple postsJWT
POST/v1/posts/meta/{postId}Update post metadataJWT
POST/v1/posts/meta/batchBatch update post metadataJWT
GET/v1/posts/randomfeatured?limit={int}Randomize featured posts (e.g. videos)JWT

Taxonomies

MethodEndpointDescriptionAuth
POST/v1/taxonomies/checkLink or unlink taxonomy terms to a postJWT
POST/v1/taxonomies/addCreate taxonomy termsJWT
DELETE/v1/taxonomies/removeRemove taxonomy termsJWT

Conventions

  • Auth:

    • Basic → used only for token issuance
    • JWT → required for all protected endpoints
  • Content-Type: application/json

  • Responses: Consistent JSON structure with structured error payloads

  • Batch endpoints: Accept arrays of objects


API in Depth

🔐 Authentication

JWT-based authentication with Basic Auth used only to obtain the initial token.

Login (Get JWT)
GET /v1/auth/loginAuthorization: Basic base64(username:password)Content-Type: application/json
# Local cURL example:
curl -X GET "http://localhost:9080/PostWizardREST/v1/auth/login" \
-H "Authorization: Basic $(echo -n 'username:password'| base64)" \
-H "Content-Type: application/json"

Response

{
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"type": "bearer",
"expiration": "2025-10-06T16:33:01+07:00"
}

Usage

Authorization: Bearer <jwt>

Tokens are valid for 1 hour and must be refreshed after expiration.


📝 Posts

Read
  • GET /v1/posts/{postId} — Get post
  • GET /v1/posts/meta/{postId} — Get post metadata
  • GET /v1/posts/meta/dump — Get all post metadata
  • GET /v1/posts/dump?type={postType} — Get posts by type (post, attachment, all)

Update
POST /v1/posts/{postId}Content-Type: application/json
{
"title": "Updated Post Title",
"content": "Updated post content..."
}

Metadata Update
POST /v1/posts/meta/{postId}?autothumb={bool}&retries={int}&timeout={sec}Content-Type: application/json
{
"thumbURL": "http://example.com/thumb.jpg",
"yoastFocusKw": "java",
"yoastMetaDesc": "Yoast-compatible meta description"
}

Batch Operations
  • POST /v1/posts/batch — Batch post updates
  • POST /v1/posts/meta/batch — Batch metadata updates
[
{ "postID": 1, "title": "First Post" },
{ "postID": 2, "status": "publish" }
]

Featured Content
GET /v1/posts/randomfeatured?limit={int}

Randomizes featured posts (e.g. videos).


🏷️ Taxonomies

Link / Unlink Terms
POST /v1/taxonomies/check?id={postId}&link={bool}&unlink={bool}Content-Type: application/json
{
"name": "Technology",
"slug": "tech",
"taxonomy": {
"taxonomy_name": "category",
"taxonomy_description": "This is a new category."
}
}

Add Terms
POST /v1/taxonomies/add?clean={bool}Content-Type: application/json
{
"name": "Java 21",
"slug": "java-21",
"taxonomy": { "taxonomy_name": "post_tag" }
}

Remove Terms
DELETE /v1/taxonomies/removeContent-Type: application/json
{
"name": "Obsolete Term",
"taxonomy": { "taxonomy_name": "category" }
}

Project Structure

src/main/java/net/ygbstudio/postwizard/
├── auth/ # Authentication & authorization
├── dao/ # Data access layer
├── dto/ # Data transfer objects
├── entities/ # JPA entities
├── exceptions/ # Custom exceptions
├── filters/ # HTTP filters
├── mappers/ # Exception mappers
├── models/ # Domain models
├── rest/ # REST endpoints
├── services/ # Business logic
├── tasks/ # Scheduled tasks
└── utils/ # Utilities

Code Formatting

Uses fmt-maven-plugin, based on the Google Java Style Guide.

mvn fmt:format

📄 License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).

⚠️ Disclaimer

This project is provided as-is, without warranty of any kind, express or implied.

The author assumes no responsibility for security issues, data loss, or misuse. Users are solely responsible for compliance with applicable laws, platform terms of service, and content regulations when using or adapting this code.

About

A high-performance RESTful backend service for WordPress-based publishing systems, providing centralized content persistence, validation, and automation-oriented workflows.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

256 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🧙‍♂️ PostWizardREST

JavaCode StyleLicense: MPL 2.0Status: Archived

A high-performance, secure RESTful API for WordPress content management, built with modern Java Enterprise architectural patterns.

PostWizardREST provides a robust complement to the default WordPress REST API, offering performance improvements in specific automation-heavy and enterprise deployment scenarios, enhanced security features, and advanced content management capabilities.

⚠️ Project Status

Archived / Discontinued

PostWizardREST is no longer actively maintained, and the associated service is no longer available.

This repository is preserved for reference and educational purposes only.
No support, updates, security patches, or guarantees are provided.


Historical note

All documentation below reflects the system’s design, features, and API as they existed during active development. It is preserved for architectural reference and educational purposes.


Why was PostWizardREST created?

PostWizardREST was designed as an integration hub and server-side extension for projects such as PostWizardX3, handling taxonomy creation, post management, and media-related workflows outside of WordPress’ runtime.

While the WordPress REST API is suitable for many use cases, it is intentionally constrained by WordPress’ execution model, plugin ecosystem, and PHP-based request lifecycle. PostWizardREST explored an alternative approach: offloading critical content management workflows to a dedicated Java-based service, while remaining fully compatible with the WordPress database and ecosystem.

This design was motivated by the need for greater control over execution, security boundaries, and data modeling, particularly in high-volume or automation-heavy scenarios.

By decoupling these responsibilities from WordPress, the project aimed to leverage established Enterprise Java capabilities, resulting in:

  • Direct database access, avoiding repeated WordPress bootstrap and plugin execution overhead
  • Scheduled and batch jobs with proper locking, retries, and concurrency control
  • Application-server–managed threading and resource pools, instead of request-bound execution
  • A REST API decoupled from WordPress’ PHP execution model, enabling reliable integration with external automation systems
  • Documentation-driven API design with explicit contracts
  • Structured metadata handling with cascading and relational consistency
  • Type-safe APIs to reduce common runtime and data-shape errors
  • Explicit control over database connections, transactions, and isolation levels
  • Extensibility by default, without reliance on WordPress hooks or filters
  • Reduced attack surface, by minimizing public exposure of WordPress endpoints commonly targeted by automated attacks against WordPress installations
  • Observability and audit logging, enabling detection of abnormal behavior and performance bottlenecks
  • Developer-friendly modeling of taxonomies and custom fields for Java-based teams
  • A WordPress domain abstraction, designed with future integration into Jakarta EE or Spring ecosystems in mind, including message-driven and batch-oriented enterprise workflows
  • Compatibility with existing WordPress plugins, including Yoast SEO and CompressX
  • JWT-based authentication, role-based access control, and request validation
  • Consistent response formats and structured error handling
  • Integration testing, CI/CD readiness, and container-friendly deployment

In short, PostWizardREST was not intended to replace WordPress, but to isolate automation-heavy, security-sensitive, or high-throughput operations into a system better suited for those concerns, while still using WordPress as the content source of truth.

✨ Features

Core Features

  • Full CRUD operations for WordPress posts
  • Advanced taxonomy management (categories, tags, custom taxonomies)
  • Extensible metadata system
  • Batch processing using Jakarta Concurrency
  • Scheduled and automated content tasks

Security Features

  • JWT-based authentication
  • Secure HS256 key generation using SecureRandom
  • Role-based access control (RBAC)
  • Request validation and sanitization
  • Audit logging
  • Probe and automated scan detection

Operational

  • Jenkins - CI/CD pipeline integration

Logging

The application implements a structured, file-based logging system designed for observability, auditing, and troubleshooting in automation-heavy environments.

  • Log Levels
    Controlled via the PWLOG_LEVEL environment variable:

    • DEBUG → full trace logging (Level.ALL)
    • Any other value → defaults to INFO
  • Log Output & Organization

    • Logs are written to a PWLogs directory in the application working directory
    • Each logger writes to a dedicated file named after its class
    • Logs are appended by default (configurable)
  • Key Capabilities

    • Method entry/exit logging with parameter tracking
    • Automatic caller method detection
    • REST request logging (request path and client IP) for critical endpoints
    • Log file rotation using sequence-based file handlers
  • Format

    • Human-readable output via Java SimpleFormatter
    • Includes timestamp, log level, and source class/method

To enable debug logging:

export PWLOG_LEVEL="DEBUG"

🛠️ Tech Stack

Core Technologies

  • Java (JDK 21)
  • Jakarta EE 10 (platform API, provided by the application server)
  • Hibernate ORM 7
  • MariaDB 10.6+
  • JWT (JJWT)

Key Dependencies

  • MariaDB JDBC Driver
  • Apache Commons Lang 3
  • JSpecify
  • Jersey Client
  • Jakarta JSON Processing (JSON-P)

Development & Testing

  • Maven
  • JUnit (unit and integration testing)
  • Arquillian (container-based integration testing)
  • ShrinkWrap Resolver (test deployment assembly)
  • SpotBugs (static analysis)
  • fmt-maven-plugin (code formatting)
  • Maven WAR Plugin

📋 Prerequisites

Development

  • JDK 21
  • Maven 3.8+
  • MariaDB 10.6+ or MySQL 8.0+
  • Docker (optional)

Application Servers

  • Primary: OpenLiberty 23.0.0.3+
  • Other Jakarta EE 10 compatible servers: WildFly 27+, GlassFish 7.x, supported Payara releases

Note: Some server-specific configuration may be required for non-OpenLiberty deployments.

Getting Started

  1. Clone the repository

    git clone https://github.com/Urbine/PostWizardREST.git
    cd PostWizardREST
  2. Configure database access in:

    • src/main/liberty/config/server.xml
    • src/main/resources/META-INF/persistence.xml
  3. Build the project

    mvn -DskipTests package

    Note: The -DskipTests option is used to skip the tests during the build process. At that time in the project's lifecycle, the test suite was executed manually before every commit, so that the pipeline could take care of the remote deployment. Improving that used to be a milestone in the roadmap

  4. Deploy the generated WAR to a Jakarta EE 10–compatible application server.

API Documentation

API Overview (OpenAPI-Style)

Authentication

MethodEndpointDescriptionAuth
GET/v1/auth/loginAuthenticate user and issue JWT tokenBasic

Posts

MethodEndpointDescriptionAuth
GET/v1/posts/{postId}Retrieve a single postJWT
GET/v1/posts/meta/{postId}Retrieve metadata for a postJWT
GET/v1/posts/meta/dumpRetrieve metadata for all postsJWT
GET/v1/posts/dump?type={postType}Retrieve posts by typeJWT
POST/v1/posts/{postId}Update post contentJWT
POST/v1/posts/batchBatch update multiple postsJWT
POST/v1/posts/meta/{postId}Update post metadataJWT
POST/v1/posts/meta/batchBatch update post metadataJWT
GET/v1/posts/randomfeatured?limit={int}Randomize featured posts (e.g. videos)JWT

Taxonomies

MethodEndpointDescriptionAuth
POST/v1/taxonomies/checkLink or unlink taxonomy terms to a postJWT
POST/v1/taxonomies/addCreate taxonomy termsJWT
DELETE/v1/taxonomies/removeRemove taxonomy termsJWT

Conventions

  • Auth:

    • Basic → used only for token issuance
    • JWT → required for all protected endpoints
  • Content-Type: application/json

  • Responses: Consistent JSON structure with structured error payloads

  • Batch endpoints: Accept arrays of objects


API in Depth

🔐 Authentication

JWT-based authentication with Basic Auth used only to obtain the initial token.

Login (Get JWT)
GET /v1/auth/loginAuthorization: Basic base64(username:password)Content-Type: application/json
# Local cURL example:
curl -X GET "http://localhost:9080/PostWizardREST/v1/auth/login" \
-H "Authorization: Basic $(echo -n 'username:password'| base64)" \
-H "Content-Type: application/json"

Response

{
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"type": "bearer",
"expiration": "2025-10-06T16:33:01+07:00"
}

Usage

Authorization: Bearer <jwt>

Tokens are valid for 1 hour and must be refreshed after expiration.


📝 Posts

Read
  • GET /v1/posts/{postId} — Get post
  • GET /v1/posts/meta/{postId} — Get post metadata
  • GET /v1/posts/meta/dump — Get all post metadata
  • GET /v1/posts/dump?type={postType} — Get posts by type (post, attachment, all)

Update
POST /v1/posts/{postId}Content-Type: application/json
{
"title": "Updated Post Title",
"content": "Updated post content..."
}

Metadata Update
POST /v1/posts/meta/{postId}?autothumb={bool}&retries={int}&timeout={sec}Content-Type: application/json
{
"thumbURL": "http://example.com/thumb.jpg",
"yoastFocusKw": "java",
"yoastMetaDesc": "Yoast-compatible meta description"
}

Batch Operations
  • POST /v1/posts/batch — Batch post updates
  • POST /v1/posts/meta/batch — Batch metadata updates
[
{ "postID": 1, "title": "First Post" },
{ "postID": 2, "status": "publish" }
]

Featured Content
GET /v1/posts/randomfeatured?limit={int}

Randomizes featured posts (e.g. videos).


🏷️ Taxonomies

Link / Unlink Terms
POST /v1/taxonomies/check?id={postId}&link={bool}&unlink={bool}Content-Type: application/json
{
"name": "Technology",
"slug": "tech",
"taxonomy": {
"taxonomy_name": "category",
"taxonomy_description": "This is a new category."
}
}

Add Terms
POST /v1/taxonomies/add?clean={bool}Content-Type: application/json
{
"name": "Java 21",
"slug": "java-21",
"taxonomy": { "taxonomy_name": "post_tag" }
}

Remove Terms
DELETE /v1/taxonomies/removeContent-Type: application/json
{
"name": "Obsolete Term",
"taxonomy": { "taxonomy_name": "category" }
}

Project Structure

src/main/java/net/ygbstudio/postwizard/
├── auth/ # Authentication & authorization
├── dao/ # Data access layer
├── dto/ # Data transfer objects
├── entities/ # JPA entities
├── exceptions/ # Custom exceptions
├── filters/ # HTTP filters
├── mappers/ # Exception mappers
├── models/ # Domain models
├── rest/ # REST endpoints
├── services/ # Business logic
├── tasks/ # Scheduled tasks
└── utils/ # Utilities

Code Formatting

Uses fmt-maven-plugin, based on the Google Java Style Guide.

mvn fmt:format

📄 License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).

⚠️ Disclaimer

This project is provided as-is, without warranty of any kind, express or implied.

The author assumes no responsibility for security issues, data loss, or misuse. Users are solely responsible for compliance with applicable laws, platform terms of service, and content regulations when using or adapting this code.

About

A high-performance RESTful backend service for WordPress-based publishing systems, providing centralized content persistence, validation, and automation-oriented workflows.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

256 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🧙‍♂️ PostWizardREST

JavaCode StyleLicense: MPL 2.0Status: Archived

A high-performance, secure RESTful API for WordPress content management, built with modern Java Enterprise architectural patterns.

PostWizardREST provides a robust complement to the default WordPress REST API, offering performance improvements in specific automation-heavy and enterprise deployment scenarios, enhanced security features, and advanced content management capabilities.

⚠️ Project Status

Archived / Discontinued

PostWizardREST is no longer actively maintained, and the associated service is no longer available.

This repository is preserved for reference and educational purposes only.
No support, updates, security patches, or guarantees are provided.


Historical note

All documentation below reflects the system’s design, features, and API as they existed during active development. It is preserved for architectural reference and educational purposes.


Why was PostWizardREST created?

PostWizardREST was designed as an integration hub and server-side extension for projects such as PostWizardX3, handling taxonomy creation, post management, and media-related workflows outside of WordPress’ runtime.

While the WordPress REST API is suitable for many use cases, it is intentionally constrained by WordPress’ execution model, plugin ecosystem, and PHP-based request lifecycle. PostWizardREST explored an alternative approach: offloading critical content management workflows to a dedicated Java-based service, while remaining fully compatible with the WordPress database and ecosystem.

This design was motivated by the need for greater control over execution, security boundaries, and data modeling, particularly in high-volume or automation-heavy scenarios.

By decoupling these responsibilities from WordPress, the project aimed to leverage established Enterprise Java capabilities, resulting in:

  • Direct database access, avoiding repeated WordPress bootstrap and plugin execution overhead
  • Scheduled and batch jobs with proper locking, retries, and concurrency control
  • Application-server–managed threading and resource pools, instead of request-bound execution
  • A REST API decoupled from WordPress’ PHP execution model, enabling reliable integration with external automation systems
  • Documentation-driven API design with explicit contracts
  • Structured metadata handling with cascading and relational consistency
  • Type-safe APIs to reduce common runtime and data-shape errors
  • Explicit control over database connections, transactions, and isolation levels
  • Extensibility by default, without reliance on WordPress hooks or filters
  • Reduced attack surface, by minimizing public exposure of WordPress endpoints commonly targeted by automated attacks against WordPress installations
  • Observability and audit logging, enabling detection of abnormal behavior and performance bottlenecks
  • Developer-friendly modeling of taxonomies and custom fields for Java-based teams
  • A WordPress domain abstraction, designed with future integration into Jakarta EE or Spring ecosystems in mind, including message-driven and batch-oriented enterprise workflows
  • Compatibility with existing WordPress plugins, including Yoast SEO and CompressX
  • JWT-based authentication, role-based access control, and request validation
  • Consistent response formats and structured error handling
  • Integration testing, CI/CD readiness, and container-friendly deployment

In short, PostWizardREST was not intended to replace WordPress, but to isolate automation-heavy, security-sensitive, or high-throughput operations into a system better suited for those concerns, while still using WordPress as the content source of truth.

✨ Features

Core Features

  • Full CRUD operations for WordPress posts
  • Advanced taxonomy management (categories, tags, custom taxonomies)
  • Extensible metadata system
  • Batch processing using Jakarta Concurrency
  • Scheduled and automated content tasks

Security Features

  • JWT-based authentication
  • Secure HS256 key generation using SecureRandom
  • Role-based access control (RBAC)
  • Request validation and sanitization
  • Audit logging
  • Probe and automated scan detection

Operational

  • Jenkins - CI/CD pipeline integration

Logging

The application implements a structured, file-based logging system designed for observability, auditing, and troubleshooting in automation-heavy environments.

  • Log Levels
    Controlled via the PWLOG_LEVEL environment variable:

    • DEBUG → full trace logging (Level.ALL)
    • Any other value → defaults to INFO
  • Log Output & Organization

    • Logs are written to a PWLogs directory in the application working directory
    • Each logger writes to a dedicated file named after its class
    • Logs are appended by default (configurable)
  • Key Capabilities

    • Method entry/exit logging with parameter tracking
    • Automatic caller method detection
    • REST request logging (request path and client IP) for critical endpoints
    • Log file rotation using sequence-based file handlers
  • Format

    • Human-readable output via Java SimpleFormatter
    • Includes timestamp, log level, and source class/method

To enable debug logging:

export PWLOG_LEVEL="DEBUG"

🛠️ Tech Stack

Core Technologies

  • Java (JDK 21)
  • Jakarta EE 10 (platform API, provided by the application server)
  • Hibernate ORM 7
  • MariaDB 10.6+
  • JWT (JJWT)

Key Dependencies

  • MariaDB JDBC Driver
  • Apache Commons Lang 3
  • JSpecify
  • Jersey Client
  • Jakarta JSON Processing (JSON-P)

Development & Testing

  • Maven
  • JUnit (unit and integration testing)
  • Arquillian (container-based integration testing)
  • ShrinkWrap Resolver (test deployment assembly)
  • SpotBugs (static analysis)
  • fmt-maven-plugin (code formatting)
  • Maven WAR Plugin

📋 Prerequisites

Development

  • JDK 21
  • Maven 3.8+
  • MariaDB 10.6+ or MySQL 8.0+
  • Docker (optional)

Application Servers

  • Primary: OpenLiberty 23.0.0.3+
  • Other Jakarta EE 10 compatible servers: WildFly 27+, GlassFish 7.x, supported Payara releases

Note: Some server-specific configuration may be required for non-OpenLiberty deployments.

Getting Started

  1. Clone the repository

    git clone https://github.com/Urbine/PostWizardREST.git
    cd PostWizardREST
  2. Configure database access in:

    • src/main/liberty/config/server.xml
    • src/main/resources/META-INF/persistence.xml
  3. Build the project

    mvn -DskipTests package

    Note: The -DskipTests option is used to skip the tests during the build process. At that time in the project's lifecycle, the test suite was executed manually before every commit, so that the pipeline could take care of the remote deployment. Improving that used to be a milestone in the roadmap

  4. Deploy the generated WAR to a Jakarta EE 10–compatible application server.

API Documentation

API Overview (OpenAPI-Style)

Authentication

MethodEndpointDescriptionAuth
GET/v1/auth/loginAuthenticate user and issue JWT tokenBasic

Posts

MethodEndpointDescriptionAuth
GET/v1/posts/{postId}Retrieve a single postJWT
GET/v1/posts/meta/{postId}Retrieve metadata for a postJWT
GET/v1/posts/meta/dumpRetrieve metadata for all postsJWT
GET/v1/posts/dump?type={postType}Retrieve posts by typeJWT
POST/v1/posts/{postId}Update post contentJWT
POST/v1/posts/batchBatch update multiple postsJWT
POST/v1/posts/meta/{postId}Update post metadataJWT
POST/v1/posts/meta/batchBatch update post metadataJWT
GET/v1/posts/randomfeatured?limit={int}Randomize featured posts (e.g. videos)JWT

Taxonomies

MethodEndpointDescriptionAuth
POST/v1/taxonomies/checkLink or unlink taxonomy terms to a postJWT
POST/v1/taxonomies/addCreate taxonomy termsJWT
DELETE/v1/taxonomies/removeRemove taxonomy termsJWT

Conventions

  • Auth:

    • Basic → used only for token issuance
    • JWT → required for all protected endpoints
  • Content-Type: application/json

  • Responses: Consistent JSON structure with structured error payloads

  • Batch endpoints: Accept arrays of objects


API in Depth

🔐 Authentication

JWT-based authentication with Basic Auth used only to obtain the initial token.

Login (Get JWT)
GET /v1/auth/loginAuthorization: Basic base64(username:password)Content-Type: application/json
# Local cURL example:
curl -X GET "http://localhost:9080/PostWizardREST/v1/auth/login" \
-H "Authorization: Basic $(echo -n 'username:password'| base64)" \
-H "Content-Type: application/json"

Response

{
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"type": "bearer",
"expiration": "2025-10-06T16:33:01+07:00"
}

Usage

Authorization: Bearer <jwt>

Tokens are valid for 1 hour and must be refreshed after expiration.


📝 Posts

Read
  • GET /v1/posts/{postId} — Get post
  • GET /v1/posts/meta/{postId} — Get post metadata
  • GET /v1/posts/meta/dump — Get all post metadata
  • GET /v1/posts/dump?type={postType} — Get posts by type (post, attachment, all)

Update
POST /v1/posts/{postId}Content-Type: application/json
{
"title": "Updated Post Title",
"content": "Updated post content..."
}

Metadata Update
POST /v1/posts/meta/{postId}?autothumb={bool}&retries={int}&timeout={sec}Content-Type: application/json
{
"thumbURL": "http://example.com/thumb.jpg",
"yoastFocusKw": "java",
"yoastMetaDesc": "Yoast-compatible meta description"
}

Batch Operations
  • POST /v1/posts/batch — Batch post updates
  • POST /v1/posts/meta/batch — Batch metadata updates
[
{ "postID": 1, "title": "First Post" },
{ "postID": 2, "status": "publish" }
]

Featured Content
GET /v1/posts/randomfeatured?limit={int}

Randomizes featured posts (e.g. videos).


🏷️ Taxonomies

Link / Unlink Terms
POST /v1/taxonomies/check?id={postId}&link={bool}&unlink={bool}Content-Type: application/json
{
"name": "Technology",
"slug": "tech",
"taxonomy": {
"taxonomy_name": "category",
"taxonomy_description": "This is a new category."
}
}

Add Terms
POST /v1/taxonomies/add?clean={bool}Content-Type: application/json
{
"name": "Java 21",
"slug": "java-21",
"taxonomy": { "taxonomy_name": "post_tag" }
}

Remove Terms
DELETE /v1/taxonomies/removeContent-Type: application/json
{
"name": "Obsolete Term",
"taxonomy": { "taxonomy_name": "category" }
}

Project Structure

src/main/java/net/ygbstudio/postwizard/
├── auth/ # Authentication & authorization
├── dao/ # Data access layer
├── dto/ # Data transfer objects
├── entities/ # JPA entities
├── exceptions/ # Custom exceptions
├── filters/ # HTTP filters
├── mappers/ # Exception mappers
├── models/ # Domain models
├── rest/ # REST endpoints
├── services/ # Business logic
├── tasks/ # Scheduled tasks
└── utils/ # Utilities

Code Formatting

Uses fmt-maven-plugin, based on the Google Java Style Guide.

mvn fmt:format

📄 License

This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).

⚠️ Disclaimer

This project is provided as-is, without warranty of any kind, express or implied.

The author assumes no responsibility for security issues, data loss, or misuse. Users are solely responsible for compliance with applicable laws, platform terms of service, and content regulations when using or adapting this code.

About

A high-performance RESTful backend service for WordPress-based publishing systems, providing centralized content persistence, validation, and automation-oriented workflows.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages