# Policies & Permissions Policies control who can access your REST API endpoints. They are checked before your controller method runs — if the policy returns `false`, the request is rejected with a `403` response. ## Creating a Policy Extend `BasePolicy` and implement `verifyRequest()`: ```php currentUserCan('fcrm_manage_contacts'); } } ``` ### Binding a Policy to Routes Use `withPolicy()` when registering routes: ```php $app->router ->prefix('my-plugin') ->withPolicy('MyPlugin\Policies\MyPolicy') ->group(function ($router) { $router->get('/items', 'MyPlugin\Controllers\ItemController@index'); $router->post('/items', 'MyPlugin\Controllers\ItemController@store'); $router->delete('/items/{id}', 'MyPlugin\Controllers\ItemController@destroy')->int('id'); }); ``` ## Method-Specific Permissions The framework automatically matches policy method names to controller method names. If a policy method matching the controller method exists, it runs **instead of** `verifyRequest()`. ```php class MyPolicy extends BasePolicy { // Fallback for any route without a specific policy method public function verifyRequest(Request $request) { return $this->currentUserCan('fcrm_read_contacts'); } // Runs for ItemController@store public function store(Request $request) { return $this->currentUserCan('fcrm_manage_contacts'); } // Runs for ItemController@destroy public function destroy(Request $request) { return $this->currentUserCan('fcrm_manage_contacts_delete'); } } ``` With this setup: - `GET /items` → calls `verifyRequest()` → requires `fcrm_read_contacts` - `POST /items` → calls `store()` → requires `fcrm_manage_contacts` - `DELETE /items/{id}` → calls `destroy()` → requires `fcrm_manage_contacts_delete` ### Read/Write Pattern A common pattern is to check the HTTP method in `verifyRequest()`: ```php public function verifyRequest(Request $request) { if ($request->method() == 'GET') { return $this->currentUserCan('fcrm_read_contacts'); } return $this->currentUserCan('fcrm_manage_contacts'); } ``` ## FluentCRM Capabilities FluentCRM defines 16 granular capabilities. Use `$this->currentUserCan()` in your policies to check them. ### Dashboard | Capability | Description | |------------|-------------| | `fcrm_view_dashboard` | View the CRM dashboard | ### Contacts | Capability | Description | |------------|-------------| | `fcrm_read_contacts` | View contacts | | `fcrm_manage_contacts` | Add, update, and import contacts | | `fcrm_manage_contacts_delete` | Delete contacts | | `fcrm_manage_contacts_export` | Export contacts | ### Tags, Lists & Companies | Capability | Description | |------------|-------------| | `fcrm_manage_contact_cats` | Create and update tags, lists, companies, segments | | `fcrm_manage_contact_cats_delete` | Delete tags, lists, companies, segments | ### Emails | Capability | Description | |------------|-------------| | `fcrm_read_emails` | View emails and campaigns | | `fcrm_manage_emails` | Create, edit, and send emails | | `fcrm_manage_email_delete` | Delete emails | | `fcrm_manage_email_templates` | Manage email templates | ### Forms | Capability | Description | |------------|-------------| | `fcrm_manage_forms` | Manage subscription forms | ### Automations | Capability | Description | |------------|-------------| | `fcrm_read_funnels` | View automations | | `fcrm_write_funnels` | Create and edit automations | | `fcrm_delete_funnels` | Delete automations | ### Settings | Capability | Description | |------------|-------------| | `fcrm_manage_settings` | Manage CRM settings | ::: tip WordPress administrators (`manage_options`) automatically have all FluentCRM capabilities. ::: ## Custom Permissions You can register your own capabilities that appear in FluentCRM's permission manager: ```php add_filter('fluent_crm/readable_permissions', function ($permissions) { $permissions['my_plugin_manage'] = [ 'title' => __('My Plugin - Manage', 'my-plugin'), 'depends' => [], ]; $permissions['my_plugin_delete'] = [ 'title' => __('My Plugin - Delete', 'my-plugin'), 'depends' => ['my_plugin_manage'], ]; return $permissions; }); ``` The `depends` array defines prerequisite capabilities — a user must have all listed capabilities before this one can be assigned. Then use them in your policy: ```php public function verifyRequest(Request $request) { return $this->currentUserCan('my_plugin_manage'); } public function destroy(Request $request) { return $this->currentUserCan('my_plugin_delete'); } ``` ## Middleware Routes support `before` and `after` middleware for cross-cutting concerns like logging or rate limiting. ### Before Middleware Runs before the permission check. Can modify the request or block execution: ```php $app->router ->prefix('my-plugin') ->withPolicy('MyPlugin\Policies\MyPolicy') ->before('MyPlugin\Middleware\LogRequest') ->group(function ($router) { $router->get('/items', 'MyPlugin\Controllers\ItemController@index'); }); ``` ```php method() . ' ' . $request->url()); return $next($request); } } ``` ### After Middleware Runs after the response is generated. Can transform the response: ```php $app->router ->prefix('my-plugin') ->after('MyPlugin\Middleware\AddHeaders') ->group(function ($router) { // ... }); ``` ### Execution Order 1. **Before middleware** pipeline 2. **Policy** permission check (`verifyRequest` or method-specific) 3. **Controller** method 4. **After middleware** pipeline ## Complete Example A full plugin with policy, custom permissions, and method-specific authorization: ```php // my-plugin.php add_action('fluentcrm_loaded', function ($app) { $app->router ->prefix('my-reports') ->withPolicy('MyPlugin\Policies\ReportPolicy') ->group(function ($router) { $router->get('/', 'MyPlugin\Controllers\ReportController@index'); $router->post('/', 'MyPlugin\Controllers\ReportController@create'); $router->get('/{id}', 'MyPlugin\Controllers\ReportController@show')->int('id'); $router->delete('/{id}', 'MyPlugin\Controllers\ReportController@destroy')->int('id'); }); }); // Register custom capabilities add_filter('fluent_crm/readable_permissions', function ($permissions) { $permissions['my_plugin_read_reports'] = [ 'title' => __('My Plugin - View Reports', 'my-plugin'), 'depends' => [], ]; $permissions['my_plugin_manage_reports'] = [ 'title' => __('My Plugin - Manage Reports', 'my-plugin'), 'depends' => ['my_plugin_read_reports'], ]; return $permissions; }); ``` ```php currentUserCan('my_plugin_read_reports'); } public function create(Request $request) { return $this->currentUserCan('my_plugin_manage_reports'); } public function destroy(Request $request) { return $this->currentUserCan('my_plugin_manage_reports'); } } ``` **Source:** `app/Http/Policies/BasePolicy.php`, `app/Services/PermissionManager.php`, `vendor/wpfluent/framework/src/WPFluent/Http/Route.php`