You are here

hubspot.module in HubSpot 6.2

Sends Webform results to HubSpot's Leads API by using Webform's provided hooks.

File

hubspot.module
View source
<?php

/**
 * @file
 * Sends Webform results to HubSpot's Leads API by using Webform's provided hooks.
 */
define('HUBSPOT_SLUG', 'hubspot-drupal');
define('HUBSPOT_CLIENT_ID', '734f89bf-1b88-11e1-829a-3b413536dd4c');
define('HUBSPOT_APP_PAGE', 'https://app.hubspot.com/market/front/hubspot-drupal');
define('HUBSPOT_GUID', 'b147161c-4e34-4d90-bb95-e4594dcb98fb');

/**
 * Implements hook_menu() to get the config page listed
 */
function hubspot_menu() {
  $items = array();
  $items['admin/settings/hubspot'] = array(
    'title' => 'HubSpot integration settings',
    'description' => 'Set up HubSpot integration and leads insertion.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'hubspot_admin_settings',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'hubspot.admin.inc',
  );
  return $items;
}

/**
 * Refreshes Hubspot OAuth Access Token when expired.
 */
function hubspot_oauth_refresh() {
  $data = array(
    'refresh_token' => variable_get('hubspot_refresh_token'),
    'client_id' => HUBSPOT_CLIENT_ID,
    'grant_type' => 'refresh_token',
  );
  $data = drupal_http_build_query($data);
  $options = array(
    'headers' => array(
      'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8',
    ),
    'method' => 'POST',
    'data' => $data,
  );
  $return = drupal_http_request('https://api.hubapi.com/auth/v1/refresh', $options);
  if ($return->code == '200') {
    $return_data = json_decode($return->data, true);
    $hubspot_access_token = $return_data['access_token'];
    variable_set('hubspot_access_token', $hubspot_access_token);
    $hubspot_refresh_token = $return_data['refresh_token'];
    variable_set('hubspot_refresh_token', $hubspot_refresh_token);
    $hubspot_expires_in = $return_data['expires_in'];
    variable_set('hubspot_expires_in', $hubspot_expires_in);
    return TRUE;
  }
  else {
    drupal_set_message(t('Refresh token failed with Error Code "%code: %status_message". Reconnect to your Hubspot account.'), 'error', FALSE);
    watchdog('hubspot', 'Refresh token failed with Error Code "%code: %status_message". Visit the Hubspot module settings page and reconnect to your Hubspot account.', array(
      '%code' => $return->code,
      '%status_message' => $return->status_message,
    ), WATCHDOG_INFO);
    return FALSE;
  }
}

/**
 * Intercepts the WebForm submission and send it off to HubSpot. Implements
 * hook_webform_submission_insert().
 */
