You are here

facebook_tracking_pixel.module in Facebook Tracking Pixel 7

Same filename and directory in other branches
  1. 8 facebook_tracking_pixel.module

facebook_tracking_pixel.module Facebook Tracking Module.

@author Brady Owens <info@fastglass.net>

File

facebook_tracking_pixel.module
View source
<?php

/**
 * @file facebook_tracking_pixel.module
 * Facebook Tracking Module.
 *
 * @author Brady Owens <info@fastglass.net>
 */

/**
 * Implements hook_menu().
 */
function facebook_tracking_pixel_menu() {
  $items = [];
  $items['admin/config/system/facebook_tracking_pixel'] = [
    'title' => 'Administer Facebook Tracking Pixel',
    'description' => 'Facebook Tracking pixel module.',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_settings_form',
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.inc',
    'type' => MENU_NORMAL_ITEM,
  ];
  $items['admin/config/system/facebook_tracking_pixel/default'] = [
    'title' => 'Administer Facebook Tracking Pixel',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 0,
  ];
  $items['admin/config/system/facebook_tracking_pixel/base_codes'] = [
    'title' => 'Base Tracking Codes',
    'page arguments' => [
      'facebook_tracking_pixel_base_codes_form',
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.inc',
    'type' => MENU_LOCAL_TASK,
  ];
  $items['admin/config/system/facebook_tracking_pixel/user_registration'] = [
    'title' => 'Track User Registration',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_user_registration',
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.inc',
    'type' => MENU_LOCAL_TASK,
  ];
  $items['admin/config/system/facebook_tracking_pixel/base_codes/delete/%'] = [
    'title' => 'Delete a Base Code',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_base_codes_delete_form',
      6,
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.inc',
    'type' => MENU_CALLBACK,
  ];
  $items['admin/config/system/facebook_tracking_pixel/base_codes/edit/%'] = [
    'title' => 'Edit a Base Code',
    'page callback' => 'drupal_get_form',
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.inc',
    'page arguments' => [
      'facebook_tracking_pixel_base_codes_edit_form',
      6,
    ],
    'type' => MENU_CALLBACK,
  ];
  $items['admin/config/system/facebook_tracking_pixel/purge'] = [
    'title' => 'Purge',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_form_purge',
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 50,
  ];
  $items['admin/config/system/facebook_tracking_pixel/path'] = [
    'title' => 'Track Events by Path',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_track_by_path_form',
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.path.inc',
    'type' => MENU_LOCAL_TASK,
  ];
  $items['admin/config/system/facebook_tracking_pixel/path/add'] = [
    'title' => 'Add tracking based on path',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_path_add_form',
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.path.inc',
    'type' => MENU_LOCAL_ACTION,
  ];
  $items['admin/config/system/facebook_tracking_pixel/path/delete/%'] = [
    'title' => 'Deleting an event',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_path_delete_form',
      6,
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.path.inc',
    'type' => MENU_CALLBACK,
  ];
  $items['admin/config/system/facebook_tracking_pixel/path/edit/%'] = [
    'title' => 'Update details of an event',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_path_edit_form',
      6,
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.path.inc',
    'type' => MENU_CALLBACK,
  ];
  $items['admin/config/system/facebook_tracking_pixel/commercetracking'] = [
    'title' => 'Commerce Tracking',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_commerce_form',
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.commerce.inc',
    'type' => MENU_LOCAL_TASK,
  ];
  $items['admin/config/system/facebook_tracking_pixel/enhanced'] = [
    'title' => 'Enhanced Tracking',
    'page callback' => 'drupal_get_form',
    'page arguments' => [
      'facebook_tracking_pixel_form_enhanced',
    ],
    'access arguments' => [
      'administer facebook tracking pixels',
    ],
    'file' => 'facebook_tracking_pixel.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 35,
  ];
  return $items;
}

/**
 * Implements hook_permission().
 */
function facebook_tracking_pixel_permission() {
  $permissions['administer facebook tracking pixels']['title'] = t('Administer Facebook Tracking Pixels.');
  return $permissions;
}

/**
 * Implements hook_page_build().
 */
function facebook_tracking_pixel_page_build(&$page) {

  // Assertain which role should see the tracking information.
  global $user;

  // Default to no tracking.
  $trackable = 0;

  // Determin if the user is trackable based on roles assigned.
  $trackable += _facebook_tracking_pixel_roles($user);

  // Only process tracking codes if the user is trackable.
  if ($trackable > 0) {

    // Pull base code IDs from database and build the noscript header includes.
    $basecodes = db_select('facebook_tracking_pixel_base_codes', 'c')
      ->fields('c')
      ->orderBy('weight')
      ->execute()
      ->fetchAllAssoc('base_code_id');

    // Facebook static code.
    $fb_noscript_src = facebook_tracking_pixel_base_code_nojs();

    // Facebook JS code.
    $fb_script_src = facebook_tracking_pixel_base_code_js();

    // Script path.
    $path = variable_get('facebook_tracking_pixel_path', 'public://facebook_tracking_pixel');

    // Process anything that could be stored in the session.
    if (!empty($_SESSION['facebook_tracking_pixel'])) {

      // We use this foreach to step through the session variables for special
      // case codes.
      foreach ($_SESSION['facebook_tracking_pixel'] as $key => $value) {
        switch ($key) {
          case 'registration':
            $userregfile = $path . '/registrationtracking/fb_trk_user_registration.js';
            $page['content']['#attached']['js']['facebook_tracking_pixel_path_user_registration'] = [
              'type' => 'file',
              'group' => JS_THEME,
              'data' => $userregfile,
              'preprocess' => (bool) variable_get('facebook_tracking_pixel_aggregation', FALSE),
            ];

            // Assemble code and pull the FBID from the session variable.
            $fb_base_code_nojs = $fb_noscript_src[0] . $_SESSION['facebook_tracking_pixel']['registration_fbid'] . $fb_noscript_src[1];
            drupal_add_html_head([
              '#type' => 'markup',
              '#markup' => $fb_base_code_nojs,
              '#weight' => 150,
            ], 'facebook_tracking_pixel_path_user_registration');

            // We remove the session variables, we do not want it loading but once.
            unset($_SESSION['facebook_tracking_pixel']['registration']);
            unset($_SESSION['facebook_tracking_pixel']['registration_fbid']);

            // If this is a user registration event we stop processing.
            return;
            break;
          case 'ftpdcaddtocart':
            $ftpdcbasecodeid = variable_get('facebook_tracking_pixel_commerce_tracking_basecode');
            $ftpdcfbid = db_select('facebook_tracking_pixel_base_codes', 'c')
              ->fields('c', [
              'base_code_fbid',
            ])
              ->condition('base_code_id', $ftpdcbasecodeid, '=')
              ->execute()
              ->fetchField();

            // Prepare an array of arguments to do text replacements.
            $argreplace = [
              '@cur' => $value['currency_code'],
              '@id' => $value['content_id'],
              '@quantity' => $value['quantity'],
              '@val' => $value['value'],
            ];

            // This event will require the JS to be inline in the page.
            $reservedevents = facebook_tracking_pixel_events_reserved();
            $ftpdcpurcode = format_string($reservedevents['ftpdcaddtocart']['code'], $argreplace);
            $inlinejs = $fb_script_src[0] . $ftpdcfbid . $fb_script_src[1] . $ftpdcpurcode;

            // JS to load into page header.
            $page['content']['#attached']['js']['facebook_tracking_pixel_path_drupal_commerce_addtocart'] = [
              'type' => 'inline',
              'group' => JS_THEME,
              'data' => $inlinejs,
              'preprocess' => (bool) variable_get('facebook_tracking_pixel_aggregation', FALSE),
            ];

            // Noscript for header.
            $fb_base_code_nojs = $fb_noscript_src[0] . $ftpdcfbid . $fb_noscript_src[1];
            drupal_add_html_head([
              '#type' => 'markup',
              '#markup' => $fb_base_code_nojs,
              '#weight' => 150,
            ], 'facebook_tracking_pixel_path_drupal_commerce_addtocart');

            // Delete session variable.
            unset($_SESSION['facebook_tracking_pixel']['ftpdcaddtocart']);
            break;
          case 'ftpdcinitiatecheckout':
            $ftpdcbasecodeid = variable_get('facebook_tracking_pixel_commerce_tracking_basecode');
            $ftpdcfbid = db_select('facebook_tracking_pixel_base_codes', 'c')
              ->fields('c', [
              'base_code_fbid',
            ])
              ->condition('base_code_id', $ftpdcbasecodeid, '=')
              ->execute()
              ->fetchField();
            $subdir = variable_get('facebook_tracking_pixel_commerce_js_subdir', 'commercetracking');
            $ftpdcfilname = $path . '/' . $subdir . '/' . 'fb_trk_checkoutstart_' . $ftpdcfbid . '.js';

            // JS to load into page header.
            $page['content']['#attached']['js']['facebook_tracking_pixel_path_drupal_commerce_initiatecheckout'] = [
              'type' => 'file',
              'group' => JS_THEME,
              'data' => $ftpdcfilname,
              'preprocess' => (bool) variable_get('facebook_tracking_pixel_aggregation', FALSE),
            ];

            // Noscript for header.
            $fb_base_code_nojs = $fb_noscript_src[0] . $ftpdcfbid . $fb_noscript_src[1];
            drupal_add_html_head([
              '#type' => 'markup',
              '#markup' => $fb_base_code_nojs,
              '#weight' => 150,
            ], 'facebook_tracking_pixel_path_drupal_commerce_initiatecheckout');

            // Delete session variable.
            unset($_SESSION['facebook_tracking_pixel']['ftpdcinitiatecheckout']);
            unset($subdir);
            break;
          case 'ftpdcpurchase':
            $ftpdcbasecodeid = variable_get('facebook_tracking_pixel_commerce_tracking_basecode');
            $ftpdcfbid = db_select('facebook_tracking_pixel_base_codes', 'c')
              ->fields('c', [
              'base_code_fbid',
            ])
              ->condition('base_code_id', $ftpdcbasecodeid, '=')
              ->execute()
              ->fetchField();

            // We have to load the order and retrieve the total and currency
            $order = commerce_order_load($value);
            $wrapper = entity_metadata_wrapper('commerce_order', $order);
            $currency_code = $wrapper->commerce_order_total->currency_code
              ->value();
            $total = $wrapper->commerce_order_total->amount
              ->value();
            $total = sprintf('%.2f', $total / 100);

            // Add the products to the contents parameter, I am using the node ID as the product ID.
            $order_contents = '';
            foreach ($order->commerce_line_items['und'] as $order_line_item) {
              $line_item = commerce_line_item_load($order_line_item['line_item_id']);
              if ($line_item && $line_item->type == 'product') {
                $order_contents .= '{"id":' . $line_item->data['context']['entity']['entity_id'] . ', "quantity":' . $line_item->quantity . '}';
              }
            }

            // Prepare an array of arguments to do text replacements.
            // Add the order contents to the replace array.
            $argreplace = [
              '@contents' => $order_contents,
              '@cur' => $currency_code,
              '@val' => $total,
            ];

            // This event will require the JS to be inline in the page.
            $reservedevents = facebook_tracking_pixel_events_reserved();
            $ftpdcpurcode = format_string($reservedevents['ftpdcpurchase']['code'], $argreplace);
            $inlinejs = $fb_script_src[0] . $ftpdcfbid . $fb_script_src[1] . $ftpdcpurcode;
            $page['content']['#attached']['js']['facebook_tracking_pixel_path_drupal_commerce_purchase'] = [
              'type' => 'inline',
              'group' => JS_THEME,
              'data' => $inlinejs,
              'preprocess' => FALSE,
            ];

            // Noscript for header.
            $fb_base_code_nojs = $fb_noscript_src[0] . $ftpdcfbid . $fb_noscript_src[1];
            drupal_add_html_head([
              '#type' => 'markup',
              '#markup' => $fb_base_code_nojs,
              '#weight' => 150,
            ], 'facebook_tracking_pixel_path_drupal_commerce_purchase');

            // Delete session variable.
            unset($_SESSION['facebook_tracking_pixel']['ftpdcpurchase']);
            break;

          // If an alter hook has been created. Allow it to be displayed.
          default:
            $context = [
              'fb_script_src' => $fb_script_src,
              'fb_noscript_src' => $fb_noscript_src,
            ];
            drupal_alter('facebook_tracking_pixel_event_' . $key, $value, $page, $context);

            // Delete session variable for the custom tracking code.
            unset($_SESSION['facebook_tracking_pixel'][$key]);
            break;
        }
      }
    }

    // Gather the path based tracking codes.
    $trackingpaths = facebook_tracking_pixel_path_codes();

    // If we have tracking codes. Build the page items.
    if (!empty($trackingpaths)) {
      $i = 0;
      foreach ($trackingpaths as $code) {
        $page['content']['#attached']['js']['facebook_tracking_pixel_path_' . $i] = [
          'type' => 'file',
          'group' => JS_THEME,
          'data' => $code['event_js_file'],
          'preprocess' => (bool) variable_get('facebook_tracking_pixel_aggregation', FALSE),
        ];

        // Assemble code.
        if (isset($basecodes[$code['event_base_code_id']])) {
          $fb_base_code_nojs = $fb_noscript_src[0] . $basecodes[$code['event_base_code_id']]->base_code_fbid . $fb_noscript_src[1];
          drupal_add_html_head([
            '#type' => 'markup',
            '#markup' => $fb_base_code_nojs,
            '#weight' => 150 + $i,
          ], 'facebook_tracking_pixel_path_noscript_' . $i);
          $i++;
        }

        // If we have a tracking path with the same base code id, we must drop
        // the base code ID so it is not loaded below. Preventing duplicate codes
        // loading on the same page since the path code will contain the base code
        // JS components.
        if (array_key_exists($code['event_base_code_id'], $basecodes)) {
          unset($basecodes[$code['event_base_code_id']]);
        }
      }
    }

    // Process global tracking codes that are to run on the entire site.
    $i = 0;
    foreach ($basecodes as $id => $values) {
      if ($values->base_code_global == 1) {

        // Our static tracking file.
        $file = $path . '/fb_tkpx.' . $values->base_code_fbid . '.js';

        // Page content with the static tracking file.
        $page['content']['#attached']['js']['facebook_tracking_pixel_' . $i] = [
          'type' => 'file',
          'group' => JS_THEME,
          'data' => $file,
          'preprocess' => (bool) variable_get('facebook_tracking_pixel_aggregation', FALSE),
        ];

        // Assemble noscript code and add it to the head.
        $fb_base_code_nojs = $fb_noscript_src[0] . $values->base_code_fbid . $fb_noscript_src[1];
        drupal_add_html_head([
          '#type' => 'markup',
          '#markup' => $fb_base_code_nojs,
          '#weight' => 200 + $i,
        ], 'facebook_tracking_pixel_noscript_' . $i);
      }
      $i++;
    }
  }
}

/**
 * Return keyed array of standard events.
 *
 * @return array
 */
function facebook_tracking_pixel_events() {
  $hook = 'facebook_tracking_pixel_events';
  $results = module_invoke_all($hook);
  if (!is_array($results)) {
    $results = [];
  }
  drupal_alter($hook, $results);
  return $results;
}

/**
 * Implements hook_facebook_tracking_pixel_events().
 *
 * This is a model of how other modules can alter tracking events. Events
 * are keyed wih the name of the event per Facebook documentation. The sub-array
 * contains the human readable name and the JS code for the event.
 *
 * @return array
 */
function facebook_tracking_pixel_facebook_tracking_pixel_events() {
  $events = [];
  $events['pageview'] = [
    'name' => t('Key Page View'),
    'code' => 'fbq(\'track\', \'ViewContent\');',
  ];
  $events['search'] = [
    'name' => t('Search'),
    'code' => 'fbq(\'track\', \'Search\');',
  ];
  $events['addtocart'] = [
    'name' => t('Add to Cart'),
    'code' => 'fbq(\'track\', \'AddToCart\');',
  ];
  $events['addtowish'] = [
    'name' => t('Add to Wishlist'),
    'code' => 'fbq(\'track\', \'AddToWishlist\');',
  ];
  $events['checkoutstart'] = [
    'name' => t('Initiate checkout'),
    'code' => 'fbq(\'track\', \'InitiateCheckout\');',
  ];
  $events['addpaymentinfo'] = [
    'name' => t('Add Payment Info'),
    'code' => 'fbq(\'track\', \'AddPaymentInfo\');',
  ];
  $events['lead'] = [
    'name' => t('Lead'),
    'code' => 'fbq(\'track\', \'Lead\');',
  ];
  $events['registration'] = [
    'name' => t('Complete Registration'),
    'code' => 'fbq(\'track\', \'CompleteRegistration\');',
  ];
  return $events;
}

/**
 * Returns the events reserved for this module.
 *
 * @return array
 */
function facebook_tracking_pixel_events_reserved() {
  $events = [];
  $events['ftpregistration'] = [
    'name' => t('Complete Registration'),
    'code' => 'fbq(\'track\', \'CompleteRegistration\');',
  ];
  $events['ftpdcinitiatecheckout'] = [
    'name' => t('Initiate checkout'),
    'code' => 'fbq(\'track\', \'InitiateCheckout\');',
  ];
  $events['ftpdcaddtocart'] = [
    'name' => t('Add to Cart'),
    'code' => 'fbq(\'track\', \'AddToCart\', {contents: [{"id":@id, "quantity":@quantity}], content_type: \'product\', value: \'@val\', currency: \'@cur\'});',
  ];
  $events['ftpdcpurchase'] = [
    'name' => t('Make Purchase'),
    'code' => 'fbq(\'track\', \'Purchase\', {contents: [@contents], content_type: \'product\', value: \'@val\', currency: \'@cur\'});',
  ];
  return $events;
}

/**
 * Return keyed array of standard events in a format for select boxes.
 *
 * @return array
 */
function facebook_tracking_pixel_events_options() {
  $events = facebook_tracking_pixel_events();
  $options = [];
  foreach ($events as $key => $value) {
    $options[$key] = $value['name'];
  }
  return $options;
}

/**
 * Implements hook_theme().
 */
function facebook_tracking_pixel_theme() {
  return [
    'facebook_tracking_pixel_base_codes_form' => [
      'render element' => 'form',
      'file' => 'facebook_tracking_pixel.admin.inc',
    ],
    'facebook_tracking_pixel_track_by_path_form' => [
      'render element' => 'form',
      'file' => 'facebook_tracking_pixel.admin.path.inc',
    ],
  ];
}

/**
 * Returns the pieces of the FB tracking JS script.
 *
 * @return array
 */
function facebook_tracking_pixel_base_code_js() {
  $fb_script_src = [
    '!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
    n.push=n;n.loaded=!0;n.version=\'2.0\';n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
    document,\'script\',\'//connect.facebook.net/en_US/fbevents.js\');
    fbq(\'init\', \'',
    '\');fbq(\'track\', "PageView");',
  ];
  return $fb_script_src;
}

/**
 * Returns the noscript code.
 *
 * @return array
 */
function facebook_tracking_pixel_base_code_nojs() {

  // Facebook static code.
  $fb_noscript_src = [
    '<noscript><img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=',
    '&ev=PageView&noscript=1"/></noscript>',
  ];
  return $fb_noscript_src;
}

/**
 * Returns all the path codes and allows other modules to alter them.
 *
 * @return array
 */
function facebook_tracking_pixel_path_codes() {
  $trackingpaths =& drupal_static(__FUNCTION__);
  if (!$trackingpaths) {
    $result = db_select('facebook_tracking_pixel_events_path', 'g')
      ->fields('g', [
      'event_path',
      'event_js_file',
      'event_base_code_id',
    ])
      ->condition('event_enable', 1, '=');
    $result = $result
      ->execute();
    while ($code = $result
      ->fetchAssoc()) {
      $trackingpaths[] = $code;
    }

    // Allow other modules to alter the codes.
    drupal_alter('facebook_tracking_pixel', $trackingpaths);
  }
  return $trackingpaths;
}

/**
 * Based on visibility setting this function an integer. Anything greater than
 * 0 is trackable.
 *
 * @param object $account
 *  user object
 *
 * @return bool
 */
function _facebook_tracking_pixel_roles($account) {

  // Pull role information from database.
  $sql = 'select * from {variable} where name like :name';
  $result = db_query($sql, [
    ':name' => 'facebook_tracking_pixel_roles_%',
  ])
    ->fetchAll();

  // Pull the visibility setting. A value of 1 means the roles are inverted in
  // the selection UI.
  $visibility = variable_get('facebook_tracking_pixel_visibility_roles', 0);

  // If the selection is inverted we enable visibility. Otherwise default is
  // no tracking.
  $enabled = $visibility;
  $roles = [];

  // Build array of role information.
  if (!empty($result)) {
    foreach ($result as $item) {
      if ($item->value == 'i:1;') {
        $roles[$item->name] = 1;
      }
      elseif ($item->value == 'i:0;') {
        $roles[$item->name] = 0;
      }
    }
  }
  if (array_sum($roles) > 0) {

    // One or more roles are selected.
    foreach ($account->roles as $rid => $rname) {

      // Fixup the role name.
      $rname = str_replace(' ', '_', $rname);
      $rname = 'facebook_tracking_pixel_roles_' . $rname;

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

        // Current user is a member of a role that should be tracked/excluded
        // from tracking. The visibility variable is used and inverted. This
        // accounts for the settings in the UI of tracking only selected or
        // tracking all but selected.
        $enabled = !$visibility;
        break;
      }
    }
  }
  return $enabled;
}

/**
 * Implements hook_user_insert().
 */
function facebook_tracking_pixel_user_insert(&$edit, $account, $category) {
  $registration = variable_get('facebook_tracking_pixel_user_registration_enable', FALSE);
  if ($registration) {

    // We add the FBID to a session variable.
    $basecodeid = variable_get('facebook_tracking_pixel_user_registration_basecode');
    $base_code_fbid = db_select('facebook_tracking_pixel_base_codes', 'c')
      ->fields('c', [
      'base_code_fbid',
    ])
      ->condition('base_code_id', $basecodeid, '=')
      ->execute()
      ->fetchField();
    facebook_tracking_pixel_add_session_event('registration');
    facebook_tracking_pixel_add_session_event('registration_fbid', $base_code_fbid);
  }
}

/**
 * We use our own hook_alter to load the codes.
 * This is also an example of how another module would alter the codes.
 *
 * @param $trackingpaths
 */
function facebook_tracking_pixel_facebook_tracking_pixel_alter(&$trackingpaths) {
  if (!empty($trackingpaths)) {
    foreach ($trackingpaths as $index => $code) {
      $page_match = FALSE;
      $paths = $code['event_path'];
      $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));

      // Compare the lowercase internal and lowercase path alias (if any).
      $path_match = drupal_match_path($path, $paths);
      if ($path != $_GET['q']) {
        $path_match = $path_match || drupal_match_path($_GET['q'], $paths);
      }
      if (!$path_match) {
        unset($trackingpaths[$index]);
      }
    }
  }
}

