| name | wordpress-advanced-architecture |
| description | Advanced WordPress development with REST API endpoints, WP-CLI commands, performance optimization, and caching strategies for scalable applications. |
| user-invocable | false |
| disable-model-invocation | true |
| progressive_disclosure | {"entry_point":{"summary":"Advanced WordPress development with REST API, WP-CLI, performance optimization, and caching strategies","when_to_use":["Building custom REST API endpoints","Automating WordPress tasks with WP-CLI","Optimizing performance with caching and transients"],"quick_start":["Register custom REST endpoints with permissions","Create WP-CLI commands for automation","Implement caching with transients and object cache"]}} |
Advanced WordPress Architecture
Master advanced WordPress development patterns including REST API endpoints, WP-CLI commands, performance optimization, and caching strategies for scalable WordPress applications.
1. REST API Development
The WordPress REST API provides a powerful interface for creating custom endpoints with proper authentication, validation, and response formatting.
Endpoint Registration with Namespacing
add_action( 'rest_api_init', 'register_custom_rest_routes' );
function register_custom_rest_routes() {
$namespace = 'myplugin/v1';
register_rest_route( $namespace, '/books', [
'methods' => 'GET',
'callback' => 'get_books_callback',
'permission_callback' => '__return_true', // Public endpoint
'args' => [
'per_page' => [
'default' => 10,
'validate_callback' => function( $param ) {
return is_numeric( $param ) && $param > 0 && $param <= 100;
},
'sanitize_callback' => 'absint',
],
'page' => [
'default' => 1,
'validate_callback' => function( $param ) {
return is_numeric( $param ) && $param > 0;
},
'sanitize_callback' => 'absint',
],
],
]);
register_rest_route( $namespace, '/books/(?P<id>\d+)', [
'methods' => 'GET',
'callback' => 'get_book_callback',
'permission_callback' => '__return_true',
'args' => [
'id' => [
'validate_callback' => function( $param ) {
return is_numeric( $param );
},
'sanitize_callback' => 'absint',
],
],
]);
register_rest_route( $namespace, '/books', [
'methods' => 'POST',
'callback' => 'create_book_callback',
'permission_callback' => function() {
return current_user_can( 'edit_posts' );
},
'args' => [
'title' => [
'required' => true,
'type' => 'string',
'validate_callback' => function( $param ) {
return is_string( $param ) && strlen( $param ) > 0;
},
'sanitize_callback' => 'sanitize_text_field',
],
'content' => [
'required' => false,
'type' => 'string',
'sanitize_callback' => 'wp_kses_post',
],
'status' => [
'default' => 'draft',
'enum' => [ 'draft', 'publish', 'private' ],
],
],
]);
register_rest_route( $namespace, '/books/(?P<id>\d+)', [
'methods' => 'PUT',
'callback' => 'update_book_callback',
'permission_callback' => function( $request ) {
$book_id = $request->get_param( 'id' );
return current_user_can( 'edit_post', $book_id );
},
'args' => [
'id' => [
'validate_callback' => function( $param ) {
return is_numeric( $param );
},
'sanitize_callback' => 'absint',
],
'title' => [
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
],
'content' => [
'type' => 'string',
'sanitize_callback' => 'wp_kses_post',
],
],
]);
register_rest_route( $namespace, '/books/(?P<id>\d+)', [
'methods' => 'DELETE',
'callback' => 'delete_book_callback',
'permission_callback' => function( $request ) {
$book_id = $request->get_param( 'id' );
return current_user_can( 'delete_post', $book_id );
},
'args' => [
'id' => [
'validate_callback' => function( $param ) {
return is_numeric( $param );
},
'sanitize_callback' => 'absint',
],
],
]);
}
Complete CRUD Implementation
function get_books_callback( $request ) {
$per_page = $request->get_param( 'per_page' );
$page = $request->get_param( 'page' );
$offset = ( $page - 1 ) * $per_page;
$args = [
'post_type' => 'book',
'posts_per_page' => $per_page,
'offset' => $offset,
'post_status' => 'publish',
];
$query = new WP_Query( $args );
if ( ! $query->have_posts() ) {
return rest_ensure_response([
'books' => [],
'total' => 0,
'page' => $page,
'per_page' => $per_page,
]);
}
$books = [];
while ( $query->have_posts() ) {
$query->the_post();
[] = [
=> (),
=> (),
=> (),
=> (),
=> ( ),
=> (),
];
}
();
= ([
=> ,
=> ->found_posts,
=> ,
=> ,
=> ( ->found_posts / ),
]);
->( , ( ) );
( > ) {
= - ;
->( , ( ) );
}
( < ( ->found_posts / ) ) {
= + ;
->( , ( ) );
}
;
}
{
= ->( );
= ( );
( ! || !== ->post_type ) {
(
,
,
[ => ]
);
}
= [
=> ->ID,
=> ->post_title,
=> ( , ->post_content ),
=> ->post_excerpt,
=> ( , ->post_author ),
=> ( , ),
=> ( , ),
=> ->post_status,
=> ( ),
=> ( , ),
=> [
=> ( ->ID, , ),
=> () ( ->ID, , ),
],
];
( );
}
{
= ->( );
= ->( );
= ->( );
= [
=> ,
=> ,
=> ,
=> ,
=> (),
];
= ( , );
( ( ) ) {
(
,
->(),
[ => ]
);
}
( ->( ) ) {
( , , ( ->( ) ) );
}
( ->( ) ) {
( , , ( ->( ) ) );
}
= ([
=> ,
=> ,
=> ,
=> ( ),
]);
->( );
->( , ( ) );
;
}
{
= ->( );
= ( );
( ! || !== ->post_type ) {
(
,
,
[ => ]
);
}
= [ => ];
( ->( ) ) {
[] = ->( );
}
( ->( ) ) {
[] = ->( );
}
( ->( ) ) {
[] = ->( );
}
= ( , );
( ( ) ) {
(
,
->(),
[ => ]
);
}
([
=> ,
=> ,
=> ( ),
]);
}
{
= ->( );
= ( );
( ! || !== ->post_type ) {
(
,
,
[ => ]
);
}
= ->( );
= ( , );
( ! ) {
(
,
,
[ => ]
);
}
([
=> ,
=> ,
=> ? : ,
]);
}
Controller Pattern for Complex Endpoints
For complex REST endpoints, use a controller class to organize logic:
<?php
namespace MyPlugin\API;
class Books_Controller extends \WP_REST_Controller {
protected $namespace = 'myplugin/v1';
protected $rest_base = 'books';
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->rest_base, [
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_items' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'create_item' ],
'permission_callback' => [ $this, 'create_item_permissions_check' ],
'args' => $this->get_endpoint_args_for_item_schema( :: ),
],
=> [ , ],
]);
( ->namespace, . ->rest_base . , [
=> [
=> [
=> ,
=> ,
],
],
[
=> ::,
=> [ , ],
=> [ , ],
=> [
=> ->( [ => ] ),
],
],
[
=> ::,
=> [ , ],
=> [ , ],
=> ->( :: ),
],
[
=> ::,
=> [ , ],
=> [ , ],
=> [
=> [
=> ,
=> ,
=> ,
],
],
],
=> [ , ],
]);
}
{
}
{
}
{
}
{
}
{
}
{
;
}
{
;
}
{
( );
}
{
= ->( );
( , );
}
{
= ->( );
( , );
}
{
( ->schema ) {
->( ->schema );
}
= [
=> ,
=> ,
=> ,
=> [
=> [
=> ,
=> ,
=> [ , , ],
=> ,
],
=> [
=> ,
=> ,
=> [ , , ],
=> ,
],
=> [
=> ,
=> ,
=> [ , ],
],
=> [
=> ,
=> ,
=> [ , , ],
=> [ , ],
],
],
];
->schema = ;
->( ->schema );
}
}
( , function() {
= \API\();
->();
});
REST API Authentication
add_action( 'rest_api_init', function() {
wp_localize_script( 'my-ajax-script', 'wpApiSettings', [
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' ),
]);
});
2. WP-CLI Commands
WP-CLI enables automation of WordPress tasks through custom commands.
Custom Command Registration
<?php
namespace MyPlugin\CLI;
class Books_Command {
public function list( $args, $assoc_args ) {
$defaults = [
'format' => 'table',
'status' => 'any',
];
$assoc_args = wp_parse_args( $assoc_args, $defaults );
$query_args = [
'post_type' => 'book',
'posts_per_page' => -1,
'post_status' => $assoc_args['status'],
];
$books = get_posts( $query_args );
if ( empty( $books ) ) {
\WP_CLI::warning( 'No books found.' );
return;
}
$items = [];
( ) {
[] = [
=> ->ID,
=> ->post_title,
=> ->post_status,
=> ( , ->post_author ),
=> ( , ),
];
}
\WP_CLI\Utils\( [], , [ , , , , ] );
\WP_CLI::( ( , ( ) ) );
}
{
= [];
= [
=> ,
=> ,
];
= ( , );
= [
=> ,
=> ,
=> [],
=> [],
=> (),
];
= ( , );
( ( ) ) {
\WP_CLI::( . ->() );
}
( ( [] ) ) {
( , , ( [] ) );
}
( ( [] ) ) {
( , , ( [] ) );
}
\WP_CLI::( ( , , ) );
}
{
= [];
= ( [] );
( ! ( ) ) {
\WP_CLI::( . );
}
= ( , ( ) );
= ( );
= ( );
= ;
\WP_CLI::( ( , ) );
= \WP_CLI\Utils\( , );
( ) {
= ( , );
( ) {
\WP_CLI::( ( , [] ) );
} {
= [
=> ,
=> [],
=> [] ?? ,
=> [] ?? ,
];
= ( , );
( ! ( ) ) {
( ( [] ) ) {
( , , [] );
}
++;
}
}
->();
}
->();
( ) {
\WP_CLI::( ( , ) );
} {
\WP_CLI::( ( , , ) );
}
}
{
= ( [] ) ? ( [] ) : ;
= ( [] ) ? [] : ;
= \WP_CLI\Utils\( , );
( = ; <= ; ++ ) {
= [
=> ,
=> ( , ),
=> ( , ),
=> ,
];
= ( );
( , , ( , ( , ) ) );
( , , ( , ) );
->();
}
->();
\WP_CLI::( ( , ) );
}
}
( ( ) && WP_CLI ) {
\WP_CLI::( , );
}
Interactive Prompts and Confirmation
public function delete_all( $args, $assoc_args ) {
$books = get_posts([
'post_type' => 'book',
'posts_per_page' => -1,
'fields' => 'ids',
]);
$count = count( $books );
if ( 0 === $count ) {
\WP_CLI::warning( 'No books to delete.' );
return;
}
\WP_CLI::confirm( sprintf( 'Are you sure you want to delete %d books?', $count ), $assoc_args );
$progress = \WP_CLI\Utils\make_progress_bar( 'Deleting books', $count );
foreach ( $books as $book_id ) {
wp_delete_post( $book_id, true );
$progress->tick();
}
->();
\WP_CLI::( ( , ) );
}
Testing WP-CLI Commands
wp cli command-list
wp help books
wp help books create
wp books list
wp books list --format=json
wp books create "Test Book" --status=publish
wp books generate --count=50
wp books import books.csv --dry-run
wp books delete-all --yes
3. Performance Optimization
Transients API (Expiring Cache)
function get_popular_books() {
$transient_key = 'popular_books';
$popular_books = get_transient( $transient_key );
if ( false === $popular_books ) {
$popular_books = new WP_Query([
'post_type' => 'book',
'posts_per_page' => 10,
'meta_key' => '_view_count',
'orderby' => 'meta_value_num',
'order' => 'DESC',
]);
set_transient( $transient_key, $popular_books, HOUR_IN_SECONDS );
}
return $popular_books;
}
add_action( 'save_post_book', 'invalidate_books_cache' );
function invalidate_books_cache( $post_id ) {
delete_transient( 'popular_books' );
}
set_site_transient( , , DAY_IN_SECONDS );
= ( );
( );
;
->( );
Object Caching (Redis, Memcached)
wp_cache_add( 'my_key', $data, 'my_group', 3600 );
$data = wp_cache_get( 'my_key', 'my_group' );
if ( false === $data ) {
$data = expensive_database_query();
wp_cache_set( 'my_key', $data, 'my_group', 3600 );
}
wp_cache_delete( 'my_key', 'my_group' );
wp_cache_flush();
function get_user_books( $user_id ) {
$cache_key = "user_{$user_id}_books";
$cache_group = 'user_books';
$books = wp_cache_get( $cache_key, $cache_group );
if ( false === $books ) {
$books = ([
=> ,
=> ,
=> -,
]);
( , , , HOUR_IN_SECONDS );
}
;
}
( , , , );
{
( , );
}
Redis Configuration (object-cache.php)
<?php
global $redis_server;
$redis_server = [
'host' => '127.0.0.1',
'port' => 6379,
'auth' => '',
'database' => 0,
];
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_TIMEOUT', 1 );
define( 'WP_REDIS_READ_TIMEOUT', 1 );
Database Query Optimization
$posts = get_posts([ 'post_type' => 'book', 'posts_per_page' => -1 ]);
foreach ( $posts as $post ) {
$author = get_user_by( 'id', $post->post_author );
$meta = get_post_meta( $post->ID, '_isbn', true );
}
$posts = get_posts([ 'post_type' => 'book', 'posts_per_page' => -1 ]);
$author_ids = wp_list_pluck( $posts, 'post_author' );
$authors = get_users([ 'include' => $author_ids ]);
$authors_by_id = [];
foreach ( $authors as $author ) {
$authors_by_id[ $author->ID ] = $author;
}
update_post_caches( $posts, );
( ) {
= [ ->post_author ];
= ( ->ID, , );
}
;
= ->();
;
->();
Lazy Loading and Pagination
function get_books_paginated( $page = 1, $per_page = 20 ) {
$args = [
'post_type' => 'book',
'posts_per_page' => $per_page,
'paged' => $page,
];
return new WP_Query( $args );
}
add_action( 'wp_ajax_load_more_books', 'ajax_load_more_books' );
add_action( 'wp_ajax_nopriv_load_more_books', 'ajax_load_more_books' );
function ajax_load_more_books() {
check_ajax_referer( 'load_more_nonce', 'nonce' );
$page = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
$query = get_books_paginated( $page, 10 );
if ( $query->have_posts() ) {
ob_start();
( ->() ) {
->();
( , );
}
= ();
([
=> ,
=> ->max_num_pages > ,
]);
} {
( );
}
}
<img src= loading= alt=>
Profiling with Query Monitor
do_action( 'qm/start', 'my_expensive_operation' );
do_action( 'qm/stop', 'my_expensive_operation' );
do_action( 'qm/debug', 'Custom debug message' );
do_action( 'qm/info', $data_to_inspect );
Query Monitor shows:
4. Caching Strategies
Fragment Caching
function render_book_grid() {
$cache_key = 'book_grid_html';
$html = get_transient( $cache_key );
if ( false === $html ) {
ob_start();
$books = new WP_Query([
'post_type' => 'book',
'posts_per_page' => 12,
]);
if ( $books->have_posts() ) {
echo '<div class="book-grid">';
while ( $books->have_posts() ) {
$books->the_post();
?>
<div class="book-item">
<h3><?php the_title(); ?></h3>
<?php the_post_thumbnail( 'medium' ); ?>
</div>
<?php
}
echo '</div>';
}
wp_reset_postdata();
$html = ob_get_clean();
( $, $, );
}
$;
}
Page Caching vs Object Caching
header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
function add_cache_headers() {
if ( is_admin() || is_user_logged_in() ) {
return;
}
if ( is_page() || is_single() ) {
header( 'Cache-Control: public, max-age=3600' );
}
if ( is_archive() || is_home() ) {
header( 'Cache-Control: public, max-age=1800' );
}
}
add_action( 'send_headers', 'add_cache_headers' );
Cache Invalidation Patterns
set_transient( 'data', $value, 12 * HOUR_IN_SECONDS );
add_action( 'save_post_book', 'clear_book_caches' );
function clear_book_caches( $post_id ) {
delete_transient( 'popular_books' );
delete_transient( 'recent_books' );
wp_cache_delete( "book_{$post_id}", 'books' );
$post = get_post( $post_id );
wp_cache_delete( "user_{$post->post_author}_books", 'user_books' );
}
function get_cache_version() {
$version = wp_cache_get( 'cache_version', 'global' );
if ( false === $version ) {
$version = time();
wp_cache_set( 'cache_version', $version, );
}
;
}
{
= ();
= ;
( , );
}
{
= ();
= ;
( , , , HOUR_IN_SECONDS );
}
{
= ();
( , , );
}
( , , );
{
();
}
CDN Integration
add_filter( 'wp_get_attachment_url', 'cdn_rewrite_url' );
add_filter( 'wp_calculate_image_srcset', 'cdn_rewrite_srcset' );
function cdn_rewrite_url( $url ) {
$cdn_domain = 'https://cdn.example.com';
$site_url = site_url();
if ( strpos( $url, '/wp-content/uploads/' ) !== false ) {
return str_replace( $site_url, $cdn_domain, $url );
}
return $url;
}
function cdn_rewrite_srcset( $sources ) {
if ( ! is_array( $sources ) ) {
return $sources;
}
foreach ( $sources as &$source ) {
$source['url'] = cdn_rewrite_url( $source['url'] );
}
return $sources;
}
( , );
{
= ;
= ;
= ;
= ( );
( , [
=> [
=> ,
=> ,
=> ,
],
=> ([
=> [ ],
]),
]);
}
5. Advanced Database Patterns
WP_Query Optimization
$query = new WP_Query([
'post_type' => 'book',
'fields' => 'ids',
]);
$count = new WP_Query([
'post_type' => 'book',
'posts_per_page' => -1,
'fields' => 'ids',
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
]);
$query = new WP_Query([
'post_type' => 'book',
'meta_query' => [
'relation' => 'AND',
[
'key' => '_pages',
'value' => 200,
'compare' => '>',
'type' => 'NUMERIC',
],
[
'key' => '_rating',
'value' => 4,
'compare' => '>=',
'type' => ,
],
],
=> ,
=> ,
]);
Direct SQL for Complex Queries
global $wpdb;
$results = $wpdb->get_results("
SELECT
p.ID,
p.post_title,
pm1.meta_value as isbn,
pm2.meta_value as pages,
pm3.meta_value as rating
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm1 ON p.ID = pm1.post_id AND pm1.meta_key = '_isbn'
LEFT JOIN {$wpdb->postmeta} pm2 ON p.ID = pm2.post_id AND pm2.meta_key = '_pages'
LEFT JOIN {$wpdb->postmeta} pm3 ON p.ID = pm3.post_id AND pm3.meta_key = '_rating'
WHERE p.post_type = 'book'
AND p.post_status = 'publish'
AND CAST(pm2.meta_value AS UNSIGNED) > 200
ORDER BY CAST(pm3.meta_value AS DECIMAL(3,2)) DESC
LIMIT 20
");
$min_pages = 200;
$results = $wpdb->get_results( $wpdb->prepare("
SELECT p.ID, p.post_title, pm.meta_value as pages
FROM {$wpdb->posts} p
INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE p.post_type = 'book'
AND pm.meta_key = '_pages'
AND CAST(pm.meta_value AS UNSIGNED) > %d
ORDER BY p.post_date DESC
", $min_pages ) );
Database Indexing
register_activation_hook( __FILE__, 'create_custom_indexes' );
function create_custom_indexes() {
global $wpdb;
$wpdb->query("
CREATE INDEX idx_post_type_status
ON {$wpdb->posts} (post_type, post_status)
");
$wpdb->query("
CREATE INDEX idx_meta_key_value
ON {$wpdb->postmeta} (meta_key, meta_value(191))
");
$wpdb->query("
CREATE INDEX idx_post_type_date
ON {$wpdb->posts} (post_type, post_date)
");
}
register_deactivation_hook( __FILE__, 'remove_custom_indexes' );
function remove_custom_indexes() {
global $wpdb;
$wpdb->query( "DROP INDEX idx_post_type_status ON {$wpdb->posts}" );
$wpdb->query( "DROP INDEX idx_meta_key_value ON {$wpdb->postmeta}" );
$wpdb->( );
}
6. Multisite Development
Network-Activated Plugins
if ( is_multisite() ) {
}
add_action( 'network_admin_menu', 'add_network_admin_page' );
function add_network_admin_page() {
add_menu_page(
'Network Settings',
'My Plugin',
'manage_network_options',
'my-network-settings',
'render_network_settings_page'
);
}
add_site_option( 'my_network_setting', 'value' );
$value = get_site_option( 'my_network_setting' );
update_site_option( 'my_network_setting', 'new_value' );
delete_site_option( 'my_network_setting' );
Cross-Site Operations
$current_blog_id = get_current_blog_id();
switch_to_blog( 2 );
$posts = get_posts([ 'post_type' => 'book' ]);
update_option( 'my_option', 'value' );
restore_current_blog();
$sites = get_sites([ 'number' => 999 ]);
foreach ( $sites as $site ) {
switch_to_blog( $site->blog_id );
$count = wp_count_posts( 'book' );
error_log( "Site {$site->blog_id} has {$count->publish} books" );
restore_current_blog();
}
7. Best Practices
Service-Oriented Architecture
<?php
namespace MyPlugin\Services;
class BookService {
private $cache;
private $validator;
public function __construct( CacheService $cache, ValidationService $validator ) {
$this->cache = $cache;
$this->validator = $validator;
}
public function get_book( $book_id ) {
$cache_key = "book_{$book_id}";
$book = $this->cache->get( $cache_key );
if ( false === $book ) {
$book = get_post( $book_id );
if ( $book && 'book' === $book->post_type ) {
$this->cache->set( $cache_key, $book, HOUR_IN_SECONDS );
}
}
return ;
}
{
= ->validator->( );
( ! ( ) ) {
( , , );
}
= ([
=> ,
=> [],
=> [],
=> [],
]);
( ( ) ) {
;
}
->cache->( );
;
}
}
{
= [];
{
->services[ ] = ;
}
{
( ! ( ->services[ ] ) ) {
( );
}
->services[ ];
}
}
= ();
->( , () );
->( , () );
->( , (
->( ),
->( )
) );
Event-Driven Design
do_action( 'myplugin_book_created', $book_id, $book_data );
do_action( 'myplugin_book_updated', $book_id, $old_data, $new_data );
do_action( 'myplugin_book_deleted', $book_id );
add_action( 'myplugin_book_created', function( $book_id, $book_data ) {
}, 10, 2 );
$book_data = apply_filters( 'myplugin_before_book_save', $book_data, $book_id );
$notification_recipients = apply_filters( 'myplugin_notification_recipients', [ 'admin@example.com' ], $book_id );
Scalability Considerations
function process_books_batch() {
$offset = 0;
$batch_size = 100;
do {
$books = get_posts([
'post_type' => 'book',
'posts_per_page' => $batch_size,
'offset' => $offset,
'fields' => 'ids',
]);
foreach ( $books as $book_id ) {
update_post_meta( $book_id, '_processed', time() );
}
$offset += $batch_size;
wp_cache_flush();
} ( ( ) === );
}
Related Skills
When building advanced WordPress applications, consider these complementary skills (available in the skill library):
- WordPress Plugin Fundamentals: Core plugin architecture and hooks - essential foundation for custom REST endpoints and WP-CLI commands
- WordPress Security & Data Validation: Security best practices - critical for securing REST API endpoints and validating user input
- WordPress Testing & QA: Testing REST endpoints and WP-CLI - comprehensive testing strategies for advanced WordPress features
- GraphQL: Alternative to REST API - consider GraphQL as a modern alternative to WordPress REST API for complex data queries
- Docker: Development environment setup - containerize WordPress development for consistent and reproducible environments
References