'How can we help', 'page callback' => 'drupalorg_search_help_js', 'access callback' => 'user_access', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); return $items; } /** * Implementation of hook_theme(). */ function drupalorg_search_theme() { return array( 'drupalorg_search_help_results' => array( 'arguments' => array('results' => array()), ), ); } /** * Implementation of hook_apachesolr_facets(). * * Returns an array keyed by block delta. */ function drupalorg_search_apachesolr_facets() { return array( 'meta_type' => array( 'info' => t('Drupalorg Search: Filter by meta type'), 'facet_field' => '{!ex=meta_type}ss_meta_type', 'exclude_filter' => '', ), 'sort_created' => array( 'info' => t('New content'), 'facet_field' => 'created', 'direction' => 'desc', ), ); } /** * Implementation of hook_apachesolr_multisitesearch_facets(). */ function drupalorg_search_apachesolr_multisitesearch_facets() { return drupalorg_search_apachesolr_facets(); } /** * Implementation of hook_apachesolr_prepare_query(). * * Add project sorts whenever we have an ss_meta_type of theme or module. */ function drupalorg_search_apachesolr_prepare_query(&$query, &$params) { // The additional project sorts are only relevant if the query is filtering // on a project type (modules or themes). if ($query->has_filter('ss_meta_type', 'theme') || $query->has_filter('ss_meta_type', 'module')) { project_solr_add_sorts($query); } } /** * Implement hook_block(). */ function drupalorg_search_block($op = 'list', $delta = 0, $edit = array()) { // Instead of a monolithic function, split out this code into separate // functions for each operation (which we're going to need when we port to // D7, anyway). switch ($op) { case 'list': return drupalorg_search_block_info(); case 'view': return drupalorg_search_block_view($delta); } } /** * Declare all the blocks provided by drupalorg_search. */ function drupalorg_search_block_info() { $blocks = array( 'search_box' => array( 'info' => t('Drupalorg Search: Search box'), 'cache' => BLOCK_NO_CACHE, ), 'drupalorg_search_navigation' => array( 'info' => t('Drupalorg Search: Navigation'), 'cache' => BLOCK_NO_CACHE, ), 'drupalorg_search_alternate' => array( 'info' => t('Drupalorg Search: Alternate Searches'), 'cache' => BLOCK_NO_CACHE, ), 'drupalorg_search_users' => array( 'info' => t('Drupalorg Search: User Search'), 'cache' => BLOCK_NO_CACHE, ), ); // Add the facet blocks. $enabled_facets = apachesolr_get_enabled_facets('drupalorg_search'); $facets = drupalorg_search_apachesolr_facets(); foreach ($enabled_facets as $delta => $facet_field) { $blocks[$delta] = $facets[$delta] + array('cache' => BLOCK_NO_CACHE); } return $blocks; } /** * Render the content for the requested drupalorg_search block. */ function drupalorg_search_block_view($delta) { switch ($delta) { case 'search_box': if (drupalorg_crosssite_apachesolr_has_searched() && ($response = apachesolr_static_response_cache()) && ($query = apachesolr_current_query())) { $querystring = $query->get_query_basic(); } else { $querystring = ''; } // We need to special case POST requests, because the search module // doesn't trigger search on POST requests. if (!empty($querystring) || (arg(0) == 'search' && $_SERVER['REQUEST_METHOD'] == 'POST')) { return array( 'subject' => t('Search again'), 'content' => drupal_get_form('drupalorg_search_block_form', $querystring), ); } break; case 'meta_type': if (drupalorg_crosssite_apachesolr_has_searched() && ($response = apachesolr_static_response_cache()) && ($query = apachesolr_current_query())) { $entries = array(); $total = 0; $has_active = FALSE; foreach (drupalorg_crosssite_meta_types() as $name => $description) { if (!empty($response->facet_counts->facet_fields->ss_meta_type->$name)) { $count = $response->facet_counts->facet_fields->ss_meta_type->$name; $total += $count; $new_query = clone $query; $active = $query->has_filter('ss_meta_type', $name); $has_active |= $active; $new_query->remove_filter('ss_meta_type'); $new_query->add_filter('ss_meta_type', $name); $path = 'search/' . arg(1) . '/' . $new_query->get_query_basic(); $querystring = $new_query->get_url_queryvalues(); $entries[] = l(t('@facet (@count)', array('@facet' => $description, '@count' => $count)), $path, array('query' => $querystring, 'html' => TRUE, 'attributes' => $active ? array('class' => 'selected') : array())); } } if (count($entries)) { // Add the "All" entry. $new_query = clone $query; $new_query->remove_filter('ss_meta_type'); $path = 'search/' . arg(1) . '/' . $new_query->get_query_basic(); $querystring = $new_query->get_url_queryvalues(); array_unshift($entries, l(t('All (@count)', array('@count' => $total)), $path, array('query' => $querystring, 'html' => TRUE, 'attributes' => !$has_active ? array('class' => 'selected') : array()))); return array( 'subject' => t('or filter by…'), 'content' => theme('item_list', $entries), ); } } break; case 'drupalorg_search_navigation': if (drupalorg_crosssite_apachesolr_has_searched() && ($response = apachesolr_static_response_cache()) && ($query = apachesolr_current_query())) { $project_type_term = drupalorg_search_get_project_type_term($response); if (!isset($project_type_term)) { $form = drupal_get_form('drupalorg_search_sort_form'); } else { $form = drupal_get_form('project_solr_browse_projects_form', $project_type_term, 'search/' . arg(1) . '/' . $query->get_keys()); } $block['content'] = $form; return $block; } break; case 'drupalorg_search_alternate': // Pull any existing search terms to use in our links. $search_term = search_get_keys(); if (empty($search_term) && isset($_GET['text'])) { $search_term = $_GET['text']; } // Provide selections for all the site-search options. $searches = array( 'apachesolr_multisitesearch' => 'Posts', 'drupalorg' => 'IRC Nicks', 'user_search' => 'Users', ); $items = array(); foreach ($searches as $module => $title) { $items[$module] = l(t($title), 'search/' . $module . ($search_term ? '/' . $search_term : '')); } $items['issues'] = l(t('Advanced Issues'), 'search/issues', array('query' => array('text' => $search_term))); // Remove our current search (since the list should simply be other options). if (arg(0) == 'search' && arg(1)) { unset($items[arg(1)]); } $block = array( 'title' => t('or search for…'), 'content' => theme('item_list', $items), ); return $block; case 'drupalorg_search_users': return array( 'title' => t('Search Users'), 'content' => drupal_get_form('search_form', NULL, '', 'user_search', t('Username')), ); } } /** * Implementation of hook_form_search_form_alter(). */ function drupalorg_search_form_search_form_alter(&$form, $form_state) { if (drupalorg_crosssite_apachesolr_has_searched() && ($response = apachesolr_static_response_cache()) && ($query = apachesolr_current_query())) { $form['#access'] = FALSE; } } /** * Implementation of hook_form_FORM_ID_alter(). */ function drupalorg_search_form_project_solr_browse_projects_form_alter(&$form, &$form_state) { global $pager_total_items; // The type being searched for, this is always plural $type = $form['#parameters'][2]->name; $results = t('@result @type match your search', array('@result' => $pager_total_items[0], '@type' => $type)); // Check to see if the project_solr_browse_projects form is being used in // our block on the core search page. We could test $form['path']['#value'] // here instead, but it's not really any better that way, so arg() works. if (arg(0) === 'search' && (arg(1) === 'apachesolr_search' || arg(1) === 'apachesolr_multisitesearch')) { // If we're being reused on the core search results page, we add our own // submit handler so that we can properly handle the "meta type" stuff. $form['#submit'][] = 'drupalorg_search_project_solr_browse_project_form_submit'; // We default the text to our current search terms so that we don't get // errors when attempting to sort by relevancy. We make the access false, // so that the values aren't visible and we don't have 2 search forms. $query = apachesolr_current_query(); $form['text']['#default_value'] = $query->get_keys(); $form['text']['#access'] = FALSE; } else { // If not on the core search page, add a results count title to the form $form['results'] = array( '#value' => '

' . $results . '

', '#weight' => -10, ); } } /** * Submit handler for project_solr_browse_project_form on the search page. * * This deals with inserting ss_meta_type values into the path that we * redirect to, so that the whole search page still works and remembers the * value of "refine your search" that the user has selected. */ function drupalorg_search_project_solr_browse_project_form_submit(&$form, &$form_state) { $query = apachesolr_current_query(); // There might not be any filters yet. To avoid special-casing this, we just // explode() the existing space-delimited filters into an array, // conditionally append our filter into the array, and then when we're done, // we use implode() to re-create a space-delimited string and let implode() // handle the special cases of 0 or 1 filters for us. $filters = explode(' ', $form_state['redirect']['query']['filters']); foreach($query->get_filters() as $filter) { if ($filter['#name'] == 'ss_meta_type') { $filters[] = $filter['#query']; } } $form_state['redirect']['query']['filters'] = implode(' ', $filters); unset($form_state['redirect']['query']['keys']); } /** * Form callback; display a search form in a block. */ function drupalorg_search_block_form(&$form_state, $querystring) { $form['search-wrapper'] = array( '#prefix' => '
', '#suffix' => '
', ); $form['search-wrapper']['query'] = array( '#type' => 'textfield', '#default_value' => $querystring, '#size' => 10, ); $form['search-wrapper']['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), ); return $form; } /** * Submit callback; redirect the user to the search result page. */ function drupalorg_search_block_form_submit($form, &$form_state) { $query = $_GET; unset($query['q']); $form_state['redirect'] = array('search/' . arg(1) . '/' . $form_state['values']['query'], $query); } /** * Get the taxonomy term for the project type (if any) in a given Solr search. * * This function loops over all of the active facets in the given Solr query * response. If one of the facets selected a "meta_type" for the search, and * the meta_type is either "module" or "theme", it loads the corresponding * taxonomy term object and returns that. * * @param $response * The ApacheSolr response object for the currently active search. * * @return * The taxonomy $term object if the search's meta_type is "module" or * "theme", otherwise NULL. * * @see taxonomy_get_term() */ function drupalorg_search_get_project_type_term($response) { if (isset($response->responseHeader->params->fq)) { // Depending on how many facets are in the currently active filter, fq // might either be a single value or an array. If there's a single facet, // we turn it into an array so the rest of this function can always assume // it needs to iterate. $fq = $response->responseHeader->params->fq; if (!is_array($fq)) { $fq = array($fq); } foreach ($fq as $query_snippet) { if (preg_match('/^{!tag=meta_type}ss_meta_type:(.*)$/', $query_snippet, $matches)) { $meta_type = trim($matches[1]); if ($meta_type == 'theme') { $tid = DRUPALORG_THEME_TID; } elseif($meta_type == 'module') { $tid = DRUPALORG_MODULE_TID; } if (isset($tid)) { return taxonomy_get_term($tid); } } } } } /** * Generates the "How can we help you" block for use on the community page. */ function drupalorg_search_help_form(&$form_state) { $form = array(); // We're going to leverage some existing autocomplete functionality, so add // the autocomplete js + our js. drupal_add_js('misc/autocomplete.js'); drupal_add_js(drupal_get_path('module', 'drupalorg_search') . '/js/community.js'); // Text field for searching documentation items. $form['search_term'] = array( '#type' => 'textfield', '#title' => t('Search Documentation'), ); // Hidden auto-lookup field for using auto-complete-like functionality. $form['search_term_autolookup'] = array( '#type' => 'hidden', '#id' => 'edit-search-term-autolookup', '#value' => check_url(url('drupalorg-search/help/js', array('absolute' => TRUE))), '#attributes' => array( 'class' => 'autolookup', ), ); return $form; } /** * Theme the results of our documentation search against Solr. * * @param array $results * An array of results containing, at minimum, a score, a title, and a link. * * @return string $output * An html ul representation of li items containing relevancy (score) + * a link to the content. */ function theme_drupalorg_search_help_results($results) { $output = ''; if (!empty($results)) { $output = '

Here\'s what we found:

'; $output .= ''; } else { $output = '

We\'re sorry, but there were no results for your search.

'; } return $output; } /** * Menu callback. Retrieves and returns a themed list of documentation results * from Solr based on an initial search term or terms. * * @param string $search_term * A term or terms to search for in Solr. * * @return * A json object representing a themed list of results from Solr. */ function drupalorg_search_help_js($search_term = NULL) { $results = array(); if (!empty($search_term)) { $results = apachesolr_search_execute($search_term, 'ss_meta_type:documentation', ''); } $output = theme('drupalorg_search_help_results', $results); drupal_json($output); } /** * This generates a form containing sort selection and a submit button. * * Generate a form with a sort selection to allow ordering page content * based on the available sorting methods. */ function drupalorg_search_sort_form(&$form_state) { $form = array(); // Add the sort selection field to our form. $form['solrsort'] = project_solr_get_solrsort_field(); $form['submit'] = array( '#type' => 'submit', '#value' => t('Search'), ); return $form; } /** * Create a query with the right version filter and redirect to the right page. * * Create a new query, add any version filtering if it was selected in the * form, and redirect back to the relevant page with the appropriate filter * string. */ function drupalorg_search_sort_form_submit($form, &$form_state) { $query = apachesolr_current_query(); $path = $query->get_path(); // We create a new query with our base path so that we don't need to remove // any existing drupal_core selection, and so that the implict type and // module tid filters don't end up in the url string. $query = apachesolr_drupal_query('', '', '', $path); if (!empty($form_state['values']['solrsort'])) { list($sort, $direction) = explode(' ', $form_state['values']['solrsort']); $query->set_solrsort($sort, $direction); } $form_state['redirect'] = array($query->get_path(), $query->get_url_queryvalues()); }