/**
 * Remove a base code by the FBID number.
 *
 * @param int $tid
 * @param int $fbid
 *
 * @return bool
 */
function facebook_tracking_pixel_base_code_delete($tid, $fbid) {
  $status = TRUE;

  // Remove JS file.
  $filename = 'fb_tkpx.' . $fbid . '.js';
  $filedelete = facebook_tracking_pixel_delete_file($filename);
  if (!$filedelete) {
    $status = FALSE;
  }
  if (!$status) {
    drupal_set_message(t('Failed to delete base code file.'), 'error', FALSE);
  }

  // Remove base code from database.
  if (!db_delete('facebook_tracking_pixel_base_codes')
    ->condition('base_code_id', $tid, '=')
    ->execute()) {
    $status = FALSE;
  }
  $pathcount = db_select('facebook_tracking_pixel_events_path', 'c')
    ->fields('c')
    ->condition('event_base_code_id', $tid, '=')
    ->countQuery()
    ->execute()
    ->fetchField();
  if ($pathcount > 0) {
    $subdir = variable_get('facebook_tracking_pixel_path_subdir', 'pathtracking');
    try {
      $deletepathuids = db_select('facebook_tracking_pixel_events_path', 'c')
        ->fields('c', [
        'event_uid',
      ])
        ->condition('event_base_code_id', $tid, '=')
        ->execute()
        ->fetchAssoc();
      foreach ($deletepathuids as $item) {
        facebook_tracking_pixel_delete_file('fb_trk.' . $item . '.js', $subdir);
      }
    } catch (Exception $e) {
      watchdog('facebook_tracking_pixel', 'Failed to delete path items when deleting a base code %error.', [
        '%error' => $e
          ->getMessage(),
      ], WATCHDOG_ERROR, NULL);
      drupal_set_message('Could not save the JS file. Check the Drupal and PHP logs.', 'error', FALSE);
      $status = FALSE;
    }

    // Remove path tracking referencing this basecode from the database.
    try {
      db_delete('facebook_tracking_pixel_events_path')
        ->condition('event_base_code_id', $tid, '=')
        ->execute();
    } catch (Exception $e) {
      watchdog('facebook_tracking_pixel', 'Failed to delete path items DB entries when deleting a base code %error.', [
        '%error' => $e
          ->getMessage(),
      ], WATCHDOG_ERROR, NULL);
      $status = FALSE;
    }
  }

  // If the Base Code ID being deleted matches one use for user tracking, destroy.
  $usertrackingid = variable_get('facebook_tracking_pixel_user_registration_basecode', NULL);
  if ($usertrackingid == $tid) {
    variable_del('facebook_tracking_pixel_user_registration_basecode');
    variable_del('facebook_tracking_pixel_user_registration_enable');
    unset($_SESSION['facebook_tracking_pixel']['registration']);
    unset($_SESSION['facebook_tracking_pixel']['registration_fbid']);
    facebook_tracking_pixel_delete_file('fb_trk_user_registration.js', 'registrationtracking');
  }
  if (!$status) {
    drupal_set_message(t('Failed to remove base code from database.'), 'error', FALSE);
  }
  if (!$status) {
    drupal_set_message(t('Check your PHP server logs.'), 'error', FALSE);
  }
  else {
    drupal_set_message(t('Base code deleted.'), 'status', FALSE);
  }
  if ($filedelete) {
    facebook_tracking_pixel_clear_cache();
  }
  return $status;
}

