Developer documentation for the bulk action subsystem in the WPResidence real estate CRM. Covers the AJAX endpoints, operations matrix, and helper functions in libs/bulk-functions.php.
AJAX Endpoints
| Action | Entity |
|---|---|
| wpestate_crm_bulk_contacts | Contacts |
| wpestate_crm_bulk_deals | Deals |
| wpestate_crm_bulk_tasks | Tasks |
| wpestate_crm_bulk_activities | Activities |
All four endpoints verify nonce via check_ajax_referer(‘wpestate_crm_nonce’, ‘security’).
Common Request Parameters
- ids – array of integer IDs.
- operation – whitelisted operation string (see per-entity list below).
- value – optional value used by operations that need one (agent ID for bulk_assign_agent, stage name for bulk_change_stage, tag string for bulk_add_tag).
Response
JSON on success: { count: int } – number of rows affected.
Operations Matrix
Contacts
- bulk_delete – iterates and calls wpestate_crm_delete_contact().
- bulk_change_stage – updates lifecycle_stage on each row.
- bulk_assign_agent – updates assigned_agent_id on each row.
- bulk_add_tag – appends to tags CSV string, preventing duplicates.
Deals
- bulk_delete
- bulk_change_stage – updates stage (note: stage for deals vs status for other entities).
Tasks
- bulk_delete
- bulk_mark_complete – sets task_status=’Completed’ and completed_at=NOW().
Activities
- bulk_delete only. Activities are append-only by design.
Helper Functions
| Function | Purpose |
|---|---|
| wpestate_crm_validate_entity_type($type) | Whitelist check: contacts, leads, enquiries, deals, tasks |
| wpestate_crm_get_entity_table_info($type) | Returns {table, pk} for the entity |
| wpestate_crm_bulk_delete($type, $ids) | Generic delete using prepared IN (…) clause |
| wpestate_crm_bulk_update_status($type, $ids, $new_status) | Generic status update with per-entity column mapping |
SQL Safety
The bulk_delete helper builds IN clauses with parameter placeholders and calls $wpdb->prepare(). There is no direct interpolation of the ID array into SQL. The $ids input is cast to an integer array with array_map(‘absint’, $ids) before the prepare call.
Permissions
Each handler calls wpestate_crm_user_can($entity, ‘edit’) or wpestate_crm_user_can($entity, ‘delete’) depending on operation. Per-row ownership is also enforced for non-admins. Rows not owned by the user are silently skipped, so the affected count reflects reality.
Triggers and Side Effects
Bulk operations fire the same hooks as single-row operations:
- Bulk delete fires wpestate_crm_after_delete_* per row.
- Bulk change-stage fires wpestate_crm_after_update_* per row, which cascades into webhooks, automations, and HubSpot sync.
On large selections this can generate significant load. Consider wrapping bulk calls in remove_action() before and re-adding after if you need to suppress cascades for a specific import task.
Extending
- Add your own operations by filtering the whitelist in a child plugin.
- For custom entity types, extend the get_entity_table_info() map and register a new wp_ajax_wpestate_crm_bulk_{type} handler.