|
/ Documentation /Plugin Integration/ SureContact Third-Party Integration — Step-by-Step Guide

SureContact Third-Party Integration — Step-by-Step Guide

This document explains how external WordPress plugins can register their own integrations with SureContact, so they appear in the Integrations admin UI, participate in the rule engine, and send contacts to the SureContact CRM.

It assumes you are familiar with WordPress plugin development and basic OOP in PHP.

High-Level Flow

  • You register your integration via the surecontact_available_integrations filter.
  • SureContact loads your class through Integrations_Loader, as long as your dependency is present and the integration is enabled.
  • Your integration class extendsSureContact\Integrations\Base_Integration and:
    • Hooks into your plugin’s events (form submissions, orders, etc.).
    • Builds/normalizes contact data.
    • Calls send_to_crm() to sync contacts.
  • The SureContact rule engine:
    • Uses your integration’s item types, events, items, fields and settings.
    • Stores configuration in SureContact’s integrations database table.

1. Registering Your Integration

SureContact exposes a filter that lets you register integrations from any plugin:

  • Filtersurecontact_available_integrations
  • Locationincludes/class-integrations-loader.php

Your plugin should add to this filter after SureContact is active and before init priority 5 (when SureContact initializes integrations). The safest choice is to hook on plugins_loaded.

1.1. Basic Registration Example

In your main plugin file (e.g. my-addon/my-addon.php):

add_filter( 'surecontact_available_integrations', function( $integrations ) {
	$integrations['my_addon'] = array(
		// Human‑readable name shown in the Integrations UI.
		'name'        => 'My Addon',

		// Fully-qualified PHP class name that extends SureContact\Integrations\Base_Integration.
		'class'       => 'MyAddon\\SureContact_Integration',

		// Absolute path to your integration class file.
		// External integrations SHOULD use "file_path" instead of "file".
		'file_path'   => plugin_dir_path( __FILE__ ) . 'includes/class-surecontact-integration.php',

		// A class or function name that indicates your plugin is active.
		// SureContact only attempts to load the integration if this exists.
		'dependency'  => 'MyAddon\\Plugin',

		// WordPress plugin basename for your main plugin.
		// Used by SureContact to show activation/install hints and to auto‑activate via REST.
		'plugin_file' => 'my-addon/my-addon.php',

		// Optional: URL to an icon for the Integrations UI (e.g. SVG or PNG).
		// If omitted, the UI falls back to initials (first 2 letters of the name).
		'icon_url'    => plugin_dir_url( __FILE__ ) . 'assets/icons/my-addon.svg',
	);

	return $integrations;
} );

1.2. Configuration Array Reference

Each integration entry is an associative array with the following keys:

  • name (string, required):
    Display name (e.g. "My Addon").
  • class (string, required):
    Fully-qualified class name that must extend SureContact\Integrations\Base_Integration.
  • file (string, internal-only):
    Relative path under surecontact/includes/integrations/.
    Do not use this for third-party plugins. Use file_path instead.
  • file_path (string, recommended for third-party):
    Absolute path to your integration file (e.g. plugin_dir_path( __FILE__ ) . 'includes/class-surecontact-integration.php').
  • dependency (string, recommended):
    class name or function name that must exist for the integration to be considered “available”.
    If this is missing or does not exist, SureContact will skip loading your integration.
  • plugin_file (string, recommended):
    WordPress plugin basename — the plugin directory and main file relative to wp-content/plugins/ (e.g. 'my-addon/my-addon.php').
    Used by the admin UI and REST API to:
    • Detect if your plugin is installed.
    • Activate/deactivate the plugin via /integration-rules/activate-plugin.
  • icon_url (string, optional):
    URL to an icon image (SVG or PNG) displayed in the Integrations UI. If omitted, the UI shows a fallback initials badge (first 2 letters of the name). Can also be set via $this->icon_url in your class constructor (class value takes priority when the instance is available).
  • plugin_dependencies (array, optional):
    Additional plugin basenames that must be active before your main plugin can be activated. Used by the /integration-rules/activate-plugin endpoint to activate prerequisite plugins first (e.g., Elementor Forms registers array( 'elementor/elementor.php' ) because Elementor Pro requires Elementor). This is separate from get_additional_plugins() on your class, which handles per-item-type plugin requirements.

2. Implementing the Integration Class

Your integration class must:

  • Live in a file pointed to by your file_path entry.
  • Extend SureContact\Integrations\Base_Integration (from your own namespace).
  • Set a stable slug that matches the array key you used in the filter.

2.1. Minimal Skeleton