/**
 * Deletes all CSS & JavaScript from the file system or a single file.
 *
 * @param null $filename
 * @param null $subdir
 *
 * @return bool
 */
function facebook_tracking_pixel_delete_file($filename = NULL, $subdir = NULL) {
  $path = variable_get('facebook_tracking_pixel_path', 'public://facebook_tracking_pixel');

  // Calling the function without a file name will delete everything.
  if ($filename == NULL) {
    if (!($files = file_scan_directory($path, '/.*\\.js$/'))) {
      foreach ($files as $key => $value) {
        file_unmanaged_delete($path . '/' . $key);
      }
      return TRUE;
    }
  }
  else {
    if (!empty($subdir)) {
      $deletepath = $path . '/' . $subdir . '/' . $filename;
    }
    else {
      $deletepath = $path . '/' . $filename;
    }
    file_unmanaged_delete($deletepath);
    return TRUE;
  }
  return FALSE;
}

/**
 * Saves JavaScript in the file system (but only if not empty).
 *
 * @param $data
 * @param $filename
 * @param null $subdir
 *
 * @return bool|null|string
 */
function facebook_tracking_pixel_save_file($data, $filename, $subdir = NULL) {
  if (!drupal_strlen(trim($data))) {
    return FALSE;
  }
  $path = variable_get('facebook_tracking_pixel_path', 'public://facebook_tracking_pixel');
  if (!empty($subdir)) {
    $path = $path . '/' . $subdir;
  }
  file_prepare_directory($path, FILE_CREATE_DIRECTORY);
  $file_saved = file_unmanaged_save_data($data, $path . '/' . $filename, FILE_EXISTS_REPLACE);
  facebook_tracking_pixel_clear_cache();
  return $file_saved;
}

