QuickWP is a modern, class-based PHP toolkit for managing WordPress sites via the REST API. It provides both a clean programmatic API and ready-to-use web tools for common WordPress operations.
composer require bitshost/quickwp- PHP 7.4+
- WordPress site with REST API enabled
- WordPress Application Password for authentication
- Clean OOP Architecture β PSR-4 autoloaded classes with dependency injection
- Fluent API β Intuitive, chainable interface for all operations
- Multi-Site Support β Manage multiple WordPress sites from one installation
- Web UI Tools β Ready-to-use forms for posts, pages, media, taxonomies, and CPTs
- Flexible Access Control β HTTP Basic Auth, token auth, or no protection
- Service-Based Design β Separate services for Posts, Pages, Media, Taxonomies, and CPTs
QuickWP/
βββ src/ # Core library (PSR-4: QuickWP\)
β βββ QuickWP.php # Main facade class
β βββ Bootstrap.php # Factory for service creation
β βββ Config/
β β βββ Config.php # Base immutable config wrapper
β β βββ ConfigLoader.php # Loads config from files
β β βββ SiteConfig.php # Site-specific configuration
β βββ Http/
β β βββ AccessControl.php # Access control middleware
β β βββ RestClient.php # cURL-based REST client
β βββ Service/
β βββ PostService.php # Post CRUD operations
β βββ PageService.php # Page CRUD operations
β βββ CptService.php # Custom Post Type operations
β βββ MediaService.php # Media upload & management
β βββ MenuService.php # Menu operations
β βββ TaxonomyService.php # Categories/Tags management
β βββ TemplateService.php # Template fetching
βββ public/ # Web interface
β βββ index.php # Dashboard
β βββ quick-post.php # Create/edit posts
β βββ quick-page.php # Create/edit pages
β βββ quick-media.php # Upload media
β βββ quick-cpt.php # Custom post types
β βββ quick-edit.php # Edit by ID
β βββ quick-taxonomy.php # Categories/Tags
β βββ quick-wp.php # Legacy entry point
βββ tests/ # PHPUnit tests
βββ quick-config.php # Your site configuration
βββ quick-sites.php # Multi-site configuration (optional)
βββ composer.json # PSR-4 autoloader
composer require bitshost/quickwpOr clone the repository and run composer install.
Copy the example config and edit with your WordPress site details:
cp quick-config.example.php quick-config.php<?php
return [
// REST API Endpoints
'posts_endpoint' => 'https://your-site.com/wp-json/wp/v2/posts',
'pages_endpoint' => 'https://your-site.com/wp-json/wp/v2/pages',
'media_endpoint' => 'https://your-site.com/wp-json/wp/v2/media',
// WordPress Credentials (Application Password)
'wp_username' => 'your-username',
'wp_app_password' => 'xxxx xxxx xxxx xxxx xxxx xxxx',
// Options
'show_auth_form' => true, // Show credentials in forms
'verify_ssl' => true, // Verify SSL certificates
'debug_http' => false, // Debug cURL requests
];- Log in to your WordPress admin
- Go to Users β Profile β Application Passwords
- Enter a name (e.g., "QuickWP") and click Add New
- Copy the generated password to your
quick-config.php
Point your browser to public/index.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use QuickWP\QuickWP;
// Initialize with config directory
$qwp = QuickWP::init(__DIR__);
// Create a post
$result = $qwp->posts()->create([
'title' => 'My New Post',
'content' => '<p>Hello from QuickWP!</p>',
'status' => 'draft',
]);
if (QuickWP::isSuccess($result)) {
echo 'Post created! ID: ' . QuickWP::getId($result);
echo 'Link: ' . QuickWP::getLink($result);
} else {
echo 'Error: ' . QuickWP::getError($result);
}// Posts
$posts = $qwp->posts();
$posts->create(['title' => 'New Post', 'status' => 'publish']);
$posts->update(123, ['title' => 'Updated Title']);
$posts->get(123);
$posts->list(['per_page' => 10, 'status' => 'draft']);
$posts->delete(123, force: true);
// Pages
$pages = $qwp->pages();
$pages->create(['title' => 'New Page', 'parent' => 0, 'template' => 'full-width.php']);
// Media
$media = $qwp->media();
$media->upload($_FILES['file'], ['title' => 'My Image', 'alt_text' => 'Alt text']);
$media->setFeaturedImage(postId: 123, mediaId: 456);
// Taxonomies
$tax = $qwp->taxonomy();
$tax->createCategory(['name' => 'News', 'slug' => 'news']);
$tax->createTag(['name' => 'Featured']);
$tax->listCategories(['hide_empty' => false]);
// Custom Post Types
$cpt = $qwp->cpt();
$cpt->create('product', ['title' => 'New Product', 'status' => 'publish']);
$cpt->list('product', ['per_page' => 20]);// From explicit config array
$qwp = QuickWP::withConfig([
'posts_endpoint' => 'https://example.com/wp-json/wp/v2/posts',
'wp_username' => 'admin',
'wp_app_password' => 'xxxx xxxx xxxx',
]);
// With specific site from multi-site config
$qwp = QuickWP::init(__DIR__, siteKey: 'staging');
// Without access control enforcement
$qwp = QuickWP::init(__DIR__, enforceAccess: false);| Method | Description |
|---|---|
QuickWP::init($baseDir, $siteKey, $enforceAccess) |
Initialize from config files |
QuickWP::withConfig($array) |
Initialize with explicit config |
$qwp->posts() |
Get PostService instance |
$qwp->pages() |
Get PageService instance |
$qwp->cpt() |
Get CptService instance |
$qwp->media() |
Get MediaService instance |
$qwp->taxonomy() |
Get TaxonomyService instance |
$qwp->menus() |
Get MenuService instance |
$qwp->templates() |
Get TemplateService instance |
$qwp->getConfig() |
Get current SiteConfig |
$qwp->getClient() |
Get RestClient instance |
| Method | Description |
|---|---|
QuickWP::isSuccess($result) |
Check if operation succeeded |
QuickWP::getError($result) |
Get error message from result |
QuickWP::getId($result) |
Get created/updated item ID |
QuickWP::getLink($result) |
Get item URL/link |
$qwp->createPost($data); // Create a post
$qwp->createPage($data); // Create a page
$qwp->createCptItem($slug, $data); // Create CPT item
$qwp->uploadMedia($fileInfo, $data); // Upload media
$qwp->createCategory($data); // Create category
$qwp->createTag($data); // Create tagEach service follows a consistent CRUD pattern:
$service->create($data); // Create item
$service->update($id, $data); // Update item
$service->get($id); // Get single item
$service->list($params); // List items with filters
$service->delete($id, $force); // Delete itemCreate quick-sites.php to manage multiple WordPress sites:
<?php
return [
'default_site' => 'production',
'sites' => [
'production' => [
'label' => 'Production Site',
'posts_endpoint' => 'https://example.com/wp-json/wp/v2/posts',
'pages_endpoint' => 'https://example.com/wp-json/wp/v2/pages',
'media_endpoint' => 'https://example.com/wp-json/wp/v2/media',
'wp_username' => 'prod-admin',
'wp_app_password' => 'xxxx xxxx xxxx xxxx',
],
'staging' => [
'label' => 'Staging Site',
'posts_endpoint' => 'https://staging.example.com/wp-json/wp/v2/posts',
'pages_endpoint' => 'https://staging.example.com/wp-json/wp/v2/pages',
'media_endpoint' => 'https://staging.example.com/wp-json/wp/v2/media',
'wp_username' => 'staging-admin',
'wp_app_password' => 'yyyy yyyy yyyy yyyy',
],
],
];Switch sites via URL parameter: ?site=staging
Or programmatically:
$qwp = QuickWP::init(__DIR__, siteKey: 'staging');Configure access protection in quick-config.php:
// No protection (default)
'access_mode' => 'none',
// HTTP Basic Auth
'access_mode' => 'basic',
'access_basic_user' => 'admin',
'access_basic_password' => 'secret-password',
// Token in URL
'access_mode' => 'token',
'access_token' => 'my-secret-token',
// Access via: ?token=my-secret-token| Key | Type | Default | Description |
|---|---|---|---|
posts_endpoint |
string | '' |
WordPress posts REST endpoint |
pages_endpoint |
string | '' |
WordPress pages REST endpoint |
media_endpoint |
string | '' |
WordPress media REST endpoint |
categories_endpoint |
string | derived | Categories endpoint (auto-derived if empty) |
tags_endpoint |
string | derived | Tags endpoint (auto-derived if empty) |
wp_username |
string | '' |
WordPress username |
wp_app_password |
string | '' |
WordPress Application Password |
verify_ssl |
bool | true |
Verify SSL certificates |
debug_http |
bool | false |
Show cURL debug info |
show_auth_form |
bool | true |
Show credentials in web forms |
access_mode |
string | 'none' |
Access control: none, basic, or token |
access_basic_user |
string | '' |
HTTP Basic Auth username |
access_basic_password |
string | '' |
HTTP Basic Auth password |
access_token |
string | '' |
URL token for token auth |
cpt_default_slug |
string | 'post' |
Default custom post type slug |
page_templates |
array | [] |
Available page templates |
post_templates |
array | [] |
Available post templates |
All service methods return a standardized response array:
[
'ok' => true, // Success flag
'http_code' => 201, // HTTP status code
'json' => [...], // Decoded JSON response
'raw_body' => '...', // Raw response body
'curl_error' => null, // cURL error message (if any)
'info' => [...], // cURL info array
'headers' => [...], // Response headers
]- Never commit credentials β Keep
quick-config.phpandquick-sites.phpout of version control - Use Application Passwords β Don't use your WordPress login password
- Enable SSL verification β Keep
verify_ssl => truein production - Protect the tools folder β Use
access_mode, HTTP auth, or IP restrictions - Use minimal permissions β Create WordPress users with only the capabilities needed
- Revoke leaked passwords β If credentials are exposed, revoke them immediately in WordPress
- PHP 7.4 or higher
- cURL extension
- WordPress 5.6+ (for Application Passwords)
- WordPress REST API enabled
# Run tests
composer test
# Static analysis
composer analyseMIT License β see LICENSE for details.