function hubspot_webform_submission_insert($node, $submission) {
  if ($submission->is_draft == 1) {
    return;
  }
  foreach ($submission->data as $cid => $data) {
    if ($node->webform['components'][$cid]['type'] == 'hubspot_url') {
      $hubSpotURL = $data['value'][0];
      if (isset($node->webform['components'][$cid]['extra']['custom_fields'])) {
        $fields = array_filter($node->webform['components'][$cid]['extra']['custom_fields']);
      }
      else {
        $fields = array();
        foreach ($node->webform['components'] as $k => $v) {
          if ($cid != intval($v['cid'])) {
            $fields[$v['cid']] = $v['cid'];
          }
        }
      }
      $values = array();
      foreach ($fields as $cid) {
        $component = $node->webform['components'][$cid]['form_key'];
        $values[$component] = implode(',', $submission->data[$cid]['value']);
      }

      // These fields must be submitted with each request
      $values['UserToken'] = isset($_COOKIE['hubspotutk']) ? $_COOKIE['hubspotutk'] : '';
      $values['IPAddress'] = ip_address();
      $r = hubspot_insert_lead($hubSpotURL, $values);
      if (empty($r['Error']) && strpos($r['Data'], 'successfully') !== FALSE) {
        watchdog('hubspot', 'Webform "%form" results succesfully submitted to HubSpot. Response: @msg', array(
          '@msg' => strip_tags($r['Data']),
          '%form' => $node->title,
        ), WATCHDOG_INFO);
      }
      elseif (!empty($r['Error'])) {
        watchdog('hubspot', 'HTTP error when submitting HubSpot data from Webform "%form": @error', array(
          '@error' => $r['Error'],
          '%form' => $node->title,
        ), WATCHDOG_ERROR);
        if (variable_get('hubspot_debug_on', 0)) {
          drupal_mail('hubspot', 'http_error', variable_get('hubspot_debug_email', variable_get('site_mail', '')), language_default(), array(
            'errormsg' => $r['Error'],
            'hubspot_url' => $hubSpotURL,
            'node_title' => $node->title,
          ), variable_get('site_mail', ''));
        }
      }
      else {
        watchdog('hubspot', 'HubSpot error when submitting Webform "%form": @error', array(
          '@error' => $r['Data'],
          '%form' => $node->title,
        ), WATCHDOG_ERROR);
        if (variable_get('hubspot_debug_on', 0)) {
          drupal_mail('hubspot', 'hub_error', variable_get('hubspot_debug_email', variable_get('site_mail', '')), language_default(), array(
            'errormsg' => $r['Data'],
            'hubspot_url' => $hubSpotURL,
            'node_title' => $node->title,
          ), variable_get('site_mail', ''));
        }
      }
    }
  }
}

/**
 * Implements hook_mail() to send error messages to the administrator.
 */
function hubspot_mail($key, &$message, $params) {
  $message['subject'] = t('HubSpot leads insertion error');
  switch ($key) {
    case 'http_error':
      $message['body'][] = t('When attempting to submit the form "@form" to HubSpot, a HTTP error occurred.', array(
        '@form' => $params['node_title'],
      ));
      break;
    case 'hub_error':
      $message['body'][] = t('Upon submitting the Webform "@form" to HubSpot, an error was returned.', array(
        '@form' => $params['node_title'],
      ));
      break;
  }
  $message['body'][] = t('Error message: @message', array(
    '@message' => $params['errormsg'],
  ));
  $message['body'][] = t('HubSpot POST URL: @url', array(
    '@url' => $params['hubspot_url'],
  ));
  $message['body'][] = t('To adjust the debugging settings, visit @url', array(
    '@url' => url('admin/config/content/hubspot', array(
      'absolute' => TRUE,
    )),
  ));
}

/**
 * Executes the HubSpot API POST to insert a lead
 *
 * @param string $formURL HubSpot-provided POST URL to submit to
 * @param array $fields Form fields, such as name and contact info
 *
 * @return array with fields Data, Error, and HTTPCode.
 *         Error is the HTTP error message from drupal_http_request,
 *         and HTTPCode is the HTTP response code of the request.
 */
function hubspot_insert_lead($formURL, $fields) {
  $strPost = "";

  // Turn $fields into POST-compatible list of parameters
  foreach ($fields as $fieldName => $fieldValue) {
    $strPost .= urlencode($fieldName) . '=';
    $strPost .= urlencode($fieldValue);
    $strPost .= '&';
  }
  $strPost = rtrim($strPost, '&');

  // nuke the final ampersand
  // send POST data
  $r = drupal_http_request($formURL, array(
    'Content-Type' => 'application/x-www-form-urlencoded',
  ), 'POST', $strPost);
  return array(
    'Data' => isset($r->data) ? $r->data : '',
    'Error' => isset($r->error) ? $r->error : '',
    'HTTPCode' => $r->code,
  );
}

/**
 * Creates a WebForm component to contain the form's HubSpot POST URL.
 * Implements hook_webform_component_info().
 */
function hubspot_webform_component_info() {
  return array(
    'hubspot_url' => array(
      'label' => t('HubSpot POST URL'),
      'description' => t("A HubSpot API POST URL, to submit a form's contents to HubSpot Leads."),
      'features' => array(
        'csv' => FALSE,
        'email' => FALSE,
        'title_display' => FALSE,
        // prevents the "Display" field from being displayed while editing the component
        'required' => FALSE,
      ),
    ),
  );
}