/**
 * Function to call from CRUD operations to clear caches.
 */
function facebook_tracking_pixel_clear_cache() {
  cache_clear_all('*', 'cache_page', TRUE);

  // Clear views cache if available.
  if (module_exists('views')) {
    cache_clear_all('*', 'cache_views', TRUE);
    cache_clear_all('*', 'cache_views_data', TRUE);
  }

  // Trigger reloading the CSS and JS file cache in AdvAgg, if available.
  if (module_exists('advagg')) {
    module_load_include('inc', 'advagg', 'advagg.cache');
    advagg_push_new_changes();
  }
}

/**
 * Adds Facebook Pixel event to the user session to be added to the page code.
 *
 * @param string $event
 *   A Facebook Pixel event to be added to the page code via sessions.
 *
 * @param string $value
 *   If the event has a value it can be passed.
 *
 * @see facebook_tracking_pixel_events() for details on events.
 */
function facebook_tracking_pixel_add_session_event($event, $value = NULL) {

  // In the session variable we store the key to our array of events.
  if (!isset($_SESSION['facebook_tracking_pixel'])) {
    $_SESSION['facebook_tracking_pixel'] = [];
  }

  // Use event name for array key as well, so that we don't send
  // the same event multiple times. And if a value is supplied it
  // is passed in the session variable.
  if (!empty($value)) {
    $_SESSION['facebook_tracking_pixel'][$event] = $value;
  }
  else {
    $_SESSION['facebook_tracking_pixel'][$event] = TRUE;
  }
}