<?php
namespace MyAddon;

use SureContact\Integrations\Base_Integration;

class SureContact_Integration extends Base_Integration {

	public function __construct() {
		// Slug MUST match the key used in surecontact_available_integrations.
		$this->slug        = 'my_addon';
		$this->name        = 'My Addon';
		$this->description = 'Syncs My Addon events and contacts to SureContact CRM.';
		$this->docs_url    = 'https://example.com/docs/my-addon-surecontact';
		$this->icon_url    = plugin_dir_url( __DIR__ ) . 'assets/icons/my-addon.svg';

		// Optional: a class or function that must exist for this integration
		// to be considered active on the filesystem level.
		$this->dependency  = 'MyAddon\\Plugin';

		parent::__construct();
	}

	/**
	 * Initialize all hooks for this integration.
	 *
	 * This method is called ONLY when the integration is enabled in SureContact.
	 */
	protected function init() {
		// Example: listen to your plugin's events.
		add_action( 'my_addon_form_submitted', array( $this, 'handle_form_submission' ), 10, 2 );
	}

	/**
	 * Handle a form submission (example).
	 *
	 * @param array $submission Raw submission data from your plugin.
	 * @param int   $user_id    Related WordPress user ID (0 if not applicable).
	 */
	public function handle_form_submission( $submission, $user_id = 0 ) {
		// 1) Build or normalize data into SureContact CRM format.
		$data = $this->build_crm_data(
			array(
				'email'      => $submission['email'] ?? '',
				'first_name' => $submission['first_name'] ?? '',
				'last_name'  => $submission['last_name'] ?? '',
			),
			array(
				'my_custom_field' => $submission['custom'] ?? '',
			),
			array(
				'source_form_id' => $submission['form_id'] ?? '',
			)
		);

		// 2) Optionally pass lists/tags/context from your own settings or logic.
		$context = array(
			'list_uuids' => array(), // e.g. mapped from your own config.
			'tag_uuids'  => array(),
		);

		// 3) Send to SureContact CRM (queues or immediate send handled by Contact_Service).
		$result = $this->send_to_crm( $data, $user_id, $context );

		// 4) Optional: handle WP_Error or success for logging.
		if ( is_wp_error( $result ) ) {
			// Your own logging or error handling.
			return;
		}
	}
}

Key points:

  • parent::__construct() is required so Base_Integration can:
    • Initialize Contact_Service and integrations DB access.
    • Register field mapping hooks.
    • Check whether the integration is enabled.
    • Call your init() method only when enabled.
  • Use either:
    • build_crm_data() directly (like form integrations), or
    • normalize_data() plus send_to_crm() for WordPress/user-like data.

3. Participating in the Rule Engine UI

SureContact’s React-based rule engine uses your integration class to:

  • List supported item types (forms, products, videos, etc.).
  • Show events per item type (e.g., completedabandonedsubmitted).
  • Populate item dropdowns with items (forms, products, etc.).
  • Display and save per-item configuration and field mappings.

You can support all of these via a small set of methods on your integration class.

3.1. Declare Item Types

Implement get_item_types() to tell SureContact which item types you support:

public function get_item_types() {
	return array(
		array(
			'key'   => 'form',
			'label' => __( 'Forms', 'surecontact' ),
		),
		array(
			'key'   => 'campaign',
			'label' => __( 'Campaigns', 'surecontact' ),
		),
	);
}

These item types will show in:

  • The Integrations table.
  • The rule builder when users pick an integration and target.

3.2. Declare Events Per Item Type

Implement get_events_by_item_type( $item_type ) to describe which events can trigger rules:

public function get_events_by_item_type( $item_type ) {
	if ( 'form' === $item_type ) {
		return array(
			array(
				'key'   => 'submitted',
				'label' => __( 'Form Submitted', 'surecontact' ),
			),
		);
	}

	if ( 'campaign' === $item_type ) {
		return array(
			array(
				'key'   => 'started',
				'label' => __( 'Campaign Started', 'surecontact' ),
			),
			array(
				'key'   => 'completed',
				'label' => __( 'Campaign Completed', 'surecontact' ),
			),
		);
	}

	return array();
}

The keys you return here (e.g. 'submitted''completed') are used by:

  • The rule engine UI (event dropdown).
  • The integrations DB (event column).
  • Your own logic when reading configuration and deciding when to call send_to_crm().

3.3. Provide Item Lists (Forms, Products, etc.)

The REST endpoint /integration-rules/items/{slug}?type={type} calls your integration to get items.

