array('href' => 'start', 'title' => t('Get Started'), '#site' => 'main', 'attributes' => array('title' => t('Getting Started with Drupal'))),
'forum' => array('href' => 'community', 'title' => t('Community & Support'), '#site' => 'main', 'attributes' => array('title' => t('Drupal Community and Support'))),
'handbooks' => array('href' => 'documentation', 'title' => t('Documentation'), '#site' => 'main', 'attributes' => array('title' => t('Drupal Documentation'))),
'project' => array('href' => 'download', 'title' => t('Download & Extend'), '#site' => 'main', 'attributes' => array('title' => t('Download and Extend Drupal'))),
'marketplace' => array('href' => 'drupal-services', 'title' => t('Marketplace'), '#site' => 'main', 'attributes' => array('title' => t('Buy Drupal Products and Services'))),
'about' => array('href' => 'about', 'title' => t('About'), '#site' => 'main', 'attributes' => array('title' => t('About Drupal'))),
);
// Make all external links right.
$nav_header_links = drupalorg_crosssite_menu_absolute_links($nav_header_links);
// Theme as links, and avoid class="links" on it.
$vars['nav_header'] = theme('links', $nav_header_links, array());
// == Build the footer navigation
$nav_footer_links = array(
array(
'news' => array('href' => 'news', 'title' => t('Drupal News'), '#site' => 'main'),
'planet' => array('href' => 'planet', 'title' => t('Planet Drupal'), '#site' => 'main', 'attributes' => array('title' => t('News from Drupal community members'))),
'association' => array('href' => '', 'title' => t('Association News'), '#site' => 'association', 'attributes' => array('title' => t('News from association.drupal.org'))),
'security' => array('href' => 'security', 'title' => t('Security Announcements'), '#site' => 'main', 'attributes' => array('title' => t('Advisories from the security team'))),
'jobs' => array('href' => 'jobs', 'title' => t('Jobs'), '#site' => 'groups', 'attributes' => array('title' => t('Jobs posted on groups.drupal.org'))),
),
array(
'community' => array('href' => 'community', 'title' => t('Community & Support'), '#site' => 'main'),
'get-involved' => array('href' => 'getting-involved', 'title' => t('Getting Involved'), '#site' => 'main', 'attributes' => array('title' => t('Learn how to contribute to the Drupal project'))),
'marketplace' => array('href' => 'drupal-services', 'title' => t('Marketplace'), '#site' => 'main', 'attributes' => array('title' => t('People and organizations offering Drupal services'))),
'groups' => array('href' => 'groups', 'title' => t('Groups & Meetups'), '#site' => 'groups', 'attributes' => array('title' => t('groups.drupal.org'))),
'dcchicago' => array('href' => '', 'title' => t('DrupalCon Chicago 2011'), '#site' => 'chicago2011', 'attributes' => array('title' => t('DrupalCon chicago2011.drupal.org'))),
'dclondon' => array('href' => '', 'title' => t('DrupalCon London 2011'), '#site' => 'london2011', 'attributes' => array('title' => t('DrupalCon london2011.drupal.org'))),
),
array(
'get-started' => array('href' => 'start', 'title' => t('Get Started'), '#site' => 'main'),
'docs' => array('href' => 'documentation', 'title' => t('Documentation Home'), '#site' => 'main', 'attributes' => array('title' => t('Guidebooks and documentation for working with Drupal'))),
'install' => array('href' => 'documentation/install', 'title' => t('Installation Guide'), '#site' => 'main', 'attributes' => array('title' => t('Guide for installing Drupal'))),
'site-building' => array('href' => 'documentation/build', 'title' => t('Site Building Guide'), '#site' => 'main', 'attributes' => array('title' => t('Guide for building and extending Drupal sites'))),
'api' => array('href' => '', 'title' => t('api.drupal.org'), '#site' => 'api', 'attributes' => array('title' => t('Drupal API Reference'))),
),
array(
'download' => array('href' => 'download', 'title' => t('Download & Extend'), '#site' => 'main'),
'download-core' => array('href' => 'project/drupal', 'title' => t('Drupal Core'), '#site' => 'main', 'attributes' => array('title' => t('Download the latest version of the Drupal software'))),
'download-modules' => array('href' => 'project/modules', 'title' => t('Modules'), '#site' => 'main', 'attributes' => array('title' => t('Download add-on features and functionality'))),
'download-themes' => array('href' => 'project/themes', 'title' => t('Themes'), '#site' => 'main', 'attributes' => array('title' => t('Download pre-designed styles for Drupal'))),
'download-profiles' => array('href' => 'project/installation+profiles', 'title' => t('Installation Profiles'), '#site' => 'main', 'attributes' => array('title' => t('Download a pre-packaged Drupal site'))),
),
array(
'about' => array('href' => 'about', 'title' => t('About'), '#site' => 'main'),
'druplicon' => array('href' => 'druplicon', 'title' => t('Druplicon'), '#site' => 'main', 'attributes' => array('title' => t('Drupal\'s mascot'))),
'association-about' => array('href' => 'about', 'title' => t('The Drupal Association'), '#site' => 'association', 'attributes' => array('title' => t('About the Drupal Association'))),
'advertise' => array('href' => 'advertising', 'title' => t('Advertise'), '#site' => 'association', 'attributes' => array('title' => t('How to advertise on Drupal.org'))),
'drupalorg' => array('href' => 'taxonomy/term/13', 'title' => t('Drupal.org'), '#site' => 'main', 'attributes' => array('title' => t('About Drupal.org'))),
),
);
$vars['nav_footer'] = '';
foreach ($nav_footer_links as $num => $links_column) {
// Make all external links right.
$links_column = drupalorg_crosssite_menu_absolute_links($links_column);
// Add alpha and omega class to first and last item.
$alpha_omega = '';
if ($num == 0) {
$alpha_omega = ' alpha';
}
else if ($num == count($nav_footer_links) - 1) {
$alpha_omega = ' omega';
}
// Theme as links, and avoid class="links" on it.
$vars['nav_footer'] .= '
';
}
// Add content header navigation.
drupalorg_crosssite_content_menu($vars);
// Add page tool navigation.
$page_tools = module_invoke_all('drupalorg_crosssite_page_tools');
if (count($page_tools) > 0) {
$vars['page_tools'] = theme('links', $page_tools);
}
// == Nav masthead links
$master_uid = drupalorg_crossite_bakery_master_uid();
$nav_masthead_links = array(
'homepage' => array('href' => 'home', 'title' => t('Drupal Homepage'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^(home|)/?$')),
'dashboard' => array('href' => 'user/' . $master_uid . '/dashboard', 'title' => t('Your Dashboard'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^user/[0-9]+/dashboard(/|$)')),
);
$userinfo = '';
if ($user->uid == 0) {
unset($nav_masthead_links['dashboard']);
$nav_masthead_links['login-register'] = array('href' => 'user', 'query' => drupal_get_destination(), 'title' => t('Login / Register'), '#active' => drupalorg_crosssite_menu_path('main', '^user(/|$)'));
}
else {
// Add user page link and logout link.
$userinfo = ''. l(t('Logged in as @username', array('@username' => $user->name)), 'user', array('html' => TRUE, 'attributes' => array('title' => t('View & edit your user profile')))) .' '. l(t('Logout'), 'logout');
if (variable_get('drupalorg_crosssite_redesign', FALSE)) {
$userinfo = '
'. l(t('Logged in as @username', array('@username' => $user->name)), 'http://' . $sites['main'] . '/user', array('html' => TRUE, 'attributes' => array('title' => t('View & edit your user profile')))) .' '. l(t('Logout'), 'logout');
}
if (user_access('access administration pages')) {
$userinfo .= ' ' . l(t('Admin'), 'admin');
}
$userinfo .= '
';
}
// Make all external links right.
$nav_masthead_links = drupalorg_crosssite_menu_absolute_links($nav_masthead_links);
// Theme as links, and avoid class="links" on it.
$vars['nav_masthead'] = theme('links', $nav_masthead_links, array()) . $userinfo;
// Put in a body class for CSS hooking and a variable for theme dependence
// if we are on the main site's home page. Many things should be different
// there.
$vars['is_drupalorg_front'] = drupalorg_crosssite_menu_site('main') && drupal_is_front_page();
if ($vars['is_drupalorg_front']) {
$vars['body_classes'] .= ' drupalorg-front';
}
}
/**
* Specify the section matching criteria.
*/
function drupalorg_crosssite_section() {
global $user, $conf;
static $section = FALSE;
if ($section === FALSE) {
$node = menu_get_object();
// Theoretically, the matching criteria made one of the areas win (have TRUE as
// the array value). If there are two menus to display on the same path, we
// are in trouble, since we only have one menu displayed per path. Fix the above
// matching in that case. (This will pick the first matched in that case).
if (drupalorg_crosssite_menu_path('main', '^(user/'. $user->uid .'(/|$)|project(/issues)?/user$)')) {
$section = 'dashboard';
}
elseif (drupalorg_crosssite_menu_path('main', '^node/1$') || drupalorg_crosssite_in_breadcrumb('main', 'node/1')
|| drupalorg_crosssite_menu_path('main', '^features$') || drupalorg_crosssite_in_breadcrumb('main', 'node/909476')) {
$section = 'about';
}
elseif (drupalorg_crosssite_menu_path('main', 'taxonomy/term/13') || drupalorg_crosssite_child_of('main', 'node/179723') || (drupalorg_crosssite_in_breadcrumb('main', 'project/drupal project') && !drupalorg_crosssite_child_of('main', 'node/' . DRUPALORG_CORE_NID))) {
$section = 'drupalorg';
}
elseif (drupalorg_crosssite_menu_path('main', '^(project|download)(/|$)') || drupalorg_crosssite_menu_path('main', '^node/\d+/(release|committers|maintainers)') || drupalorg_crosssite_menu_type('main', array('project_project', 'project_issue', 'project_release')) || drupalorg_crosssite_menu_site('localize')) {
$section = 'downloads';
}
elseif (drupalorg_crosssite_menu_path('main', '^security(|/contrib|/psa)$') || drupalorg_crosssite_menu_term('main', array(1852, 44, 1856))) {
$section = 'security';
}
elseif (drupalorg_crosssite_menu_path('main', '^(irc|mailing-lists|profile|community|getting-involved|community-spotlight)(/|$)') || drupalorg_crosssite_child_of('main', 'forum') || drupalorg_crosssite_menu_type('main', array('forum')) || drupalorg_crosssite_menu_path('main', '^node/281873$') || (drupalorg_crosssite_in_breadcrumb('main', 'node/281873') && !drupalorg_crosssite_menu_path('main', '^(node/23192|handbook/updates)(/|$)'))) {
$section = 'community';
}
elseif (drupalorg_crosssite_child_of('main', 'node/366')) {
$section = 'marketplace';
}
elseif (drupalorg_crosssite_menu_site('api')
|| (drupalorg_crosssite_menu_site('main') && isset($node) && isset($node->book['bid']))
|| drupalorg_crosssite_menu_path('main', '^(handbook|documentation)')) {
$section = 'documentation';
}
elseif (drupalorg_crosssite_menu_site('association')) {
$section = 'association';
}
elseif (drupalorg_crosssite_menu_path('main', '^user(/|$)')) {
$section = 'user';
}
elseif (drupalorg_crosssite_in_breadcrumb('main', 'admin')) {
$section = 'admin';
}
elseif (menu_get_item() !== FALSE) {
// Should not happen.
$section = NULL;
}
// Track section
if (!empty($conf['googleanalytics_codesnippet_before'])) {
$conf['googleanalytics_codesnippet_before'] .= "_gaq.push(['_setCustomVar', 2, 'Drupalorg-section', '" . $section . "', 3]);"; // 3 is page-level
}
}
return $section;
}
/**
* Content for the content top menu.
*
* We implement this as "custom menus", since we need to have cross-site menu
* items in some cases, and having these sycned across all subsites would be
* painful (read: menu items would have different URLs and menu ids on subsites,
* since an API link on the docs site would link out to API while a docs link
* on the API would link out to the docs site).
*/
function drupalorg_crosssite_content_menu(&$vars) {
global $user;
// Identify sections names/titles to be displayed above content area menus.
$section_names = array(
'about' => 'About Drupal',
'downloads' => 'Download & Extend',
'documentation' => 'Documentation',
'community' => 'Community & Support',
'dashboard' => check_plain($user->name),
'localize' => 'Localize',
'association' => 'Drupal Association',
'drupalorg' => 'Drupal.org',
'marketplace' => 'Marketplace',
'security' => 'Security advisories',
);
// Set the section_name variable to be output in page.tpl.php.
if (isset($section_names[drupalorg_crosssite_section()])) {
$vars['section_name'] = $section_names[drupalorg_crosssite_section()];
}
// Now ask for all the menu items for the matched menu.
$nav_content_links = array();
switch (drupalorg_crosssite_section()) {
case 'documentation':
$nav_content_links = array(
'home' => array('href' => 'node/26419', 'title' => t('Docs Home'), '#site' => 'main', '#active' => (drupalorg_crosssite_menu_type('main', array('book')) || drupalorg_crosssite_menu_path('main', '^(documentation|handbook)(/|$)')) && !drupalorg_crosssite_menu_path('main', '^(node/23192|handbook/updates)(/|$)')),
'api' => array('href' => '
', 'title' => t('API'), '#site' => 'api', '#active' => drupalorg_crosssite_in_breadcrumb('api', 'api/drupal', $vars) || drupalorg_crosssite_menu_site('api')),
'recent' => array('href' => 'handbook/updates', 'title' => t('Recently Updated'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^(node/23192|handbook/updates)(/|$)')),
);
break;
case 'downloads':
$nav_content_links = array(
'home' => array('href' => 'download', 'title' => t('Download & Extend Home'), '#site' => 'main'),
'core' => array('href' => 'node/' . DRUPALORG_CORE_NID, 'title' => t('Drupal Core'), '#active' => drupalorg_crosssite_child_of('main', 'node/' . DRUPALORG_CORE_NID, $vars), '#site' => 'main'),
'modules' => array('href' => 'project/modules', 'title' => t('Modules'), '#site' => 'main', '#active' => drupalorg_crosssite_in_breadcrumb('main', 'project/modules', $vars) || drupalorg_crosssite_menu_path('main', '^project/modules')),
'themes' => array('href' => 'project/themes', 'title' => t('Themes'), '#site' => 'main', '#active' => drupalorg_crosssite_child_of('main', 'project/themes', $vars) || drupalorg_crosssite_child_of('main', 'project/theme engines', $vars)),
'translations' => array('href' => '', 'title' => t('Translations'), '#site' => 'localize', '#active' => drupalorg_crosssite_menu_site('localize') || drupalorg_crosssite_in_breadcrumb('main', 'project/translations', $vars)),
'install-profiles' => array('href' => 'project/installation+profiles', 'title' => t('Installation Profiles'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^project/installation profiles') || drupalorg_crosssite_in_breadcrumb('main', 'project/installation profiles', $vars)),
);
break;
case 'community':
$nav_content_links = array(
'home' => array('href' => 'community', 'title' => t('Community Home'), '#site' => 'main'),
'getting-involved' => array('href' => 'getting-involved', 'title' => t('Getting Involved'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^(getting-involved|community-spotlight)(/|$)') || drupalorg_crosssite_menu_path('main', '^node/281873$') || (drupalorg_crosssite_in_breadcrumb('main', 'node/281873') && !drupalorg_crosssite_menu_path('main', '^irc(/|$)') && !drupalorg_crosssite_menu_path('main', '^mailing-lists(/|$)'))),
'chat' => array('href' => 'irc', 'title' => t('Chat'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^irc(/|$)')),
'lists' => array('href' => 'mailing-lists', 'title' => t('Mailing Lists'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^mailing-lists(/|$)')),
'members' => array('href' => 'profile', 'title' => t('Member Directory'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^profile(/|$)'), '#title_match' => 'q'),
'forum' => array('href' => 'forum', 'title' => t('Forum'), '#site' => 'main', '#active' => drupalorg_crosssite_in_breadcrumb('main', 'forum', $vars), '#title_match' => 'q'),
'groups' => array('href' => 'groups', 'title' => t('Groups & Meetups'), '#site' => 'groups'),
);
break;
case 'association':
$nav_content_links = array(
'home' => array('href' => '', 'title' => t('Association Home'), '#site' => 'association'),
'news' => array('href' => 'news', 'title' => t('News'), '#site' => 'association', '#active' => drupalorg_crosssite_menu_term('association', array(263))),
'about' => array('href' => 'node/58', 'title' => t('About'), '#site' => 'association', '#active' => drupalorg_crosssite_child_of('association', 'about')),
'donate' => array('href' => 'node/67', 'title' => t('Donate'), '#site' => 'association'),
'membership' => array('href' => 'node/78', 'title' => t('Memberships'), '#site' => 'association'),
'faq' => array('href' => 'node/65', 'title' => t('FAQ'), '#site' => 'association'),
'staff' => array('href' => 'node/61', 'title' => t('Staff'), '#site' => 'association'),
'contact' => array('href' => 'contact', 'title' => t('Contact'), '#site' => 'association'),
);
break;
case 'dashboard':
$code_item = menu_get_item('user/' . $user->uid . '/track/code');
$nav_content_links = array(
'your-dashboard' => array('title' => t('Dashboard'), 'href' => 'user/' . $user->uid . '/dashboard', '#site' => 'main'),
'your-posts' => array('title' => t('Your Posts'), 'href' => 'user/' . $user->uid . '/track', '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^user/' . $user->uid . '/track$')),
'commits' => array('title' => t('Your Commits'), 'href' => 'user/' . $user->uid . '/track/code', '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^user/' . $user->uid . '/track/code'), '#enabled' => $code_item['access']),
'your-issues' => array('title' => t('Your Issues'), 'href' => 'project/issues/user', '#site' => 'main'),
'your-projects' => array('title' => t('Your Projects'), 'href' => 'project/user', '#site' => 'main'),
'your-groups' => array('title' => t('Your Groups'), 'href' => 'groups/my', '#site' => 'groups'),
'your-profile' => array('title' => t('Profile'), 'href' => 'user/'. $user->uid, '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^user/' . $user->uid . '(?!/(dashboard|track))')),
);
break;
case 'user':
if (is_numeric(arg(1))) {
$account = user_load(arg(1));
$code_item = menu_get_item('user/' . $account->uid . '/track/code');
$nav_content_links = array(
'user-profile' => array('title' => t('Profile'), 'href' => 'user/'. $account->uid, '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^user/' . $account->uid . '(?!/(dashboard|track))')),
'posts' => array('title' => t('Posts'), 'href' => 'user/' . $account->uid . '/track', '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^user/' . $account->uid . '/track$')),
'commits' => array('title' => t('Commits'), 'href' => 'user/' . $account->uid . '/track/code', '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^user/' . $account->uid . '/track/code'), '#enabled' => $code_item['access']),
);
}
break;
case 'drupalorg':
$nav_content_links = array(
'home' => array('title' => t('Drupal.org Projects'), 'href' => 'taxonomy/term/13', '#active' => drupalorg_crosssite_child_of('main', 'project/drupal project', $vars) && !(drupalorg_crosssite_child_of('main', 'node/3202') || drupalorg_crosssite_child_of('main', 'node/18753') || drupalorg_crosssite_child_of('main', 'node/525912') || drupalorg_crosssite_child_of('main', 'node/107028') || drupalorg_crosssite_child_of('main', 'node/651778'))),
'drupalorg-faq' => array('title' => t('FAQ'), 'href' => 'node/179723', '#active' => drupalorg_crosssite_child_of('main', 'node/179723')),
'webmasters' => array('title' => t('Webmasters'), 'href' => 'node/3202', '#active' => drupalorg_crosssite_child_of('main', 'node/3202', $vars)),
'documentation' => array('title' => t('Documentation'), 'href' => 'node/18753', '#active' => drupalorg_crosssite_child_of('main', 'node/18753', $vars)),
'projectapplications' => array('title' => t('Project Applications'), 'href' => 'node/1025112', '#active' => drupalorg_crosssite_child_of('main', 'node/1025112', $vars)),
'infrastructure' => array('title' => t('Infrastructure'), 'href' => 'node/107028', '#active' => drupalorg_crosssite_child_of('main', 'node/107028', $vars)),
'theme' => array('title' => t('Theme'), 'href' => 'node/651778', '#active' => drupalorg_crosssite_child_of('main', 'node/651778', $vars)),
);
break;
case 'marketplace':
$nav_content_links = array(
'services' => array('title' => t('Services'), 'href' => 'node/21791', '#active' => drupalorg_crosssite_child_of('main', 'drupal-services')),
'hosting' => array('title' => t('Hosting'), 'href' => 'node/21785', '#active' => drupalorg_crosssite_child_of('main', 'hosting')),
'training' => array('title' => t('Training'), 'href' => 'node/313581', '#active' => drupalorg_crosssite_child_of('main', 'training-services')),
);
break;
case 'security':
$nav_content_links = array(
'core' => array('title' => t('Drupal core'), 'href' => 'security', '#active' => drupalorg_crosssite_menu_term('main', array(1852))),
'contrib' => array('title' => t('Contributed projects'), 'href' => 'security/contrib', '#active' => drupalorg_crosssite_menu_term('main', array(44))),
'psa' => array('title' => t('Public service anouncements'), 'href' => 'security/psa', '#active' => drupalorg_crosssite_menu_term('main', array(1856))),
);
break;
}
if (count($nav_content_links)) {
// Make all external links right.
$nav_content_links = drupalorg_crosssite_menu_absolute_links($nav_content_links);
// Check the links to see if it is an active link. We want to know if the
// tab root is the current page, replacing % with the used value. Example:
// user/%/edit.
$item = menu_get_item();
$parts = explode('/', $item['tab_root']);
$args = arg();
foreach ($parts as $index => $part) {
if ($part === '%') {
$parts[$index] = $args[$index];
}
}
$tab_root_href = implode('/', $parts);
foreach ($nav_content_links as $key => $link) {
// Disable if applicable
if (isset($link['#enabled']) && !$link['#enabled']) {
unset($nav_content_links[$key]);
continue;
}
if ($link['href'] === '') {
$link['href'] = variable_get('site_frontpage', 'node');
}
// Menu items which do not have placeholders for all their arguments will
// have an inaccurate tab_root, so allow using $_REQUEST['q']. Example:
// forum.
$title_match = $tab_root_href;
if (isset($link['#title_match']) && $link['#title_match'] === 'q') {
$title_match = $_REQUEST['q'];
}
if (isset($link['href']) && ($link['href'] === $title_match) && (empty($link['language']) || $link['language']->language == $language->language)) {
// This is an active link/tab, therefore we don't want to display the
// page title. Used in page.tpl.php.
$vars['matched_content_link'] = TRUE;
}
}
// Theme the links for the page.
$vars['nav_content'] = theme('links', $nav_content_links);
$vars['nav_content_class'] = ' class="clear-block nav-content-'. drupalorg_crosssite_section() .'"';
}
else {
// Else just return an empty content nav menu.
$vars['nav_content'] = $vars['nav_content_class'] = '';
}
}
// == API functions ============================================================
function drupalorg_crosssite_child_of($site_key, $path, &$vars = NULL) {
return drupalorg_crosssite_menu_path($site_key, '^(' . $path . '|' . drupal_get_path_alias($path) . ')(/|$)') || drupalorg_crosssite_in_breadcrumb($site_key, $path, $vars);
}
/**
* Find a path in the breadcrumb. If found, return TRUE and set the shortened
* breadcrumb.
*
* @param $site_key
* One of the sitekeys as defined in drupalorg_crosssite_menu_sites().
* @param $path
* The path to search for, as used in the previously-set breadcrumb.
* @param $path
* If you want to render part of the breadcrumbs, pass $vars.
* @return
* TRUE if found, and modify $vars['breadcrumb'].
*/
function drupalorg_crosssite_in_breadcrumb($site_key, $path, &$vars = NULL) {
if (drupalorg_crosssite_menu_site($site_key)) {
$url = url($path);
foreach (drupal_get_breadcrumb() as $n => $breadcrumb) {
if (strpos($breadcrumb, 'href="' . $url . '"') !== FALSE) {
if (isset($vars)) {
$vars['breadcrumb'] = theme('breadcrumb', array_slice(drupal_get_breadcrumb(), $n + 1));
}
return TRUE;
}
}
}
return FALSE;
}
/**
* Which site is which URL?
*
* We have multiple keys for different functionality, so in case we need to
* break these out, we can quickly swap these URLs and be done with updating
* the navigation by deploying the new version of this module across all
* subsites.
*/
function drupalorg_crosssite_menu_sites() {
$base_domain = variable_get('drupalorg_base_domain', 'drupal.org');
return array(
'main' => $base_domain,
'api' => 'api.' . $base_domain,
'association' => 'association.' . $base_domain,
'groups' => 'groups.' . $base_domain,
'localize' => 'localize.' . $base_domain,
'chicago2011' => 'chicago2011.drupal.org',
'london2011' => 'london2011.drupal.org',
);
}
/**
* Check whether we are on the specified site.
*
* @param $site_key
* One of the sitekeys as defined in drupalorg_crosssite_menu_sites().
* @return
* TRUE if on the site specified by $site_key.
*/
function drupalorg_crosssite_menu_site($site_key) {
static $site = NULL;
static $sites = NULL;
if (!isset($site)) {
$site = variable_get('drupalorg_site', 'main');
$sites = drupalorg_crosssite_menu_sites();
}
return isset($sites[$site_key]) && isset($sites[$site]) && ($site_key == $site);
}
/**
* Check whether we are viewing any of the specified node types on the given site.
*
* @param $site_key
* One of the sitekeys as defined in drupalorg_crosssite_menu_sites().
* @param $node_types
* An array of possible node types to check for.
* @return
* TRUE if on the site specified by $site_key, looking at a node of any of the
* types specified in $node_types.
*/
function drupalorg_crosssite_menu_type($site_key, $node_types) {
// menu_get_object() gets us the node, if we have a node loaded on the path.
if (drupalorg_crosssite_menu_site($site_key) && ($node = menu_get_object())) {
return in_array($node->type, $node_types);
}
}
/**
* Check whether we are viewing any of the specified node terms on the given site.
*
* @param $site_key
* One of the sitekeys as defined in drupalorg_crosssite_menu_sites().
* @param $node_tids
* An array of possible node term IDs to check for.
* @return
* TRUE if on the site specified by $site_key, looking at a node of any of the
* term IDs specified in $node_tids.
*/
function drupalorg_crosssite_menu_term($site_key, $node_tids) {
// menu_get_object() gets us the node, if we have a node loaded on the path.
if (drupalorg_crosssite_menu_site($site_key) && ($node = menu_get_object())) {
return count(array_intersect(array_keys($node->taxonomy), $node_tids)) > 0;
}
}
/**
* Check whether we are viewing any of the specified paths on the given site.
*
* @param $site_key
* One of the sitekeys as defined in drupalorg_crosssite_menu_sites().
* @param $path_regex
* A Per regular expression to match against the current path.
* @return
* TRUE if on the site specified by $site_key, looking at a path matching
* $path_regex.
*/
function drupalorg_crosssite_menu_path($site_key, $path_regex = '') {
// menu_get_object() gets us the node, if we have a node loaded on the path.
if (drupalorg_crosssite_menu_site($site_key)) {
if (empty($path_regex)) {
// We need to match the front page.
return (empty($_GET['q']));
}
else {
// Use the full preg_match.
return preg_match('#'. $path_regex .'#', drupal_get_path_alias($_GET['q']));
}
}
}
/**
* Make sure outside links are absolute and add "active" classes as required.
*
* @param $links
* List of links array as expected by theme('links') with #site and
* #active keys for the individual links to specify which site to point
* the link to and whether the item is active.
*
* - For possible #site values, @see drupalorg_crosssite_menu_sites().
* - #active can be built with @see drupalorg_crosssite_menu_path(),
* @see drupalorg_crosssite_menu_site() and
* @see drupalorg_crosssite_menu_type() (as well as possibly
* @see user_access() and friends, if you made sure the link will be
* local, so you can do local access checks against it).
*
* @return
* The modified link array.
*/
function drupalorg_crosssite_menu_absolute_links($links) {
static $sites = NULL;
if (!isset($sites)) {
$sites = drupalorg_crosssite_menu_sites();
}
$activated_links = array();
foreach ($links as $key => $link) {
// If we are not on the given site, convert the link to an absolute link
// to the given site.
if (isset($link['#site']) && !drupalorg_crosssite_menu_site($link['#site'])) {
$link['href'] = 'http://'. $sites[$link['#site']] .'/'. ($link['href'] == '' ? '' : $link['href']);
}
// Otherwise, it might be an active link still, so add on the active class,
// if we know #active was defined TRUE.
elseif (!empty($link['#active'])) {
// theme('link') uses the key as class, so add active class that way.
$key = $key .' active';
$link['attributes']['class'] = 'active';
}
$activated_links[$key] = $link;
}
return $activated_links;
}
/**
* Arrange local tasks for user pages.
*/
function drupalorg_crosssite_menu_alter(&$items) {
if (isset($items['user/%user/dashboard'])) {
$items['user/%user/dashboard']['type'] = MENU_CALLBACK;
}
if (isset($items['user/%user/track'])) {
$items['user/%user/track']['type'] = MENU_CALLBACK;
}
if (isset($items['user/%user/track/code'])) {
$items['user/%user/track/code']['type'] = MENU_CALLBACK;
}
// Modify the local tasks for search to hide the tabs.
if (module_exists('search')) {
foreach (module_implements('search') as $module) {
if (isset($items['search/' . $module . '/%menu_tail'])) {
$items['search/' . $module . '/%menu_tail']['type'] = MENU_CALLBACK;
}
}
}
}
// == Search functions =========================================================
/**
* Define Mark Boulton's "filter by..." entries.
*/
function drupalorg_crosssite_meta_types() {
return array(
// 'API' => t('API'),
'module' => t('Modules'),
'theme' => t('Themes'),
'documentation' => t('Documentation'),
'forum-issues' => t('Forums & Issues'),
'group' => t('Groups'),
);
}
/**
* Implementation of hook_apachesolr_modify_query().
*
* Exclude the meta_type filter from faceting.
*/
function drupalorg_crosssite_apachesolr_modify_query(&$query, &$params) {
// TODO: some pending improvements to Apachesolr may simplify this.
foreach ($query->get_filters() as $filter) {
if ($filter['#name'] == 'ss_meta_type') {
$query->remove_filter($filter['#name'], $filter['#value']);
$query->add_filter('{!tag=meta_type}' . $filter['#name'], $filter['#value']);
}
}
if (isset($params['facet.field'])) {
foreach ($params['facet.field'] as &$field) {
if ($field == 'ss_meta_type') {
$field = '{!ex=meta_type}' . $field;
}
}
}
}
/**
* Implementation of hook_apachesolr_update_index().
*
* This adds our specific facets to the Apachesolr search index.
*/
function drupalorg_crosssite_apachesolr_update_index(&$document, $node) {
if ($type = drupalorg_crosssite_meta_type_traverse($node, drupalorg_crosssite_get_meta_type_rules())) {
$document->ss_meta_type = $type;
}
}
/**
* Implementation of hook_apachesolr_node_exclude().
*
* Excludes all nodes that are not publicly accessible to anonymous users. This
* is done so that we can ensure that private content is not indexed and Solr
* and potentially retrieved in an insecure fashion.
*/
function drupalorg_crosssite_apachesolr_node_exclude($node, $namespace) {
static $account;
if (!isset($account)) {
// Load the anonymous user.
$account = drupal_anonymous_user();
}
if (!node_access('view', $node, $account)) {
// If the document isn't publicly accessible to everyone, don't index it.
return TRUE;
}
}
/**
* Define rules, per site in the multi-site index, for what meta-types should be
* applied to what type of content.
*/
function drupalorg_crosssite_get_meta_type_rules() {
$site = variable_get('drupalorg_site', 'main');
$rule_set = array();
// For now, make these the rules for all sites, but can be sectioned off by
// site using $site if needed.
$rule_set = array(
// Define the type of selector: in this case, type.
'type' => array(
// Define the type values that map to meta-types: in this case,
// project_project, book, project_issue, and forum.
'project_project' => array(
// Define a sub-selector to only be run after matching on the primary
// selector: in this case, taxonomy.
'taxonomy' => array(
// Define taxonomy term values and resultant meta types: in this
// case after matching a type of project_project, an associated
// tid of DRUPALORG_MODULE_TID maps to 'module' while an associated
// tid of DRUPALORG_THEME_TID maps to 'theme'.
DRUPALORG_MODULE_TID => 'module',
DRUPALORG_THEME_TID => 'theme',
),
),
'book' => 'documentation',
'project_issue' => 'forum-issues',
'forum' => 'forum-issues',
'og' => 'group',
// Map the session from chicago2011.drupal.org to the 'documentation' metatype
'session' => 'documentation',
),
);
return $rule_set;
}
/**
* Recursively iterates through an array looking for type or taxonomy filters,
* and attempting to match against values in the passed in array.
*
* This function takes an array (set in the $conf array in settings.php) and
* handles two conditionals: type and taxonomy. Type values match against the
* node type and taxonomy values match against associated taxonomy terms. If a
* node matches all the criteria, a string will be returned representing the
* meta-type of the node for use by the apachesolr module.
*
* @param object $node
* A fully-formed node object as passed from hook_apachesolr_update_index.
* @param mixed $value
* An array initially respresents the order of operations and the
* resulting meta type value. Currently supported comparisons are type and
* taxonomy. In the final iteration of drupalorg_crosssite_meta_type_traverse,
* $value should be a string value rather than an array.
* @see drupalorg_crosssite_get_meta_type_rules for the 'main' site to see
* an example of $value.
*
* @return mixed
* Returns NULL if no meta type is found for the particular node, otherwise,
* if a meta-type is found, a string representing that meta-type is returned.
*
* @see drupalorg_crosssite_get_meta_type_rules
*/
function drupalorg_crosssite_meta_type_traverse(&$node, $value) {
// If we've traversed to a point where we have a string value
// simply return it.
if (is_string($value)) {
return $value;
}
// If we have a meta type based off of the node type, check that first.
if (isset($value['type'])) {
// If our node type has an associated meta-type (or further filtering)
// recursively call this function to determine the meta-type.
if (in_array($node->type, array_keys($value['type']))) {
return drupalorg_crosssite_meta_type_traverse($node, $value['type'][$node->type]);
}
}
// If we have a meta-type based off of taxonomy, check that next.
if (isset($value['taxonomy'])) {
// If we have a taxonomy term that relates to a meta-type, determine all
// matching terms in the node.
if ($keys = array_intersect(array_keys($node->taxonomy), array_keys($value['taxonomy']))) {
// We should only ever have 1 match (meta-type is singular), so do a
// sanity check. If we do only have 1 term, recursively call this function
// to determine the meta-type.
if (count($keys) == 1) {
$tid = array_pop($keys);
return drupalorg_crosssite_meta_type_traverse($node, $value['taxonomy'][$tid]);
}
}
}
}
/**
* Implementation of hook_form_search_theme_form_alter().
*/
function drupalorg_crosssite_form_search_theme_form_alter(&$form, $form_state) {
global $theme;
if ($theme === 'bluecheese') {
// If we already ran a query, remember those values in the header search bar.
$meta_type = '';
if (drupalorg_crosssite_apachesolr_has_searched() && $query = apachesolr_current_query()) {
// If a meta_type was specified to refine the search, save that.
$filter = $query->get_filters('ss_meta_type');
if (!empty($filter)) {
$meta_type = $filter[0]['#value'];
}
// Default the search text to the value of the queried text.
$form['search_theme_form']['#default_value'] = $query->get_keys();
}
$form['search_theme_form']['#title'] = t('Search Drupal.org');
$form['advanced'] = array(
'#type' => 'fieldset',
'#title' => t('Refine your search'),
'#collapsible' => !(drupal_is_front_page() && drupalorg_crosssite_menu_site('main')),
'#collapsed' => !(drupal_is_front_page() && drupalorg_crosssite_menu_site('main')),
);
$form['advanced']['meta_type'] = array(
'#type' => 'radios',
'#options' => array_merge(array('' => t('All')), drupalorg_crosssite_meta_types()),
'#default_value' => $meta_type,
);
$form['#submit'][] = 'drupalorg_crosssite_search_theme_form_submit';
}
}
function drupalorg_crosssite_search_theme_form_submit($form, &$form_state) {
// If the redirect is already an array, we'll keep the query params
// ($form_state['redirect'][1]) otherwise, we'll build the entire path
// manually because we want to be very explicit about where we send the
// searches so that they function with apachesolr_multisitesearch.
if (!is_array($form_state['redirect'])) {
$form_state['redirect'] = array($form_state['redirect']);
}
// Determine what search is available to us. Ideally, this should always be
// multisitesearch, but if it's not part of the multisitesearch index, then
// fall back to apachesolr, and if we're not using solr, fall back to the
// Drupal core search.
// TODO: Determine if @see search_get_implementing_modules() could supplant
// this functionality. At present, it's only on d.o, therefore it can't be
// counted on to exist.Rather than duplicating the function, I've opted for
// simple logic at present, but this can be changed.
if (module_exists('apachesolr_multisitesearch')) {
$path = 'apachesolr_multisitesearch';
}
else if (module_exists('apachesolr_search')) {
$path = 'apachesolr_search';
}
else {
$path = 'node';
}
// We override the entire search path if we are pushing to another site,
// we end up exactly where we want.
$form_id = $form['form_id']['#value'];
$path = 'search/' . $path . '/' . trim($form_state['values'][$form_id]);
// We want links to redirect to the appropriate site: initially this will
// be the main site for all searches, but may expand over time as new meta-
// types are defined.
$links = array();
// Create a link array out of our current redirect url. By default, links to
// the 'main' site, but can be overridden via the $conf array if needed.
$links[] = array('href' => $path, '#site' => variable_get('drupalorg_search_site', 'main'));
// We only push back to the main site in the scenario where multisitesearch
// is turned on. If it's not turned on, we assume this simply runs a single-
// site implementation of search.
if (module_exists('apachesolr_multisitesearch')) {
// Make it an absolute link so that searches return to the appropriate site.
$links = drupalorg_crosssite_menu_absolute_links($links);
}
// Take our newly created link and make it our redirect path.
$form_state['redirect'][0] = $links[0]['href'];
if (!empty($form_state['values']['meta_type'])) {
$form_state['redirect'][1]['filters'] = 'ss_meta_type:'. $form_state['values']['meta_type'];
}
}
/**
* Provide a single check for both multi-site searches and single-site searches
* so that blocks that are agnostic about the type of search can still behave
* as intended on the search pages.
*
* @return bool
* Returns TRUE if an apachesolr search has been run, regardless of whether it
* is a multisitesearch or a single site search. Returns FALSE otherwise.
*/
function drupalorg_crosssite_apachesolr_has_searched() {
// If we have a single-site search for apachesolr, return TRUE.
if (module_exists('apachesolr') && apachesolr_has_searched()) {
return TRUE;
}
// If we are using apachesolr_multisitesearch and we have a multisitesearch,
// then return TRUE.
if (module_exists('apachesolr_multisitesearch') && apachesolr_multisitesearch_has_searched()) {
return TRUE;
}
// In all other scenarios, return FALSE;
return FALSE;
}
/**
* Get the master uid from bakery's init field.
*/
function drupalorg_crossite_bakery_master_uid() {
global $user;
if (!variable_get('bakery_is_master', 0)) {
return preg_replace('!^.+/user/(\d+)/.+$!', '\1', $user->init);
}
else {
return $user->uid;
}
}