View source
<?php
require_once 'path_breadcrumbs.info.inc';
define('PATH_BREADCRUMBS_RICH_SNIPPETS_DISABLED', 0);
define('PATH_BREADCRUMBS_RICH_SNIPPETS_RDFA', 1);
define('PATH_BREADCRUMBS_RICH_SNIPPETS_MICRODATA', 2);
define('PATH_BREADCRUMBS_CACHE_STORAGE', 'cache_path_breadcrumbs');
function path_breadcrumbs_page_alter() {
if (!variable_get('path_breadcrumbs_enable_on_error_pages', FALSE)) {
$bad_statuses = array(
'404 Not Found',
'403 Forbidden',
);
$http_headers = drupal_get_http_header();
$status = isset($http_headers['status']) ? $http_headers['status'] : '200 OK';
if (in_array($status, $bad_statuses)) {
return;
}
}
path_breadcrumbs_set_breadcrumb();
}
function path_breadcrumbs_set_breadcrumb($path = NULL) {
if (!isset($path)) {
$path = current_path();
}
$path_breadcrumbs_data = path_breadcrumbs_load_variant($path);
if ($path_breadcrumbs_data && isset($path_breadcrumbs_data->build)) {
drupal_set_breadcrumb($path_breadcrumbs_data->build);
}
}
function path_breadcrumbs_load_variant($path) {
global $language_url;
if (empty($path)) {
return FALSE;
}
$path_breadcrumbs_data =& drupal_static(__FUNCTION__ . '::' . $path);
if (!empty($path_breadcrumbs_data)) {
return $path_breadcrumbs_data;
}
$cache_enabled = variable_get('path_breadcrumbs_cache_enabled', FALSE);
$cache_lifetime = variable_get('path_breadcrumbs_cache_lifetime', CACHE_PERMANENT);
if ($cache_lifetime > CACHE_PERMANENT) {
$cache_lifetime += REQUEST_TIME;
}
if ($cache_enabled) {
$cache_id = __FUNCTION__ . ':' . $path . ':' . $language_url->language;
$cache = cache_get($cache_id, PATH_BREADCRUMBS_CACHE_STORAGE);
if (!empty($cache->data)) {
if ($cache->data == 'none') {
return FALSE;
}
if (count(module_implements('path_breadcrumbs_view_alter')) > 0) {
$built_breadcrumbs = $cache->data->build;
$path_breadcrumbs = $cache->data->variant;
$path_breadcrumbs->from_cache = TRUE;
$contexts = path_breadcrumbs_get_contexts_from_arguments($path_breadcrumbs->arguments, FALSE, $path);
drupal_alter('path_breadcrumbs_view', $built_breadcrumbs, $path_breadcrumbs, $contexts);
}
$path_breadcrumbs_data = $cache->data;
return $cache->data;
}
}
$path_breadcrumbs_data = new stdClass();
$variants = path_breadcrumbs_load_by_path($path);
foreach ($variants as $breadcrumb) {
$matched_path = preg_replace("\n /\\/% # start with slash-percent\n [^\\/]+ # all symbols except for the slash\n /x", '/*', $breadcrumb->path);
if (drupal_match_path($path, $matched_path)) {
$contexts = path_breadcrumbs_get_contexts_from_arguments($breadcrumb->arguments, FALSE, $path);
if (isset($contexts['broken_context'])) {
continue;
}
if (!empty($breadcrumb->access)) {
$access = ctools_access($breadcrumb->access, $contexts);
if (!$access) {
continue;
}
}
$path_breadcrumbs_data->variant = $breadcrumb;
$path_breadcrumbs_data->build = _path_breadcrumbs_build_breadcrumbs($breadcrumb, $contexts);
if ($cache_enabled) {
cache_set($cache_id, $path_breadcrumbs_data, PATH_BREADCRUMBS_CACHE_STORAGE, $cache_lifetime);
}
return $path_breadcrumbs_data;
}
}
if ($cache_enabled) {
cache_set($cache_id, 'none', PATH_BREADCRUMBS_CACHE_STORAGE, $cache_lifetime);
}
return FALSE;
}
function _path_breadcrumbs_build_breadcrumbs($path_breadcrumb, $contexts = array()) {
$breadcrumb = array();
module_invoke_all('path_breadcrumbs_view', $path_breadcrumb, $contexts);
if ($path_breadcrumb->home == TRUE) {
$home = variable_get('path_breadcrumbs_home_link_title', 'Home');
$breadcrumb[] = l($home, '<front>');
}
$titles = implode("\n", $path_breadcrumb->titles);
$paths = implode("\n", $path_breadcrumb->paths);
$paths = rawurldecode($paths);
$replace = array();
$search = array();
if (!empty($path_breadcrumb->arguments)) {
foreach ($path_breadcrumb->arguments as $keyword => $argument) {
$search[] = '!' . $keyword;
$replace[] = arg($argument['position']);
}
}
$search[] = '!page_title';
$replace[] = drupal_get_title();
$titles = str_replace($search, $replace, $titles);
$paths = str_replace($search, $replace, $paths);
$contexts['site'] = ctools_context_create('path_breadcrumbs_site');
$titles = ctools_context_keyword_substitute($titles, array(), $contexts);
$paths = ctools_context_keyword_substitute($paths, array(), $contexts);
$path_breadcrumb->titles_prepared = explode("\n", $titles);
$path_breadcrumb->paths_prepared = explode("\n", $paths);
if (count($path_breadcrumb->titles_prepared) == 1 && $path_breadcrumb->titles_prepared[0] == '<none>' && $path_breadcrumb->paths_prepared[0] == '<none>') {
$path_breadcrumb->titles_prepared = array();
$path_breadcrumb->paths_prepared = array();
}
foreach ($path_breadcrumb->titles_prepared as $key => $title) {
if (empty($title)) {
continue;
}
$options = array();
$decode_html_entities = variable_get('path_breadcrumbs_decode_entities', TRUE);
if ($decode_html_entities) {
$title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
}
$truncate_length = variable_get('path_breadcrumbs_truncate_title_length', '');
$title_length = drupal_strlen($title);
if ($truncate_length && $truncate_length < $title_length) {
$options['attributes']['title'] = $title;
$title = truncate_utf8($title, $truncate_length + 3, TRUE, TRUE);
}
if (isset($path_breadcrumb->paths_prepared[$key]) && $path_breadcrumb->paths_prepared[$key] != '<none>') {
$path = _path_breadcrumbs_clean_url($path_breadcrumb->paths_prepared[$key], $options);
$breadcrumb[] = l($title, $path, $options);
}
elseif (isset($path_breadcrumb->paths_prepared[$key]) && $path_breadcrumb->paths_prepared[$key] == '<none>') {
$breadcrumb[] = check_plain($title);
}
}
$path_breadcrumb->from_cache = FALSE;
drupal_alter('path_breadcrumbs_view', $breadcrumb, $path_breadcrumb, $contexts);
return $breadcrumb;
}
function path_breadcrumbs_ctools_plugin_directory($owner, $plugin_type) {
if ($owner == 'ctools') {
return 'plugins/' . $plugin_type;
}
}
function path_breadcrumbs_flush_caches() {
return array(
PATH_BREADCRUMBS_CACHE_STORAGE,
);
}
function path_breadcrumbs_theme_registry_alter(&$theme_registry) {
global $theme_key;
$internal_render = variable_get('path_breadcrumbs_internal_render', 1);
$themes = variable_get('path_breadcrumbs_internal_render_themes', array());
if ($internal_render && (empty($themes) || in_array($theme_key, $themes))) {
$theme_registry['breadcrumb']['theme path'] = drupal_get_path('module', 'path_breadcrumbs');
$theme_registry['breadcrumb']['function'] = 'path_breadcrumbs_breadcrumb';
}
}
function path_breadcrumbs_breadcrumb($variables) {
$breadcrumbs = $variables['breadcrumb'];
if (!empty($breadcrumbs)) {
$output = '<h2 class="element-invisible">' . t('You are here') . '</h2>';
$hide_single_breadcrumb = variable_get('path_breadcrumbs_hide_single_breadcrumb', 0);
if ($hide_single_breadcrumb && count($breadcrumbs) == 1) {
return FALSE;
}
if (is_array($breadcrumbs[count($breadcrumbs) - 1])) {
array_pop($breadcrumbs);
}
$elem_tag = 'span';
$elem_property = '';
$root_property = '';
$options = array(
'html' => TRUE,
);
$snippet = variable_get('path_breadcrumbs_rich_snippets', PATH_BREADCRUMBS_RICH_SNIPPETS_DISABLED);
if ($snippet == PATH_BREADCRUMBS_RICH_SNIPPETS_RDFA) {
$options['attributes'] = array(
'rel' => 'v:url',
'property' => 'v:title',
);
$options['absolute'] = TRUE;
$elem_property = ' typeof="v:Breadcrumb"';
$root_property = ' xmlns:v="http://rdf.data-vocabulary.org/#"';
}
elseif ($snippet == PATH_BREADCRUMBS_RICH_SNIPPETS_MICRODATA) {
$options['attributes'] = array(
'itemprop' => 'url',
);
$options['absolute'] = TRUE;
$elem_property = ' itemscope itemtype="http://data-vocabulary.org/Breadcrumb"';
$elem_tag = 'div';
drupal_add_css(drupal_get_path('module', 'path_breadcrumbs') . '/css/path_breadcrumbs.css');
}
foreach ($breadcrumbs as $key => $breadcrumb) {
$classes = array(
'inline',
);
$classes[] = $key % 2 ? 'even' : 'odd';
if ($key == 0) {
$classes[] = 'first';
}
if (count($breadcrumbs) == $key + 1) {
$classes[] = 'last';
}
preg_match('/href="([^"]+?)"/', $breadcrumb, $matches);
$href = '';
if (!empty($matches[1])) {
global $base_path;
global $language_url;
$base_string = rtrim($base_path, "/");
if (!variable_get('clean_url', 0)) {
$base_string .= '?q=';
}
$enabled_negotiation_types = variable_get("language_negotiation_language", array());
if (!empty($enabled_negotiation_types['locale-url']) && !empty($language_url->prefix)) {
$base_string .= '/' . $language_url->prefix;
}
if ($matches[1] == $base_string || $matches[1] == '' || $matches[1] == '/') {
$href = '';
}
elseif (stripos($matches[1], "{$base_string}/") === 0) {
$href = drupal_substr($matches[1], drupal_strlen("{$base_string}/"));
}
else {
$href = stripos($matches[1], '/') === 0 ? drupal_substr($matches[1], 1) : $matches[1];
}
$href = empty($href) ? '<front>' : $href;
}
$title = trim(strip_tags($breadcrumb));
if ($snippet == PATH_BREADCRUMBS_RICH_SNIPPETS_MICRODATA) {
$title = '<span itemprop="title">' . $title . '</span>';
}
if (preg_match('/<a\\s.*?title="([^"]+)"[^>]*>/i', $breadcrumb, $attr_matches)) {
$options['attributes']['title'] = $attr_matches[1];
}
else {
unset($options['attributes']['title']);
}
$href = rawurldecode($href);
$href = _path_breadcrumbs_clean_url($href, $options, 'none');
$new_breadcrumb = !empty($href) ? l($title, $href, $options) : $title;
$breadcrumbs[$key] = '<' . $elem_tag . ' class="' . implode(' ', $classes) . '"' . $elem_property . '>' . $new_breadcrumb . '</' . $elem_tag . '>';
}
$delimiter = check_plain(variable_get('path_breadcrumbs_delimiter', '»'));
$delimiter = '<span class="delimiter">' . trim($delimiter) . '</span>';
$classes = array(
'breadcrumb',
);
$prefix = '';
$path_breadcrumbs_data = path_breadcrumbs_load_variant(current_path());
if (user_access('administer path breadcrumbs') && $path_breadcrumbs_data && isset($path_breadcrumbs_data->variant)) {
$contextual_links = array(
'#type' => 'contextual_links',
'#contextual_links' => array(
'path_breadcrumbs' => array(
'admin/structure/path-breadcrumbs/edit',
array(
$path_breadcrumbs_data->variant->machine_name,
),
),
),
);
$prefix = drupal_render($contextual_links);
$classes[] = 'contextual-links-region';
}
$output .= '<div class="' . implode(' ', $classes) . '"' . $root_property . '>' . $prefix . implode(" {$delimiter} ", $breadcrumbs) . '</div>';
return $output;
}
return FALSE;
}
function path_breadcrumbs_save($path_breadcrumbs) {
ctools_include('export');
if (!empty($path_breadcrumbs->access) && !empty($path_breadcrumbs->logic)) {
$path_breadcrumbs->access['logic'] = $path_breadcrumbs->logic;
}
elseif (empty($path_breadcrumbs->access)) {
$path_breadcrumbs->access = array();
}
if (!isset($path_breadcrumbs->arguments)) {
$path_breadcrumbs->arguments = array();
}
if (!isset($path_breadcrumbs->export_type)) {
$path_breadcrumbs->export_type = NULL;
}
$path_breadcrumbs->data = array(
'titles' => $path_breadcrumbs->titles,
'paths' => $path_breadcrumbs->paths,
'home' => $path_breadcrumbs->home,
'translatable' => $path_breadcrumbs->translatable,
'arguments' => $path_breadcrumbs->arguments,
'access' => $path_breadcrumbs->access,
);
if (!empty($path_breadcrumbs->custom)) {
$path_breadcrumbs->data['custom'] = $path_breadcrumbs->custom;
}
$save_result = ctools_export_crud_save('path_breadcrumbs', $path_breadcrumbs);
if ($save_result) {
path_breadcrumbs_object_cache_clear($path_breadcrumbs->machine_name);
$path_breadcrumbs->is_new = $save_result == SAVED_NEW;
module_invoke_all('path_breadcrumbs_save', $path_breadcrumbs);
cache_clear_all('*', PATH_BREADCRUMBS_CACHE_STORAGE, TRUE);
}
return $save_result;
}
function path_breadcrumbs_delete($name) {
$path_breadcrumbs = path_breadcrumbs_load_by_name($name);
module_invoke_all('path_breadcrumbs_delete', $path_breadcrumbs);
ctools_export_crud_delete('path_breadcrumbs', $path_breadcrumbs);
path_breadcrumbs_object_cache_clear($name);
cache_clear_all('*', PATH_BREADCRUMBS_CACHE_STORAGE, TRUE);
}
function path_breadcrumbs_load_prepare($path_breadcrumbs_raw) {
$path_breadcrumbs = (object) array_merge((array) $path_breadcrumbs_raw, $path_breadcrumbs_raw->data);
$path_breadcrumbs->disabled = isset($path_breadcrumbs->disabled) ? $path_breadcrumbs->disabled : FALSE;
$path_breadcrumbs->is_overwritten = $path_breadcrumbs->export_type == (EXPORT_IN_DATABASE | EXPORT_IN_CODE);
unset($path_breadcrumbs->data);
return $path_breadcrumbs;
}
function path_breadcrumbs_load($path_id) {
$paths =& drupal_static(__FUNCTION__);
if (!isset($paths[$path_id])) {
ctools_include('export');
$result = ctools_export_load_object('path_breadcrumbs', 'conditions', array(
'path_id' => $path_id,
));
$path_breadcrumbs = reset($result);
if (!empty($path_breadcrumbs)) {
$path_breadcrumbs = path_breadcrumbs_load_prepare($path_breadcrumbs);
$paths[$path_id] = $path_breadcrumbs;
}
}
return isset($paths[$path_id]) ? $paths[$path_id] : FALSE;
}
function path_breadcrumbs_load_by_name($name) {
ctools_include('export');
$result = ctools_export_load_object('path_breadcrumbs', 'names', array(
$name,
));
if (!empty($result[$name])) {
$path_breadcrumbs = path_breadcrumbs_load_prepare($result[$name]);
}
return isset($path_breadcrumbs) ? $path_breadcrumbs : FALSE;
}
function path_breadcrumbs_load_by_name_multiple($names) {
ctools_include('export');
$result = ctools_export_load_object('path_breadcrumbs', 'names', $names);
foreach ($result as $name => $path_breadcrumbs) {
$result[$name] = path_breadcrumbs_load_prepare($path_breadcrumbs);
}
return $result;
}
function path_breadcrumbs_load_all() {
ctools_include('export');
$data = ctools_export_load_object('path_breadcrumbs', 'all');
$data = array_map('path_breadcrumbs_load_prepare', $data);
uasort($data, '_path_breadcrumbs_sort_weight');
return $data;
}
function path_breadcrumbs_load_by_path($path) {
$data =& drupal_static(__FUNCTION__);
$pattern_needle = path_breadcrumbs_path_pattern($path);
if (empty($data[$pattern_needle])) {
$cache = cache_get(__FUNCTION__, PATH_BREADCRUMBS_CACHE_STORAGE);
if (isset($cache->data)) {
$data = $cache->data;
}
else {
ctools_include('export');
$result = path_breadcrumbs_load_all();
foreach ($result as $path_breadcrumbs) {
if (empty($path_breadcrumbs->disabled)) {
$pattern = path_breadcrumbs_path_pattern($path_breadcrumbs->path);
$data[$pattern][] = $path_breadcrumbs;
}
}
cache_set(__FUNCTION__, $data, PATH_BREADCRUMBS_CACHE_STORAGE);
}
}
return isset($data[$pattern_needle]) ? $data[$pattern_needle] : array();
}
function path_breadcrumbs_get_contexts_from_arguments($arguments, $empty = FALSE, $path = NULL) {
$contexts = array();
ctools_include('context');
if (!empty($arguments)) {
foreach ($arguments as $keyword => $arg) {
if (!empty($arg['argument'])) {
$argument = ctools_get_argument($arg['argument']);
if (isset($arg['settings'])) {
$argument = array_merge($argument, $arg['settings']);
}
$arg = $empty ? NULL : arg($arg['position'], $path);
$context = call_user_func($argument['context'], $arg, $argument, $empty);
if (!empty($context)) {
$context->keyword = $keyword;
$context->identifier = $argument['identifier'];
$contexts[$keyword] = $context;
if ($context->plugin == 'user') {
$context->plugin = 'path_breadcrumbs_user';
}
}
else {
$contexts['broken_context'] = $keyword;
}
}
}
}
return $contexts;
}
function path_breadcrumbs_object_cache_get($name, $skip_cache = FALSE) {
ctools_include('object-cache');
return ctools_object_cache_get('path_breadcrumbs', $name, $skip_cache);
}
function path_breadcrumbs_object_cache_set($name, $data) {
ctools_include('object-cache');
$data = (object) $data;
ctools_object_cache_set('path_breadcrumbs', $name, $data);
}
function path_breadcrumbs_object_cache_clear($name) {
ctools_include('object-cache');
ctools_object_cache_clear('path_breadcrumbs', $name);
}
function path_breadcrumbs_path_pattern($path) {
$cache =& drupal_static(__FUNCTION__);
if (empty($cache[$path])) {
$cache[$path] = preg_replace("\n /\\/ # start with slash\n [^\\/]+ # all symbols except for the slash\n /x", '/%', $path);
}
return $cache[$path];
}
function _path_breadcrumbs_sort_weight($a, $b) {
$a_weight = isset($a->weight) ? $a->weight : 0;
$b_weight = isset($b->weight) ? $b->weight : 0;
if ($a_weight == $b_weight) {
return 0;
}
return $a_weight < $b_weight ? -1 : 1;
}
function path_breadcrumbs_export($path_breadcrumbs, $indent) {
if (empty($path_breadcrumbs->data)) {
$path_breadcrumbs->data = array(
'titles' => $path_breadcrumbs->titles,
'paths' => $path_breadcrumbs->paths,
'home' => $path_breadcrumbs->home,
'translatable' => $path_breadcrumbs->translatable,
'arguments' => $path_breadcrumbs->arguments,
'access' => $path_breadcrumbs->access,
);
if (!empty($path_breadcrumbs->custom)) {
$path_breadcrumbs->data['custom'] = $path_breadcrumbs->custom;
}
}
return ctools_export_object('path_breadcrumbs', $path_breadcrumbs, $indent);
}
function path_breadcrumbs_export_list() {
$list = array();
$result = path_breadcrumbs_load_all();
uksort($result, 'strnatcmp');
foreach ($result as $path_breadcrumbs) {
$string = $path_breadcrumbs->name . " (" . $path_breadcrumbs->machine_name . ")";
$list[$path_breadcrumbs->machine_name] = check_plain($string);
}
return $list;
}
function path_breadcrumbs_panels_pane_content_alter(&$content, $pane, $args, $context, $renderer, $display) {
if (empty($content)) {
return;
}
if ($content->type == 'page_breadcrumb') {
path_breadcrumbs_set_breadcrumb();
$content->content = theme('breadcrumb', array(
'breadcrumb' => drupal_get_breadcrumb(),
));
}
}
function _path_breadcrumbs_clean_url($url, &$options, $method = NULL) {
$options['fragment'] = '';
$options['query'] = array();
$url_short = htmlspecialchars_decode($url, ENT_NOQUOTES);
$url_parts = parse_url($url_short);
if (!empty($url_parts['fragment'])) {
$options['fragment'] = $url_parts['fragment'];
list($url_short, ) = explode('#', $url_short, 2);
}
$options['query'] = array();
if (!empty($url_parts['query'])) {
list($url_short, ) = explode('?', $url_short, 2);
parse_str($url_parts['query'], $query);
$options['query'] += $query;
}
if (empty($method)) {
$method = variable_get('path_breadcrumbs_url_cleaning_method', 'none');
}
if ($method == 'none') {
return $url_short;
}
if (preg_match('@^http(s?)://@i', $url_short)) {
return $url_short;
}
$ctools_cleanstring_settings = array(
'clean id' => 'path_breadcrumbs_url',
'lower case' => TRUE,
'transliterate' => TRUE,
'reduce ascii' => FALSE,
'separator' => '-',
);
$pieces = explode('/', $url_short);
$results = array();
if ($method == 'ctools') {
ctools_include('cleanstring');
foreach ($pieces as $piece) {
$results[] = ctools_cleanstring($piece, $ctools_cleanstring_settings);
}
$options['fragment'] = ctools_cleanstring($options['fragment'], $ctools_cleanstring_settings);
}
elseif ($method == 'pathauto' && module_exists('pathauto')) {
module_load_include('inc', 'pathauto');
foreach ($pieces as $piece) {
$results[] = pathauto_cleanstring($piece);
}
$options['fragment'] = pathauto_cleanstring($options['fragment']);
}
else {
$results = $pieces;
}
return implode('/', $results);
}
function _path_breadcrumbs_themes_option_list() {
$result = array();
$admin_theme = variable_get('admin_theme');
foreach (list_themes() as $theme) {
$result[$theme->name] = $theme->info['name'];
if ($theme->status) {
$result[$theme->name] = '<strong title="' . t('This theme is enabled') . '">' . $result[$theme->name] . '</strong>';
}
if ($theme->name == $admin_theme) {
$result[$theme->name] = $theme->info['name'] . ' (<em>' . t('Administration theme') . '</em>)';
}
}
return $result;
}