/**
 * Returns currency codes from the xml file.
 *
 * This is used if Drupal Commerce is not available.
 *
 * @return array
 */
function facebook_tracking_pixel_get_currency_codes() {
  $currencyfile = drupal_get_path('module', 'facebook_tracking_pixel') . '/' . 'currency-codes-iso4217.xml';
  $currencydata = simplexml_load_file($currencyfile);
  $json_string = json_encode($currencydata);
  $result_array = json_decode($json_string, TRUE);
  $currencycodes = [];
  foreach ($result_array['CcyTbl']['CcyNtry'] as $item) {
    if (!empty($item['Ccy'])) {
      $currencycodes[$item['Ccy']] = $item['CcyNm'] . ' (' . $item['Ccy'] . ')';
    }
  }
  return $currencycodes;
}

/**
 * Implements hook_commerce_cart_product_add().
 *
 * Tracks when an item is added to the cart.
 *
 * @param $order
 * @param $product
 * @param $quantity
 * @param $line_item
 */
function facebook_tracking_pixel_commerce_cart_product_add($order, $product, $quantity, $line_item) {
  $enable = variable_get('facebook_tracking_pixel_commerce_tracking_enable', NULL);
  if ($enable && ($options = variable_get('facebook_tracking_pixel_commerce_tracking_options_selection', NULL))) {
    if (array_key_exists('addtocart', $options)) {

      // I am using the node ID as the product ID.
      $value = [
        'content_id' => $line_item->data['context']['entity']['entity_id'],
        'currency_code' => $line_item->commerce_unit_price['und'][0]['currency_code'],
        'quantity' => $quantity,
        'value' => commerce_currency_amount_to_decimal($line_item->commerce_unit_price['und'][0]['amount'], $line_item->commerce_unit_price['und'][0]['currency_code']),
      ];
      facebook_tracking_pixel_add_session_event('ftpdcaddtocart', $value);
    }
  }
}

/**
 * Implements hook_commerce_checkout_router().
 *
 * Tracks when a customer enters the checkout workflow.
 *
 * @param $order
 * @param $checkout_page
 */
function facebook_tracking_pixel_commerce_checkout_router($order, $checkout_page) {
  $enable = variable_get('facebook_tracking_pixel_commerce_tracking_enable', NULL);
  $options = variable_get('facebook_tracking_pixel_commerce_tracking_options_selection', NULL);
  if ($enable && !empty($options)) {
    if (array_key_exists('checkoutstart', $options)) {
      if ($checkout_page['page_id'] == 'checkout') {
        facebook_tracking_pixel_add_session_event('ftpdcinitiatecheckout');
      }
    }
  }
}

/**
 * Implements hook_commerce_checkout_complete().
 *
 * This fires when checkout is complete to track the event.
 *
 * @param $order
 */
function facebook_tracking_pixel_commerce_checkout_complete($order) {
  $enable = variable_get('facebook_tracking_pixel_commerce_tracking_enable', 0);
  if ($enable) {
    $options = variable_get('facebook_tracking_pixel_commerce_tracking_options_selection');
    if (array_key_exists('purchase', $options)) {

      // We pass and store the order ID number so it can be used to populate currency
      // and total values in the page build.
      facebook_tracking_pixel_add_session_event('ftpdcpurchase', $order->order_id);
    }
  }
}

