You are here

optimizely.module in Optimizely 7.2

Optimizely module

Originally for Visual Website Optimizer by Awesome Software, http://www.awesome-software.net/ and Ted Cooper (ELC) http://drupal.org/user/784944

Ported to Optimizely by netstudio.gr and Yannis Karampelas (http://drupal.org/user/1145950).

Adds Optimizely javascript (snippet) to the page which loads the A/B test from the optimizely.com website.

7.x-2.x Functionality added to support multiple project entries from an Optimizely account. Each entry specifies target paths to include the Optimizely projects on the specific site paths. Targeting paths eliminates the need to load Optimizely tests on every page of a site.

7.x-2.x by Darren "Dee" Lee (DeeZone: http://drupal.org/user/288060) and Peter Lehrer (plehrer: http://drupal.org/user/2257350) Sponsored by DoSomething.org (http://www.dosomething.org)

File

optimizely.module
View source
<?php

/**
 * @file
 * Optimizely module
 *
 * Originally for Visual Website Optimizer by Awesome Software, http://www.awesome-software.net/
 * and Ted Cooper (ELC) http://drupal.org/user/784944
 *
 * Ported to Optimizely by netstudio.gr and Yannis Karampelas (http://drupal.org/user/1145950).
 *
 * Adds Optimizely javascript (snippet) to the page which loads the A/B test from
 * the optimizely.com website.
 *
 * 7.x-2.x Functionality added to support multiple project entries from an Optimizely account. Each entry
 * specifies target paths to include the Optimizely projects on the specific site paths. Targeting paths
 * eliminates the need to load Optimizely tests on every page of a site.
 *
 * 7.x-2.x by Darren "Dee" Lee (DeeZone: http://drupal.org/user/288060) and Peter Lehrer (plehrer: http://drupal.org/user/2257350)
 * Sponsored by DoSomething.org (http://www.dosomething.org)
 */

/**
 * Implements hook_help().
 *
 * Help text related to the modules functionality and use.
 */
function optimizely_help($path, $arg) {
  switch ($path) {
    case 'admin/help#optimizely':
      return '<p>' . t('<a href="http://optimize.ly/OZRdc0">Optimizely</a> is a third party service to add A/B testing to a web site. The tests are applied to the site by loading javascript snippets generated by the Optimizely web site. The generated javascript files are applied to certain paths on the site based on Project entries managed by the Optimizely module. To start to apply the general, site wide Optimizely javascript file the <a href="@settings">Optimizely account ID</a> must be entered in the module administration page.', array(
        '@settings' => url('admin/config/system/optimizely/settings'),
      )) . '</p><p>Enable or disable each project
entry to apply the project settings while not needing to remove the actual entry. The default entry can be disabled when additional project entries are made with more specific settings. This can include using the the orginal Project Code.';
    case 'admin/config/system/optimizely':
      return t('<p>A listing of the Optimizely projects. Each entry can be enabled / disable for specific or wildcard paths. Enabled entries are highlighted in green while disabled entries are in red. The top, "Default" entry can not be deleted but its settings can be adjusted or completely disabled.</p>
							  <p>The goal of having multiple projects is to minimize the size of the Optimizely hosted javascript file. If all experiments are contained in a single file and processed on every page load there may be an issue with decreased page load time. Having multiple projects and loading them on specific paths that apply to the experiments helps to minimize the size of the file and eliminate processing unused javascript in the user\'s browser.</p>');
      break;
    case 'admin/config/system/optimizely/add_update':
      return t('Add or edit specific project entries. Each entry should have an Optimizely project / experiment assigned to it. as well as a range of website paths where the Optimizely javascript hosted file should should be included.');
      break;
    case 'admin/config/system/optimizely/settings':
      return t('Add the Optimizely account ID supplied by the Optimizely website. The account ID is essential to setting up the initial site wide default project entry.');
      break;
  }
}

/**
 * Implements hook_menu().
 *
 * Menu entries that define the paths to trigger specific functionality when the path is accessed.
 */
function optimizely_menu() {
  $items = array();
  $items['admin/config/system/optimizely'] = array(
    'title' => 'Optimizely',
    'description' => 'List of all different projects to put Optimizely code snippet.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'optimizely_project_list_form',
    ),
    'access arguments' => array(
      'administer optimizely',
    ),
    'file' => 'optimizely.admin.inc',
    'file path' => drupal_get_path('module', 'optimizely'),
  );
  $items['admin/config/system/optimizely/default'] = array(
    'title' => 'Project Listing',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 0,
  );
  $items['admin/config/system/optimizely/add_update'] = array(
    'title' => 'Add Project',
    'description' => 'Add Project entry',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'optimizely_add_update_form',
    ),
    'access arguments' => array(
      'administer optimizely',
    ),
    'file' => 'optimizely.admin.inc',
    'file path' => drupal_get_path('module', 'optimizely'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 10,
  );
  $items['admin/config/system/optimizely/add_update/%'] = array(
    'title' => 'Optimizely Edit Project',
    'description' => 'Configure Project entry',
    'page callback' => 'optimizely_add_update_update',
    'page arguments' => array(
      5,
    ),
    'access arguments' => array(
      'administer optimizely',
    ),
    'file' => 'optimizely.admin.inc',
    'file path' => drupal_get_path('module', 'optimizely'),
    'weight' => 11,
  );
  $items['admin/config/system/optimizely/settings'] = array(
    'title' => 'Account Info',
    'description' => 'Configure your Optimizely account details',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'optimizely_account_settings_form',
    ),
    'access arguments' => array(
      'administer optimizely',
    ),
    'file' => 'optimizely.admin.inc',
    'file path' => drupal_get_path('module', 'optimizely'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 30,
  );
  $items['admin/config/system/optimizely/delete/%'] = array(
    'title' => 'Delete Project',
    'description' => 'Deletes the target project from the database.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'optimizely_delete_page',
      5,
    ),
    'access arguments' => array(
      'administer optimizely',
    ),
    'file' => 'optimizely.admin.inc',
    'file path' => drupal_get_path('module', 'optimizely'),
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/system/optimizely/ajax'] = array(
    'title' => 'Optimizely Administer AJAX',
    'page callback' => 'optimizely_ajax_enable',
    'access arguments' => array(
      'administer optimizely',
    ),
    'file' => 'optimizely.admin.inc',
    'file path' => drupal_get_path('module', 'optimizely'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_permission().
 *
 * Limit access to the module settings to accounts that have the "Administer Optimizely module" privladge.
 */
function optimizely_permission() {
  return array(
    'administer optimizely' => array(
      'title' => t('Administer Optimizely module'),
      'description' => t('Administer access to everything in module'),
      'restrict access' => TRUE,
    ),
  );
}

/**
 * Implements hook_theme().
 *
 * All of the template definitions. All related templates can be found /template in the module folder.
 * The template layout can be over ridden by the site theme by copying these template files into theme
 * directory.
 *
 * See http://www.jaypan.com/tutorial/themeing-drupal-7-forms-including-css-and-js for details on setting up
 * theme function rather than tpl files.
 */
function optimizely_theme($existing, $type, $theme, $path) {
  return array(
    'optimizely_projects_table' => array(
      'render element' => 'element',
    ),
    'optimizely_account_settings_form' => array(
      'render element' => 'form',
      'template' => 'optimizely-account-settings-form',
      'path' => drupal_get_path('module', 'optimizely') . '/templates',
    ),
    'optimizely_add_update_form' => array(
      'render element' => 'form',
      'template' => 'optimizely-add-update-form',
      'path' => drupal_get_path('module', 'optimizely') . '/templates',
      '#project_code' => 'project_code',
    ),
  );
}

/**
 * Implements hook_init().
 *
 * This function impliments the rules entered for each project entry. The goal
 * is to control when an entry (Optimizely hosted javascript file) is applied to
 * a page.
 *
 * The "Paths" setting for each entry are interpited as literal paths or a whole range of
 * paths noted with wildcards "*". A Project entry can appear on one or more paths that can
 * include wildcards. The <front> token is supported in the possible path values.
 *
 * For example, '<front>' will add the Optimizely snippet on the front page, and
 * 'clubs/*' will place the snippet on all pages bellow 'clubs/'. Note: The javascript
 * call / snippet will only appear on the actual 'clubs' page if you specify 'clubs'
 * without the wildcard.
 *
 * A disabled project entry will be ignored allowing entries to persist but be applied.
 */
function optimizely_init() {
  $current_path = current_path();
  $current_path_alias = drupal_lookup_path('alias', $current_path);
  $wildcard_match = FALSE;
  $add_snippet = FALSE;
  $every_page = FALSE;

  // Load all entries in the optimizely table
  $query = db_select('optimizely', 'o', array(
    'target' => 'slave',
  ))
    ->fields('o')
    ->condition('o.enabled', 1, '=')
    ->orderBy('oid');

  // Fetch the result set.
  $result = $query
    ->execute();

  // Query results found
  if ($result) {

    // Loop through each row of the found results
    while ($project = $result
      ->fetchAssoc()) {

      // Only process the entries that are enabled
      if ($project['enabled']) {

        // Target paths from database for project and get real path for <front> if a part of target paths for project
        $project_paths = unserialize($project['path']);
        $front_index = array_search('<front>', $project_paths);
        !is_int($front_index) ?: ($project_paths[$front_index] = variable_get('site_frontpage'));

        // Check all paths for alias or sytem URL values, foreach loop based on
        // orginal array value, addiitonal values added will not effect the array
        foreach ($project_paths as $project_path) {

          // Remove parameters
          if (strpos($project_path, '?') !== FALSE) {
            $project_path = substr($project_path, 0, strpos($project_path, '?'));

            // Look for wildcard match
            if (stristr($current_path, $project_path) || stristr(drupal_lookup_path('alias', $current_path), $project_path) || stristr(drupal_lookup_path('source', $current_path), $project_path)) {
              $add_snippet = TRUE;
              break 2;
            }
          }
          if (strpos($project_path, '*') !== FALSE) {

            // Sitewide wild card
            if ($project_path == '*') {
              $add_snippet = TRUE;
              $every_page = TRUE;
              break 2;
            }
            else {

              // Remove wildcard, get base path(s)
              $project_path = substr($project_path, 0, -2);

              // Look for wildcard match
              if (stristr($current_path, $project_path) || stristr(drupal_lookup_path('alias', $current_path), $project_path) || stristr(drupal_lookup_path('source', $current_path), $project_path)) {
                $add_snippet = TRUE;
                break 2;
              }
            }
          }

          // Build out $project_paths with possible source and alias values to
          // test with drupal_match_path()
          $project_path_source = drupal_lookup_path('source', $project_path);
          !$project_path_source ?: ($project_paths[] = $project_path_source);
          $project_path_alias = drupal_lookup_path('alias', $project_path);
          !$project_path_alias ?: ($project_paths[] = $project_path_alias);
        }

        // Prep for drupal_match_path()
        $project_paths = implode("\n", array_unique($project_paths));
        if (drupal_match_path($current_path, $project_paths) || drupal_match_path($current_path_alias, $project_paths)) {
          $add_snippet = TRUE;
          break;
        }
      }
    }
    if ($add_snippet) {
      $options = array(
        'type' => 'external',
        'every_page' => $every_page,
        'group' => JS_LIBRARY,
        'weight' => 0,
      );

      // Add javascript call to page markup
      drupal_add_js('//cdn.optimizely.com/js/' . $project['project_code'] . '.js', $options);
    }
  }
}

Functions

Namesort descending Description
optimizely_help Implements hook_help().
optimizely_init Implements hook_init().
optimizely_menu Implements hook_menu().
optimizely_permission Implements hook_permission().
optimizely_theme Implements hook_theme().