Business Requirements
- Contacts can be uniquely identified by email addresses. A person who has two different email addresses entered into the system is regarded as two different persons.
- A lead captured on the sell page will be added to Agentbox tagged with the ‘prospective vendor’ Contact-Class. If the lead’s email address already exists under that Contact-Class, no action will be taken.
- A lead captured on the lease-with-us page will be added to Agentbox tagged with the ‘prospective landlord’ Contact-Class. If the lead’s email address already exists under that Contact-Class, no action will be taken.
- A lead captured on the buy page will be added to Agentbox tagged with the ‘prospective buyer’ Contact-Class. If the lead’s email address already exists under that Contact-Class, no action will be taken.
- A lead captured on the re-blog page will be added to Agentbox tagged with the ‘Newsletter’ Subscription. If the lead’s email address already exists under that Subscription, no action will be taken.
Agentbox APIs
Agentbox provides REST APIs that can Get, Add and Update the Contacts objects. The supported methods are GET, POST and PUT.
Contact Form 7 Setup
The css class ‘cu-cf-api’ is added to the shortcode of the CF7 form.
[contact-form-7 id="1598" title="REC Freebie" html_id="cu-cf-sell" html_class="cu-cf-simple cu-cf-api"]
When the form is submitted, it also transmits two hidden fields: the page-slug and the wordpress ajax url. The hidden field function is provided by another plugin called ‘Contact Form 7 – Dynamic Text Extension’.
[dynamichidden from-page "CF7_get_post_var key='slug'"]
[dynamichidden ajax-url "wp_ajax_url"]
Javascript
The JS is titled “Agentbox API’ and is stored under Elementor Custom Code.
An event listener is added to the form to listen to the ‘wpcf7mailsent’ event which is fired when the email is successfully sent. The event function will then carry out the followings:
- Capture the submitted form data.
- Make an ajax call to a PHP function to check whether the submitted email address exits or not. The ajax call returns the Contact object if the address already exists in Agentbox.
- If the address does not exist, then perform the add contact function by making another ajax call to a PHP function.
- If the address already exists, it will check whether the address also belongs to the required Contact-Class and perform the necessary action to update the Agentbox or do nothing.
- Note: AJAX cannot directly send the APIs to Agentbox as this will cause the CORS error. PHP functions are used to make these calls.
var formElm = document.querySelector('.cu-cf-api');
formElm.addEventListener('wpcf7mailsent', function (event) {
var contactFname = '';
var contactLname = '';
var contactEmail = '';
var WPajaxURL = '';
var fromPage = '';
var inputs = event.detail.inputs;
// Get form's input values
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].name === 'contact-Fname') {
contactFname = (inputs[i].value);
} // end if firstname
if (inputs[i].name === 'contact-Lname') {
contactLname = (inputs[i].value);
} // end if lastname
if (inputs[i].name === 'contact-email') {
contactEmail = inputs[i].value;
} // end if
if (inputs[i].name === 'ajax-url') {
WPajaxURL = inputs[i].value;
} // end if
if (inputs[i].name === 'from-page') {
fromPage = inputs[i].value;
} // end if
} // end for loop
var request = new XMLHttpRequest();
request.open('POST', WPajaxURL, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.onload = function () {
if (this.status >= 200 && this.status < 400) {
console.log('Check contact email done! Details below:');
if (isJsonString(this.response)) {
var respObj = JSON.parse(this.response);
// console.log(respObj);
if (respObj.response.items === '0') {
console.log('Perform Add Function');
add_contact(contactFname, contactLname, contactEmail, fromPage, WPajaxURL);
} else {
console.log('Perform Update Function');
update_contact(respObj, fromPage, WPajaxURL);
}
} else {
console.log('Response is not Json: ' + this.response);
}
} else {
console.log('Failure. Details below:');
console.log(this.response);
}
};
request.onerror = function () {
// Connection error
console.log('Connection error!');
};
request.send('action=ivr_process_contact&contact_email=' + contactEmail);
}, false); // end wpcf7mailsent eventlistener
/**
* add_contact()
* Fires ajax to trigger a PHP function where the POST API is sent
* to add a Contact in Agentbox.
*/
function add_contact(contactFname, contactLname, contactEmail, fromPage, ajaxurl) {
var fromPageObj = processFromPage(fromPage);
var request = new XMLHttpRequest();
request.open('POST', ajaxurl, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.onload = function () {
if (this.status >= 200 && this.status < 400) {
console.log('Contact added!');
} else {
console.log('Add Contact Failed.');
}
// console.log(this.response);
};
request.onerror = function () {
// Connection error
console.log('Connection error!');
};
request.send('action=ivr_add_contact&contact_fname=' + contactFname + '&contact_lname=' + contactLname +
'&contact_email=' + contactEmail + '&contact_class=' + fromPageObj.conClass + '&class_id=' + fromPageObj
.classId + '&contact_subs=' + fromPageObj.conSubs + '&from_page=' + fromPage);
} // end add_contact()
/**
* update_contact()
* Fires ajax to trigger a PHP function where the PUT API is sent
* to update the Contact in Agentbox.
*/
function update_contact(contactObj, fromPage, ajaxurl) {
var hasConClassesArr = getContactClasses(contactObj);
var hasSubsArr = getSubscriptions(contactObj);
switch (fromPage) {
case ('sell'): {
if (hasConClassesArr.includes('Prospective Vendor')) {
console.log('already a Prospective Vendor, no action required.');
return;
}
break;
}
case ('lease-with-us'): {
if (hasConClassesArr.includes('Prospective Landlord')) {
console.log('already a Prospective Landlord, no action required.');
return
}
break;
}
case ('buy'): {
if (hasConClassesArr.includes('Prospective Buyer')) {
console.log('already a Prospective Buyer, no action required.');
return
}
break;
}
case ('re-blog'): {
if (hasSubsArr.includes('Newsletters')) {
console.log('already subscribes to Newsletters, no action required.');
return
}
break;
}
} // end switch
var fromPageObj = processFromPage(fromPage);
var contactID = contactObj.response.contacts[0].id;
var request = new XMLHttpRequest();
request.open('POST', ajaxurl, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.onload = function () {
if (this.status >= 200 && this.status < 400) {
console.log('Contact updated!');
} else {
console.log('Update Contact Failed. Details below:');
}
// console.log(this.response);
};
request.send('action=ivr_update_contact&contact_class=' + fromPageObj.conClass + '&class_id=' + fromPageObj
.classId + '&contact_subs=' + fromPageObj.conSubs + '&from_page=' + fromPage + '&contact_id=' + contactID);
} // end update_contact()
/**
* processFromPage()
* Based on the value of fromPage, set the corresponding Contact Class,
* Class ID, or Contact Subscription.
* Returns an object.
*/
function processFromPage(fromPage) {
var conClass = 'na';
var classId = 0;
var conSubs = 'na';
switch (fromPage) {
case ('sell'): {
conClass = 'Prospective Vendor';
classId = 18;
break;
}
case ('lease-with-us'): {
conClass = 'Prospective Landlord';
classId = 20;
break;
}
case ('buy'): {
conClass = 'Prospective Buyer';
classId = 19;
break;
}
case ('re-blog'): {
conSubs = 'Newsletters';
break;
}
} // end switch
return {
conClass: conClass,
classId: classId,
conSubs: conSubs
};
} // end processFromPage()
/**
* isJsonString(str)
* Return true if str is a json string
*
*/
function isJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
/**
* getContactClasses()
* Return an array containing the contact classes of the contact. *
*/
function getContactClasses(contactObj) {
var classArr = [];
var classObjArr = contactObj.response.contacts[0].contactClasses;
classObjArr.forEach(function (classObj) {
classArr.push(classObj.name);
});
return classArr;
} // end getContactClasses()
/**
* getSubscriptions()
* Return an array containing the subscriptions of the contact.
*/
function getSubscriptions(contactObj) {
return contactObj.response.contacts[0].subscriptions;
} // end getSubscriptions()
PHP
The file ‘agentbox-api.php’ contains the necessary functions to send the calls to Agentbox using the CURL function. It is placed inside the folder ‘/agentbox-calls’ under the Astra Child theme.
<?php
define('CID', 'aHR0cHM6Ly9yZWNvbGxlY3RpdmUuYWdlbnRib3hjcm0uY29tLmF1L2FkbWluLw');
define('API_KEY', 'f0d4-4292-9a49-2cd5-a9bc-7b7f-1d4f-53fc-c1cc-3e25');
define('RESOURCE_URL', 'https://api.agentboxcrm.com.au/contacts');
/**
* ivr_process_contact()
* This function handles the ajax call from Freebie form and Subscription form
* It checks whether the submitted contact_email exists or not in Agentbox.
* if exits, $response contains the Contact data in json format
*
*/
function ivr_process_contact() {
$ch = curl_init();
$contact_email = $_POST['contact_email'];
$dataArr = [ 'page' => 1,
'limit' => 20,
'filter[email]' => $contact_email,
'filter[matchAllContactClass]' => false,
'filter[reqIncSurroundSuburbs]' => false,
'filter[limitSearch]' => true,
'include' => 'contactClasses,subscriptions',
'version' => 2
];
$q_data = http_build_query($dataArr);
$getUrl = RESOURCE_URL. "?". $q_data;
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_URL, $getUrl);
curl_setopt($ch, CURLOPT_TIMEOUT, 80);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-Client-ID: '. CID,
'X-API-Key: '. API_KEY
));
$response = curl_exec($ch);
if (curl_error($ch)) {
echo 'Request Error:' . curl_error($ch);
} else {
echo $response;
}
curl_close($ch);
die( );
} // end ivr_process_contact()
/**
* ivr_add_contact()
* This function handle the ajax calls for creation of a new Contact in Agentbox.
* The created Contact will be tagged under a particular Contact Class or
* Subscription according to business logic
* Returns a json to indicate success or failure.
*/
function ivr_add_contact() {
$ch = curl_init();
$contact_fname = $_POST['contact_fname'];
$contact_lname = $_POST['contact_lname'];
$contact_email = $_POST['contact_email'];
$contact_class = $_POST['contact_class'];
$class_id = $_POST['class_id'];
$contact_subs = $_POST['contact_subs'];
$from_page = $_POST['from_page'];
if ($from_page === 're-blog') {
$page_param = '"subscriptions": [{"name": "'.
$contact_subs. '"} ]';
} else {
$page_param = '"contactClasses": [{"id": '. $class_id.
', "name": "'. $contact_class. '"} ]';
} // end if-else
$data_json = '{
"contact": {
"firstName": "'. $contact_fname. '",
"lastName": "'. $contact_lname. '",
"email": "'. $contact_email. '",'. $page_param. '}}';
$post_Url = RESOURCE_URL. "?version=2";
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_URL, $post_Url);
curl_setopt($ch, CURLOPT_TIMEOUT, 80);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-Client-ID: '. CID,
'X-API-Key: '. API_KEY,
'Content-Type: application/json',
'Content-Length: '. strlen($data_json)
)
);
$response = curl_exec($ch);
if (curl_error($ch)) {
echo 'Request Error:' . curl_error($ch);
} else {
echo $response;
}
curl_close($ch);
die( );
} // end ivr_add_contact()
/**
* ivr_update_contact()
* This function handle the ajax calls for updating an existing Contact in Agentbox.
* This updates are for Contact Classes and Subscriptions (Newsletter) based on which
* pages the requests are come from.
* Returns a json to indicate success or failure.
*/
function ivr_update_contact() {
$ch = curl_init();
$contact_id = $_POST['contact_id'];
$contact_class = $_POST['contact_class'];
$class_id = $_POST['class_id'];
$contact_subs = $_POST['contact_subs'];
$from_page = $_POST['from_page'];
if ($from_page === 're-blog') {
$page_param = '"subscriptions": [{"name": "'.
$contact_subs. '"} ],
"subscriptionsAppendable":true';
} else {
$page_param = '"contactClasses": [{"id": '. $class_id.
', "name": "'. $contact_class. '"} ],
"contactClassesAppendable":true';
} // end if-else
$data_json = '{"contact": {'. $page_param. '}}';
// $put_Url = RESOURCE_URL. "/$contact_id?version=2";
$put_Url = RESOURCE_URL. "/". $contact_id. "?version=2";
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_URL, $put_Url);
curl_setopt($ch, CURLOPT_TIMEOUT, 80);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-Client-ID: '. CID,
'X-API-Key: '. API_KEY,
'Content-Type: application/json',
'Content-Length: '. strlen($data_json)
)
);
$response = curl_exec($ch);
if (curl_error($ch)) {
echo 'Request Error:' . curl_error($ch);
} else {
echo $response;
}
curl_close($ch);
die( );
} // end ivr_update_contact()
