__('Less Annoying CRM', 'advanced-form-integration'),
'tasks' => [
'add_contact' => __('Add Contact', 'advanced-form-integration')
]
];
return $actions;
}
add_filter('adfoin_settings_tabs', 'adfoin_lacrm_settings_tab', 10, 1);
function adfoin_lacrm_settings_tab($providers) {
$providers['lacrm'] = __('Less Annoying CRM', 'advanced-form-integration');
return $providers;
}
add_action('adfoin_settings_view', 'adfoin_lacrm_settings_view', 10, 1);
function adfoin_lacrm_settings_view($current_tab) {
if ($current_tab !== 'lacrm') return;
$title = __('Less Annoying CRM', 'advanced-form-integration');
$key = 'lacrm';
$arguments = wp_json_encode([
'platform' => $key,
'fields' => [
['key' => 'apiToken', 'label' => __('API Token', 'advanced-form-integration'), 'hidden' => true],
]
]);
$instructions = __('Provide your Less Annoying CRM API Token.', 'advanced-form-integration');
echo adfoin_platform_settings_template($title, $key, $arguments, $instructions);
}
add_action('wp_ajax_adfoin_get_lacrm_credentials', 'adfoin_get_lacrm_credentials');
function adfoin_get_lacrm_credentials() {
adfoin_verify_nonce();
wp_send_json_success(adfoin_read_credentials('lacrm'));
}
add_action('wp_ajax_adfoin_save_lacrm_credentials', 'adfoin_save_lacrm_credentials');
function adfoin_save_lacrm_credentials() {
adfoin_verify_nonce();
if ($_POST['platform'] === 'lacrm') {
$data = adfoin_array_map_recursive('sanitize_text_field', $_POST['data']);
adfoin_save_credentials('lacrm', $data);
}
wp_send_json_success();
}
function adfoin_lacrm_credentials_list() {
foreach (adfoin_read_credentials('lacrm') as $option) {
printf('', esc_attr($option['id']), esc_html($option['title']));
}
}
add_action('adfoin_lacrm_job_queue', 'adfoin_lacrm_job_queue', 10, 1);
function adfoin_lacrm_job_queue($data) {
adfoin_lacrm_send_data($data['record'], $data['posted_data']);
}
function adfoin_lacrm_send_data($record, $posted_data) {
$record_data = json_decode($record['data'], true);
if (isset($record_data['action_data']['cl']) && adfoin_check_conditional_logic($record_data['action_data']['cl'], $posted_data)) {
return;
}
$data = isset($record_data['field_data']) ? $record_data['field_data'] : array();
adfoin_lacrm_sync($record, $data, $posted_data);
}
/*
* Splits the mapped values into company and contact fields, keeping "0".
*/
function adfoin_lacrm_parse_fields($data, $posted_data) {
$company_fields = [];
$contact_fields = [];
unset($data['credId'], $data['userId'], $data['users']);
foreach ($data as $key => $value) {
if (!is_string($value) || $value === '') continue;
$value = trim((string) adfoin_get_parsed_values($value, $posted_data));
if ($value === '') continue;
if (strpos($key, 'company__') === 0) {
$company_fields[substr($key, 9)] = $value;
} else {
$contact_fields[$key] = $value;
}
}
return [$company_fields, $contact_fields];
}
/*
* Creates or updates the company and the contact.
*
* $extra_company / $extra_contact are extra API parameters (custom fields)
* added by the PRO action, keyed by LACRM field name.
*/
function adfoin_lacrm_sync($record, $data, $posted_data, $extra_company = [], $extra_contact = []) {
$cred_id = isset($data['credId']) ? $data['credId'] : '';
$credentials = adfoin_get_credentials_by_id('lacrm', $cred_id);
$api_token = isset($credentials['apiToken']) ? $credentials['apiToken'] : '';
if ($api_token === '') {
adfoin_lacrm_log_skipped($record, __('Not sent: no Less Annoying CRM account is selected, or the account has no API key.', 'advanced-form-integration'));
return;
}
list($company_fields, $contact_fields) = adfoin_lacrm_parse_fields($data, $posted_data);
$company_name = isset($company_fields['Company Name']) ? $company_fields['Company Name'] : '';
$raw_email = isset($contact_fields['Email']) ? $contact_fields['Email'] : '';
$email = sanitize_email($raw_email);
if ($raw_email !== '' && !$email) {
adfoin_lacrm_log_skipped($record, sprintf(__('Not sent: "%s" is not a valid email address.', 'advanced-form-integration'), $raw_email));
return;
}
if ($company_name === '' && !$email) {
adfoin_lacrm_log_skipped($record, __('Not sent: map a contact email or a company name. Both are empty for this submission.', 'advanced-form-integration'));
return;
}
// LACRM requires an owner on new records; fall back to the API key's user.
$user_id = isset($data['userId']) ? trim((string) $data['userId']) : '';
if ($user_id === '') {
$me = adfoin_lacrm_request('GetUser', [], $api_token);
$user_id = isset($me['UserId']) ? (string) $me['UserId'] : '';
}
if ($company_name !== '') {
$company = adfoin_lacrm_find('company', $company_name, $api_token, $record);
if ($company === false) return;
$company_params = array_merge(adfoin_lacrm_contact_params($company_fields, $company ?: []), $extra_company);
if ($company) {
unset($company_params['Company Name']);
if ($company_params) {
adfoin_lacrm_request('EditContact', ['ContactId' => $company['ContactId']] + $company_params, $api_token, $record);
}
} else {
$company_params = ['IsCompany' => true, 'AssignedTo' => $user_id, 'Company Name' => $company_name] + $company_params;
adfoin_lacrm_request('CreateContact', $company_params, $api_token, $record);
}
}
if (!$email) return;
$contact = adfoin_lacrm_find('contact', $email, $api_token, $record);
if ($contact === false) return;
$contact_params = array_merge(adfoin_lacrm_contact_params($contact_fields, $contact ?: []), $extra_contact);
if ($company_name !== '') {
$contact_params['Company Name'] = $company_name;
}
if ($contact) {
adfoin_lacrm_request('EditContact', ['ContactId' => $contact['ContactId']] + $contact_params, $api_token, $record);
} else {
// LACRM requires a name; use the email when none is mapped.
if (empty($contact_params['Name'])) {
$contact_params['Name'] = $email;
}
adfoin_lacrm_request('CreateContact', ['IsCompany' => false, 'AssignedTo' => $user_id] + $contact_params, $api_token, $record);
}
}
/*
* Builds the standard field parameters. When $existing (the current record)
* is given, list fields keep their current entries: LACRM's EditContact
* replaces the whole list, so new values are appended instead.
*/
function adfoin_lacrm_contact_params($fields, $existing = []) {
$params = [];
foreach (['Name', 'Company Name', 'Job Title', 'Background Info'] as $key) {
if (isset($fields[$key])) {
$params[$key] = $fields[$key];
}
}
$lists = [
'Email' => isset($fields['Email']) ? ['Text' => $fields['Email'], 'Type' => 'Work'] : null,
'Phone' => isset($fields['Phone']) ? ['Text' => $fields['Phone'], 'Type' => 'Work'] : null,
'Website' => isset($fields['Website']) ? ['Text' => $fields['Website']] : null,
'Address' => adfoin_lacrm_address($fields),
];
foreach ($lists as $key => $item) {
if (!$item) continue;
$current = isset($existing[$key]) && is_array($existing[$key]) ? $existing[$key] : [];
if ($existing && adfoin_lacrm_list_has($current, $item)) continue;
$params[$key] = $existing ? array_merge(adfoin_lacrm_clean_list($current), [$item]) : [$item];
}
return $params;
}
function adfoin_lacrm_list_has($list, $item) {
$needle = strtolower(trim(isset($item['Text']) ? $item['Text'] : (($item['Street'] ?? '') . '|' . ($item['City'] ?? '') . '|' . ($item['Zip'] ?? ''))));
foreach ($list as $entry) {
$value = isset($item['Text']) ? ($entry['Text'] ?? '') : (($entry['Street'] ?? '') . '|' . ($entry['City'] ?? '') . '|' . ($entry['Zip'] ?? ''));
if (strtolower(trim($value)) === $needle) return true;
}
return false;
}
/*
* Drops read-only keys (TypeId) from list entries returned by LACRM.
*/
function adfoin_lacrm_clean_list($list) {
return array_map(function ($entry) {
unset($entry['TypeId']);
return $entry;
}, $list);
}
/*
* Finds a company by exact name or a contact by exact email.
* Returns the record, null when there is none, or false when the search
* failed (logged), so the caller does not create a duplicate.
*/
function adfoin_lacrm_find($type, $search_term, $api_token, $record = []) {
$parameters = [
'SearchTerms' => $search_term,
'RecordTypeFilter' => $type === 'company' ? 'Companies' : 'Contacts',
'MaxNumberOfResults' => 25,
];
$response = adfoin_lacrm_request('GetContacts', $parameters, $api_token);
if (!is_array($response) || !isset($response['Results'])) {
$reason = is_array($response) && isset($response['ErrorDescription']) ? $response['ErrorDescription'] : __('no response', 'advanced-form-integration');
if ($record) {
adfoin_lacrm_log_skipped($record, sprintf(__('Not sent: searching Less Annoying CRM for an existing record failed (%s).', 'advanced-form-integration'), $reason));
}
return false;
}
$needle = strtolower(trim($search_term));
// Search matches partial text, so compare exactly.
foreach ($response['Results'] as $result) {
if ($type === 'company') {
$name = isset($result['Company Name']) && $result['Company Name'] !== '' ? $result['Company Name'] : ($result['CompanyMetaData']['CompanyName'] ?? '');
if (strtolower(trim((string) $name)) === $needle) return $result;
} else {
foreach ((array) ($result['Email'] ?? []) as $entry) {
if (strtolower(trim($entry['Text'] ?? '')) === $needle) return $result;
}
}
}
return null;
}
/*
* Kept for add-ons that call it; returns the matching ContactId or false.
*/
function adfoin_lacrm_search($type, $search_term, $api_token) {
$found = adfoin_lacrm_find($type, $search_term, $api_token);
return $found ? $found['ContactId'] : false;
}
function adfoin_lacrm_log_skipped($record, $message) {
adfoin_add_to_log(new WP_Error('lacrm_not_sent', $message), 'https://api.lessannoyingcrm.com/v2/', ['method' => 'POST'], $record);
}
function adfoin_lacrm_request($function, $parameters, $api_token, $record = []) {
$url = 'https://api.lessannoyingcrm.com/v2/';
// The v2 API takes a JSON body and the raw API key as Authorization.
$headers = [
'Content-Type' => 'application/json',
'Authorization' => $api_token
];
$body = [
'Function' => $function,
'Parameters' => (object) $parameters
];
$response = wp_remote_post($url, [
'headers' => $headers,
'body' => wp_json_encode($body),
'timeout' => 30
]);
if($record) {
// Log the request body only, so the API key stays out of the log.
adfoin_add_to_log($response, $url, ['method' => 'POST', 'body' => $body], $record);
}
if (is_wp_error($response)) {
return [];
}
$response_body = wp_remote_retrieve_body($response);
return json_decode($response_body, true);
}
/**
* Build the v2 Address parameter: an array of address objects. Returns null
* when no address part was mapped, so array_filter() drops the key.
*/
function adfoin_lacrm_address($fields) {
$address = array_filter([
'Street' => isset($fields['address__Street']) ? $fields['address__Street'] : '',
'City' => isset($fields['address_City']) ? $fields['address_City'] : '',
'State' => isset($fields['address_State']) ? $fields['address_State'] : '',
'Zip' => isset($fields['address_Zip']) ? $fields['address_Zip'] : '',
'Country' => isset($fields['address_Country']) ? $fields['address_Country'] : ''
], 'strlen');
if (empty($address)) {
return null;
}
$address['Type'] = 'Work';
return $address;
}
add_action('wp_ajax_adfoin_get_lacrm_users', 'adfoin_get_lacrm_users');
function adfoin_get_lacrm_users() {
adfoin_verify_nonce();
$cred_id = isset($_POST['credId']) ? sanitize_text_field( wp_unslash( $_POST['credId'] ) ) : '';
$credentials = adfoin_get_credentials_by_id('lacrm', $cred_id);
$api_token = isset($credentials['apiToken']) ? $credentials['apiToken'] : '';
if (empty($api_token)) {
wp_send_json_error(__('This account has no API key. Check it under AFI Settings > Less Annoying CRM.', 'advanced-form-integration'));
}
$response = adfoin_lacrm_request('GetUsers', [], $api_token);
if (!is_array($response) || isset($response['ErrorDescription'])) {
$reason = is_array($response) && isset($response['ErrorDescription']) ? $response['ErrorDescription'] : __('no response', 'advanced-form-integration');
wp_send_json_error(sprintf(__('Could not load users: %s', 'advanced-form-integration'), $reason));
}
$users = [];
foreach ($response as $user) {
if (isset($user['UserId'])) {
$users[$user['UserId']] = trim(($user['FirstName'] ?? '') . ' ' . ($user['LastName'] ?? ''));
}
}
wp_send_json_success($users);
}
add_action('adfoin_action_fields', 'adfoin_lacrm_action_fields');
function adfoin_lacrm_action_fields() {
?>