You are here

pardot.module in Pardot Integration 7

Same filename and directory in other branches
  1. 8 pardot.module
  2. 6 pardot.module
  3. 7.2 pardot.module
  4. 2.x pardot.module

Pardot integration module.

File

pardot.module
View source
<?php

/**
 * @file
 * Pardot integration module.
 */
define('PARDOT_STATUS_NEW', 'new');
define('PARDOT_STATUS_FAILED', 'failed');
define('PARDOT_STATUS_UPLOADED', 'uploaded');
define('PARDOT_PAGES', "admin\nadmin/*\nbatch\nnode/add*\nnode/*/*\nuser/*/*");

/**
 * Implements hook_init().
 *
 * Add site tracking javascript. This is split into to calls to be consistent
 * with the reference javascript and still provide a reasonable way to futz
 * with the implementation though the theming layer.
 */
function pardot_init() {
  global $user;
  if (_pardot_visibility_pages() == 1) {
    if (_pardot_visibility_roles($user)) {

      // Add Pardot JavaScript.
      pardot_js();
      drupal_add_js(drupal_get_path('module', 'pardot') . '/pardot.js', array(
        'scope' => 'footer',
      ));
    }
  }
}

/**
 * Implements hook_theme().
 */
function pardot_theme($existing, $type, $theme, $path) {
  return array(
    'pardot_webform_components_form' => array(
      'render element' => 'form',
      'file' => 'pardot.admin.inc',
    ),
    'pardot_admin_scoring' => array(
      'render element' => 'form',
      'file' => 'pardot.admin-scoring.inc',
    ),
    'pardot_admin_campaign' => array(
      'render element' => 'form',
      'file' => 'pardot.admin-campaign.inc',
    ),
  );
}

/**
 * Implements hook_menu().
 */
