ccl.module in Custom Contextual Links 8
Same filename and directory in other branches
Main CCL module file.
File
ccl.moduleView source
<?php
/**
* @file
* Main CCL module file.
*/
/**
* Implements hook_permission().
*/
function ccl_permission() {
return array(
'use ccl' => array(
'title' => t('Add custom contextual links'),
),
);
}
/**
* Implements hook_menu().
*/
function ccl_menu() {
$items['admin/config/user-interface/ccl'] = array(
'title' => 'Custom Contextual Links',
'description' => 'Add custom contextul links to blocks and nodes',
'page callback' => 'ccl_admin',
'access arguments' => array(
'use ccl',
),
'file' => 'ccl.admin.inc',
);
$items['admin/config/user-interface/ccl/add'] = array(
'title' => 'Add new link',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ccl_add_form',
),
'access arguments' => array(
'use ccl',
),
'type' => MENU_LOCAL_ACTION,
'file' => 'ccl.admin.inc',
);
$items['admin/config/user-interface/ccl/%/delete'] = array(
'title' => 'Delete custom link',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ccl_delete_confirm',
4,
),
'access arguments' => array(
'use ccl',
),
'file' => 'ccl.admin.inc',
);
$items['admin/config/user-interface/ccl/%/edit'] = array(
'title' => 'Edit custom link',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ccl_add_form',
4,
),
'access arguments' => array(
'use ccl',
),
'file' => 'ccl.admin.inc',
);
$items['admin/config/user-interface/ccl/autocomplete'] = array(
'title' => 'Node autocomplete',
'page callback' => 'ccl_node_autocomplete',
'access arguments' => array(
'use ccl',
),
'file' => 'ccl.admin.inc',
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_features_api().
*/
function ccl_features_api() {
return array(
'ccl' => array(
'name' => 'Custom Contextual Links',
'file' => drupal_get_path('module', 'ccl') . '/ccl.features.inc',
'default_hook' => 'ccl_features_preset',
'feature_source' => TRUE,
),
);
}
/**
* Retrieve a link based on it's title.
*/
function ccl_get_presets($key = NULL) {
$presets = array();
if ($key) {
$key_parts = explode('||ID', $key);
$results = db_query('SELECT * FROM {ccl} WHERE clid = :clid AND title = :title', array(
':clid' => $key_parts[1],
':title' => $key_parts[0],
));
}
else {
$results = db_query('SELECT * FROM {ccl}');
}
while ($result = $results
->fetchObject()) {
$presets[] = $result;
}
return $presets;
}
/**
* Implements hook_contextual_links_view_alter().
*
* TODO:
* - Make sure all links are work in a multilanguage setup.
*/
function ccl_contextual_links_view_alter(&$element, $items) {
// Get the destination parameter.
$dest = drupal_get_destination();
// Check if we have a node link to process.
if (isset($element['#element']['#node']->nid)) {
$node = $element['#element']['#node'];
$node_cache = ccl_cache_get('ccl_nodes');
// Global elements.
foreach ($node_cache['global'] as $id => $link) {
if ($processed_link = _ccl_prepare_link($link, $dest, $node)) {
$element['#links']['ccl-global-node-' . $id] = $processed_link;
}
}
// Content Type.
if (in_array($node->type, array_keys($node_cache['ct']))) {
foreach ($node_cache['ct'][$node->type] as $id => $link) {
if ($processed_link = _ccl_prepare_link($link, $dest, $node)) {
$element['#links']['ccl-ct-' . $id] = $processed_link;
}
}
}
// Individual nodes.
if (in_array($node->nid, array_keys($node_cache['ids']))) {
foreach ($node_cache['ids'][$node->nid] as $id => $link) {
if ($processed_link = _ccl_prepare_link($link, $dest, $node)) {
$element['#links']['ccl-node-' . $id] = $processed_link;
}
}
}
}
// Invoke submodules.
foreach (\Drupal::moduleHandler()
->getImplementations('ccl_add_link') as $module) {
$element = \Drupal::moduleHandler()
->invoke($module, 'ccl_add_link', [
$element,
$dest,
]);
}
}
/**
* Helper function to get ccl settings out of the cache.
*/
function ccl_cache_get($type) {
$cache = \Drupal::cache()
->get($type);
// If nothing is set in the cache then recreate it.
if (!isset($cache->cid)) {
_ccl_update_cache();
$cache = \Drupal::cache()
->get($type);
}
return $cache->data;
}
/**
* Helper function for token replacement, destination and access control.
*/
function _ccl_prepare_link($link, $destination, $node = NULL) {
// Token replacement for the URL.
$link['href'] = $node ? \Drupal::token()
->replace($link['href'], array(
'node' => $node,
)) : \Drupal::token()
->replace($link['href']);
// Check the access permission.
if (\Drupal::service("path.validator")
->isValid($link['href'], TRUE)) {
// Token replacement for the title.
$link['title'] = $node ? \Drupal::token()
->replace($link['title'], array(
'node' => $node,
)) : \Drupal::token()
->replace($link['title']);
// Add classes if available.
if (isset($link['advanced']['class'])) {
$link['attributes']['class'] = explode(" ", $link['advanced']['class']);
}
// Add link target if set.
if (isset($link['advanced']['target'])) {
$link['attributes']['target'] = explode(" ", $link['advanced']['target']);
}
// Add anchor if available
if (isset($link['advanced']['anchor'])) {
$link['fragment'] = $link['advanced']['anchor'];
}
// Add query if available and destination.
if (!\Drupal\Component\Utility\UrlHelper::isExternal($link['href']) && (!isset($link['advanced']['destination']) || $link['advanced']['destination'])) {
$link['query'] = $destination;
}
if (isset($link['advanced']['query']) && !empty($link['advanced']['query'])) {
$query = $node ? \Drupal::token()
->replace($link['advanced']['query'], array(
'node' => $node,
)) : \Drupal::token()
->replace($link['advanced']['query']);
$qparts = explode('&', $query);
foreach ($qparts as $value) {
$kv = explode('=', $value);
$link['query'][$kv[0]] = $kv[1];
}
}
return $link;
}
else {
return FALSE;
}
}
/**
* Helper function to write ccl settings into the cache.
*/
function _ccl_update_cache() {
// Create entry for nodes.
$nodes = db_query("SELECT * FROM {ccl} WHERE type = :type", array(
':type' => 'node',
));
$node_cache = array(
'global' => array(),
'ct' => array(),
'ids' => array(),
);
foreach ($nodes as $node) {
$node->options = unserialize($node->options);
$advanced = array();
if (isset($node->options['advanced_css'])) {
$advanced['class'] = $node->options['advanced_css'];
}
if (isset($node->options['advanced_anchor'])) {
$advanced['anchor'] = $node->options['advanced_anchor'];
}
if (isset($node->options['advanced_query'])) {
$advanced['query'] = $node->options['advanced_query'];
}
if (isset($node->options['advanced_target']) && $node->options['advanced_target'] != "default") {
$advanced['target'] = $node->options['advanced_target'];
}
if (isset($node->options['advanced_destination'])) {
$advanced['destination'] = $node->options['advanced_destination'];
}
if ($node->options['node_options'] == 'global') {
$node_cache['global'][] = array(
'title' => $node->title,
'href' => $node->link,
'advanced' => $advanced,
);
}
elseif ($node->options['node_options'] == 'node') {
$node_cache['ids'][$node->options['node_id']][] = array(
'title' => $node->title,
'href' => $node->link,
'advanced' => $advanced,
);
}
else {
$node_cache['ct'][$node->options['node_type']][] = array(
'title' => $node->title,
'href' => $node->link,
'advanced' => $advanced,
);
}
}
\Drupal::cache()
->set('ccl_nodes', $node_cache);
// Invoke cache_update hook for submodules.
foreach (\Drupal::moduleHandler()
->getImplementations('ccl_cache_update') as $module) {
\Drupal::moduleHandler()
->invoke($module, 'ccl_cache_update');
}
}
Functions
Name | Description |
---|---|
ccl_cache_get | Helper function to get ccl settings out of the cache. |
ccl_contextual_links_view_alter | Implements hook_contextual_links_view_alter(). |
ccl_features_api | Implements hook_features_api(). |
ccl_get_presets | Retrieve a link based on it's title. |
ccl_menu | Implements hook_menu(). |
ccl_permission | Implements hook_permission(). |
_ccl_prepare_link | Helper function for token replacement, destination and access control. |
_ccl_update_cache | Helper function to write ccl settings into the cache. |