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'] .= '
'. theme('links', $links_column, array()) .'
'; } // 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)), 'cvsapplications' => array('title' => t('CVS Applications'), 'href' => 'node/525912', '#active' => drupalorg_crosssite_child_of('main', 'node/525912', $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; } }