Actions & Filters
PrimoCRM exposes WordPress actions (events you can react to) and filters
(values and registries you can modify). All hooks use the primocrm_ prefix.
PrimoCRM itself ships no paid code and no licence checks. Everything the Pro add-on adds, it adds through the hooks on this page, so anything Pro can do here your own plugin can do too.
Action hooks (events)
Section titled “Action hooks (events)”React to these with add_action.
Contact lifecycle
Section titled “Contact lifecycle”| Hook | Arguments | Fires when |
|---|---|---|
primocrm_contact_created |
$contact_id |
A contact is created |
primocrm_contact_updated |
$contact_id, $changed_keys |
A contact is updated ($changed_keys are the changed field names) |
primocrm_contact_deleted |
$contact_id, $email |
A contact is deleted (the address is passed because the row is already gone) |
primocrm_contact_status_changed |
$contact_id, $new_status, $old_status |
A contact’s status changes |
primocrm_contact_unsubscribed |
$contact_id |
A contact unsubscribes |
primocrm_contact_resubscribed |
$contact_id |
A contact opts back in |
primocrm_double_optin_confirmed |
$contact_id |
A contact confirms a double opt-in link |
primocrm_contact_tag_added |
$contact_id, $tag_id |
A tag is applied |
primocrm_contact_tag_removed |
$contact_id, $tag_id |
A tag is removed |
primocrm_contact_list_added |
$contact_id, $list_id |
Added to a list |
primocrm_contact_list_removed |
$contact_id, $list_id |
Removed from a list |
Engagement and forms
Section titled “Engagement and forms”| Hook | Arguments | Fires when |
|---|---|---|
primocrm_form_submitted |
$form_id, $entry_id, $contact_id, $data |
A PrimoCRM form is processed |
primocrm_email_opened |
$contact_id, $campaign_id |
An email open is tracked |
primocrm_email_link_clicked |
$contact_id, $campaign_id, $url |
A tracked link is clicked |
Campaigns and email templates
Section titled “Campaigns and email templates”These are the write side of the campaign and template screens. A plugin that adds its own settings to a campaign stores them here, next to the campaign the user just saved.
| Hook | Arguments | Fires when |
|---|---|---|
primocrm_campaign_saved |
$campaign_id, $request, $is_new |
A campaign is created or updated ($request is the WP_REST_Request) |
primocrm_campaigns_deleted |
$campaign_ids |
One or more campaigns are deleted |
primocrm_email_template_saved |
$template_id, $request, $is_new |
An email template is created or updated |
primocrm_health_check_tick |
none | The five-minute queue health check runs, a ready-made slot for periodic work |
System
Section titled “System”| Hook | Arguments | Fires when |
|---|---|---|
primocrm_loaded |
$plugin |
Inside REST route registration. A catalog handshake, not a reliable boot hook |
primocrm_automations_paused_for_handlers |
$automation_ids |
Automations were paused because a trigger or action handler disappeared |
primocrm_automations_resumed_for_handlers |
$automation_ids |
Those automations were resumed because the handler came back |
Example:
add_action( 'primocrm_contact_created', function ( $contact_id ) { error_log( "New PrimoCRM contact: {$contact_id}" );} );
add_action( 'primocrm_email_link_clicked', function ( $contact_id, $campaign_id, $url ) { // Score the contact, notify a channel, etc.}, 10, 3 );Filter hooks (registries)
Section titled “Filter hooks (registries)”These collect extendable things. Full recipes are in Extending PrimoCRM.
| Filter | Value | Purpose |
|---|---|---|
primocrm_automation_triggers |
array | Register or modify automation triggers |
primocrm_automation_actions |
array | Register or modify automation actions |
primocrm_condition_options |
array (fields, operators) |
Add condition-builder fields and operators |
primocrm_form_field_types |
array (type to class) | Register custom form field types |
primocrm_migration_sources |
array (key to source) | Register migration source providers |
primocrm_smart_code_catalog |
array | Add entries to the smart-code picker |
primocrm_smart_codes |
$content, $contact, $context |
Replace your own smart codes while an email is rendered |
primocrm_mail_providers |
array (id to descriptor) | Register an API email provider, with the settings it needs |
primocrm_smtp_send |
$result, $provider, $atts, $settings |
Do the sending for your provider. Return null and PrimoCRM falls back to wp_mail |
primocrm_email_editors |
array (type to descriptor) | Register an email editor as a template type |
primocrm_double_optin_sources |
array of keys | Which contact sources require double opt-in |
A catalog entry with no registered handler is listed as unavailable rather than
hidden, so give it a requires_plugin string naming what it needs. PrimoCRM
shows that as “Requires X” and refuses to let it be chosen.
Filter hooks (payloads)
Section titled “Filter hooks (payloads)”The REST payload for one campaign or template, on its way to the admin app. Use these to send your own fields to a UI you injected through the JavaScript seams below.
| Filter | Value | Purpose |
|---|---|---|
primocrm_campaign_response |
$campaign, $campaign_id |
Attach your fields to a single campaign response |
primocrm_email_template_response |
$template, $template_id |
Attach your fields to a single template response |
primocrm_pre_send_campaign |
$taken_over, $campaign, $settings, $request |
Return a WP_REST_Response to take the send over entirely. Anything else and PrimoCRM sends normally |
primocrm_campaign_sent_elsewhere |
$handled, $campaign |
Return true when your code already queued this campaign, so the built-in queue builder skips it |
Branding and promotion
Section titled “Branding and promotion”| Filter | Value | Purpose |
|---|---|---|
primocrm_brand_name |
string | The brand name shown in admin |
primocrm_brand_menu_icon |
string | The admin menu icon |
primocrm_brand |
array | The brand descriptor localized to the app |
primocrm_show_upsell |
bool | Return false to remove the “Upgrade” button from the admin header. The Pro add-on does this for you |
primocrm_upgrade_url |
string | Where that button points |
primocrm_show_reports_menu |
bool | Return true when you add a tab through primocrm.reports.tabs, so the WordPress sidebar lists Reports. Off by default, because without a tab the screen has nothing to show. The Pro add-on does this for you |
Filter hooks (behavior and tuning)
Section titled “Filter hooks (behavior and tuning)”| Filter | Value | Purpose |
|---|---|---|
primocrm_send_batch_size |
int | Emails per campaign worker batch |
primocrm_send_rate_per_hour |
int | Campaign send throttle |
primocrm_automation_batch_limit |
int | Rows per automation worker batch |
primocrm_email_body_retention_days |
int | How long rendered email bodies are retained |
primocrm_async_automation_delivery |
bool | Toggle async delivery of automation emails |
primocrm_auto_create_contact_status |
$status, $source |
Status for contacts auto-created by triggers or user sync |
primocrm_require_postal_address |
bool | Whether a postal address is required before a campaign can be sent |
primocrm_trust_proxy_headers |
bool | Whether to trust proxy headers for the submitter IP on forms |
primocrm_migration_step_budget |
float (seconds, default 10) | How long one import or migration request may work before it hands back and the next request continues |
JavaScript hooks (wp.hooks)
Section titled “JavaScript hooks (wp.hooks)”The admin app is a React single-page app, and these wp.hooks filters are how
another plugin puts its own UI inside it. There are no standalone add-on pages.
Each filter returns descriptors with a mount callback, not React elements:
the app and your plugin may be running different React versions, so PrimoCRM
gives you a DOM node and you render into it yourself.
| Filter | Purpose |
|---|---|
primocrm.settings.tabs |
Add a tab to the Settings screen |
primocrm.reports.tabs |
Add a tab to Reports. The Reports screen and its app menu item exist only while something has registered one; for the WordPress sidebar entry, also return true from primocrm_show_reports_menu |
primocrm.campaigns.rowActions |
Add an action to a campaign row |
primocrm.campaignCreate.sections |
Add a section to a numbered step of the campaign wizard |
primocrm.campaignDetails.panels |
Add a panel to the campaign detail screen |
primocrm.emailEditor.init |
Build your editor into the container PrimoCRM renders for your template type |
primocrm.emailEditor.destroy |
Tear that editor down again |