Skip to content

jooservices/wordpress-sdk

Repository files navigation

JOOservices WordPress SDK

CI PHP Version License: MIT Packagist Version

DTO-first PHP 8.5 SDK for the WordPress REST API, built for typed content automation, pagination, media, settings, users, taxonomies, discovery, and custom/plugin endpoints.

Package name: jooservices/wordpress-sdk

Install

composer require jooservices/wordpress-sdk

Quick start

use JOOservices\WordPress\Sdk\Data\Query\ListPostsQuery;
use JOOservices\WordPress\Sdk\WordPressService;

$wordpress = WordPressService::create(
    baseUrl: getenv('WORDPRESS_URL'),
    username: getenv('WORDPRESS_USER'),
    password: getenv('WORDPRESS_APP_PASSWORD'),
);

$posts = $wordpress->posts()->list(new ListPostsQuery(
    perPage: 10,
    search: 'automation',
    fields: 'id,title,link,date',
    embed: true,
));

foreach ($posts as $post) {
    echo $post->title->rendered . PHP_EOL;
}

Supported endpoints

Endpoint Service Status
Posts posts() CRUD
Pages pages() CRUD
Media media() list/get/upload/delete
Users users() CRUD + me()
Comments comments() CRUD
Categories categories() CRUD
Tags tags() CRUD
Search search() list/search
Taxonomies taxonomies() list/get
Post types postTypes() list/get
Statuses statuses() list/get
Application Passwords applicationPasswords() list/get/create/delete/deleteAll
Settings settings() get/update
Discovery / schema discovery() index/routes/schema
Custom endpoints custom() GET/POST/PUT/PATCH/DELETE raw arrays
Revisions revisions() posts/pages/block autosaves
Plugins plugins() raw admin operations
Themes themes() raw admin reads
Blocks / block types / renderer / directory blocks(), blockTypes(), blockRenderer(), blockDirectory() raw editor operations
Menus / navigation menuLocations(), navigations(), navMenus(), navMenuItems() raw navigation operations
Templates / template parts / global styles templates(), templateParts(), globalStyles() raw block theme operations
Widgets / sidebars widgets(), widgetTypes(), sidebars() raw widget operations
Site Health siteHealth() raw diagnostic test reads

SDK helper extras

The SDK also ships with optional developer-experience helpers under JOOservices\WordPress\Sdk\Support.

  • PostBuilder helps assemble post payloads fluently before calling posts()->create() or update().
  • ContentBuilder helps generate Gutenberg-compatible block markup in PHP.
  • PostTemplate, concrete templates, and createFromTemplate() are template helpers built on top of normal post creation.

These helpers are not native WordPress REST API resources. They are kept as SDK extras because they reduce repetitive WordPress payload-building while staying generic to SDK users.

The Docker integration suite verifies these helpers against a real local WordPress REST API. composer test:wordpress starts Docker services, installs WordPress with WP-CLI, creates test auth, uploads local media fixtures, and runs the main integration tests. Optional WordPress capabilities that need extra plugins, block registration, or block-theme state live in the independent composer test:wordpress:extended suite. No manual WordPress setup is required; use composer test:wordpress:reset to wipe the disposable database and uploads volume.

DTO-first querying

The SDK accepts either raw query arrays or typed query DTOs for list and read operations.

use JOOservices\WordPress\Sdk\Data\Query\ListCommentsQuery;

$comments = $wordpress->comments()->list(new ListCommentsQuery(
    post: 42,
    status: 'approve',
    perPage: 25,
    fields: 'id,content,date',
));

Pagination

WordPress pagination headers are exposed through PaginatedCollection. List-style services provide auto-pagination helpers where WordPress returns paginated collections.

$media = $wordpress->media()->list(['per_page' => 20, 'page' => 2]);

printf(
    "Loaded %d items out of %d across %d pages\n",
    count($media),
    $media->total,
    $media->totalPages,
);
foreach ($wordpress->posts()->cursor(['per_page' => 50]) as $post) {
    // Streams one page at a time.
}

$wordpress->posts()->each(function ($post): bool {
    return $post->id !== 123; // return false to stop early
}, ['status' => 'publish']);

Use all() only when loading every matching post into memory is acceptable.

Site settings and custom routes

$settings = $wordpress->settings()->get();
$wordpress->settings()->update(['title' => 'New title']);

$routes = $wordpress->discovery()->routes();
$schema = $wordpress->discovery()->schema('/wp/v2/posts');

$items = $wordpress->custom()->get('/my-plugin/v1/items', ['page' => 1]);
$created = $wordpress->custom()->post('/my-plugin/v1/items', ['name' => 'Example']);

Custom endpoint paths are relative to the configured WordPress REST API root. Full external URLs are rejected.

Application passwords

$password = $wordpress->applicationPasswords()->create('me', [
    'name' => 'Publishing Worker',
]);

WordPress returns the raw generated application password only in the create response. Store it immediately in a secret manager and never log it.

Admin and editor endpoint groups

Broad WordPress admin/editor endpoint groups are exposed as raw arrays until their response schemas prove stable enough for public DTO contracts.

$plugins = $wordpress->plugins()->list();
$themes = $wordpress->themes()->list();
$revisions = $wordpress->revisions()->posts(123)->list();
$rendered = $wordpress->blockRenderer()->render('core/latest-posts', ['postsToShow' => 3]);
$templates = $wordpress->templates()->list();
$health = $wordpress->siteHealth()->backgroundUpdates();

Most of these endpoints require authenticated users with admin/editor capabilities. Block renderer requests are sent with WordPress editor context because the REST renderer endpoint validates dynamic blocks against editor-only route context.

Error handling

use JOOservices\WordPress\Sdk\Exceptions\UnauthorizedException;
use JOOservices\WordPress\Sdk\Exceptions\WordPressApiException;

try {
    $wordpress->posts()->get(123, ['context' => 'edit']);
} catch (UnauthorizedException $exception) {
    // Refresh credentials or verify the app password.
} catch (WordPressApiException $exception) {
    $payload = $exception->toArray(); // sanitized diagnostic payload
}

Documentation

Start with:

Development

composer lint
composer lint:all
composer test
composer test:integration
composer test:wordpress
composer test:wordpress:extended
composer test:wordpress:reset
composer test:integration:docker
composer test:coverage
composer test:coverage:gate
composer test:coverage-map
composer quality
composer check
composer ci

Run composer test:wordpress for the one-command Docker/WP-CLI WordPress integration flow. Run composer test:wordpress:extended after it, or by itself, for optional capabilities such as deterministic plugin reads, dynamic block rendering, global styles, navigation/template routes, site health reads, and the chaptered story template workflow with uploaded media. See Testing for details, safety guards, reset commands, and route skip policy.

composer test:coverage now includes a Clover XML audit gate. Aggregate statement coverage must stay at or above 90%, and no coverable production file, class, or method in src/ may remain at 0% coverage unless it has a documented exclusion reason in tools/test-coverage-gate.php.

Security

Use WordPress application passwords through environment variables. Do not commit live credentials, and do not log authorization headers or raw secrets. See SECURITY.md.

About

DTO-first PHP 8.5 SDK for the WordPress REST API, built for typed content automation, pagination, media, users, taxonomies, and custom endpoints.

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages