datalayer.module in dataLayer 7
Same filename and directory in other branches
Client-side data space.
File
datalayer.moduleView source
<?php
/**
* @file
* Client-side data space.
*/
/**
* Implements hook_menu().
*/
function datalayer_menu() {
$items['admin/config/search/datalayer'] = array(
'title' => 'Data Layer',
'description' => 'Output page meta data for client-side use.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'datalayer_settings_form',
),
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'datalayer.admin.inc',
);
return $items;
}
/**
* Implements hook_libraries_info().
*
* Defines external libraries.
*/
function datalayer_libraries_info() {
$libraries = array();
$libraries['data-layer-helper'] = array(
'name' => 'Data Layer Helper',
'version' => '0.1.0',
'vendor url' => 'https://github.com/google/data-layer-helper',
'download url' => 'https://github.com/google/data-layer-helper/archive/master.zip',
'files' => array(
'js' => array(
'data-layer-helper.js' => array(
'type' => 'file',
'group' => JS_LIBRARY,
'every_page' => TRUE,
),
),
),
'error message' => t('Data layer helper library missing.'),
);
return $libraries;
}
/**
* Implements hook_preprocess_HOOK().
*
* Add data for output.
*/
function datalayer_preprocess_page(&$variables) {
global $user;
// Add details about the page entity.
if (variable_get('datalayer_add_page_meta', TRUE)) {
datalayer_add(datalayer_get_page_data());
}
if (variable_get('datalayer_expose_user_details')) {
datalayer_add(datalayer_get_user_data());
}
// Always output active uid.
datalayer_add(array(
'userUid' => $user->uid,
));
}
/**
* Implements hook_preprocess_HOOK().
*
* Outputs data inclusions for the page.
*/
function datalayer_preprocess_html(&$variables) {
// Get active data, includes defaults.
$output_data = datalayer_add();
// Allow modules to alter data with hook_datalayer_alter().
drupal_alter('datalayer', $output_data);
$output = !empty($output_data) ? drupal_json_encode($output_data) : '';
$render = array(
'#type' => 'html_tag',
'#tag' => 'script',
'#value' => 'dataLayer = [' . $output . '];',
'#attributes' => array(
'type' => 'text/javascript',
),
);
drupal_add_html_head($render, 'datalayer_meta');
// Include data-layer-helper library.
if (variable_get('datalayer_lib_helper', FALSE)) {
// Libraries 2.0.
if (function_exists('libraries_load')) {
if (($library = libraries_detect('data-layer-helper')) && !empty($library['installed'])) {
libraries_load('data-layer-helper');
}
else {
// Something went wrong.
$error = $library['error'];
$error_message = $library['error message'];
}
}
else {
// Libraies 1.0.
$path = libraries_get_path('data-layer-helper');
if (!empty($path) && file_exists($path . '/data-layer-helper.js')) {
drupal_add_js($path . '/data-layer-helper.js');
}
}
}
// Output configred language data.
$languages = language_list();
if (count($languages)) {
drupal_add_js(array(
'dataLayer' => array(
'languages' => $languages,
'defaultLang' => language_default('language'),
),
), 'setting');
}
// Common datalayer JS.
drupal_add_js(drupal_get_path('module', 'datalayer') . '/datalayer.js');
}
/**
* Collects up meta data for output.
*
* @param string $type
* Entity type to collect meta from, defaults to generic.
*
* @return array
* Array of all candidate entity properties.
*/
function _datalayer_collect_meta_properties($type = '') {
$hooks = array();
if (is_string($type) && !empty($type)) {
$hooks[] = "datalayer_{$type}_meta";
}
$hooks[] = 'datalayer_meta';
// Avoid duplicate builds.
$properties =& drupal_static(__FUNCTION__ . $type);
if (!isset($properties)) {
$properties = array();
foreach ($hooks as $hook) {
foreach (module_implements($hook) as $module) {
// Call modules implementing datalayer_meta() and combine results.
$properties = array_merge($properties, module_invoke($module, $hook));
}
if (!empty($properties)) {
break;
}
}
drupal_alter($hooks, $properties);
}
return $properties;
}
/**
* Implements hook_datalayer_meta().
*
* Defines default meta data.
*/
function datalayer_datalayer_meta() {
return array(
'language',
'tnid',
'vid',
'name',
'uid',
'created',
'status',
);
}
/**
* Implements hook_datalayer_current_user_meta().
*
* Defines current user meta data.
*/
function datalayer_datalayer_current_user_meta() {
return array(
'name',
'mail',
'roles',
'created',
'access',
);
}
/**
* Return all the page meta data.
*
* @return array
* Page data.
*/
function datalayer_get_page_data() {
$type = FALSE;
$obj = _datalayer_menu_get_any_object($type);
if (is_object($obj) && $type) {
// @todo Add field data.
// Populate entity properties and values.
return _datalayer_get_entity_data($obj, $type);
}
return array();
}
/**
* Return all user data based on configured URL patterns.
*
* @return array
* The user data.
*/
function datalayer_get_user_data() {
global $user;
$user_data = array();
if (!user_is_anonymous()) {
$exp_user_urls = variable_get('datalayer_expose_user_details', array());
$exp_user_roles = array_filter(variable_get('datalayer_expose_user_details_roles', array()));
$matched_roles = !empty($exp_user_roles) ? array_intersect_key($user->roles, $exp_user_roles) : $user->roles;
// Honor settings.
if ($exp_user_urls && count($matched_roles)) {
$path = current_path();
$path_alias = drupal_lookup_path('alias', $path);
if (drupal_match_path($path, $exp_user_urls) || drupal_match_path($path_alias, $exp_user_urls)) {
// Output various entity properties. Allow additions/alterations.
// NOTE: Properties mean different things on different entity types.
$properties = _datalayer_collect_meta_properties('current_user');
$user_meta = variable_get('datalayer_current_user_meta', array());
$selected_properties = _datalayer_get_selected_properties($properties, $user_meta);
$user_prefix = 'user';
$user_data = _datalayer_collect_meta_values($selected_properties, $user, $user_prefix);
if (in_array('roles', $selected_properties)) {
$user_data[$user_prefix . 'Roles'] = array_values($matched_roles);
}
}
}
}
return $user_data;
}
/**
* Collect entity data for output and altering.
*
* @param object $obj
* Entity object of the page menu callback.
* @param string $type
* String representing entitie's type.
*
* @return array
* All properties and values for output of page entity.
*/
function _datalayer_get_entity_data($obj, $type) {
$output_data =& drupal_static(__FUNCTION__);
if (empty($output_data)) {
// Explicit additions and generalized properties...
$entity_info = entity_get_info($type);
$bundle = FALSE;
// Entity type.
$output_data['entityType'] = $type;
// Entity bundle.
if (isset($obj->{$entity_info['entity keys']['bundle']})) {
$bundle = $obj->{$entity_info['entity keys']['bundle']};
$output_data['entityBundle'] = $bundle;
}
// Entity indetifier.
if (isset($obj->{$entity_info['entity keys']['id']})) {
$output_data['entityId'] = $obj->{$entity_info['entity keys']['id']};
}
// Entity title.
if (isset($entity_info['entity keys']) && isset($entity_info['entity keys']['label']) && isset($obj->{$entity_info['entity keys']['label']})) {
$output_data['entityLabel'] = $obj->{$entity_info['entity keys']['label']};
}
elseif ($entity_info['label'] === 'User') {
// User entities don't report a label.
$output_data['entityLabel'] = $obj->name;
}
// Output various entity properties. Allow additions/alterations.
// NOTE: Properties mean different things on different entity types.
$properties = _datalayer_collect_meta_properties($type);
$entity_meta = array_filter(variable_get('datalayer_global_entity_meta', array()));
$selected_properties = _datalayer_get_selected_properties($properties, $entity_meta);
$output_data = array_merge(_datalayer_collect_meta_values($selected_properties, $obj), $output_data);
// Output term data.
if (variable_get('datalayer_output_terms', module_exists('taxonomy'))) {
$selected_vocabs = array_filter(variable_get('datalayer_vocabs', array()));
if ($type == 'taxonomy_term') {
$output_data['entityTaxonomy'] = array(
$obj->vocabulary_machine_name => array(
$obj->tid => $obj->name,
),
);
}
else {
// Meta data on content.
if ($taxonomy = _datalayer_get_entity_terms($type, $bundle, $obj)) {
// Limit configured vocabs.
if (empty($selected_vocabs)) {
$output_data['entityTaxonomy'] = $taxonomy;
}
else {
foreach ($taxonomy as $vocab => $terms) {
if (isset($selected_vocabs[$vocab])) {
$output_data['entityTaxonomy'][$vocab] = $terms;
}
}
}
}
}
}
}
return $output_data;
}
/**
* Allow adding to the data layer easy on the fly, similar to drupal_add_js().
*
* Passing empty params will return current dataLayer output.
*
* @param array $data
* An array of dataLayer data keyed by variable name (optional).
* @param bool $overwrite
* If data should overwrite existing dataLayer vars of same name (optional).
*
* @return array
* All data layer data added thus far.
*/
function datalayer_add(array $data = array(), $overwrite = FALSE) {
$output_data =& drupal_static(__FUNCTION__, _datalayer_defaults());
// If we've been given data, add it to the output.
if (!empty($data)) {
if ($overwrite) {
$output_data = array_merge($output_data, $data);
}
else {
$output_data += $data;
}
}
return $output_data;
}
/**
* Defines Drupal-wide data layer defaults.
*/
function _datalayer_defaults() {
global $language;
return array(
'drupalLanguage' => $language->language,
'drupalCountry' => variable_get('site_default_country', ''),
);
}
/**
* Agnosticly get the current menu object. Passed type will be set for you.
*
* @param string $return_type
* Pass in a type variable by reference for later use.
*
* @return object
* Entity object of current menu callback page.
*/
function _datalayer_menu_get_any_object(&$return_type) {
// Figure out how this entity is loaded.
$type = FALSE;
$item = menu_get_item();
// Non-entities may not have load functions.
if (is_array($item['load_functions'])) {
$vals = array_values($item['load_functions']);
$load_function = $vals[0];
$arg_position = array_search($load_function, $item['load_functions']);
// Compare to entity types.
$entity_info = entity_get_info();
foreach ($entity_info as $i => $e) {
if ($e['load hook'] == $load_function) {
$type = $i;
}
}
}
// Many happy returns.
if ($type && ($obj = menu_get_object($type, $arg_position))) {
if (is_object($obj)) {
$return_type = $type;
return $obj;
}
else {
return FALSE;
}
}
else {
return FALSE;
}
}
/**
* Fetch all taxonomy terms from an entity.
*
* All fields of field type "taxonomy_term_reference" will be included.
* Idea found at https://api.drupal.org/comment/50393#comment-50393
*
* @param string $entity_type
* What type of entity.
* @param string $bundle
* What bundle within entity type.
* @param object $entity
* Actual entity object to process.
*
* @return array
* Array with tids of entity.
*/
function _datalayer_get_entity_terms($entity_type, $bundle, $entity) {
$terms = array();
// Use very lightweight field info list to find relevant fields.
foreach (field_info_field_map() as $field_name => $field_info) {
if ($field_info['type'] != "taxonomy_term_reference") {
continue;
}
if (array_key_exists($entity_type, $field_info['bundles'])) {
if (in_array($bundle, $field_info['bundles'][$entity_type])) {
if (isset($entity->{$field_name})) {
// Collect terms from fields for return.
$values = field_get_items($entity_type, $entity, $field_name);
foreach ((array) $values as $term_array) {
// Limit to existant tids.
if (isset($term_array['tid'])) {
$term = taxonomy_term_load($term_array['tid']);
if (isset($term->tid) && isset($term->name)) {
$terms[$term->vocabulary_machine_name][$term->tid] = $term->name;
}
}
}
}
}
}
}
return $terms;
}
/**
* Add the meta properties for given entity.
*
* @param array $properties
* Selected properties for the entity.
* @param object $entity
* The entity.
* @param string $key_prefix
* The prefix for the property name.
*/
function _datalayer_collect_meta_values(array $properties, $entity, $key_prefix = 'entity') {
// Build meta output...
$meta_data = array();
foreach ($properties as $p) {
if (isset($entity->{$p})) {
$meta_data[$key_prefix . ucfirst($p)] = $entity->{$p};
}
}
return $meta_data;
}
/**
* Determine which properties will be output based on configuration.
*
* @param array $properties
* Available properties for the entity.
* @param array $selected
* Selected properties for the entity.
*/
function _datalayer_get_selected_properties(array $properties, array $selected) {
$selected_properties = array_filter($selected);
// Honor selective output configuration.
$selected_properties = empty($selected_properties) ? $properties : $selected_properties;
return $selected_properties;
}
Functions
Name | Description |
---|---|
datalayer_add | Allow adding to the data layer easy on the fly, similar to drupal_add_js(). |
datalayer_datalayer_current_user_meta | Implements hook_datalayer_current_user_meta(). |
datalayer_datalayer_meta | Implements hook_datalayer_meta(). |
datalayer_get_page_data | Return all the page meta data. |
datalayer_get_user_data | Return all user data based on configured URL patterns. |
datalayer_libraries_info | Implements hook_libraries_info(). |
datalayer_menu | Implements hook_menu(). |
datalayer_preprocess_html | Implements hook_preprocess_HOOK(). |
datalayer_preprocess_page | Implements hook_preprocess_HOOK(). |
_datalayer_collect_meta_properties | Collects up meta data for output. |
_datalayer_collect_meta_values | Add the meta properties for given entity. |
_datalayer_defaults | Defines Drupal-wide data layer defaults. |
_datalayer_get_entity_data | Collect entity data for output and altering. |
_datalayer_get_entity_terms | Fetch all taxonomy terms from an entity. |
_datalayer_get_selected_properties | Determine which properties will be output based on configuration. |
_datalayer_menu_get_any_object | Agnosticly get the current menu object. Passed type will be set for you. |