Intercom Installation

Purpose of this page

The purpose of this page is to educate and instruct a developer on how to install Intercom on the ProcessMaker Enterprise Trial server.

The reason that this is needed is because there is currently no way to add javascript through a plugin to the designer or form builder interface. If someone is aware of how to do this, please add a comment below explaining how.

Note: In order for the plugin to work, the Intercom PHP SDK is required. The SDK is installed through composer and is located within the intercom/vendor directory.

Intercom Bitbucket repo: https://bitbucket.org/colosa/intercom

intercom.php

In the main file of the plugin, within the setup function, we need to insert the following code:

intercom.php -> setup function
$this->registerJavascript('processes/main', 'intercom/javascript');
$this->registerJavascript('cases/main', 'intercom/javascript');
$this->registerJavascript('setup/main', 'intercom/javascript');
$this->registerJavascript('dashboard/index', 'intercom/javascript');

intercom/javascript.js

Then we need to add a file to the root directory of the plugin, called javascript.js:

javascript.js
 //Light weight cross browser ajax functions so that I don't need to include jQuery just to make ajax calls
function empGetXmlHttp() {
    var xmlhttp;
    try {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP1");
    } catch (e) {
        try {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (E) {
            xmlhttp = false;
        }
    }
    if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
        xmlhttp = new XMLHttpRequest();
    }
    return xmlhttp;
}
function empAjax(ajax_server, method, parameters, callback, asynchronous , destroy){
    var obj, response;
    obj = empGetXmlHttp();
    try{
        if (typeof(asynchronous)==='undefined') asynchronous = false;
        if (typeof(callback)==='undefined') callback = false;
        if (typeof(destroy)==='undefined') destroy = false;
        if (typeof(method)==='undefined') method = 'GET';
        obj.onreadystatechange=function() {
            if ( obj.readyState==4 && obj.status == 200){
                if ( callback ) callback(obj.responseText);
                if ( destroy ){
                    empProcessingAjax=false;
                }
            }
        };
        obj.open( method, ajax_server, asynchronous );

        if(method == 'GET'){
            obj.send();
        }else if(method == 'POST'){
            obj.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
            obj.setRequestHeader("Content-length", parameters.length);
            obj.setRequestHeader("Connection", "close");
            obj.send(parameters);
        }

        if (!asynchronous){
            if ( callback ) callback(obj.responseText);
            return obj.responseText;
        }
    }catch(ss){
        alert("Error: "+ alert(ss));
    }
}
//Get the users information so that we can log them into intercom
var userInfo = JSON.parse(empAjax('../intercom/getUserInfo.php'));

//Load intercom
(function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic("reattach_activator");ic("update",intercomSettings);}else{var d=document;var i=function(){i.c(arguments)};i.q=[];i.c=function(args){i.q.push(args)};w.Intercom=i;function l(){var s=d.createElement("script");s.type="text/javascript";s.async=true;s.src="https://widget.intercom.io/widget/pcrrsla5";var x=d.getElementsByTagName("script")[0];x.parentNode.insertBefore(s,x);}if(w.attachEvent){w.attachEvent("onload",l);}else{w.addEventListener("load",l,false);}}})()

//Instantiate intercom with the app id and the users id (their email address)
window.Intercom("boot", {
    app_id: userInfo.app_id,
    user_id: userInfo.user_id
});

//Capture events - this is how we know which page the user visits and can track this in intercom
var arrUrl = window.location.href.split('/');
var page = arrUrl[arrUrl.length-2];
window.Intercom('trackEvent', 'visited_'+page);

/opt/processmaker/workflow/engine/templates/designer/index.html

Because at the time of this writing, there is no way to add javascript to the designer, we had to hard code this file in order to add intercom to the designer. We still cannot add javascript to the dynaform builder because there is no page refresh, just a page overlay. If someone knows how to add the javascript to the form builder, please comment below.

The below code needs to be added within the header. I put it at the very end of the header tag.

index.html hack
{literal}
<script>
    //Light weight cross browser ajax functions so that I don't need to include jQuery just to make ajax calls
    function empGetXmlHttp() {
        var xmlhttp;
        try {
            xmlhttp = new ActiveXObject("Msxml2.XMLHTTP1");
        } catch (e) {
            try {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (E) {
                xmlhttp = false;
            }
        }
        if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
            xmlhttp = new XMLHttpRequest();
        }
        return xmlhttp;
    }
    function empAjax(ajax_server, method, parameters, callback, asynchronous , destroy){
        var obj, response;
        obj = empGetXmlHttp();
        try{
            if (typeof(asynchronous)==='undefined') asynchronous = false;
            if (typeof(callback)==='undefined') callback = false;
            if (typeof(destroy)==='undefined') destroy = false;
            if (typeof(method)==='undefined') method = 'GET';
            obj.onreadystatechange=function() {
                if ( obj.readyState==4 && obj.status == 200){
                    if ( callback ) callback(obj.responseText);
                    if ( destroy ){
                        empProcessingAjax=false;
                    }
                }
            };
            obj.open( method, ajax_server, asynchronous );

            if(method == 'GET'){
                obj.send();
            }else if(method == 'POST'){
                obj.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
                obj.setRequestHeader("Content-length", parameters.length);
                obj.setRequestHeader("Connection", "close");
                obj.send(parameters);
            }

            if (!asynchronous){
                if ( callback ) callback(obj.responseText);
                return obj.responseText;
            }
        }catch(ss){
            alert("Error: "+ alert(ss));
        }
    }
    //Get the users information so that we can log them into intercom
    //var userInfo = JSON.parse(empAjax('intercom/getUserInfo.php'));
    var userInfo = JSON.parse(empAjax('intercom/getUserInfo-local.php'));
    //Load intercom
    (function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic("reattach_activator");ic("update",intercomSettings);}else{var d=document;var i=function(){i.c(arguments)};i.q=[];i.c=function(args){i.q.push(args)};w.Intercom=i;function l(){var s=d.createElement("script");s.type="text/javascript";s.async=true;s.src="https://widget.intercom.io/widget/pcrrsla5";var x=d.getElementsByTagName("script")[0];x.parentNode.insertBefore(s,x);}if(w.attachEvent){w.attachEvent("onload",l);}else{w.addEventListener("load",l,false);}}})()
    //Instantiate intercom with the app id and the users id (their email address)
    window.Intercom("boot", {
        app_id: userInfo.app_id,
        user_id: userInfo.user_id
    });

    //Capture events - this is how we know which page the user visits and can track this in intercom
	//We cannot capture this dynamically because the actual url is the same as the process list.
    window.Intercom('trackEvent', 'visited_designer');