Note: The methods in sections 3.3 and 3.4 (get_forms()get_item_config_fields()get_item_title()) are not inherited from Base_Integration. They are convention-based methods that the REST API discovers on your class via method_exists(). If absent, they are silently skipped (no error). Exception: get_item_fields() — if absent, the fields endpoint returns a WP_Error (HTTP 400), so you should implement it if your integration uses the field mapping UI. This differs from get_item_types() and get_events_by_item_type(), which are defined in Base_Integration with empty-array defaults that you override.

SureContact constructs the method name dynamically as get_{type}s() (e.g. get_forms()get_products()), so you must implement a method matching each item type key you declared in get_item_types().

Example for type=form:

/**
 * Return all forms for this integration.
 *
 * Each item should have at least: id, title, and type.
 *
 * @return array
 */
public function get_forms() {
	$forms = array();

	// Replace this with your own form retrieval logic.
	foreach ( my_addon_get_forms() as $form ) {
		$forms[] = array(
			'id'    => (string) $form->id,
			'title' => $form->title,
			'type'  => 'form',
		);
	}

	return $forms;
}

When the user opens the rule builder and selects your integration + item type, SureContact will call your method to populate the item dropdown.

3.4. Provide Field Definitions & Item-Level Config

When the admin edits rules for a specific item, SureContact calls:

  • GET /integration-rules/fields?slug={slug}&item_id={id}[&type={type}]

This ultimately calls get_item_fields( $item_id ) (if implemented) on your integration:

/**
 * Return fields for a specific item (for field mapping UI).
 *
 * @param string $item_id Item ID.
 * @return array
 */
public function get_item_fields( $item_id ) {
	// Example structure:
	return array(
		array(
			'key'   => 'email',
			'label' => __( 'Email', 'surecontact' ),
			'type'  => 'email',
		),
		array(
			'key'   => 'first_name',
			'label' => __( 'First Name', 'surecontact' ),
			'type'  => 'text',
		),
		// ...
	);
}

If you want to expose per-item configuration fields (for the right-hand side of the rule editor), implement get_item_config_fields( $item_id, $event = null ):

/**
 * Return event‑specific configuration fields for a given item.
 *
 * @param string      $item_id Item ID (e.g. form ID).
 * @param string|null $event   Event key (e.g. 'submitted').
 * @return array
 */
public function get_item_config_fields( $item_id, $event = null ) {
	unset( $item_id ); // Use in your own implementation.

	// Example for a single event; you can branch by $event.
	return array(
		'add_lists' => array(
			'label'       => __( 'Add to Lists', 'surecontact' ),
			'description' => __( 'Lists to add contacts to when this event fires.', 'surecontact' ),
			'type'        => 'list-select',
			'default'     => array(),
		),
		'add_tags'  => array(
			'label'       => __( 'Add Tags', 'surecontact' ),
			'description' => __( 'Tags to add when this event fires.', 'surecontact' ),
			'type'        => 'tag-select',
			'default'     => array(),
		),
	);
}

The admin UI will:

  • Render these fields.
  • Save values into SureContact’s integrations table as config.
  • Pass the saved configuration back to you when you process events.

4. Using Integration Settings & Mappings in Your Code

SureContact stores integration configuration (global and per-item) in its own database table.
Base_Integration provides helpers to read these settings safely.

Some commonly useful helpers:

  • Global integration settings:
    • get_settings_fields() — you define field schema for the global settings UI.
    • get_settings() / get_setting( $key, $default ) — read values.
    • is_setting_enabled( $key, $default ) — typical boolean checks.
  • Metadata mapping (IDs → UUIDs):
    • get_metadata_mapping( $type )
    • update_metadata_mapping( $type, $mappings )
    • convert_ids_to_uuids( $external_ids, $type )
  • Lists/tags merging:
    • Override should_use_global_lists_tags( $context ) if you want to merge global lists/tags with context-specific ones.
    • prepare_lists_and_tags( $data, $user_id, $context ) (called automatically by send_to_crm()).

Use these helpers to:

  • Respect global settings and per-item rules.
  • Map your own IDs to SureContact list/tag UUIDs.
  • Avoid duplicating persistence logic in your plugin.

5. Lifecycle Hooks You Can Rely On

SureContact fires several hooks around integrations and contact sync that may be useful in your plugin or for debugging.

5.1. Filter: surecontact_available_integrations

  • Type: Filter
  • LocationIntegrations_Loader::register_integrations()
  • Signature:
/**
 * @param array $integrations Associative array of slug => config.
 * @return array
 */
apply_filters( 'surecontact_available_integrations', $integrations );

Use this to register or modify integrations, as described in section 1.

