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

Showcase Project Events

★ 0stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/violika7-cell/wordpress-plugin-architecture-example/archive/refs/heads/main.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

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