Skip to main content

Middlewares

Middleware in ModulesPress provides a powerful mechanism to intercept, transform, and control the REST request-response lifecycle. Each middleware acts as a configurable checkpoint in your plugin's request processing pipeline.

Key Middleware Characteristics

Middleware Execution Logic

The core principle of middleware is simple yet powerful:

  • If a middleware returns the WP_REST_Request object, processing continues to the next middleware or route handler
  • If a middleware returns a WP_REST_Response object, request processing immediately stops, and that response is sent back to the client

Middleware Configuration

Middlewares are configured within a module's middlewares() method using the MiddlewareConsumer:

class BooksModule extends ModulesPressModule
{
public function middlewares(MiddlewareConsumer $consumer): void
{
$consumer->apply(/* Middleware configuration */)
}
}

Middleware Application Strategies

1. Route Method Filtering

You can apply middlewares to specific HTTP methods:

$consumer->apply(AuthMiddleware::class)
->forRoutes([
// Only apply to POST and PUT methods
['path' => '*' 'methods' => [RequestMethod::POST, RequestMethod::PUT]]
]);

2. Path-Based Routing

Apply middlewares to specific path patterns:

$consumer->apply(AdminAuthMiddleware::class)
->forRoutes([
// Apply only to admin routes
['path' => '#^admin/.*$#', 'methods' => ['*']]
]);

3. Combining Path and Method Filtering

$consumer->apply(SecureMiddleware::class)
->forRoutes([
// Only secure POST requests to book-related routes
[
'path' => '#^books/.*$#',
'methods' => [RequestMethod::POST]
]
]);

4. Global Middleware

Apply middleware to all routes:

// Apply to all routes and all methods
$consumer->apply(LoggingMiddleware::class)
->forRoutes('*');

5. Regex-Based Route Matching

$consumer->apply(ApiKeyMiddleware::class)
->forRoutes(
// Match all routes starting with 'api/'
'#^api/.*$#',
// Exact route matching
'books/special'
);

Route Exclusion Mechanisms

Exclude specific routes from middleware processing:

$consumer->apply(AuthMiddleware::class)
->exclude([
// Exclude public routes
['path' => '#^public/.*$#', 'methods' => ['*']],
// Exclude specific method on a route
['path' => 'login', 'methods' => [RequestMethod::POST]]
]);

Middleware Types

1. Functional Middleware

Inline, anonymous function-based middleware:

$consumer->apply(
function (WP_REST_Request $req, WP_REST_Response $res) {
// Simple header manipulation
$res->header('X-Processed', 'true');
return $req; // Continue processing
}
)->forRoutes('*');

2. Class-Based Middleware

Dependency-injectable, more structured middleware:

#[Injectable]
class AuthMiddleware implements Middleware
{
public function __construct(
private AuthService $authService
) {}

public function use(WP_REST_Request $req, WP_REST_Response $res): WP_REST_Request|WP_REST_Response
{
if (!$this->authService->isAuthenticated($req)) {
$res->set_status(401);
$res->set_data(['error' => 'Unauthorized']);
return $res; // Immediately terminate
//or throw new UnauthorizedHttpException();
}

return $req; // Continue to next middleware
}
}

//Usage
$consumer->apply(
AuthMiddleware::class,
new LoggingMiddleware("BooksModule") // A middleware instance without service dependencies
)->forRoutes('*');

Advanced Middleware Patterns

1. Conditional Middleware

$consumer->apply(
function (WP_REST_Request $req, WP_REST_Response $res) {
// Dynamic middleware logic
if ($req->get_method() === 'POST') {
$res->header('X-Request-Type', 'Create');
}
return $req;
}
)->forRoutes([
['routes' => '*', 'methods' => [RequestMethod::POST, RequestMethod::PUT]]
]);

2. Chained Transformations

$consumer->apply(
function (WP_REST_Request $req) {
// First transformation
$req['timestamp'] = time();
return $req;
}
)->apply(
function (WP_REST_Request $req) {
// Second transformation
$req['processed'] = true;
return $req;
}
)->forRoutes('*');

Use Case Examples

Authentication Middleware

class JwtAuthMiddleware implements Middleware 
{
public function use(WP_REST_Request $req, WP_REST_Response $res): WP_REST_Request|WP_REST_Response
{
$token = $req->get_header('Authorization');

if (!$this->tokenService->validate($token)) {
$res->set_status(401);
$res->set_data(['error' => 'Invalid token']);
return $res; // Terminate request
}

return $req; // Continue processing
}
}

Rate Limiting Middleware

class RateLimitMiddleware implements Middleware 
{
public function use(WP_REST_Request $req, WP_REST_Response $res): WP_REST_Request|WP_REST_Response
{
$clientIp = $req->get_remote_addr();

if ($this->rateLimiter->isLimitExceeded($clientIp)) {
$res->set_status(429);
$res->set_data([
'error' => 'Rate limit exceeded',
'retry_after' => $this->rateLimiter->getRetryDelay()
]);
return $res; // Immediately return error response
}

return $req; // Continue processing
}
}

Best Practices

Middleware Design Guidelines
  • Keep middleware logic concise and focused
  • Prefer immutable transformations
  • Handle errors gracefully
  • Use dependency injection for complex logic
  • Minimize performance overhead
Potential Pitfalls
  • Avoid complex state management in middleware
  • Don't perform heavy computations
  • Be careful with request mutation
  • Implement proper error handling
  • Secure sensitive operations

Performance Considerations

  • Middleware adds minimal processing overhead
  • Prefer lightweight, stateless implementations
  • Cache expensive operations when possible
  • Use functional middlewares for simple transformations

Conclusion

Middleware in ModulesPress offers a flexible, powerful mechanism for intercepting and processing HTTP requests. By understanding its configuration options and execution model, you can create robust, secure, and efficient REST API within your WP plugins.