field_redirection.module in Field Redirection 7.2
Same filename and directory in other branches
Provides a field formatter to redirect to another path.
File
field_redirection.moduleView source
<?php
/**
* @file
* Provides a field formatter to redirect to another path.
*/
/**
* Implements hook_permission().
*/
function field_redirection_permission() {
return array(
'bypass redirection' => array(
'title' => t('Bypass Redirection'),
'description' => t('Allow the user to see the page this field belongs to and <em>not</em> redirect to the given path; the user will instead be provided a link to the path.'),
),
);
}
/**
* Implements hook_field_formatter_info().
*/
function field_redirection_field_formatter_info() {
return array(
'field_redirection' => array(
'label' => t('Redirect'),
// Default settings.
'settings' => array(
'code' => '301',
'404_if_empty' => FALSE,
// Flag to indicate how to show blocks on pages:
// 0 = Ignore the setting.
// 1 = Redirect on all except listed pages.
// 2 = Redirect only on listed pages.
'page_restrictions' => 0,
'pages' => '',
),
// The supported field types.
'field types' => array(
'entityreference',
'file',
'image',
'link_field',
'node_reference',
'taxonomy_term_reference',
'url',
'user_reference',
),
),
);
}
/**
* Implements hook_field_formatter_settings_from().
*/
function field_redirection_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
// Shortcuts to make the rest of the code simpler.
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$codes = field_redirection_http_codes();
// Load the current selection, default to "301".
$code = 301;
if (!empty($settings['code']) && isset($codes[$settings['code']])) {
$code = $settings['code'];
}
// Build a new structure for this formatter settings form element.
$element = array();
// Choose the redirector.
$element['code'] = array(
'#title' => 'HTTP status code',
'#type' => 'select',
'#options' => field_redirection_http_codes(),
'#default_value' => $code,
);
// 404 if the field value is empty.
$element['404_if_empty'] = array(
'#type' => 'checkbox',
'#title' => t('404 if URL empty'),
'#default_value' => !empty($settings['404_if_empty']),
'#description' => t('Optionally display a 404 error page if the associated URL field is empty.'),
);
$element['note'] = array(
'#markup' => t('Note: If the destination path is the same as the current path it will behave as if it is empty.'),
'#prefix' => '<p>',
'#suffix' => '</p>',
);
// Provide targeted URL rules to trigger this action.
$element['page_restrictions'] = array(
'#type' => 'radios',
'#title' => t('Redirect page restrictions'),
'#default_value' => empty($settings['page_restrictions']) ? 0 : $settings['page_restrictions'],
'#options' => array(
0 => t('Redirect on all pages.'),
1 => t('Redirect only on the following pages.'),
2 => t('Redirect on all pages except the following pages.'),
),
);
$element['pages'] = array(
'#type' => 'textarea',
'#title' => t('Paths'),
'#default_value' => empty($settings['pages']) ? '' : $settings['pages'],
'#description' => t("Enter one page per line as Drupal paths. The '@wildcard' character is a wildcard. Example paths are '@example_blog' for the blog page and '@example_all_personal_blogs' for every personal blog. '@frontpage' is the front page. You can also use tokens in this field, for example '@example_current_node' can be used to define the current node path.", array(
'@wildcard' => '*',
'@example_blog' => 'blog',
'@example_all_personal_blogs' => 'blog/*',
'@frontpage' => '<front>',
'@example_current_node' => 'node/[node:nid]',
)),
'#states' => array(
'invisible' => array(
':input[name~="page_restrictions"]' => array(
array(
'value' => '0',
),
),
),
),
);
// Show the token browser.
$element['available_tokens'] = array(
'#type' => 'container',
'#weight' => 100,
'#states' => $element['pages']['#states'],
);
$element['available_tokens']['tokens'] = array(
'#value' => 'Browse available tokens',
'#theme' => 'token_tree',
'#token_types' => array(
$instance['entity_type'],
),
'#dialog' => TRUE,
);
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function field_redirection_field_formatter_settings_summary($field, $instance, $view_mode) {
$output = '';
// Shortcuts to make the rest of the code simpler.
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$codes = field_redirection_http_codes();
// Display a "hair on fire" warning message if the view mode is not 'full'.
if ($view_mode != 'full') {
$bad_modes = array(
'default' => 'Default',
'teaser' => 'Teaser',
'rss' => 'RSS',
'search_index' => 'Search index',
'search_result' => 'Search result',
'diff_standard' => 'Revision comparison',
'revision' => 'Revision',
'token' => 'Token',
);
if (array_key_exists($view_mode, $bad_modes)) {
$output .= '<h2>' . t('Danger, Will Robinson!') . '</h2>';
$output .= '<p>' . t('The Redirect formatter should not be used with the ":mode" view mode, it works best when used with the ":full" view mode.', array(
':mode' => $bad_modes[$view_mode],
':full' => t('Full content'),
)) . '</p>';
}
else {
$output .= '<h3>' . t('Careful now!') . '</h3>';
$output .= '<p>' . t('Be careful using the Redirect formatter with this view mode, it could lead to problems.') . '</p>';
}
}
// Work out which redirection code was being used, default to "301".
$code = 301;
if (!empty($settings['code']) && isset($codes[$settings['code']])) {
$code = $settings['code'];
}
$output .= t('Redirect method: @code', array(
'@code' => $codes[$code],
));
// Indicate if the option is used.
if ($settings['404_if_empty']) {
$output .= ' (404 if empty)';
}
// Show path rules if the page_restrictions option is enabled.
if (!empty($settings['page_restrictions']) && !empty($settings['pages'])) {
$output .= '<br />' . t('Redirect restricted to certain paths.');
}
return $output;
}
/**
* The standard HTTP redirection codes that are supported.
*
* @return array
* The supported HTTP codes.
*/
function field_redirection_http_codes() {
return array(
'300' => t('300: Multiple Choices (rarely used)'),
'301' => t('301: Moved Permanently (default)'),
'302' => t('302: Found (rarely used)'),
'303' => t('303: See Other (rarely used)'),
'304' => t('304: Not Modified (rarely used)'),
'305' => t('305: Use Proxy (rarely used)'),
'307' => t('307: Temporary Redirect (temporarily moved)'),
);
}
/**
* Implements hook_field_formatter_view().
*
* If we have a node reference and we can redirect to it lets do it!
*/
function field_redirection_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
// Shortcuts to make the rest of the code simpler.
$settings = $display['settings'];
$codes = field_redirection_http_codes();
// Optionally control the list of pages this works on.
if (!empty($settings['page_restrictions']) && !empty($settings['pages'])) {
// 1 = Redirect only on these pages, 2 = Redirect on all other pages.
// Remove '1' from this value so it can be XOR'd later on.
$page_restrictions = $settings['page_restrictions'] - 1;
// Do raw token replacements.
$pages = token_replace($settings['pages'], array(
$entity_type => $entity,
), array(
'clear' => 1,
'sanitize' => 0,
));
// Normalise all paths to lower case.
$pages = drupal_strtolower($pages);
$path_alias = drupal_strtolower(drupal_get_path_alias($_GET['q']));
$page_match = drupal_match_path($path_alias, $pages);
if ($path_alias != $_GET['q']) {
$page_match = $page_match || drupal_match_path($_GET['q'], $pages);
}
// Stop processing if the page restrictions have matched.
if (!($page_restrictions xor $page_match)) {
return;
}
}
// Don't execute if running via the CLI, e.g. Drush.
if (constant('PHP_SAPI') == 'cli') {
return;
}
elseif (strpos($_SERVER['PHP_SELF'], 'cron.php') !== FALSE) {
return;
}
elseif ($_GET['q'] == 'admin/reports/status/run-cron') {
return;
}
elseif (defined('MAINTENANCE_MODE') || variable_get('maintenance_mode', 0)) {
return;
}
// Make some of the rest of the code simpler.
$item = !empty($items[0]) ? $items[0] : array();
$response_code = 301;
if (!empty($settings['code']) && isset($codes[$settings['code']])) {
$response_code = $settings['code'];
}
// Work out the destination path to redirect to. Each field type is handled
// slightly differently, so identify that here.
$path = '';
$options = array();
if (!empty($field['type'])) {
switch ($field['type']) {
// Entity reference field from the EntityReference module.
case 'entityreference':
if (!empty($item['target_id'])) {
$referenced_entities = entity_load($field['settings']['target_type'], array(
$item['target_id'],
));
if (!empty($referenced_entities)) {
$referenced_entity = reset($referenced_entities);
if (!empty($referenced_entity)) {
$uri = entity_uri($field['settings']['target_type'], $referenced_entity);
if (!empty($uri['path'])) {
$path = drupal_get_path_alias($uri['path']);
}
}
}
}
break;
// Fields from the core Image and File modules.
case 'file':
case 'image':
if (!empty($item['uri'])) {
$path = file_create_url($item['uri']);
}
break;
// Link field from the Link module.
case 'link_field':
if (!empty($item['url'])) {
// The path is the URL field itself.
$path = $item['url'];
// Cover for cases when a query string was provided.
if (!empty($item['query'])) {
$options['query'] = $item['query'];
}
// Optional fragment.
if (!empty($item['fragment'])) {
$options['fragment'] = $item['fragment'];
}
// Special handling for the front page.
if ($path == '<front>') {
$path = '<front>';
}
}
break;
// Node reference field from the node_reference module, part of the
// References module.
case 'node_reference':
case 'node_reference_autocomplete':
if (!empty($item['nid'])) {
// Wrap the internal system path with its alias.
$path = drupal_get_path_alias('node/' . $item['nid']);
}
break;
// Term reference field from the core Taxonomy module.
case 'taxonomy_term_reference':
case 'taxonomy_term_reference_autocomplete':
if (!empty($item['tid'])) {
// Wrap the internal system path with its alias.
$path = drupal_get_path_alias('taxonomy/term/' . $item['tid']);
}
break;
// URL field from the URL module.
case 'url':
if (!empty($item['path'])) {
$path = $item['path'];
$options = $item['options'];
}
break;
// User reference field from the user_reference module, part of the
// References module.
case 'user_reference':
case 'user_reference_autocomplete':
if (!empty($item['uid'])) {
// Wrap the internal system path with its alias.
$path = drupal_get_path_alias('user/' . $item['uid']);
}
break;
}
}
// Don't redirect if the destination is the current page.
if (!empty($path)) {
// Simplest case.
if ($_GET['q'] == $path) {
$path = '';
}
else {
$current_path = current_path();
if ($path == $current_path || $path == url($current_path, array(
'absolute' => TRUE,
))) {
$path = '';
}
elseif ($path == '<front>' && drupal_is_front_page()) {
$path = '';
}
}
}
// Only proceed if a path was identified.
if (!empty($path)) {
// Use default language to not prepend language prefix if path is absolute
// without hostname.
if ($path[0] == '/') {
$path = substr($path, 1);
$options['language'] = language_default();
}
// If the user has permission to bypass the page redirection, return a
// message explaining where they would have been redirected to.
if (user_access('bypass redirection')) {
// "Listen very carefully, I shall say this only once." - 'Allo, 'Allo.
$message = t('This page is set to redirect to <a href="!path">another URL</a>, but you have permission to see the page and not be automatically redirected.', array(
'!path' => url($path, $options),
));
if (empty($_SESSION['messages']['warning']) || !in_array($message, $_SESSION['messages']['warning'])) {
drupal_set_message($message, 'warning');
}
$elements = array();
$elements[] = array(
'#theme' => 'link',
'#text' => t('Redirected location'),
'#path' => $path,
'#options' => array(
'attributes' => array(),
'html' => FALSE,
),
);
return $elements;
}
else {
// If caching this page, add 'Cache-Control' header before redirecting.
$caching_enabled = variable_get('cache', 0);
$page_cacheable = drupal_page_is_cacheable();
$no_session_cookie = !isset($_COOKIE[session_name()]);
if ($caching_enabled && $page_cacheable && $no_session_cookie) {
// @see drupal_serve_page_from_cache().
// If the client sent a session cookie, a cached copy will only be
// served to that one particular client due to Vary: Cookie. Thus, do
// not set max-age > 0, allowing the page to be cached by external
// proxies, when a session cookie is present unless the Vary header has
// been replaced or unset in hook_boot().
$max_age = !isset($_COOKIE[session_name()]) || isset($hook_boot_headers['vary']) ? variable_get('page_cache_maximum_age', 0) : 0;
drupal_add_http_header('Cache-Control', 'public, max-age=' . $max_age);
}
drupal_goto($path, $options, $response_code);
}
}
elseif (!user_access('bypass redirection') && $display['settings']['404_if_empty']) {
drupal_not_found();
}
}
Functions
Name![]() |
Description |
---|---|
field_redirection_field_formatter_info | Implements hook_field_formatter_info(). |
field_redirection_field_formatter_settings_form | Implements hook_field_formatter_settings_from(). |
field_redirection_field_formatter_settings_summary | Implements hook_field_formatter_settings_summary(). |
field_redirection_field_formatter_view | Implements hook_field_formatter_view(). |
field_redirection_http_codes | The standard HTTP redirection codes that are supported. |
field_redirection_permission | Implements hook_permission(). |