Havenlytics action hooks are the do_action() events the plugin fires at key moments during its lifecycle, rendering, and data operations. They let you run your own code — logging, CRM sync, custom markup, integrations — without editing a single plugin file. This reference documents every action hook that exists in Havenlytics 3.3.1, grouped by subsystem, with the exact parameters each one passes.
Note: Every Havenlytics hook is prefixed
hvnly_. There are nohavenlytics_hooks. If a hook name is not listed on this page, it does not exist in the plugin — do not rely on it.
How action hooks work in Havenlytics
Havenlytics fires actions with the standard WordPress do_action() function. You subscribe with add_action(), matching the hook name and the number of arguments it passes:
<?php
/**
* Run custom setup after Havenlytics has fully loaded.
* Fired once, at the end of the plugin boot sequence.
*/
add_action( 'hvnly_loaded', function () {
// All Havenlytics services, CPTs and REST routes are now available.
if ( function_exists( 'HVNLY_NAB' ) ) {
// e.g. warm a cache, register an integration, etc.
}
} );
When a hook passes parameters, declare the priority and the argument count in add_action() so WordPress hands them to your callback:
<?php
// hvnly_property_agents_saved passes ( int $property_id, array $agent_ids )
add_action( 'hvnly_property_agents_saved', function ( $property_id, $agent_ids ) {
error_log( sprintf(
'Property %d now has %d assigned agent(s).',
$property_id,
count( $agent_ids )
) );
}, 10, 2 ); // priority 10, accepts 2 arguments
Lifecycle & bootstrap actions
These fire as the plugin and its modules initialize. Use them to register integrations at the right moment.
| Hook | Fires at | Parameters | When it runs |
|---|---|---|---|
hvnly_loaded | havenlytics.php | — | End of boot, after all services are wired. |
hvnly_frontend_services_registered | includes/Frontend.php | — | After frontend services are registered. |
hvnly_database_services_registered | includes/Database/Database.php | array $instances | After database services are registered. |
hvnly_database_service_instantiated | includes/Database/Database.php | string $class, object $service | After each database service is instantiated. |
hvnly_agent_init | includes/Agent/AgentBootstrap.php | AgentBootstrap $this | Agent module initialized. |
hvnly_contact_agent_before_bootstrap | includes/ContactAgent/ContactAgentModule.php | $module | Before the Contact Agent module boots. |
hvnly_contact_agent_bootstrapped | includes/ContactAgent/ContactAgentModule.php | $module | After the Contact Agent module boots. |
hvnly_contact_agent_init | includes/ContactAgent/ContactAgentBootstrap.php | $bootstrap, $module | Contact Agent bootstrap complete. |
hvnly_contact_agent_frontend_registered | includes/ContactAgent/ContactAgentFrontend.php | — | After the Contact Agent frontend registers. |
hvnly_contact_agent_ajax_registered | includes/ContactAgent/AjaxHandler.php | $handler | After Contact Agent AJAX handlers register. |
Settings & cache actions
Fire after configuration changes or cache clears — ideal for invalidating your own caches in sync with Havenlytics.
| Hook | Parameters | When it runs |
|---|---|---|
hvnly_settings_updated | string $group, array $settings | A settings group (or all) was saved or reset. |
hvnly_property_view_type_synced | string $view_type, array $settings | The property view-type option was synced. |
hvnly_cache_cleared | — | All plugin cache was cleared. |
hvnly_cache_pattern_cleared | string $pattern | Cache entries matching a pattern were cleared. |
hvnly_cache_expired_cleared | — | Expired cache entries were cleared. |
hvnly_set_cached_search_results | string $cache_key, mixed $data, int $duration | Search results were written to cache. |
hvnly_shortcode_caches_cleared | — | Shortcode output caches were cleared. |
hvnly_property_query_cache_set | string $key, mixed $payload, int $ttl, array $options | A property query result was cached. |
hvnly_property_query_cache_invalidated | int $generation | The property query cache generation was bumped. |
hvnly_cleared_terms_cache | string $taxonomy | Search-terms cache cleared for a taxonomy. |
hvnly_cleared_all_search_cache | — | All search caches cleared. |
hvnly_cleared_property_cache | int $post_id | Cached search results for a property cleared. |
Template & layout actions
These are the injection points inside Havenlytics templates. Hook them to add markup around content regions, single-property sections, or the property loop.
| Hook | Parameters | When it runs |
|---|---|---|
hvnly_before_main_content | — | Before the main content region (single, archive, taxonomy, search shortcode). |
hvnly_after_main_content | — | After the main content region. |
hvnly_single_property_elements | — | Single-property element render point. |
hvnly_single_property_header | — | Single-property header section. |
hvnly_single_property_layout_grid | — | Single-property grid layout. |
hvnly_single_property_main_content | — | Single-property main content. |
hvnly_single_property_sidebar | — | Single-property sidebar. |
hvnly_single_property_similar_properties | — | Similar-properties section. |
hvnly_single_agent_header | — | Single-agent header. |
hvnly_single_agent_profile_row | — | Single-agent profile row. |
hvnly_single_agent_listings_section | — | Single-agent listings section. |
hvnly_single_agent_main_content | — | Single-agent main content. |
hvnly_single_agent_sidebar | — | Single-agent sidebar. |
hvnly_before_single_agency / hvnly_after_single_agency | array $agency, WP_Term $term | Around single-agency content. |
hvnly_before_property_taxonomy / hvnly_after_property_taxonomy | — | Around the property-taxonomy (no-results) block. |
hvnly_property_loop_start / hvnly_property_loop_end | — | At the start and end of the property loop. |
hvnly_before_template_part / hvnly_after_template_part | string $template_name, string $template_path, string $located, array $args | Around every template part loaded via hvnly_get_template(). |
hvnly_get_template_part_{$slug} | string $slug, string $name, array $args | Dynamic — fires per template-part slug (e.g. hvnly_get_template_part_content). |
Tip:
hvnly_get_template_part_{$slug}is a dynamic hook. The{$slug}is replaced by the template-part slug being loaded, sohvnly_get_template_part('content','single-property')fireshvnly_get_template_part_content.
Archive, card & shortcode actions
| Hook | Parameters | When it runs |
|---|---|---|
hvnly_before_archive_property / hvnly_after_archive_property | — | Around each property archive card. |
hvnly_before_archive_agent / hvnly_after_archive_agent | — | Around each agent archive card. |
hvnly_before_archive_agency / hvnly_after_archive_agency | — | Around each agency archive card. |
hvnly_before_shortcode_loop / hvnly_after_shortcode_loop | array $atts | Around a shortcode property loop (grid/list). |
hvnly_after_shortcode_assets_enqueued | — | After shortcode assets are enqueued. |
Agent & agency actions
| Hook | Parameters | When it runs |
|---|---|---|
hvnly_agent_post_type_registered | string $slug | The hvnly_agent CPT was registered. |
hvnly_agent_agency_taxonomy_registered | string $taxonomy | The hvnly_agent_agency taxonomy was registered. |
hvnly_property_agents_saved | int $property_id, array $agent_ids | A property’s assigned agents were saved. |
hvnly_agent_profile_saved | int $agent_id | An agent profile was saved. |
hvnly_agent_delete_wizard_completed | int $agent_id, int $user_id, mixed $target | The agent delete wizard finished. |
Agent Workspace & portal actions
| Hook | Parameters | When it runs |
|---|---|---|
hvnly_workspace_init | WorkspaceBootstrap $this | The Workspace module initialized. |
hvnly_workspace_enqueue_assets | — | The Workspace shortcode requested asset enqueue. |
hvnly_workspace_assets_registered | array $asset | A Workspace asset was registered. |
hvnly_workspace_assets_enqueued | — | Workspace assets were enqueued. |
hvnly_workspace_page_created | int $page_id | The Workspace page was auto-created. |
hvnly_workspace_before_template / hvnly_workspace_after_template | string $path, string $template, array $args | Around a Workspace template load. |
hvnly_workspace_audit | string $event, array $context | A Workspace security-audit event. |
hvnly_portal_notification_created | int $id, array $row | A portal notification row was created. |
hvnly_workspace_agent_activity | int $user_id, string $activity | Agent activity (login / workspace visit) recorded. |
hvnly_property_workflow_transitioned | int $post_id, string $to, string $from, int $user_id | A property workflow status transitioned. |
Authentication, identity & provisioning actions
| Hook | Parameters | When it runs |
|---|---|---|
hvnly_workspace_registration_status_changed | int $user_id, string $status, int $agent_id, string $previous | An agent’s registration status changed. |
hvnly_workspace_agent_provisioned | int $agent_id, int $user_id | An Agent CPT was provisioned for a user. |
hvnly_workspace_user_provisioned_for_agent | int $user_id, int $agent_id | A WordPress user was provisioned for an agent. |
hvnly_workspace_identity_link_set | int $agent_id, int $user_id, mixed $current | The agent↔user identity link was set. |
hvnly_identity_verification_logged | array $entry | An identity-verification audit entry was logged. |
Email verification actions
| Hook | Parameters | When it runs |
|---|---|---|
hvnly_email_verification_email_before_send | int $user_id, array $context, bool $is_resend | Just before a verification email is sent. |
hvnly_email_verification_email_sent | int $user_id, bool $is_resend | A verification email was sent. |
hvnly_email_verification_sent | int $user_id | Verification email dispatched (first send). |
hvnly_email_verification_resent | int $user_id | Verification email resent. |
hvnly_email_verification_verified | int $user_id | A user verified their email. |
hvnly_email_verification_expired | int $user_id | A verification token expired. |
hvnly_email_verification_failed | int $user_id, string $reason | A verification attempt failed. |
hvnly_email_verification_admin_verified | int $user_id, int $actor_id | An admin manually verified a user’s email. |
hvnly_email_changed | int $user_id, string $old_email, string $new_email | A user’s email changed (triggers re-verification). |
Email pipeline actions
| Hook | Parameters | When it runs |
|---|---|---|
hvnly_email_import_success_sent | int $import_count, WP_User $user, array $context | The import-success email was sent. |
hvnly_email_property_workflow_sent | bool $sent, string $email_type, int $object_id, array $context | A property workflow email was sent. |
hvnly_email_property_admin_alert_sent | bool $sent, int $object_id, array $admin_context | A property admin-alert email was sent. |
hvnly_workspace_account_email_sent | bool $sent, string $email_type, string $to, array $context | A Workspace account email was sent. |
hvnly_workspace_registration_email_sent | bool $sent, string $email_type, int $user_id, array $context | A registration email was sent. |
hvnly_workspace_registration_admin_alert_sent | bool $sent, WP_User $user, array $admin_context | A registration admin-alert email was sent. |
Contact Agent (inquiry) actions
| Hook | Parameters | When it runs |
|---|---|---|
hvnly_contact_agent_inquiries_table_created | — | The inquiries database table was created. |
hvnly_contact_agent_inquiry_replies_table_created | — | The inquiry-replies table was created. |
hvnly_contact_agent_inquiry_created | int $inquiry_id, array $row | A new inquiry was persisted. |
hvnly_contact_agent_inquiry_status_updated | int $inquiry_id, string $status | An inquiry’s status was updated. |
hvnly_contact_agent_inquiry_deleted | int $inquiry_id | An inquiry was deleted. |
hvnly_contact_agent_inquiry_validated | array $persist_payload | An inquiry payload passed validation (AJAX). |
hvnly_contact_agent_inquiry_notified | int $inquiry_id, array $results, array $context | Inquiry notifications were sent. |
hvnly_contact_agent_inquiry_reply_sent | int $reply_id, int $inquiry_id, int $user_id, array $inquiry | A reply to an inquiry was sent. |
Worked examples
1. Inject a banner above every property archive card
<?php
add_action( 'hvnly_before_archive_property', function () {
echo '<div class="my-featured-ribbon">New this week</div>';
} );
2. Push new inquiries into an external CRM
<?php
add_action( 'hvnly_contact_agent_inquiry_created', function ( $inquiry_id, $row ) {
// $row contains sender_name, sender_email, property_id, message, etc.
wp_remote_post( 'https://crm.example.com/api/leads', array(
'timeout' => 5,
'headers' => array( 'Content-Type' => 'application/json' ),
'body' => wp_json_encode( array(
'name' => $row['sender_name'] ?? '',
'email' => $row['sender_email'] ?? '',
'property' => $row['property_id'] ?? 0,
'source' => 'havenlytics',
) ),
) );
}, 10, 2 );
3. Notify a Slack channel when an agent is approved
<?php
add_action( 'hvnly_workspace_registration_status_changed', function ( $user_id, $status, $agent_id, $previous ) {
if ( 'approved' !== $status ) {
return;
}
$user = get_userdata( $user_id );
wp_remote_post( 'https://hooks.slack.com/services/XXX/YYY/ZZZ', array(
'body' => wp_json_encode( array(
'text' => sprintf( 'Agent approved: %s', $user ? $user->user_email : $user_id ),
) ),
) );
}, 10, 4 );
Best practices
- Match the argument count. If a hook passes two parameters, register with
add_action( $hook, $cb, 10, 2 ). Omitting the count means your callback silently receives fewer arguments. - Register on
hvnly_loadedor later when your integration depends on Havenlytics services (HVNLY_NAB(), CPTs, REST routes). - Keep template-hook callbacks output-only. Hooks like
hvnly_before_main_contentrun mid-render — echo markup, don’t perform heavy queries there. - Prefer filters for data changes. Actions are for side effects; to change property data, queries, or template paths, use the corresponding Havenlytics filter hooks instead.
Performance recommendations
Performance: Actions that fire inside loops —
hvnly_before_archive_property,hvnly_property_loop_start,hvnly_get_template_part_{$slug}— run once per item. Avoid database calls or remote requests inside them; precompute data onhvnly_loadedor cache it.
- Offload slow work (CRM sync, webhooks) from request-time hooks by scheduling it with
wp_schedule_single_event()and processing it via WP-Cron. - Use the cache actions (
hvnly_cache_cleared,hvnly_property_query_cache_invalidated) to invalidate your own caches in lockstep, rather than clearing them on every request.
Security notes
Security: Hook payloads are data, not trusted output. Escape everything you print inside template actions with
esc_html(),esc_attr(), oresc_url(), and treat inquiry fields (hvnly_contact_agent_inquiry_created) as untrusted user input before sending them anywhere.
- Never expose user email, tokens, or identity data from
hvnly_workspace_*andhvnly_email_verification_*hooks to the front end or logs in production. - When calling external services from an action, use
wp_remote_post()with a short timeout and validate/sanitize the payload first — a hook firing is not authorization to leak PII.
Common mistakes
- Forgetting the argument-count parameter in
add_action(), so parameters arrive asnull. - Trying to modify data inside an action — actions do not use return values; use the matching filter hook instead.
- Assuming a hook fires on every request — many (e.g.
hvnly_workspace_*) only fire in the Agent Workspace context, and admin-only actions never fire on the front end.