Examples
Real-world code samples for WPZylos Routing.
Complete Plugin Example
Directory Structure
my-plugin/
+-- plugin.php
+-- routes/
— +-- web.php
— +-- api.php
— +-- ajax.php
+-- src/
+-- Controllers/
+-- PageController.php
+-- Api/
— +-- UserController.php
+-- Ajax/
+-- SearchController.php
Plugin Bootstrap
<?php
// plugin.php
use WPZylos\Framework\Core\Application;
use WPZylos\Framework\Core\PluginContext;
use WPZylos\Framework\Routing\RoutingServiceProvider;
$context = PluginContext::create([
'file' => __FILE__,
'slug' => 'my-plugin',
'prefix' => 'myplugin_',
'textDomain' => 'my-plugin',
'version' => '1.0.0',
]);
$app = new Application($context);
$app->register(new RoutingServiceProvider());
$app->boot();
Frontend Routes Example
<?php
// routes/web.php
use App\Controllers\PageController;
use App\Controllers\ProductController;
return function ($router) {
// Static pages
$router->get('/about', [PageController::class, 'about'])
->name('about');
// Product catalog
$router->get('/products', [ProductController::class, 'index'])
->name('products.index');
$router->get('/products/{slug}', [ProductController::class, 'show'])
->where('slug', '[a-z0-9-]+')
->name('products.show');
// Contact form
$router->get('/contact', [PageController::class, 'contact']);
$router->post('/contact', [PageController::class, 'submitContact']);
// Admin area
$router->group(['prefix' => '/account', 'middleware' => ['auth']], function ($router) {
$router->get('/dashboard', [PageController::class, 'dashboard']);
$router->get('/orders', [PageController::class, 'orders']);
$router->get('/profile', [PageController::class, 'profile']);
$router->post('/profile', [PageController::class, 'updateProfile']);
});
};
REST API Example
<?php
// routes/api.php
use App\Controllers\Api\UserController;
use App\Controllers\Api\PostController;
use App\Controllers\Api\SettingsController;
return function ($rest) {
// Public endpoints
$rest->get('/posts', [PostController::class, 'index']);
$rest->get('/posts/{id}', [PostController::class, 'show'])
->where('id', '[0-9]+');
// Authenticated endpoints
$rest->group(['middleware' => ['auth']], function ($rest) {
// User profile
$rest->get('/me', [UserController::class, 'me']);
$rest->put('/me', [UserController::class, 'updateMe']);
// Posts (author only)
$rest->post('/posts', [PostController::class, 'store'])
->permission('edit_posts');
$rest->put('/posts/{id}', [PostController::class, 'update'])
->setPermissionCallback(fn($req) => current_user_can('edit_post', $req['id']));
$rest->delete('/posts/{id}', [PostController::class, 'destroy'])
->setPermissionCallback(fn($req) => current_user_can('delete_post', $req['id']));
});
// Admin endpoints
$rest->group(['prefix' => '/admin'], function ($rest) {
$rest->get('/users', [UserController::class, 'index'])
->permission('list_users');
$rest->get('/settings', [SettingsController::class, 'index'])
->permission('manage_options');
$rest->put('/settings', [SettingsController::class, 'update'])
->permission('manage_options');
});
// Resource routes
$rest->resource('comments', CommentController::class, ['index', 'store', 'destroy']);
};
AJAX Example
<?php
// routes/ajax.php
use App\Controllers\Ajax\SearchController;
use App\Controllers\Ajax\CartController;
use App\Controllers\Ajax\SettingsController;
return function ($ajax) {
// Public search (no login required)
$ajax->public('search', [SearchController::class, 'handle'])
->withoutNonce();
$ajax->public('autocomplete', [SearchController::class, 'autocomplete'])
->withoutNonce();
// Cart actions (session-based, public)
$ajax->public('add_to_cart', [CartController::class, 'add']);
$ajax->public('remove_from_cart', [CartController::class, 'remove']);
$ajax->public('update_cart', [CartController::class, 'update']);
// User actions (login required)
$ajax->private('save_settings', [SettingsController::class, 'save']);
$ajax->private('update_profile', [SettingsController::class, 'updateProfile']);
// Admin actions
$ajax->group(['middleware' => ['admin']], function ($ajax) {
$ajax->private('bulk_delete', [SettingsController::class, 'bulkDelete']);
$ajax->private('export_data', [SettingsController::class, 'export']);
});
};
Controller Examples
REST Controller
<?php
namespace App\Controllers\Api;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
class PostController
{
public function index(WP_REST_Request $request): array
{
$page = (int) ($request->get_param('page') ?? 1);
$per_page = (int) ($request->get_param('per_page') ?? 10);
$posts = get_posts([
'posts_per_page' => $per_page,
'paged' => $page,
'post_status' => 'publish',
]);
return [
'data' => array_map([$this, 'transform'], $posts),
'meta' => [
'page' => $page,
'per_page' => $per_page,
'total' => wp_count_posts()->publish,
],
];
}
public function show(WP_REST_Request $request): array|WP_Error
{
$id = (int) $request->get_param('id');
$post = get_post($id);
if (!$post || $post->post_status !== 'publish') {
return new WP_Error('not_found', 'Post not found', ['status' => 404]);
}
return ['data' => $this->transform($post)];
}
public function store(WP_REST_Request $request): WP_REST_Response|WP_Error
{
$title = sanitize_text_field($request->get_param('title'));
$content = wp_kses_post($request->get_param('content'));
if (empty($title)) {
return new WP_Error('validation', 'Title is required', ['status' => 422]);
}
$post_id = wp_insert_post([
'post_title' => $title,
'post_content' => $content,
'post_status' => 'publish',
'post_author' => get_current_user_id(),
]);
if (is_wp_error($post_id)) {
return $post_id;
}
return new WP_REST_Response(
['data' => $this->transform(get_post($post_id))],
201
);
}
private function transform(\WP_Post $post): array
{
return [
'id' => $post->ID,
'title' => $post->post_title,
'content' => $post->post_content,
'excerpt' => get_the_excerpt($post),
'author' => get_the_author_meta('display_name', $post->post_author),
'created_at' => $post->post_date,
];
}
}
AJAX Controller
<?php
namespace App\Controllers\Ajax;
class SearchController
{
public function handle(): array
{
$query = sanitize_text_field($_POST['query'] ?? '');
if (strlen($query) < 3) {
return ['results' => [], 'message' => 'Query too short'];
}
$results = new \WP_Query([
's' => $query,
'posts_per_page' => 10,
'post_status' => 'publish',
]);
return [
'results' => array_map(fn($post) => [
'id' => $post->ID,
'title' => $post->post_title,
'url' => get_permalink($post),
'excerpt' => get_the_excerpt($post),
], $results->posts),
'total' => $results->found_posts,
];
}
}
Middleware Example
<?php
namespace App\Middleware;
class AuthMiddleware
{
public function handle($request, callable $next): mixed
{
if (!is_user_logged_in()) {
if ($request instanceof \WP_REST_Request) {
return new \WP_Error('unauthorized', 'Authentication required', ['status' => 401]);
}
wp_redirect(wp_login_url());
exit;
}
return $next($request);
}
}
class AdminMiddleware
{
public function handle($request, callable $next): mixed
{
if (!current_user_can('manage_options')) {
return new \WP_Error('forbidden', 'Admin access required', ['status' => 403]);
}
return $next($request);
}
}
class RateLimitMiddleware
{
public function handle($request, callable $next): mixed
{
$ip = $_SERVER['REMOTE_ADDR'];
$key = 'rate_limit_' . md5($ip);
$limit = 100;
$count = (int) get_transient($key);
if ($count >= $limit) {
return new \WP_Error('rate_limit', 'Too many requests', ['status' => 429]);
}
set_transient($key, $count + 1, MINUTE_IN_SECONDS);
return $next($request);
}
}