__('Intercom', 'advanced-form-integration'), 'tasks' => [ 'create_contact' => __('Create Contact', 'advanced-form-integration') ] ]; return $actions; } add_filter('adfoin_settings_tabs', 'adfoin_intercom_settings_tab', 10, 1); function adfoin_intercom_settings_tab($providers) { $providers['intercom'] = __('Intercom', 'advanced-form-integration'); return $providers; } add_action('adfoin_settings_view', 'adfoin_intercom_settings_view', 10, 1); function adfoin_intercom_settings_view($current_tab) { if ($current_tab !== 'intercom') return; $title = __('Intercom', 'advanced-form-integration'); $key = 'intercom'; $arguments = wp_json_encode([ 'platform' => $key, 'fields' => [ ['key' => 'accessToken', 'label' => __('Access Token', 'advanced-form-integration'), 'hidden' => true], ] ]); $instructions = __('Go to your Intercom Developer Hub at https://developers.intercom.com/building-apps/docs/setting-up and create an app to get your Access Token. Make sure to add "Read and write all contact data" and "Read and write all ticket data" permissions.', 'advanced-form-integration'); echo adfoin_platform_settings_template($title, $key, $arguments, $instructions); } add_action('wp_ajax_adfoin_get_intercom_credentials', 'adfoin_get_intercom_credentials'); function adfoin_get_intercom_credentials() { adfoin_verify_nonce(); wp_send_json_success(adfoin_read_credentials('intercom')); } add_action('wp_ajax_adfoin_save_intercom_credentials', 'adfoin_save_intercom_credentials'); function adfoin_save_intercom_credentials() { adfoin_verify_nonce(); if ($_POST['platform'] === 'intercom') { $data = adfoin_array_map_recursive('sanitize_text_field', $_POST['data']); adfoin_save_credentials('intercom', $data); } wp_send_json_success(); } add_action('wp_ajax_adfoin_get_intercom_fields', 'adfoin_get_intercom_fields'); function adfoin_get_intercom_fields() { adfoin_verify_nonce(); wp_send_json_success(array( array('key' => 'email', 'value' => 'Email', 'description' => 'Required. An existing contact with this email is updated instead of duplicated.'), array('key' => 'external_id', 'value' => 'External ID', 'description' => 'External identifier from your system'), array('key' => 'name', 'value' => 'Name', 'description' => 'Full name of the contact'), array('key' => 'phone', 'value' => 'Phone', 'description' => 'Contact phone number'), array('key' => 'role', 'value' => 'Role', 'description' => 'user or lead (default lead). A user can\'t be turned back into a lead.'), array('key' => 'owner_id', 'value' => 'Owner ID', 'description' => 'ID of the team member who owns this contact'), array('key' => 'avatar_image_url', 'value' => 'Avatar Image URL', 'description' => 'URL to contact avatar image'), )); } function adfoin_intercom_credentials_list() { foreach (adfoin_read_credentials('intercom') as $option) { printf('', esc_attr($option['id']), esc_html($option['title'])); } } /* * "user" or "lead" from a mapped value; anything else becomes a lead (with a note). */ function adfoin_intercom_role($value, &$notes) { $value = strtolower(trim((string) $value)); if ($value === 'user' || $value === 'lead') { return $value; } if ($value !== '') { $notes[] = sprintf(__('role "%s" is not user or lead, added as lead', 'advanced-form-integration'), $value); } return 'lead'; } /* * Contact body from mapped values, shared by the free and PRO actions. */ function adfoin_intercom_contact_body($fields, &$notes) { $contact = array('role' => adfoin_intercom_role(isset($fields['role']) ? $fields['role'] : '', $notes)); foreach (array('email', 'external_id', 'name', 'phone') as $key) { if (isset($fields[$key]) && $fields[$key] !== '') { $contact[$key] = $fields[$key]; } } foreach (array('owner_id', 'signed_up_at', 'last_seen_at') as $key) { if (isset($fields[$key]) && is_numeric($fields[$key])) { $contact[$key] = (int) $fields[$key]; } } if (isset($fields['unsubscribed_from_emails']) && $fields['unsubscribed_from_emails'] !== '') { $contact['unsubscribed_from_emails'] = filter_var($fields['unsubscribed_from_emails'], FILTER_VALIDATE_BOOLEAN); } if (!empty($fields['avatar_image_url'])) { $contact['avatar'] = $fields['avatar_image_url']; } return $contact; } /* * Mapped values, parsed and trimmed. */ function adfoin_intercom_collect($data, $posted_data) { $fields = array(); foreach ($data as $key => $value) { if ($key === 'credId' || !is_string($value)) continue; $fields[$key] = trim((string) adfoin_get_parsed_values($value, $posted_data)); } return $fields; } /* * Returns the sanitized email, or '' after logging why the submission was skipped. */ function adfoin_intercom_parse_email($raw, $record) { $email = sanitize_email($raw); if (!$email) { adfoin_intercom_log_skipped( $record, $raw === '' ? __('Not sent: the mapped email field is empty.', 'advanced-form-integration') : sprintf(__('Not sent: "%s" is not a valid email address.', 'advanced-form-integration'), $raw) ); } return $email; } function adfoin_intercom_log_skipped($record, $message) { adfoin_add_to_log(new WP_Error('intercom_not_sent', $message), 'https://api.intercom.io/', array('method' => 'POST'), $record); } /* * The contact ID for an email, '' when there is none, or a WP_Error / failed * response when the search itself failed. */ function adfoin_intercom_find_contact_by_email($email, $cred_id = '') { $response = adfoin_intercom_request('contacts/search', 'POST', array( 'query' => array('field' => 'email', 'operator' => '=', 'value' => $email), ), array(), $cred_id); if (is_wp_error($response) || 200 !== (int) wp_remote_retrieve_response_code($response)) { return is_wp_error($response) ? $response : new WP_Error('intercom_search', adfoin_intercom_error_message($response)); } $result = json_decode(wp_remote_retrieve_body($response), true); return isset($result['data'][0]['id']) ? $result['data'][0]['id'] : ''; } /* * Updates the contact with this email, or creates it. Intercom creates a * second contact for an email it already has, so it is searched first. * A user can't be turned back into a lead, so role is only sent on update * when it is "user". Logs once. */ function adfoin_intercom_upsert_contact($contact, $record, $cred_id, $notes = array()) { $contact_id = adfoin_intercom_find_contact_by_email($contact['email'], $cred_id); if (is_wp_error($contact_id)) { adfoin_intercom_log($contact_id, 'contacts/search', 'POST', array(), $record, $cred_id); return $contact_id; } if ($contact_id) { if ($contact['role'] !== 'user') { unset($contact['role']); } $notes[] = __('existing contact updated', 'advanced-form-integration'); $endpoint = 'contacts/' . $contact_id; $method = 'PUT'; } else { $endpoint = 'contacts'; $method = 'POST'; } $response = adfoin_intercom_request($endpoint, $method, $contact, array(), $cred_id); adfoin_intercom_log($response, $endpoint, $method, $contact, $record, $cred_id, $notes); return $response; } function adfoin_intercom_build_request($endpoint, $method, $data, $cred_id) { $credentials = adfoin_get_credentials_by_id('intercom', $cred_id); $access_token = isset($credentials['accessToken']) ? $credentials['accessToken'] : ''; if ( empty( $access_token ) ) { return new WP_Error( 'intercom_no_account', __( 'No Intercom account is selected, or the account has no Access Token. Check the integration and AFI Settings > Intercom.', 'advanced-form-integration' ) ); } $args = array( 'timeout' => 30, 'method' => $method, 'headers' => array( 'Authorization' => 'Bearer ' . $access_token, 'Content-Type' => 'application/json', 'Accept' => 'application/json', 'Intercom-Version' => '2.15', ), ); if ( in_array( $method, array( 'POST', 'PUT' ), true ) ) { $args['body'] = wp_json_encode($data); } return array('https://api.intercom.io/' . $endpoint, $args); } function adfoin_intercom_request($endpoint, $method = 'POST', $data = array(), $record = array(), $cred_id = '') { $request = adfoin_intercom_build_request($endpoint, $method, $data, $cred_id); if (is_wp_error($request)) { if ($record) { adfoin_add_to_log($request, $endpoint, array('method' => $method, 'body' => $data), $record); } return $request; } list($url, $args) = $request; $response = wp_remote_request($url, $args); // 429 retry — honour Retry-After, clamp 1–30 s, one retry only. if ( ! is_wp_error( $response ) && 429 === (int) wp_remote_retrieve_response_code( $response ) ) { $wait = (int) wp_remote_retrieve_header( $response, 'retry-after' ); if ( $wait < 1 ) { $wait = 1; } if ( $wait > 30 ) { $wait = 30; } sleep( $wait ); $response = wp_remote_request( $url, $args ); } if ($record) { adfoin_add_to_log($response, $url, $args, $record); } return $response; } /* * Intercom's error messages as one line. */ function adfoin_intercom_error_message($response) { if (is_wp_error($response)) { return $response->get_error_message(); } $body = json_decode(wp_remote_retrieve_body($response), true); if (!empty($body['errors']) && is_array($body['errors'])) { return implode(' ', array_filter(wp_list_pluck($body['errors'], 'message'))); } return wp_remote_retrieve_response_code($response) . ' ' . wp_remote_retrieve_response_message($response); } /* * Logs a response that was fetched without a record. */ function adfoin_intercom_log($response, $endpoint, $method, $data, $record, $cred_id, $notes = array()) { $request = adfoin_intercom_build_request($endpoint, $method, $data, $cred_id); if (!is_wp_error($response)) { if (wp_remote_retrieve_response_code($response) >= 300) { $response['response']['message'] = adfoin_intercom_error_message($response); } elseif ($notes) { $response['response']['message'] = sprintf('OK (%s)', implode('; ', $notes)); } } adfoin_add_to_log( $response, is_wp_error($request) ? $endpoint : $request[0], is_wp_error($request) ? array('method' => $method, 'body' => $data) : $request[1], $record ); } add_action('adfoin_action_fields', 'adfoin_intercom_action_fields'); function adfoin_intercom_action_fields() { ?>