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);
    }
}