/**
 * Implements hook_node_delete().
 */
function facebook_tracking_pixel_node_delete($node) {

  //  If the node being deleted has a path tracking item, disable the item.
  $result = db_select('facebook_tracking_pixel_events_path', 'c')
    ->fields('c')
    ->condition('event_path_system', 'node/' . $node->nid, '=')
    ->execute()
    ->fetchAssoc();
  if ($result) {

    // If a node exists then we update the DB to disable that item.
    db_update('facebook_tracking_pixel_events_path')
      ->fields([
      'event_enable' => 0,
    ])
      ->condition('event_id', $result['event_id'], '=')
      ->execute();
  }
}

Functions

Namesort descending Description
facebook_tracking_pixel_add_session_event Adds Facebook Pixel event to the user session to be added to the page code.
facebook_tracking_pixel_base_code_delete Remove a base code by the FBID number.
facebook_tracking_pixel_base_code_js Returns the pieces of the FB tracking JS script.
facebook_tracking_pixel_base_code_nojs Returns the noscript code.
facebook_tracking_pixel_clear_cache Function to call from CRUD operations to clear caches.
facebook_tracking_pixel_commerce_cart_product_add Implements hook_commerce_cart_product_add().
facebook_tracking_pixel_commerce_checkout_complete Implements hook_commerce_checkout_complete().
facebook_tracking_pixel_commerce_checkout_router Implements hook_commerce_checkout_router().
facebook_tracking_pixel_delete_file Deletes all CSS & JavaScript from the file system or a single file.
facebook_tracking_pixel_events Return keyed array of standard events.
facebook_tracking_pixel_events_options Return keyed array of standard events in a format for select boxes.
facebook_tracking_pixel_events_reserved Returns the events reserved for this module.
facebook_tracking_pixel_facebook_tracking_pixel_alter We use our own hook_alter to load the codes. This is also an example of how another module would alter the codes.
facebook_tracking_pixel_facebook_tracking_pixel_events Implements hook_facebook_tracking_pixel_events().
facebook_tracking_pixel_get_currency_codes Returns currency codes from the xml file.
facebook_tracking_pixel_menu Implements hook_menu().
facebook_tracking_pixel_node_delete Implements hook_node_delete().
facebook_tracking_pixel_page_build Implements hook_page_build().
facebook_tracking_pixel_path_codes Returns all the path codes and allows other modules to alter them.
facebook_tracking_pixel_permission Implements hook_permission().
facebook_tracking_pixel_save_file Saves JavaScript in the file system (but only if not empty).
facebook_tracking_pixel_theme Implements hook_theme().
facebook_tracking_pixel_user_insert Implements hook_user_insert().
_facebook_tracking_pixel_roles Based on visibility setting this function an integer. Anything greater than 0 is trackable.