/**
 * Provides default values for this component.
 */
function _webform_defaults_hubspot_url() {
  return array(
    'name' => 'HubSpot POST URL',
    'form_key' => 'hubspot',
    'pid' => 0,
    'weight' => 0,
    'value' => '',
    'extra' => array(),
  );
}

/**
 * Implements _webform_edit_component() to adjust the HubSpot POST URL edit page.
 */
function _webform_edit_hubspot_url($component) {
  $form = array();

  // Disable Description box
  $form['extra']['description'] = array();
  $form['value'] = array(
    '#type' => 'textfield',
    '#title' => t('HubSpot POST URL'),
    '#description' => t("The API POST URL provided under HubSpot's Lead API settings for this form."),
    '#default_value' => $component['value'],
  );

  // Hide display options
  $form['display'] = array(
    '#type' => 'markup',
  );

  // Overwrite the "Label" field to provide a better description
  $form['name'] = array(
    '#type' => 'textfield',
    '#default_value' => $component['name'],
    '#title' => t('Label'),
    '#description' => t('The name of this field. This field will not be displayed to users submitting the form.'),
    '#required' => TRUE,
    '#weight' => -10,
    '#maxlength' => 255,
  );
  $form_fields = array();
  $result = db_query('SELECT cid, form_key, name, type FROM {webform_component} WHERE type <> \'hubspot_url\' AND nid = :nid ORDER BY weight, name', array(
    ':nid' => $component['nid'],
  ));
  foreach ($result as $c) {
    $form_fields[$c->cid] = sprintf('%s (%s)', $c->name, $c->form_key);
  }
  $form['extra']['custom_fields'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Custom fields'),
    '#options' => $form_fields,
    '#default_value' => isset($component['extra']['custom_fields']) ? array_keys(array_filter($component['extra']['custom_fields'])) : array_keys($form_fields),
    '#description' => t('Select which fields should be sent to HubSpot'),
    '#weight' => 0,
    '#required' => FALSE,
  );
  return $form;
}

/**
 * Implements _webform_render_component(). Render this as a hidden field.
 */
function _webform_render_hubspot_url($component, $value = NULL) {
  $element = array(
    '#type' => 'hidden',
    '#title' => check_plain($component['name']),
    '#value' => isset($value[0]) ? $value[0] : $component['value'],
    '#weight' => $component['weight'],
  );
  return $element;
}

/**
 * When displaying the form results to an admin, don't show the HubSpot URL.
 */
function _webform_display_hubspot_url($component, $value, $format = 'html') {
  return array();
}

/**
 * Implements hook_footer() to inject the HubSpot JavaScript tracking code into
 * the page footer, just before </body>.
 */
function hubspot_footer($main = 0) {
  return variable_get('hubspot_log_code', '');
}

/**
 * Implements hook_perm() to decide who gets access to the recent leads block
 */
function hubspot_perm() {
  return array(
    'see recent hubspot leads',
  );
}

/**
 * Implements hook_block() to provide a HubSpot recent leads block.
 */
function hubspot_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'list':
      $blocks = array();
      $blocks[0] = array(
        'info' => t('HubSpot Recent Leads'),
        'status' => 0,
      );
      return $blocks;
      break;
    case 'view':
      if ($delta == 0 && user_access('see recent hubspot leads')) {
        $block = array();
        $block['subject'] = t('HubSpot Recent Leads');
        $leads = hubspot_get_recent();

        // This part of the HubSpot API returns HTTP error codes on failure, with no message
        if (!empty($leads['Error']) || $leads['HTTPCode'] != 200) {
          $block['content'] = t('An error occurred when fetching the HubSpot leads data: @error', array(
            '@error' => !empty($leads['Error']) ? $leads['Error'] : $leads['HTTPCode'],
          ));
          return $block;
        }
        elseif (empty($leads['Data'])) {
          $block['content'] = t('No leads to show.');
          return $block;
        }
        $items = array();
        foreach ($leads['Data'] as $lead) {

          // Note that $lead->insertedAt comes in milliseconds, not seconds, since the epoch
          $items[] = l($lead->firstName . ' ' . $lead->lastName, $lead->leadLink) . ' ' . t('(@time ago)', array(
            '@time' => format_interval(time() - intval($lead->insertedAt / 1000)),
          ));
        }
        $block['content'] = theme('item_list', $items);
        return $block;
      }
      break;
    default:

      // ignore 'configure' and 'save'
      break;
  }
}