</script>
{/literal}

intercom/getUserInfo.php

getUserInfo.php
<?php
/**
 * The purpose of this script is to get the users email address from the database and pass it to the front end so that we can instantiate intercom with it
 */
//Credentials for the database
$servername = "localhost";
$username = "ET3sales";
$password = "4wxz2mr2MRbaVHXB";
$dbname = "db_fluid";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
//We just need to get the email, that will be used for the ID of the user, and since the user has already been created in intercom when they created the trial, it will automatically pull the information based on the email address
//By selecting the email based on the workspace, we are essentially saying here that each workspace will only be one user in intercom - so if the user logs out of their admin account and logs in with a different user, they can still chat with us as themselves.
//Side note: we should probably look at making the EMAIL field an index, but for now, the performance impact is marginal.
$sql = "SELECT EMAIL FROM COMPANY_INFORMATIONS_OS_ETN_TRIAL WHERE NAME_SPACE = '". $_SESSION['WORKSPACE'] . "'";
$result = $conn->query($sql);

//There should only be 1 row in the database for the workspace that was created
if ($result->num_rows == 1) {
    // output data of each row
    while($row = $result->fetch_assoc()) {
        //Assign the row to a variable so we can use it to pass the email as the user id
        $userEmail = $row['EMAIL'];
    }
} else {
    echo print_r($result, true);
}
$conn->close();
//Create the response as a json object so that it can be used in the javascript side
$userInfo = json_encode(array(
   'app_id' => 'pcrrsla5',
   'user_id' => $userEmail,
));
//echo the response so that it gets sent to the front end
echo $userInfo; 

intercom/createUsers.php

This file is included in the script that creates the registration. It creates the user in Intercom. It is done at the time of the trial creation for 3 main purposes:

  • So that we can get the data that is collected on the form and push it to intercom
  • So that we can track when the user signed up and can use that in campaigns e.g. if a user signed up but never logged in
  • Less data to send every time the user logs into the ETrial
createUsers.php
<?php
//Use the namespace for intercom
use Intercom\IntercomBasicAuthClient;
//This script will be included in the trial creation, we don't want an error screwing up the trial creation, so we encapsulate it within a try catch
try {
    //Make sure that the email and workspace fields have a value otherwise no point in creating the user
    if (isset($_POST['form']['EMAIL']) && isset($_POST['form']['DOMAIN_WORKSPACE'])) {

        //Get some basic paths
        $sThisFilePath = dirname(__FILE__);
        $aThisFilePath = explode(PATH_SEP, $sThisFilePath);
        $sPluginPath = implode($aThisFilePath, PATH_SEP);
        //Include the composer autoloader so that it can include all the necessary classes for the intercom SDK
        require_once $sPluginPath . '/vendor/autoload.php';
        //Login to intercom
        $intercom = IntercomBasicAuthClient::factory(array(
            'app_id' => 'pcrrsla5',
            'api_key' => '369536fe07a7ea7f1adc4db955a1d35872de11a2'
        ));
        //Create the user with the form fields as custom attributes that we can then use in Intercom for campaigns and filtering
        $intercom->createUser(array(
            "user_id" => $_POST['form']['EMAIL'],
            "email" => $_POST['form']['EMAIL'],
            "name" => $_POST['form']['FIRST_NAME'] . ' ' . $_POST['form']['LAST_NAME'],
            "custom_attributes" => array(
                "phone" => $_POST['form']['PHONE'],
                "country" => $_POST['form']['COUNTRY'],
                "industry" => $_POST['form']['INDUSTRY'],
                "company_size" => $_POST['form']['COMPANY_SIZE'],
                "job_function" => $_POST['form']['JOB_FUNCTION'],
                "company_name" => $_POST['form']['COMPANY_NAME'],
                "workspace" => $_POST['form']['DOMAIN_WORKSPACE']
            )
        ));

    }
}catch(Exception $e){
    //Exceptions
}

processmaker/workflow/engine/templates/cases/casesStartCase.js

In this file, we simply add an event to call the parent window's Intercom api and pass through an event to increment the number of cases that the user has started.

This allows us to know how many cases the user creates.

casesStartCase.js hack
parent.Intercom('trackEvent', 'count_cases');

processmaker/workflow/engine/templates/processes/main.js

In this file, we simply add an event to call the Intercom api and pass through an event to increment the number of processes that the user has started.

This allows us to know how many processes the user creates.

main.js hack
 Intercom('trackEvent', 'count_processes');