# Routing FluentCRM's router is available via the `fluentcrm_loaded` action. All routes you register are served under `/wp-json/fluent-crm/v2/`. ## Registering Routes Hook into `fluentcrm_loaded` to access the `$app->router`: ```php add_action('fluentcrm_loaded', function ($app) { $app->router->get('/my-endpoint', 'MyPlugin\Controllers\MyController@index'); }); ``` This registers a GET endpoint at `/wp-json/fluent-crm/v2/my-endpoint`. ## HTTP Methods The router supports all standard HTTP verbs: ```php $router->get($uri, $callback); $router->post($uri, $callback); $router->put($uri, $callback); $router->patch($uri, $callback); $router->delete($uri, $callback); $router->any($uri, $callback); // responds to all HTTP methods ``` ::: tip FluentCRM's JavaScript REST client sends PUT, PATCH, and DELETE as POST requests with an `X-HTTP-Method-Override` header. The framework handles this automatically. ::: ## Route Callbacks Callbacks can be a `Controller@method` string or a closure: ```php // Controller string (recommended) $router->get('/items', 'MyPlugin\Controllers\ItemController@index'); // Closure $router->get('/ping', function () { return ['status' => 'ok']; }); ``` ## Route Groups Group routes that share a prefix, policy, or namespace: ```php add_action('fluentcrm_loaded', function ($app) { $app->router ->prefix('my-plugin') ->namespace('MyPlugin\Controllers') ->withPolicy('MyPlugin\Policies\MyPolicy') ->group(function ($router) { $router->get('/', 'ItemController@index'); // GET /my-plugin/ $router->get('/items', 'ItemController@list'); // GET /my-plugin/items $router->post('/items', 'ItemController@create'); // POST /my-plugin/items $router->put('/items/{id}', 'ItemController@update'); // PUT /my-plugin/items/{id} $router->delete('/items/{id}', 'ItemController@delete'); // DELETE /my-plugin/items/{id} }); }); ``` ### Group Methods | Method | Description | |--------|-------------| | `prefix($prefix)` | Prepends a URL prefix to all routes in the group | | `namespace($ns)` | Sets the controller namespace so you can use short class names | | `withPolicy($class)` | Applies a policy class for authorization (see [Policies](./rest-api-policies)) | | `group($callback)` | Defines the route group; receives `$router` as argument | All group methods are optional and chainable. You can register routes without a group: ```php $app->router->post('/my-endpoint', 'MyPlugin\Controllers\MyController@create'); ``` ## Route Parameters Define dynamic segments using `{param}` syntax: ```php $router->get('/contacts/{id}', 'ContactController@show'); ``` Parameters are passed as arguments to the controller method: ```php public function show($id) { $contact = Subscriber::findOrFail($id); return $this->sendSuccess(['contact' => $contact]); } ``` ### Parameter Constraints Chain constraint methods to validate parameter formats: | Method | Accepts | |--------|---------| | `int($param)` | Integers only | | `alpha($param)` | Alphabetic characters only | | `alphaNum($param)` | Alphanumeric characters | | `alphaNumDash($param)` | Alphanumeric, dashes, and underscores | | `where($param, $regex)` | Custom regex pattern | ```php // Single constraint $router->get('/contacts/{id}', 'ContactController@show')->int('id'); // Multiple constraints $router->get('/contacts/{id}/{slug}', 'ContactController@show') ->int('id') ->alpha('slug'); // Custom regex $router->get('/reports/{type}', 'ReportController@show') ->where('type', '[a-z_]+'); ``` ## Without Groups Routes registered without `prefix()` or `group()` are available directly under the FluentCRM base URL: ```php add_action('fluentcrm_loaded', function ($app) { $app->router->get('/health-check', function () { return ['status' => 'ok', 'timestamp' => current_time('mysql')]; }); }); // Accessible at: /wp-json/fluent-crm/v2/health-check ``` ## Nested Groups You can nest groups for more complex URL structures: ```php $app->router ->prefix('my-plugin') ->withPolicy('MyPlugin\Policies\MyPolicy') ->group(function ($router) { $router->get('/', 'MyPlugin\Controllers\DashboardController@index'); $router->prefix('reports')->group(function ($router) { $router->get('/', 'MyPlugin\Controllers\ReportController@index'); $router->get('/{id}', 'MyPlugin\Controllers\ReportController@show')->int('id'); }); }); // Routes: // GET /my-plugin/ // GET /my-plugin/reports/ // GET /my-plugin/reports/{id} ``` **Source:** `vendor/wpfluent/framework/src/WPFluent/Http/Router.php`, `vendor/wpfluent/framework/src/WPFluent/Http/Route.php`