/**
 * Gets the most recent HubSpot leads
 *
 * Docs: http://docs.hubapi.com/wiki/Searching_Leads
 *
 * @param int $n Number of leads to fetch
 */
function hubspot_get_recent($n = 5) {
  $access_token = variable_get('hubspot_access_token', '');
  $n = intval($n);
  if (empty($access_token)) {
    return array(
      'Error' => t('This site is not connected to a Hubspot Account.'),
    );
  }
  $r = drupal_http_request("https://api.hubapi.com/leads/v1/list/?access_token={$access_token}&sort=insertedAt&dir=desc&max={$n}");
  if ($r['HTTPCode'] == '401') {
    $refresh = hubspot_oauth_refresh();
    if ($refresh) {
      $access_token = variable_get('hubspot_access_token', '');
      $r = drupal_http_request("https://api.hubapi.com/leads/v1/list/?access_token={$access_token}&sort=insertedAt&dir=desc&max={$n}");
    }
  }
  return array(
    'Data' => json_decode($r->data),
    'Error' => isset($r->error) ? $r->error : '',
    'HTTPCode' => $r->code,
  );
}

/**
 * Implements hook_help() for the admin help page.
 */
function hubspot_help($path, $arg) {
  $output = '';
  switch ($path) {
    case 'admin/help#hubspot':
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The HubSpot module provides leads integration with the HubSpot API, allowing forms created with the Webform module to submit their data to HubSpot for leads tracking. It also allows you to easily embed the HubSpot JavaScript tracking code in your site to track the visits of each lead. Further information is available in the Drupal <a href="http://drupal.org/node/1195370">handbook pages for this module.</a>') . '</p>';
      $output .= '<h3>' . t('Creating a HubSpot Webform') . '</h3>';
      $output .= '<p>' . t("To have a Webform's data sent to HubSpot for leads tracking, complete the following steps:") . '</p>';
      $output .= '<ol>';
      $output .= '<li>' . t('Log in to your HubSpot account and visit the Settings page. Click the HubSpot Lead API link under Lead Management.') . '</li>';
      $output .= '<li>' . t('Press Add New Form and specify the form name, email list, and lead nurturing campaign as desired.') . '</li>';
      $output .= '<li>' . t('Submit the form. HubSpot will now provide an API POST URL; save this somewhere.') . '</li>';
      $output .= '<li>' . t('In your Drupal admin, use the Add content page to create a new Webform. Enter as many questions ("components") as you\'d like. Name them according to the "Form field keys" section below.') . '</li>';
      $output .= '<li>' . t('Finally, create a component named "hubspot" with the type "HubSpot POST URL". Supply the API POST URL in the box provided, select which form fields should be sent to HubSpot, and save the form.') . '</li>';
      $output .= '</ol>';
      $output .= '<p>' . t('The Webform will now automatically send any submissions directly to HubSpot via the POST URL you provided. You may customize, theme, or alter the form as much as you like, so long as the HubSpot POST URL field remains.') . '</p>';
      $output .= '<p>' . t('Please note that HubSpot applies a 500-character limit to each form field submitted, so you may want to set the "Maxlength" setting on the Webform fields appropriately.') . '</p>';
      $output .= '<h3>' . t('Form field keys') . '</h3>';
      $output .= '<p>' . t('Each Webform component\'s "field key" specifies what the field will be named when sent to HubSpot. Certain field keys have significance with HubSpot. For example, submitting a field with the key "FirstName" allows HubSpot to automatically recognize it as the person\'s first name when displaying the lead information. Here is a list of HubSpot-recognized field keys:') . '</p>';
      $output .= '<dl>';
      $output .= '<dt>' . t('FirstName, LastName, and FullName') . '</dt>';
      $output .= '<dd>' . t('Use FirstName or LastName to send those fields separately; send FullName for HubSpot to automatically split the name into first and last names.') . '</dd>';
      $output .= '<dt>' . t('Email, Phone, Fax, Website, and TwitterHandle') . '</dt>';
      $output .= '<dd>' . t("Specify these field keys to get the user's contact information recognized by HubSpot.") . '</dd>';
      $output .= '<dt>' . t('Company, NumberEmployees, AnnualRevenue, and JobTitle') . '</dt>';
      $output .= '<dd>' . t("Capture the user's employment information.") . '</dd>';
      $output .= '<dt>' . t('Address, City, State, ZipCode, Country') . '</dt>';
      $output .= '<dd>' . t("Capture the user's location.") . '</dd>';
      $output .= '<dt>' . t('Message') . '</dt>';
      $output .= '<dd>' . t('Allow the user to send a custom message.') . '</dd>';
      $output .= '</dl>';
      $output .= '<p>' . t('Specify these as the <strong>Field Key</strong> when adding components in your form. The field key is not shown to users filling out the form, but only used by HubSpot to display the data; the "Label" field specifies what your users will see.') . '</p>';
      $output .= '<p>' . t('Note that you may provide other custom fields with any field key you like, if you have other data you wish to collect. HubSpot will store all data sent to it and display it in the "Form Data" tab when viewing each lead.') . '</p>';
      $output .= '<p>' . t("Also, if you're using HubSpot's Salesforce integration, you must use field keys that correspond to the field's API Name in Salesforce.") . '</p>';
      $output .= '<h3>' . t('HubSpot Javascript tracking code') . '</h3>';
      $output .= '<p>' . t('HubSpot supports using a JavaScript tracking system to analyze potential leads on your site. You can get the JavaScript code from your HubSpot settings, under External Site Traffic Logging, and paste it into the HubSpot integration settings page in Drupal to have it automatically included on every page.') . '</p>';
      break;
    case 'node/%/webform':
      $output .= '<p>' . t('If you\'d like this form\'s results to be posted to HubSpot\'s leads tracking system, make sure it has a "HubSput POST URL" component filled in with the information from the HubSpot Lead API page in your HubSpot settings.') . '</p>';
      break;
  }
  return $output;
}

