Developer documentation for the permissions layer in the WPResidence real estate CRM. Entry point: libs/permissions.php.
The manage_crm Capability
Registered on activation via wpestate_crm_register_capabilities(); added to the administrator role by default. Removed on deactivation via wpestate_crm_remove_capabilities().
Every CRM operation first checks current_user_can(‘manage_crm’). Users without this capability see a permission error, or a redirect to the login page for frontend CRM templates.
user_can API
wpestate_crm_user_can( $module, $action = 'view' )
- $module: contacts, deals, tasks, activities, automations, settings, import_export.
- $action: view, edit, delete (reserved for future granularity; currently not enforced beyond module-level).
Returns true if the user’s role grants access, false otherwise.
Default Permissions Matrix
| Role | Contacts | Deals | Tasks | Activities | Automations | Settings | Import/Export |
|---|---|---|---|---|---|---|---|
| administrator | all | all | all | all | all | all | all |
| wpresidence_agent / wpresidence_agent_role | own | own | own | own | none | none | own |
| author | own | own | own | own | none | none | none |
Levels: all (full access), own (scoped to ownership), none (denied). Seeded into wpestate_crm_permissions option on activation by wpestate_crm_seed_permissions().
Ownership Scope
wpestate_crm_get_ownership_where( $user_id = null )
Returns a SQL WHERE fragment:
- Administrators: ‘1=1’ – no restriction.
- Agents (wpresidence_agent, wpresidence_agent_role): (user_id = %d OR assigned_agent_id = %d).
- Authors and others: user_id = %d.
Used throughout CRUD get_* functions and stats queries.
Per-Record Ownership Check
wpestate_crm_user_owns_contact( $contact_id )
Used in AJAX mutation handlers to prevent a user from editing a record they can see by ID but do not actually own. This closes the gap where a scope filter lets a user read a list, but they might still craft a mutation request for a row they do not own.
Capability Lifecycle
- Activation → wpestate_crm_register_capabilities() adds manage_crm to administrator and seeds the permissions matrix.
- Deactivation → wpestate_crm_remove_capabilities() removes the capability from all roles.
- Uninstall → uninstall.php also removes the capability, as defense in depth.
Overriding the Matrix
The wpestate_crm_permissions option contains the matrix. To customize:
$perms = get_option('wpestate_crm_permissions', []); $perms['editor'] = [ 'contacts' => 'all', 'deals' => 'own', 'tasks' => 'own', 'activities' => 'all', 'automations' => 'none', 'settings' => 'none', 'import_export' => 'own', ]; update_option('wpestate_crm_permissions', $perms);
The wpestate_crm_user_can() function reads from this option first. Any custom role appearing in the matrix is honored.
Security Notes
- All mutation endpoints combine capability check, nonce, and per-record ownership check. Missing any one is a bug and should be reported.
- SQL queries use $wpdb->prepare() with placeholders. The ownership WHERE fragment is always concatenated with prepared values, never raw user input.
Filter Hooks (If You Fork)
No apply_filters() hooks exist in the current permission code. If you need to alter behavior cleanly, either update the wpestate_crm_permissions option at runtime via an init hook, or override wpestate_crm_user_can by declaring it before the plugin file loads. PHP’s function-if-not-exists pattern is not used here, so in practice you would need to replace the plugin file or fork the function.