WP Manifestindependent plugin directory
manifest / developer / wordpress-plugin-architecture-example

Showcase Project Events

by Victoria Bondar · github.com/violika7-cell/wordpress-plugin-architecture-example

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/violika7-cell/wordpress-plugin-architecture-example/archive/refs/heads/main.zip

Readme

WordPress Plugin Architecture Example

A compact WordPress plugin showcasing clean boundaries, a custom database table, an application service, idempotent writes, REST endpoints, capability checks, and unit-testable domain logic.

Showcase note: all code and data in this repository are synthetic. No client implementation or proprietary logic is included.

Problem

A WordPress application needs to record project status events from multiple sources. A naive plugin might write directly to $wpdb from REST callbacks and duplicate events when a request is retried.

This example demonstrates a safer design:

  • controllers handle HTTP concerns;
  • services enforce business rules;
  • repositories own persistence;
  • domain objects validate state;
  • idempotency keys prevent duplicate writes;
  • schema creation is isolated in an installer.

Architecture

REST Controller
      |
      v
ProjectEventService
      |
      v
ProjectEventRepositoryInterface
      |
      v
WpdbProjectEventRepository
      |
      v
custom wp_showcase_project_events table

What this repository demonstrates

  • WordPress plugin bootstrap without theme coupling
  • dependency injection
  • custom table migration with dbDelta()
  • $wpdb->prepare() usage
  • idempotent application service
  • explicit domain validation
  • REST schema validation
  • capability-based authorization
  • safe error responses
  • unit tests without a WordPress runtime
  • CI with multiple PHP versions

Installation

Requirements:

  • PHP 8.1+
  • WordPress 6.x+
  • Composer for tests/autoloading
composer install

Place the plugin directory in wp-content/plugins/ and activate Showcase Project Events.

Activation creates a small custom table using the WordPress database prefix.

REST API

Create an event

POST /wp-json/showcase-events/v1/projects/123/events
Content-Type: application/json
X-WP-Nonce: <nonce>

{
  "type": "deployed",
  "message": "Release 1.4 deployed to staging",
  "idempotency_key": "deploy-123-release-1.4"
}

Allowed event types in this demo:

  • created
  • updated
  • deployed
  • failed

Repeated requests with the same idempotency key return the existing event instead of inserting a duplicate.

List project events

GET /wp-json/showcase-events/v1/projects/123/events

Decisions

Custom table instead of posts

Event data is append-oriented and operational. A dedicated table avoids forcing log-like records into the posts/meta model and makes indexing explicit.

Idempotency at the application boundary

Retries are common in webhooks, jobs, and unreliable networks. The service requires a caller-supplied idempotency key and the table enforces uniqueness.

Repository interface

Business logic does not know about $wpdb. That keeps the service independently testable and makes persistence replaceable.

Domain validation

ProjectEvent validates project IDs, event types, message length, and idempotency keys before persistence.

Error handling

  • Validation failures return HTTP 400.
  • Unauthorized requests are blocked by permission_callback.
  • Duplicate idempotency keys resolve to the existing record.
  • Database write failures become controlled application exceptions.
  • Internal SQL details are never returned to the browser.

Security considerations

  • REST endpoints require manage_options in this showcase.
  • All route parameters and JSON fields are validated.
  • SQL values use $wpdb->prepare() or safe insert helpers.
  • Output uses structured REST responses rather than raw HTML.
  • No secrets or credentials are stored by this plugin.
  • Table names use the WordPress prefix and are never accepted from user input.
  • Error logs should not include sensitive payloads in a real application.

Testing

composer test

Unit tests cover:

  • event validation;
  • new event recording;
  • retry/idempotency behavior;
  • repository failure propagation.

Production extensions

For a real product I would consider:

  • dedicated capabilities rather than manage_options;
  • pagination/cursor support;
  • retention/archival policy;
  • structured logs and correlation IDs;
  • audit actor/source fields;
  • migration versioning;
  • integration tests against WordPress;
  • observability metrics;
  • background queue processing where event volume is high.

License

MIT

Read the full README on GitHub →