Functions

Namesort descending Description
hubspot_block Implements hook_block() to provide a HubSpot recent leads block.
hubspot_footer Implements hook_footer() to inject the HubSpot JavaScript tracking code into the page footer, just before </body>.
hubspot_get_recent Gets the most recent HubSpot leads
hubspot_help Implements hook_help() for the admin help page.
hubspot_insert_lead Executes the HubSpot API POST to insert a lead
hubspot_mail Implements hook_mail() to send error messages to the administrator.
hubspot_menu Implements hook_menu() to get the config page listed
hubspot_oauth_refresh Refreshes Hubspot OAuth Access Token when expired.
hubspot_perm Implements hook_perm() to decide who gets access to the recent leads block
hubspot_webform_component_info Creates a WebForm component to contain the form's HubSpot POST URL. Implements hook_webform_component_info().
hubspot_webform_submission_insert Intercepts the WebForm submission and send it off to HubSpot. Implements hook_webform_submission_insert().
_webform_defaults_hubspot_url Provides default values for this component.
_webform_display_hubspot_url When displaying the form results to an admin, don't show the HubSpot URL.
_webform_edit_hubspot_url Implements _webform_edit_component() to adjust the HubSpot POST URL edit page.
_webform_render_hubspot_url Implements _webform_render_component(). Render this as a hidden field.

Constants

Namesort descending Description
HUBSPOT_APP_PAGE
HUBSPOT_CLIENT_ID
HUBSPOT_GUID
HUBSPOT_SLUG @file Sends Webform results to HubSpot's Leads API by using Webform's provided hooks.