5.2. Action: surecontact_integration_loaded

  • Type: Action
  • Location: After each integration instance is created in load_integrations()
  • Signature:
/**
 * @param string                                      $slug     Integration slug.
 * @param \SureContact\Integrations\Base_Integration $instance Integration instance.
 */
do_action( 'surecontact_integration_loaded', $slug, $instance );

Use this if you need to:

  • Inspect or further configure integrations after they are loaded.
  • Attach cross‑integration behavior or logging.

5.3. Action: surecontact_integrations_loaded

  • Type: Action
  • Location: After all integrations have been processed in load_integrations()
  • Signature:
/**
 * @param array<string, \SureContact\Integrations\Base_Integration> $loaded_integrations
 */
do_action( 'surecontact_integrations_loaded', $loaded_integrations );

Useful for:

  • Performing logic that depends on the full set of loaded integrations.
  • Diagnostics or health checks.

5.4. Action: surecontact_contact_synced

  • Type: Action
  • Location: At the end of Base_Integration::send_to_crm() on immediate success only
  • Signature:
/**
 * Fires after a contact has been successfully synced to the CRM.
 *
 * Only fires on immediate success (not queued, not errored).
 *
 * @param string $slug    Integration slug.
 * @param int    $user_id WordPress user ID (0 if not applicable).
 * @param array  $data    Normalized data sent to the CRM.
 * @param array  $result  API response from the CRM.
 */
do_action( 'surecontact_contact_synced', $this->slug, $user_id, $data, $result );

You can hook into this from any plugin to:

  • Log successful syncs.
  • Trigger follow‑up actions (e.g., enqueue your own jobs).
  • Maintain additional local metadata based on CRM responses.

6. Activation, Availability, and Enabling

There are three separate concepts you should keep in mind:

  • Filesystem registration:
    Whether your integration is present in the surecontact_available_integrations array and its dependency exists. This controls:
    • Whether the integration shows up in the admin UI.
    • Whether the REST API considers it a valid integration.
  • WordPress plugin activation:
    Whether your own plugin (and any additional plugin dependencies) is active:
    • Controlled by WordPress and/or SureContact’s /integration-rules/activate-plugin endpoint.
    • Uses plugin_file and any additional plugin metadata.
  • Integration enabled/disabled in SureContact:
    Whether your integration is enabled in the SureContact UI:
    • Stored in SureContact’s custom integrations table (status column).
    • Checked inside Base_Integration::__construct() via is_enabled().
    • Only when enabled does SureContact call your init() method.

As a third‑party developer, you generally do not need to manipulate the database directly. Use:

  • The SureContact admin UI.
  • The existing REST endpoints (e.g. /integration-rules/toggle/integration-rules/settings/save) if you are building automation.

7. Best Practices & Recommendations

  • Use a stable slug:
    • The slug is used everywhere: database keys, REST API URLs, filter keys, and UI.
    • Changing it later will break existing configurations.
  • Avoid heavy logic in the constructor:
    • Put hooks and heavy setup in init().
    • The constructor is called even when creating temporary instances for metadata.
  • Keep get_item_fields() and get_item_config_fields() fast:
    • They are called from the admin UI.
    • Avoid unnecessary remote calls; cache where possible.
  • Respect existing patterns:
    • Reuse the standard list/tag field structures provided by Base_Integration::get_standard_list_tag_fields() where appropriate.
    • Use build_crm_data() and send_to_crm() instead of calling lower-level API clients directly.
  • Handle WP_Error from send_to_crm():
    • send_to_crm() may return WP_Error (validation, disabled sync, etc.) or a successful response/queue info array.
    • Always wrap calls with is_wp_error() before assuming success.

8. Quick Checklist

  1.  Add a surecontact_available_integrations filter in your plugin.
  2.  Provide nameclassfile_pathdependency, and plugin_file.
  3.  Implement a class extending SureContact\Integrations\Base_Integration.
  4.  Set a stable $slug matching your filter key.
  5.  Implement init() and hook into your plugin’s events.
  6.  Implement get_item_types() and get_events_by_item_type() for rule support.
  7.  Implement get_{type}s() and/or get_item_fields() to populate the UI.
  8.  Optionally implement get_item_config_fields() and get_settings_fields() for additional config.
  9.  Use build_crm_data() / normalize_data() + send_to_crm() to sync contacts.
  10.  (Optional) Hook into surecontact_contact_synced for post‑sync actions.

Was this doc helpful?
What went wrong?

We don't respond to the article feedback, we use it to improve our support content.

Need help? Contact Support
On this page
Scroll to Top