Basic Routing
AvelPress provides a powerful routing system that integrates seamlessly with WordPress REST API. It allows you to define clean, RESTful routes for your plugin or theme.
Introduction
The AvelPress router provides a Laravel-style routing interface that automatically integrates with WordPress REST API endpoints. Routes are typically defined in routes/api.php
file.
Basic Route Registration
Simple Routes
use AvelPress\Facades\Route;
// GET route
Route::get('users', function($request) {
return ['message' => 'Hello from GET route'];
});
// POST route
Route::post('users', function($request) {
return ['message' => 'User created'];
});
// PUT route
Route::put('users/{id}', function($request) {
$id = $request->get_param('id');
return ['message' => "User {$id} updated"];
});
// DELETE route
Route::delete('users/{id}', function($request) {
$id = $request->get_param('id');
return ['message' => "User {$id} deleted"];
});
Available HTTP Methods
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::delete($uri, $callback);
Route Parameters
Basic Parameters
You can capture URI segments as parameters:
// Single parameter
Route::get('users/{id}', function($request) {
$id = $request->get_param('id');
return ['user_id' => $id];
});
// Multiple parameters
Route::get('users/{userId}/posts/{postId}', function($request) {
$userId = $request->get_param('userId');
$postId = $request->get_param('postId');
return [
'user_id' => $userId,
'post_id' => $postId
];
});
Optional Parameters
// Optional parameter with default value
Route::get('users/{id?}', function($request) {
$id = $request->get_param('id') ?: 'all';
return ['user_id' => $id];
});
Parameter Constraints
You can add regular expression constraints to route parameters:
// Only accept numeric IDs
Route::get('users/{id}', function($request) {
$id = $request->get_param('id');
return ['user_id' => $id];
})->where('id', '[0-9]+');
// Multiple constraints
Route::get('users/{id}/posts/{slug}', function($request) {
// Handle request
})->where(['id' => '[0-9]+', 'slug' => '[a-z-]+']);
Route Callbacks
Closure Callbacks
Simple closures for quick routes:
Route::get('hello', function($request) {
return ['message' => 'Hello World!'];
});
Controller Callbacks
Reference controller methods (more organized):
use App\Controllers\UserController;
Route::get('users', [UserController::class, 'index']);
Route::post('users', [UserController::class, 'store']);
Route::get('users/{id}', [UserController::class, 'show']);
Route::put('users/{id}', [UserController::class, 'update']);
Route::delete('users/{id}', [UserController::class, 'destroy']);
Request Handling
Accessing Request Data
Route::post('users', function($request) {
// Get all parameters
$params = $request->get_params();
// Get specific parameter
$name = $request->get_param('name');
// Get parameter with default
$email = $request->get_param('email') ?: 'no-email@example.com';
// Get JSON body (for POST/PUT requests)
$body = $request->get_json_params();
// Get file uploads
$files = $request->get_file_params();
return ['received' => $params];
});
Request Headers
Route::get('protected', function($request) {
$authHeader = $request->get_header('authorization');
$contentType = $request->get_header('content-type');
if (!$authHeader) {
return new \WP_Error('unauthorized', 'Authorization required', ['status' => 401]);
}
return ['message' => 'Access granted'];
});
Response Handling
JSON Responses
Route::get('users', function($request) {
// Simple array (automatically converted to JSON)
return [
'users' => [
['id' => 1, 'name' => 'John'],
['id' => 2, 'name' => 'Jane']
]
];
});
Custom Status Codes
Route::post('users', function($request) {
// Return with custom status code
$response = ['message' => 'User created'];
return new \WP_REST_Response($response, 201);
});
Error Responses
Route::get('users/{id}', function($request) {
$id = $request->get_param('id');
if (!is_numeric($id)) {
return new \WP_Error(
'invalid_id',
'User ID must be numeric',
['status' => 400]
);
}
// Find user logic here
return ['user' => ['id' => $id]];
});
Route Prefixes
Using Route Groups
// Group routes with common prefix
Route::prefix('api/v1')->group(function() {
Route::get('users', [UserController::class, 'index']);
Route::get('posts', [PostController::class, 'index']);
});
// This creates routes:
// /wp-json/your-plugin/api/v1/users
// /wp-json/your-plugin/api/v1/posts
Nested Prefixes
Route::prefix('api')->group(function() {
Route::prefix('v1')->group(function() {
Route::get('users', [UserController::class, 'index']);
Route::get('posts', [PostController::class, 'index']);
});
Route::prefix('v2')->group(function() {
Route::get('users', [UserV2Controller::class, 'index']);
});
});
Middleware (Guards)
Route Guards
// Protect routes with authentication
Route::guard('auth')->group(function() {
Route::get('profile', [UserController::class, 'profile']);
Route::post('logout', [AuthController::class, 'logout']);
});
// Multiple guards
Route::guard(['auth', 'admin'])->group(function() {
Route::get('admin/users', [AdminController::class, 'users']);
});
Custom Guards
Create custom middleware in your service provider:
// In your service provider
public function boot()
{
Route::guard('custom', function($request) {
// Your custom authentication logic
if (!$this->isValidRequest($request)) {
return new \WP_Error('unauthorized', 'Access denied', ['status' => 401]);
}
return true; // Allow request to continue
});
}
Route Model Binding
Automatic Model Binding
use App\Models\User;
// Automatically inject model instance
Route::get('users/{user}', function(User $user) {
return new JsonResource($user);
});
// The {user} parameter will automatically resolve to a User model
// based on the ID in the URL
Custom Resolution
// Custom resolution logic
Route::get('users/{user:slug}', function(User $user) {
return new JsonResource($user);
});
// This will find user by 'slug' field instead of 'id'
Route Caching
For better performance in production, you can cache routes:
// In your service provider
public function boot()
{
if ($this->app->environment('production')) {
Route::cache(true);
}
}
WordPress Integration
Accessing WordPress Functions
Route::get('current-user', function($request) {
$current_user = wp_get_current_user();
if ($current_user->ID === 0) {
return new \WP_Error('not_logged_in', 'User not logged in', ['status' => 401]);
}
return [
'id' => $current_user->ID,
'name' => $current_user->display_name,
'email' => $current_user->user_email
];
});
Permission Checks
Route::get('admin/settings', function($request) {
if (!current_user_can('manage_options')) {
return new \WP_Error('insufficient_permissions', 'Access denied', ['status' => 403]);
}
// Return admin settings
return get_option('my_plugin_settings', []);
});
Complete Example
Here's a complete example showing various routing features:
<?php
use App\Controllers\UserController;
use App\Controllers\PostController;
use AvelPress\Facades\Route;
// API v1 routes
Route::prefix('api/v1')->group(function() {
// Public routes
Route::get('health', function($request) {
return ['status' => 'ok', 'timestamp' => time()];
});
// User routes
Route::prefix('users')->group(function() {
Route::get('/', [UserController::class, 'index']);
Route::get('/{id}', [UserController::class, 'show'])->where('id', '[0-9]+');
// Protected routes
Route::guard('auth')->group(function() {
Route::post('/', [UserController::class, 'store']);
Route::put('/{id}', [UserController::class, 'update']);
Route::delete('/{id}', [UserController::class, 'destroy']);
});
});
// Post routes with nested resources
Route::prefix('posts')->group(function() {
Route::get('/', [PostController::class, 'index']);
Route::get('/{id}', [PostController::class, 'show']);
Route::get('/{id}/comments', [PostController::class, 'comments']);
});
});
This routing system provides all the flexibility you need to build modern REST APIs while staying integrated with WordPress core functionality.