function pardot_menu() {
  $items['admin/config/services/pardot'] = array(
    'title' => 'Pardot',
    'description' => 'Create and edit Pardot settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pardot_admin_form',
    ),
    'access arguments' => array(
      'administer pardot',
    ),
    'type' => MENU_NORMAL_ITEM,
    // 'weight' => -1,
    'file' => 'pardot.admin.inc',
  );
  $items['admin/config/services/pardot/post_url_usage'] = array(
    'title' => 'Pardot enabled WebForms',
    'description' => 'Webforms which have been enabled for Pardot.',
    'page callback' => 'pardot_webform_enabled_pardot_load',
    'access arguments' => array(
      'administer pardot',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 20,
  );
  $items['admin/config/services/pardot/general'] = array(
    'title' => 'Settings',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/config/services/pardot/scoring'] = array(
    'title' => 'Scoring',
    'description' => 'Create and edit Pardot scoring settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pardot_admin_scoring',
    ),
    'access arguments' => array(
      'administer pardot',
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'pardot.admin-scoring.inc',
  );
  $items['admin/config/services/pardot/scoring/%pardot_scoring/edit'] = array(
    'title' => 'Scoring',
    'description' => 'Create and edit Pardot scoring settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pardot_admin_scoring_edit',
      5,
    ),
    'access arguments' => array(
      'administer pardot',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'pardot.admin-scoring.inc',
  );
  $items['admin/config/services/pardot/scoring/%pardot_scoring/delete'] = array(
    'title' => 'Scoring',
    'description' => 'Create and edit Pardot scoring settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pardot_admin_scoring_delete',
      5,
    ),
    'access arguments' => array(
      'administer pardot',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'pardot.admin-scoring.inc',
  );
  $items['admin/config/services/pardot/campaign'] = array(
    'title' => 'Campaigns',
    'description' => 'Create and edit Pardot campaign settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pardot_admin_campaign',
    ),
    'access arguments' => array(
      'administer pardot',
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'pardot.admin-campaign.inc',
  );
  $items['admin/config/services/pardot/campaign/%pardot_campaign/edit'] = array(
    'title' => 'Campaign',
    'description' => 'Create and edit Pardot campaign settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pardot_admin_campaign_edit',
      5,
    ),
    'access arguments' => array(
      'administer pardot',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'pardot.admin-campaign.inc',
  );
  $items['admin/config/services/pardot/campaign/%pardot_campaign/delete'] = array(
    'title' => 'Campaign',
    'description' => 'Create and edit Pardot campaign settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pardot_admin_campaign_delete',
      5,
    ),
    'access arguments' => array(
      'administer pardot',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'pardot.admin-campaign.inc',
  );
  $items['node/%webform_menu/webform/pardot'] = array(
    'title' => 'Pardot',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pardot_webform_components_form',
      1,
    ),
    'access callback' => 'node_access',
    'access arguments' => array(
      'update',
      1,
    ),
    'file' => 'pardot.admin.inc',
    'weight' => 1,
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function pardot_permission() {
  return array(
    'administer pardot' => array(
      'title' => t('Administer pardot'),
      'description' => t('Administer pardot'),
    ),
  );
}

/**
 * Implements hook_help().
 */
function pardot_help($path, $arg) {
  switch ($path) {
    case 'admin/config/services/pardot':
      return t('For help finding tracking code, follow the !instructions found on the Pardot help site', array(
        '!instructions' => l(t('instructions'), 'http://help.pardot.com/faqs/campaigns/tracking-code'),
      ));
  }
}

/**
 * Implements hook_form_alter().
 *
 * @see pardot_webform_submit()
 */
function pardot_form_alter(&$form, $form_state, $form_id) {
  if (strpos($form_id, 'webform_client_form') !== 0) {
    return;
  }

  // Modify all webforms to use this output thingy.
  // Load the form specific settings.
  $nid = $form['details']['nid']['#value'];
  if (empty($nid)) {
    return;
  }
  $form_settings = pardot_webform_load($nid);

  // Check to see if the form exists.
  if (empty($form_settings) || !$form_settings->is_active) {
    return;
  }
  $form['#submit'] = is_array($form['#submit']) ? $form['#submit'] : array(
    'webform_client_form_submit ',
  );
  $form['#submit'][] = 'pardot_webform_submit';
}

/**
 * Implements hook_page_build().
 */
function pardot_page_build(&$page) {
  if (isset($_SESSION['pardot_submission'])) {
    $submission = pardot_submission_load($_SESSION['pardot_submission']);

    // Update post data.
    $submission->status = PARDOT_STATUS_UPLOADED;
    pardot_submission_save($submission);
    $form_settings = pardot_webform_load($submission->form_nid);
    $url = $form_settings->url;
    $post_fields = $submission->data['post_fields'];

    // Map fields to their Pardot values.
    foreach ($post_fields as $key => $value) {
      if (!empty($form_settings->data[$key])) {
        $result[$form_settings->data[$key]['key']] = $value;
      }
      else {
        $result[$key] = $value;
      }
    }
    $url = url($form_settings->url, array(
      'query' => $result,
    ));
    $page['page_bottom']['pardot'] = array(
      '#type' => 'markup',
      '#markup' => '<iframe src="' . $url . '" width="1" height="1"></iframe>',
    );
    unset($_SESSION['pardot_submission']);
  }
}

/**
 * Processes pardot_js() variables and adds settings.
 *
 * @group themeable
 */
function pardot_js() {
  $settings['pardot_a_id'] = check_plain(variable_get('pardot_a_id', ''));

  // Compare with the internal and path alias (if any) to find any special campaigns.
  $results = db_query('SELECT campaign_id, paths FROM {pardot_campaign}');
  foreach ($results as $row) {
    $path = drupal_get_path_alias($_GET['q']);

    // Compare with the internal and path alias (if any).
    $page_match = drupal_match_path($path, $row->paths);
    if ($path != $_GET['q']) {
      $page_match = $page_match || drupal_match_path($_GET['q'], $row->paths);
    }
    if ($page_match) {
      $settings['pardot_c_id'] = check_plain($row->campaign_id);
      break;
    }
  }
  if (!isset($settings['pardot_c_id'])) {
    $settings['pardot_c_id'] = check_plain(variable_get('pardot_c_id', ''));
  }

  // Compare with the internal and path alias (if any) and add scoring.
  $path = drupal_get_path_alias($_GET['q']);
  $score = db_query("SELECT score FROM {pardot_scoring} WHERE path = :path", array(
    ':path' => $path,
  ))
    ->fetchField();
  if (!$score) {
    $score = db_query("SELECT score FROM {pardot_scoring} WHERE path = :path", array(
      ':path' => $_GET['q'],
    ))
      ->fetchField();
  }
  $settings['score'] = check_plain($score);
  drupal_add_js(array(
    'pardot' => $settings,
  ), 'setting');
}

/**
 * Loads a Pardot scoring object.
 *
 * @param int $scoring_id
 *   The scoring object ID.
 */
function pardot_scoring_load($scoring_id) {
  return db_query('SELECT * FROM {pardot_scoring} WHERE scoring_id = :scoring_id', array(
    ':scoring_id' => $scoring_id,
  ))
    ->fetchObject();
}

/**
 * Loads a Pardot campaign object.
 *
 * @param int $campaign
 *   The campaign ID.
 */
function pardot_campaign_load($campaign) {
  return db_query('SELECT * FROM {pardot_campaign} WHERE campaign_id = :campaign_id', array(
    ':campaign_id' => $campaign,
  ))
    ->fetchObject();
}

/**
 * Form submission handler for pardot_form_alter().
 *
 * Stores submissions for Pardot.
 */
function pardot_webform_submit($form, &$form_state) {
  $values = array();

  // Browser headers!
  $values['user_headers'] = _pardot_get_user_headers();

  // Collapse form values so they make more sense to Pardot.
  $values['post_fields'] = _pardot_form_collapse($form, $form_state);

  // Save the values and essential information to the database.
  $submission = new stdClass();
  $submission->form_nid = $form['#node']->nid;
  $submission->data = $values;
  pardot_submission_save($submission);
  if (!$submission->sid) {
    $message = 'Unable to save submitted entry. <pre>!data</pre>';
    $vars = array(
      '!data' => var_export($submission, TRUE),
    );
    watchdog('pardot', $message, $vars, WATCHDOG_NOTICE);
  }
  else {
    $_SESSION['pardot_submission'] = $submission->sid;
  }
}

/**
 * Returns the user headers filtered for types that shouldn't be needed.
 *
 * @return array
 *   The filtered user headers.
 */
function _pardot_get_user_headers() {
  $headers = array();

  // Getting the request headers only exists in apache.
  if (function_exists('apache_request_headers')) {
    $headers = apache_request_headers();
  }
  else {

    // Logic judiciously stolen from
    // @link http://www.php.net/manual/en/function.apache-request-headers.php#72498 @endlink
    foreach ($_SERVER as $k => $v) {
      if (substr($k, 0, 5) == 'HTTP_') {
        $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
        $headers[$k] = $v;
      }
    }
  }

  // Check to see if the function succeeded or not.
  if (!$headers) {
    return array();
  }

  // Lowercase just to be sure we're consistent.
  foreach ($headers as $key => $value) {
    $headers[strtolower($key)] = $value;
  }
  unset($headers['host']);
  unset($headers['cookie']);
  return $headers;
}

/**
 * Loads a Pardot form settings object.
 *
 * @param int $nid
 *   Associated webform node id.
 *
 * @return object|FALSE
 *   Settings object or false on failure.
 */
function pardot_webform_load($nid) {
  $record = db_query("SELECT * FROM {pardot_webform} WHERE nid = :nid", array(
    ':nid' => $nid,
  ))
    ->fetchObject();
  if ($record) {
    $record->data = unserialize($record->data);
  }
  return $record;
}

/**
 * Helper function that save form submissions.
 *
 * @param object $submission
 *   A submission object.
 */
function pardot_submission_save($submission) {

  // Set some sane defaults for new submissions.
  if (!isset($submission->submitted)) {
    $submission->submitted = $_SERVER['REQUEST_TIME'];
  }
  if (!isset($submission->status)) {
    $submission->status = PARDOT_STATUS_NEW;
  }
  if (isset($submission->sid)) {
    drupal_write_record('pardot_submissions', $submission, array(
      'sid',
    ));
  }
  else {
    drupal_write_record('pardot_submissions', $submission);
  }
}

/**
 * Loads a submission object from the database.
 *
 * @param int $sid
 *   Submission ID.
 */
function pardot_submission_load($sid) {
  $object = db_query("SELECT * FROM {pardot_submissions} WHERE sid = :sid", array(
    ':sid' => $sid,
  ))
    ->fetchObject();
  $object->data = unserialize($object->data);
  return $object;
}

/**
 * Deletes a form submission.
 *
 * Not sure there is a use case for this but it's here for completeness.
 *
 * @param int $sid
 *   Submission id.
 */
function pardot_submission_delete($sid) {
  db_delete('pardot_submissions')
    ->condition('sid', $sid)
    ->execute();
}

/**
 * Collapses a submitted form into a flat array for Pardot.
 */
function _pardot_form_collapse($form, $form_state) {
  $result = array();
  if (!empty($form_state['webform'])) {
    foreach ($form_state['webform']['component_tree']['children'] as $key => $value) {
      if (isset($form_state['values']['submitted'][$key])) {
        $form_tree[$value['form_key']] = $form_state['values']['submitted'][$key];
      }
    }
  }
  else {
    $form_tree = $form_state['values']['submitted'];
  }
  _pardot_form_collapse_form($form_tree, $form_state['values']['submitted'], $form['submitted'], $result);
  return $result;
}

/**
 * Helper function to recurse through posted webform.
 *
 * @param array $tree
 *   The post tree name => value pairs.
 * @param array $posted_values
 *   The post tree, could be name => value pairs or index => value pairs.
 * @param array $form
 *   The actual form structure of the form.
 * @param array $result
 *   Return by reference re-structured tree that Pardot will leverage.
 *
 * @see _pardot_form_collapse()
 */
function _pardot_form_collapse_form($tree, $posted_values, $form, &$result) {
  foreach ($tree as $name => $value) {

    // Expand things in fieldsets.
    if (is_array($value) && !in_array($value, $posted_values)) {
      _pardot_form_collapse_form($value, $posted_values, $form[$name], $result);
    }
    elseif (is_array($value)) {

      // If it looks like a date, and the year is reasonable then use slashes
      // 0-1-2 = M/D/Y
      if (count($value) == 3 && $value[2] > 1900 && $value[2] < 2100 && checkdate($value[0], $value[1], $value[2])) {
        $result[$name] = implode('/', $value);
      }
      else {
        $result[$name] = implode(',', $value);
      }
    }
    elseif ($form[$name]['#type'] == 'select') {

      // Map select values to text versions. The numeric values won't mean
      // much to Pardot, CRM or any other integration.
      $result[$name] = $form[$name]['#options'][$value];
    }
    elseif (!empty($form[$name]['#addressfield'])) {
      if ($address = unserialize($value)) {
        foreach ($address as $address_field => $address_field_value) {
          if (empty($result[$address_field])) {
            $result[$address_field] = $address_field_value;
          }
        }
      }
    }
    else {
      $result[$name] = $value;
    }
  }
}

/**
 * Loads all webform enabled nodes with Pardot post URL.
 *
 * @return object|FALSE
 *   Settings object or false on failure.
 */
function pardot_webform_enabled_pardot_load() {
  $results = db_query("SELECT * FROM {pardot_webform}");
  $header = array(
    t('Node'),
    t('Edit Post URL'),
    t('URL'),
    t('Active'),
  );
  $rows = array();
  foreach ($results as $result) {
    $node = node_load($result->nid);
    $rows[] = array(
      l($node->title, "node/{$result->nid}"),
      l(t('Edit'), "node/{$result->nid}/webform/pardot"),
      $result->url,
      $result->is_active,
    );
  }
  return theme('table', array(
    'header' => $header,
    'rows' => $rows,
  ));
}

/**
 * Determines if Pardot code should be add for the current page.
 *
 * @return bool
 *   Returns TRUE if GA code should be added to the page, FALSE otherwise.
 */
function _pardot_visibility_pages() {
  static $page_match;

  // Cache visibility result if function is called more than once.
  if (!isset($page_match)) {
    $visibility = variable_get('pardot_visibility_pages', 0);
    $setting_pages = variable_get('pardot_pages', PARDOT_PAGES);

    // Match path if necessary.
    if (!empty($setting_pages)) {

      // Convert path to lowercase. This allows comparison of the same path
      // with different case. Ex: /Page, /page, /PAGE.
      $pages = drupal_strtolower($setting_pages);
      if ($visibility < 2) {

        // Convert the Drupal path to lowercase.
        $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));

        // Compare the lowercase internal and lowercase path alias (if any).
        $page_match = drupal_match_path($path, $pages);
        if ($path != $_GET['q']) {
          $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
        }

        // When $visibility has a value of 0, the tracking code is displayed on
        // all pages except those listed in $pages. When set to 1, it
        // is displayed only on those pages listed in $pages.
        $page_match = !($visibility xor $page_match);
      }
      elseif (module_exists('php')) {
        $page_match = php_eval($setting_pages);
      }
      else {
        $page_match = FALSE;
      }
    }
    else {
      $page_match = TRUE;
    }
  }
  return $page_match;
}

/**
 * Determines if Pardot code should be add for the given user's role.
 *
 * @param array $user
 *   The given user.
 *
 * @return bool
 *   Returns TRUE if GA code should be added for the role, FALSE otherwise.
 */
function _pardot_visibility_roles($user) {
  $visibility = variable_get('pardot_visibility_roles', 0);
  $enabled = $visibility;
  $roles = variable_get('pardot_roles', array());
  if (array_sum($roles) > 0) {

    // One or more roles are selected.
    foreach (array_keys($user->roles) as $rid) {

      // Is the current user a member of one of these roles?
      if (isset($roles[$rid]) && $rid == $roles[$rid]) {

        // Current user is a member of a role that should be tracked/excluded
        // from tracking.
        $enabled = !$visibility;
        break;
      }
    }
  }
  else {

    // No role is selected for tracking, therefore all roles should be tracked.
    $enabled = TRUE;
  }
  return $enabled;
}

Functions

Namesort descending Description
pardot_campaign_load Loads a Pardot campaign object.
pardot_form_alter Implements hook_form_alter().
pardot_help Implements hook_help().
pardot_init Implements hook_init().
pardot_js Processes pardot_js() variables and adds settings.
pardot_menu Implements hook_menu().
pardot_page_build Implements hook_page_build().
pardot_permission Implements hook_permission().
pardot_scoring_load Loads a Pardot scoring object.
pardot_submission_delete Deletes a form submission.
pardot_submission_load Loads a submission object from the database.
pardot_submission_save Helper function that save form submissions.
pardot_theme Implements hook_theme().
pardot_webform_enabled_pardot_load Loads all webform enabled nodes with Pardot post URL.
pardot_webform_load Loads a Pardot form settings object.
pardot_webform_submit Form submission handler for pardot_form_alter().
_pardot_form_collapse Collapses a submitted form into a flat array for Pardot.
_pardot_form_collapse_form Helper function to recurse through posted webform.
_pardot_get_user_headers Returns the user headers filtered for types that shouldn't be needed.
_pardot_visibility_pages Determines if Pardot code should be add for the current page.
_pardot_visibility_roles Determines if Pardot code should be add for the given user's role.

Constants

Namesort descending Description
PARDOT_PAGES
PARDOT_STATUS_FAILED
PARDOT_STATUS_NEW @file Pardot integration module.
PARDOT_STATUS_UPLOADED