You are here

custom_search.module in Custom Search 7

Same filename and directory in other branches
  1. 8 custom_search.module
  2. 6 custom_search.module

Bring customizations to the default search box

Adds node types and taxonomy options to the search form

File

custom_search.module
View source
<?php

/**
 * @file
 * Bring customizations to the default search box
 *
 * Adds node types and taxonomy options to the search form
 */
define('CUSTOM_SEARCH_LABEL_DEFAULT', t('Search this site'));
define('CUSTOM_SEARCH_HINT_TEXT_DEFAULT', t('Enter the terms you wish to search for.'));
define('CUSTOM_SEARCH_SUBMIT_TEXT_DEFAULT', t('Search'));
define('CUSTOM_SEARCH_TYPE_SELECTOR_LABEL_DEFAULT', t('Search for'));
define('CUSTOM_SEARCH_MAX_LENGTH_DEFAULT', 128);
define('CUSTOM_SEARCH_SIZE_DEFAULT', 15);
define('CUSTOM_SEARCH_ALL_TEXT_DEFAULT', t('-Any-'));
define('CUSTOM_SEARCH_CRITERIA_OR_LABEL_DEFAULT', t('Containing any of the words'));
define('CUSTOM_SEARCH_CRITERIA_PHRASE_LABEL_DEFAULT', t('Containing the phrase'));
define('CUSTOM_SEARCH_CRITERIA_NEGATIVE_LABEL_DEFAULT', t('Containing none of the words'));
define('CUSTOM_SEARCH_FILTER_LABEL_DEFAULT', t('Filter the results'));
define('CUSTOM_SEARCH_PATHS_SELECTOR_LABEL_DEFAULT', t('Customize your search'));
define('CUSTOM_SEARCH_PATHS_TERMS_SEPARATOR_DEFAULT', '+');

/**
 * Includes
 */
module_load_include('inc', 'custom_search', 'includes/forms');
module_load_include('inc', 'custom_search', 'includes/apachesolr_search');
module_load_include('inc', 'custom_search', 'includes/google_appliance');
module_load_include('inc', 'custom_search', 'includes/luceneapi_node');
module_load_include('inc', 'custom_search', 'includes/search_api');

/**
 * Implements hook_menu().
 */
function custom_search_menu() {
  $items['admin/config/search/custom_search'] = array(
    'title' => 'Custom Search',
    'description' => 'Customize the default search, change labels, default texts, ordering, and display content types and taxonomy selectors.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'custom_search_admin',
    ),
    'access arguments' => array(
      'administer custom search',
    ),
    'file' => 'custom_search.admin.inc',
  );
  $items['admin/config/search/custom_search/settings'] = array(
    'title' => 'Settings',
    'description' => 'Change the labels, the default texts and the ordering of elements.',
    'access arguments' => array(
      'administer custom search',
    ),
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 0,
  );
  $items['admin/config/search/custom_search/content'] = array(
    'title' => 'Content',
    'description' => 'Select the content types to present as search options in the search block.',
    'page arguments' => array(
      'custom_search_content_admin',
    ),
    'access arguments' => array(
      'administer custom search',
    ),
    'file' => 'custom_search.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
  );
  $items['admin/config/search/custom_search/results'] = array(
    'title' => 'Results page',
    'description' => 'Customize the search results page.',
    'page arguments' => array(
      'custom_search_results_admin',
    ),
    'access arguments' => array(
      'administer custom search',
    ),
    'file' => 'custom_search.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 4,
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function custom_search_permission() {
  return array(
    'administer custom search' => array(
      'title' => t('Administer custom search'),
      'description' => t('Allow users to administer custom search settings'),
    ),
    'use custom search' => array(
      'title' => t('Use custom search'),
      'description' => t('Allow users to use custom search'),
    ),
  );
}

/**
 * Implements hook_form_alter().
 */
function custom_search_form_alter(&$form, &$form_state, $form_id) {

  // Filter the form_id value to identify all the custom blocks.
  $form_id_processed = $form_id;
  $delta = '';
  for ($a = 1; $a <= variable_get('custom_search_blocks_number', 1); $a++) {
    if ($form_id == 'custom_search_blocks_form_' . $a) {
      $form_id_processed = 'custom_search_blocks_form';
      $delta = 'blocks_' . $a . '_';
    }
  }
  switch ($form_id_processed) {
    case 'search_form':
      if (isset($form['module']) && $form['module']['#value'] == 'node') {
        if (isset($form['advanced']) && variable_get('custom_search_results_advanced_search', TRUE)) {

          // Reprocess the key value for later uses.
          $search_args = array(
            'keys' => array(),
            'criteria' => array(
              'phrase' => '',
              'negative' => array(),
            ),
            'types' => array(),
            'languages' => array(),
          );
          $phrase_pos = strpos($form['basic']['keys']['#default_value'], '"');
          if ($phrase_pos !== FALSE) {
            $phrase_pos_end = strpos($form['basic']['keys']['#default_value'], '"', $phrase_pos + 1);
            $search_args['criteria']['phrase'] = substr($form['basic']['keys']['#default_value'], $phrase_pos + 1, $phrase_pos_end - $phrase_pos - 1);
            $form['basic']['keys']['#default_value'] = str_replace('"' . $search_args['criteria']['phrase'] . '"', '', $form['basic']['keys']['#default_value']);
          }
          $search_key_array = explode(' ', $form['basic']['keys']['#default_value']);
          foreach ($search_key_array as $key) {
            $arg = explode(':', $key);
            if (count($arg) == 2) {
              switch ($arg[0]) {
                case 'type':
                  $search_args['types'] = explode(',', $arg[1]);
                  break;
                case 'language':
                  $search_args['languages'] = explode(',', $arg[1]);
                  break;
                default:
                  $search_args['keys'][] = $arg[1];
              }
            }
            else {
              if ($arg[0] != '') {
                if ($arg[0][0] == '-') {
                  $search_args['criteria']['negative'][] = substr($arg[0], 1);
                }
                else {
                  $search_args['keys'][] = $arg[0];
                }
              }
            }
          }

          // Criteria.
          if (!variable_get('custom_search_advanced_or_display', TRUE)) {
            $form['advanced']['keywords']['or']['#type'] = 'hidden';
          }
          if (!variable_get('custom_search_advanced_phrase_display', TRUE)) {
            $form['advanced']['keywords']['phrase']['#type'] = 'hidden';
          }
          if (!variable_get('custom_search_advanced_negative_display', TRUE)) {
            $form['advanced']['keywords']['negative']['#type'] = 'hidden';
          }
          $form['advanced']['keywords']['phrase']['#default_value'] = $search_args['criteria']['phrase'];
          $form['advanced']['keywords']['negative']['#default_value'] = implode(' ', $search_args['criteria']['negative']);

          // Content types.
          $names = array_keys(node_type_get_names());
          foreach ($names as $name) {
            if (!variable_get('custom_search_advanced_type_' . $name . '_display', TRUE)) {
              unset($form['advanced']['type']['#options'][$name]);
            }
          }
          if (!count($form['advanced']['type']['#options'])) {
            unset($form['advanced']['type']['#type']);
          }
          else {
            $form['advanced']['type']['#default_value'] = $search_args['types'];
          }

          // Languages.
          foreach (language_list('language') as $key => $entity) {
            if ($entity->enabled) {
              $language_options[$key] = $entity->name;
            }
          }

          // Add Language neutral to the list.
          $form['advanced']['language']['#options']['und'] = t('Language neutral');
          $language_options['und'] = t('Language neutral');
          foreach ($language_options as $key => $name) {
            if (!variable_get('custom_search_advanced_language_' . $key . '_display', TRUE)) {
              unset($form['advanced']['language']['#options'][$key]);
            }
          }
          if (!count($form['advanced']['language']['#options'])) {
            unset($form['advanced']['language']['#type']);
          }
          else {
            $form['advanced']['language']['#default_value'] = $search_args['languages'];
          }

          // Remove unnecessary args from keys.
          $form['basic']['keys']['#default_value'] = implode(' ', $search_args['keys']);
        }
        if (!variable_get('custom_search_results_search', TRUE)) {
          if (isset($form['basic']['keys'])) {

            // If basic search is hidden, import terms into advanced search.
            $original_keys = $form['basic']['keys']['#default_value'];
            $temp_keys = explode(' ', $original_keys);
            foreach ($temp_keys as $value) {
              if (drupal_substr($value, 0, 5) != 'type:' && drupal_substr($value, 0, 5) != 'term:') {
                $keys[] = $value;
              }
            }
            $form['advanced']['keywords']['or']['#default_value'] = implode(' ', $search_args['keys']);
          }
          if (!isset($GLOBALS['custom_search_nb_results']) || isset($GLOBALS['custom_search_nb_results']) && !$GLOBALS['custom_search_nb_results']) {
            $form['advanced']['#collapsed'] = FALSE;
          }
          $form['basic']['#prefix'] = '<div class="element-invisible">';
          $form['basic']['#suffix'] = '</div>';
        }
        $form['advanced']['#collapsible'] = variable_get('custom_search_results_advanced_search_collapsible', TRUE);
        $form['advanced']['#collapsed'] = variable_get('custom_search_results_advanced_search_collapsed', TRUE);
        if (!variable_get('custom_search_results_advanced_search', TRUE)) {
          $form['advanced']['#type'] = 'hidden';
        }
      }
      break;
    case 'search_theme_form':
    case 'search_block_form':
    case 'custom_search_blocks_form':
      if (user_access('use custom search')) {

        // Title.
        $form[$form_id]['#title'] = variable_get('custom_search_' . $delta . 'label', CUSTOM_SEARCH_LABEL_DEFAULT);
        $form[$form_id]['#title_display'] = !variable_get('custom_search_' . $delta . 'label_visibility', FALSE) ? 'invisible' : 'before';

        // Search box.
        if (module_exists('elements') && variable_get('custom_search_' . $delta . 'element', 'textfield') != 'textfield') {
          $form[$form_id]['#type'] = variable_get('custom_search_' . $delta . 'element', 'textfield');
        }
        $form[$form_id]['#weight'] = variable_get('custom_search_' . $delta . 'search_box_weight', 0);
        $form[$form_id]['#size'] = variable_get('custom_search_' . $delta . 'size', CUSTOM_SEARCH_SIZE_DEFAULT);
        $form[$form_id]['#maxlength'] = variable_get('custom_search_' . $delta . 'max_length', CUSTOM_SEARCH_MAX_LENGTH_DEFAULT);
        if (!isset($form[$form_id]['#attributes'])) {
          $form[$form_id]['#attributes'] = array(
            'class' => array(),
          );
        }
        elseif (!isset($form[$form_id]['#attributes']['class'])) {
          $form[$form_id]['#attributes']['class'] = array();
        }
        $form[$form_id]['#attributes']['class'][] = 'custom-search-box';
        $form[$form_id]['#attributes']['placeholder'] = variable_get('custom_search_' . $delta . 'text', '');
        $form[$form_id]['#attributes']['title'] = variable_get('custom_search_' . $delta . 'hint_text', CUSTOM_SEARCH_HINT_TEXT_DEFAULT);

        // CSS.
        drupal_add_css(drupal_get_path('module', 'custom_search') . '/custom_search.css');

        // Criteria.
        $criteria = array(
          'or' => 6,
          'phrase' => 7,
          'negative' => 8,
        );
        foreach ($criteria as $c => $w) {
          if (variable_get('custom_search_' . $delta . 'criteria_' . $c . '_display', FALSE)) {
            $form['custom_search_criteria_' . $c] = array(
              '#type' => 'textfield',
              '#title' => variable_get('custom_search_' . $delta . 'criteria_' . $c . '_label', constant('CUSTOM_SEARCH_CRITERIA_' . strtoupper($c) . '_LABEL_DEFAULT')),
              '#size' => 15,
              '#maxlength' => 255,
              '#weight' => variable_get('custom_search_' . $delta . 'criteria_' . $c . '_weight', $w),
            );
          }
        }

        // Content type & other searches.
        // Content types.
        $toptions = array();
        $types = array_keys(array_filter(variable_get('custom_search_' . $delta . 'node_types', array())));
        if (count($types)) {
          $names = node_type_get_names();
          if (count($types) > 1 || variable_get('custom_search_' . $delta . 'any_force', FALSE)) {
            $toptions['c-all'] = variable_get('custom_search_' . $delta . 'type_selector_all', CUSTOM_SEARCH_ALL_TEXT_DEFAULT);
          }
          foreach ($types as $type) {
            $toptions['c-' . $type] = t($names[$type]);
          }
        }
        $options = array();

        // Other searches.
        $others = array_keys(array_filter(variable_get('custom_search_' . $delta . 'other', array())));

        // If content types and other searches are combined, make an optgroup.
        if (count($others) && count($toptions) && variable_get('custom_search_' . $delta . 'type_selector', 'select') == 'select') {
          $content = module_invoke('node', 'search_info');
          $options[$content['title']] = $toptions;
        }
        else {
          $options = $toptions;
        }
        foreach (module_implements('search_info') as $module) {
          if ($module != 'node' && ($name = module_invoke($module, 'search_info'))) {
            if (in_array($module, $others)) {
              $options['o-' . $module] = t($name['title']);
            }
          }
        }
        if (count($options)) {
          $selector_type = variable_get('custom_search_' . $delta . 'type_selector', 'select');
          if ($selector_type == 'selectmultiple') {
            $selector_type = 'select';
            $multiple = TRUE;
          }
          else {
            $multiple = FALSE;
          }
          $form['custom_search_types'] = array(
            '#type' => $selector_type,
            '#multiple' => $multiple,
            '#title' => variable_get('custom_search_' . $delta . 'type_selector_label', CUSTOM_SEARCH_TYPE_SELECTOR_LABEL_DEFAULT),
            '#options' => $options,
            '#default_value' => variable_get('custom_search_' . $delta . 'type_selector', 'select') == 'checkboxes' ? array(
              'c-all',
            ) : 'c-all',
            '#attributes' => array(
              'class' => array(
                'custom-search-selector',
                'custom-search-types',
              ),
            ),
            '#weight' => variable_get('custom_search_' . $delta . 'content_types_weight', 1),
            '#validated' => TRUE,
          );

          // If there's only one type, hide the selector.
          if (count($others) + count($types) == 1 && !variable_get('custom_search_' . $delta . 'any_force', FALSE)) {
            $form['custom_search_types']['#type'] = 'hidden';
            $form['custom_search_types']['#default_value'] = key(array_slice($options, count($options) - 1));
          }
          if (!variable_get('custom_search_' . $delta . 'type_selector_label_visibility', TRUE)) {
            $form['custom_search_types']['#title_display'] = 'invisible';
          }
        }

        // Custom paths.
        if (variable_get('custom_search_' . $delta . 'paths', '') != '') {
          $options = array();
          $lines = explode("\n", variable_get('custom_search_' . $delta . 'paths', ''));
          foreach ($lines as $line) {
            $temp = explode('|', $line);
            $options[$temp[0]] = count($temp) >= 2 ? t($temp[1]) : '';
          }
          if (count($options) == 1) {
            $form['custom_search_paths'] = array(
              '#type' => 'hidden',
              '#default_value' => key($options),
            );
          }
          else {
            $form['custom_search_paths'] = array(
              '#type' => variable_get('custom_search_' . $delta . 'paths_selector', 'select'),
              '#title' => variable_get('custom_search_' . $delta . 'paths_selector_label', CUSTOM_SEARCH_PATHS_SELECTOR_LABEL_DEFAULT),
              '#options' => $options,
              '#default_value' => key($options),
              '#weight' => variable_get('custom_search_' . $delta . 'custom_paths_weight', 9),
            );
            if (!variable_get('custom_search_' . $delta . 'paths_selector_label_visibility', TRUE)) {
              $form['custom_search_paths']['#title_display'] = 'invisible';
            }
          }
        }

        // Submit button.
        $form['actions']['submit']['#value'] = variable_get('custom_search_' . $delta . 'submit_text', CUSTOM_SEARCH_SUBMIT_TEXT_DEFAULT);
        if (variable_get('custom_search_' . $delta . 'image_path', '') != '') {
          $form['actions']['submit']['#type'] = 'image_button';
          $form['actions']['submit']['#src'] = variable_get('custom_search_' . $delta . 'image_path', '');
          $form['actions']['submit']['#name'] = 'op';
          $form['actions']['submit']['#attributes'] = array(
            'alt' => array(
              variable_get('custom_search_' . $delta . 'submit_text', CUSTOM_SEARCH_SUBMIT_TEXT_DEFAULT),
            ),
            'class' => array(
              'custom-search-button',
            ),
          );
          unset($form['actions']['submit']['#value']);
        }
        elseif ($form['actions']['submit']['#value'] == '') {
          $form['actions']['submit']['#attributes'] = array(
            'style' => 'display:none;',
          );
        }
        $form['actions']['#weight'] = variable_get('custom_search_' . $delta . 'submit_button_weight', 3);

        // Popup.
        $form['popup'] = array(
          '#type' => 'fieldset',
          '#weight' => 1 + variable_get('custom_search_' . $delta . 'search_box_weight', 0),
          '#attributes' => array(
            'class' => array(
              'custom_search-popup',
            ),
          ),
        );
        if (!empty($form['custom_search_types']) && variable_get('custom_search_' . $delta . 'content_types_region', 'block') == 'popup') {
          $form['popup']['custom_search_types'] = $form['custom_search_types'];
          unset($form['custom_search_types']);
        }
        if (!empty($form['custom_search_paths']) && variable_get('custom_search_' . $delta . 'custom_paths_region', 'block') == 'popup') {
          $form['popup']['custom_search_paths'] = $form['custom_search_paths'];
          unset($form['custom_search_paths']);
        }
        foreach ($criteria as $c => $w) {
          if (variable_get('custom_search_' . $delta . 'criteria_' . $c . '_display', FALSE) && variable_get('custom_search_' . $delta . 'criteria_' . $c . '_region', 'block') == 'popup') {
            $form['popup']['custom_search_criteria_' . $c] = $form['custom_search_criteria_' . $c];
            unset($form['custom_search_criteria_' . $c]);
          }
        }

        // Invoke other modules hooks.
        foreach (module_implements('custom_search_box') as $module) {
          $function = $module . '_custom_search_box';
          if (function_exists($function)) {
            call_user_func_array($function, array(
              &$form,
              $form_id,
              $delta,
            ));
          }
        }

        // If nothing has been added to the popup, don't output any markup.
        if (!count(element_children($form['popup']))) {
          unset($form['popup']);
        }

        // Form attributes.
        $form['#attributes']['class'] = array(
          'search-form',
        );
        $form['#attributes']['role'] = 'search';
        if (!in_array('custom_search_submit', $form['#submit'])) {
          $form['#submit'][] = 'custom_search_submit';
        }
      }
      break;
  }
}

/**
 * Alter the search to respect the search modes selected.
 */
function custom_search_submit($form, &$form_state) {

  // Save delta for later use (exclusion & refresh).
  $delta = isset($form_state['values']['delta']) ? 'blocks_' . $form_state['values']['delta'] . '_' : '';
  variable_set('custom_search_delta', $delta);
  $type = 'node';
  $keys = trim($form_state['values'][$form_state['values']['form_id']]);
  if (variable_get('custom_search_' . $delta . 'operator', 'AND') == 'OR') {
    $exploded_keys = explode('"', ' ' . $keys);

    // Make sure quotes are never the first char
    $keys_array = array();
    for ($a = 0; $a < count($exploded_keys); $a = $a + 2) {
      if ($a != 0 && strlen($exploded_keys[$a]) || $a == 0 && $exploded_keys[$a] != ' ') {
        if ($a == 0) {
          $exploded_keys[$a] = substr($exploded_keys[$a], 1);
        }
        $keys_array[] = str_replace(' ', ' OR ', $exploded_keys[$a]);
      }
      if (isset($exploded_keys[$a + 1])) {
        $keys_array[] = '"' . $exploded_keys[$a + 1] . '"';
      }
    }
    $keys = implode(' ', $keys_array);
  }
  $original_keywords = $keys;
  $types = isset($form_state['values']['custom_search_types']) ? $form_state['values']['custom_search_types'] : array();
  if (!is_array($types)) {
    $types = array(
      $types,
    );
  }
  $types = array_map('_custom_search_filter_keys', array_filter($types));
  if (module_exists('taxonomy')) {
    $terms = array();
    $vocabularies = taxonomy_get_vocabularies();
    foreach ($vocabularies as $voc) {
      if (isset($form_state['values']['custom_search_vocabulary_' . $voc->vid])) {
        $vterms = $form_state['values']['custom_search_vocabulary_' . $voc->vid];
        if (!is_array($vterms)) {
          $vterms = array(
            $vterms,
          );
        }
        $terms = array_merge($terms, $vterms);
      }
    }
    $terms = array_map('_custom_search_filter_keys', array_values(array_filter($terms)));

    // If one or more -Any- is selected, delete them.
    while (($index = array_search('all', $terms)) !== FALSE) {
      array_splice($terms, $index, 1);
    }
  }

  // Invoke other modules hooks.
  $other = array();
  foreach (module_implements('custom_search_filter') as $module) {
    $function = $module . '_custom_search_filter';
    if (function_exists($function)) {
      $other = call_user_func_array($function, array(
        &$form,
        &$form_state,
        $other,
      ));
    }
  }
  $search_types = module_implements('search_info');
  if (in_array(current($types), $search_types)) {
    $type = current($types);
    $info = module_invoke($type, 'search_info');
    $path = isset($info['path']) ? $info['path'] : $type;
  }
  else {
    $path = $type;
    if (isset($form_state['values']['custom_search_criteria_or']) && trim($form_state['values']['custom_search_criteria_or']) != '') {
      $keys .= ' ' . str_replace(' ', ' OR ', trim($form_state['values']['custom_search_criteria_or']));
    }
    if (isset($form_state['values']['custom_search_criteria_negative']) && trim($form_state['values']['custom_search_criteria_negative']) != '') {
      $keys .= ' -' . str_replace(' ', ' -', trim($form_state['values']['custom_search_criteria_negative']));
    }
    if (isset($form_state['values']['custom_search_criteria_phrase']) && trim($form_state['values']['custom_search_criteria_phrase']) != '') {
      $keys .= ' "' . trim($form_state['values']['custom_search_criteria_phrase']) . '"';
    }
    $original_keywords = $keys;
    if (count($types)) {

      // If a content type is selected, and it's not -Any-,
      // search for that type.
      if (!in_array('all', $types)) {
        $keys = search_expression_insert($keys, 'type', implode(',', $types));
      }
      elseif (variable_get('custom_search_' . $delta . 'any_restricts', FALSE)) {
        $types = array_keys(array_filter(variable_get('custom_search_' . $delta . 'node_types', array())));
        $keys = search_expression_insert($keys, 'type', implode(',', $types));
      }
    }
    if (module_exists('taxonomy') && count($terms)) {
      $keys = search_expression_insert($keys, 'term', implode(',', $terms));
    }
    if (module_exists('custom_search_i18n')) {
      $i18n_search_language = variable_get('custom_search_i18n_search_language', 'all');
      if ($i18n_search_language == 'current') {
        $keys = search_expression_insert($keys, 'language', i18n_language()->language);
      }
      elseif ($i18n_search_language == 'current_neutral') {
        $keys = search_expression_insert($keys, 'language', i18n_language()->language . ',und');
      }
    }
  }
  $search_path = array(
    'path' => 'search/' . $path . '/' . $keys,
    'query' => array(),
  );

  // Integrates other search modules.
  if (module_exists('apachesolr_search')) {
    $fields = field_info_fields();
    $node_types = array_keys(node_type_get_types());
    foreach ($types as $key => $bundle) {

      // Remove the item from the array if it's not a content type.
      if (!in_array($bundle, $node_types)) {
        unset($types[$key]);
      }
    }
    $search_path = _custom_search_apachesolr_search(array(
      'keywords' => $original_keywords,
      'types' => $types,
      'terms' => !empty($terms) ? $terms : array(),
      'other' => !empty($other) ? $other : array(),
    ), $keys, $fields);
  }
  elseif (module_exists('google_appliance')) {
    $search_path = _custom_search_google_appliance_search(array(
      'keys' => $keys,
    ));
  }
  elseif (module_exists('luceneapi_node') && variable_get('luceneapi:default_search', 0)) {
    $search_path = _custom_search_lucenapi_search(array(
      'keywords' => $original_keywords,
      'types' => $types,
      'terms' => !empty($terms) ? $terms : array(),
    ));
  }
  elseif (module_exists('search_api_page')) {
    $search_api_page = search_api_page_load(variable_get('custom_search_' . $delta . 'search_api_page', 0));
    if ($search_api_page) {
      $search_path = _custom_search_search_api_search(array(
        'keywords' => $original_keywords,
        'types' => $types,
        'terms' => !empty($terms) ? $terms : array(),
        'page' => $search_api_page,
      ));
    }
  }

  // Build a custom path if needed.
  if (isset($form_state['values']['custom_search_paths']) && $form_state['values']['custom_search_paths'] != '') {
    $key = $form_state['values'][$form_state['values']['form_id']];
    $custom_path = str_replace('[key]', $key, $form_state['values']['custom_search_paths']);
    $custom_path = str_replace('[current_path]', current_path(), $custom_path);
    if (strpos($form_state['values']['custom_search_paths'], '[terms]') !== FALSE) {
      $custom_path = str_replace('[terms]', count($terms) ? implode($form_state['values']['custom_search_paths_terms_separator'], $terms) : '', $custom_path);
    }

    // Check for a query string.
    $custom_path_query_position = strpos($custom_path, '?');
    $custom_path_query = array();
    if ($custom_path_query_position !== FALSE) {
      $custom_path_query_tmp = substr($custom_path, 1 + $custom_path_query_position);
      $custom_path_query_tmp = str_replace('&amp;', '&', $custom_path_query_tmp);
      $custom_path_query_tmp = explode('&', $custom_path_query_tmp);
      foreach ($custom_path_query_tmp as $param) {
        $param_exploded = explode('=', $param);
        $custom_path_query[$param_exploded[0]] = $param_exploded[1];
      }
      $custom_path = substr($custom_path, 0, $custom_path_query_position);
    }

    // Check for external path. If not, add base path.
    if (drupal_substr($custom_path, 0, 4) != 'http') {
      $custom_path = url($custom_path, array(
        'absolute' => TRUE,
      ));
    }

    // Send the final url.
    $form_state['redirect'] = url($custom_path, array(
      'query' => $custom_path_query,
      'absolute' => TRUE,
    ));
  }
  else {
    $form_state['redirect'] = url($search_path['path'], array(
      'query' => $search_path['query'],
      'absolute' => TRUE,
    ));
  }
}

/*
 * Rewrite the sql query to exclude content types.
 */
function custom_search_query_alter(QueryAlterableInterface $query) {
  if (!$query
    ->hasTag('custom_search_ignore') && $query
    ->hasTag('node_access') && $query
    ->hasTag('pager')) {
    $excluded_types = array_filter(variable_get('custom_search_' . variable_get('custom_search_delta', '') . 'node_types_excluded', array()));
    if (!empty($excluded_types)) {
      $tables = $query
        ->getTables();
      foreach ($tables as $table) {
        if ($table['table'] == 'search_index') {
          $query
            ->condition('n.type', $excluded_types, 'NOT IN');
        }
      }
    }
  }
}

/**
 * Implements hook_block_view_alter().
 * Used to exclude Facet API searching for excluded types.
 */
function custom_search_block_view_alter(&$data, $block) {
  if ($block->module == 'facetapi') {
    $excluded_types = array_filter(variable_get('custom_search_' . variable_get('custom_search_delta', '') . 'node_types_excluded', array()));
    if (!empty($excluded_types) && isset($data['content']['bundle']) && is_array($data['content']['bundle']["#items"])) {
      foreach ($data['content']['bundle']["#items"] as $key => $item) {

        // Find the type in the link.
        preg_match('/<a(.*)href="(.*)bundle%3A(.*?)(&|")(.*)/', $item['data'], $matches);

        // Exclude it if not needed.
        if (!empty($matches) && in_array($matches[3], $excluded_types)) {
          unset($data['content']['bundle']["#items"][$key]);
        }
      }
    }
  }
}

/**
 * Implements hook_init().
 */
function custom_search_init() {
  if (user_access('use custom search')) {
    drupal_add_js(drupal_get_path('module', 'custom_search') . '/js/custom_search.js');
    drupal_add_js(array(
      'custom_search' => array(
        'form_target' => variable_get('custom_search_target', '_self'),
        'solr' => module_exists('apachesolr_search') || module_exists('search_api_solr') ? 1 : 0,
      ),
    ), array(
      'type' => 'setting',
    ));
  }
}

/**
 * Implements hook_theme().
 */
function custom_search_theme() {
  $path = drupal_get_path('module', 'custom_search') . '/theme';
  $custom_search_theme_array = array(
    'custom_search_javascript' => array(
      'variables' => array(),
    ),
    'custom_search_sort_form' => array(
      'render element' => 'form',
      'path' => $path,
      'template' => 'custom_search-sort-form',
    ),
    'search_result' => array(
      'variables' => array(
        'result' => NULL,
        'module' => NULL,
      ),
      'path' => $path,
      'file' => 'custom_search.pages.inc',
      'template' => 'custom_search-result',
    ),
    'search_results' => array(
      'variables' => array(
        'results' => NULL,
        'module' => NULL,
      ),
      'path' => $path,
      'file' => 'custom_search.pages.inc',
      'template' => 'custom_search-results',
    ),
  );

  // Panels integration.
  $router_item = db_query_range('SELECT page_callback FROM {menu_router} WHERE path = :path', 0, 1, array(
    ':path' => 'search/node/%',
  ))
    ->fetchAssoc();
  if ($router_item['page_callback'] == 'page_manager_search_page') {
    unset($custom_search_theme_array['search_results'], $custom_search_theme_array['search_result']);
  }
  return $custom_search_theme_array;
}

/**
 * Implements hook_link().
 */
function custom_search_contextual_links_view_alter(&$element, $items) {
  if (isset($element['#element']['#form_id']) && $element['#element']['#form_id'] == 'search_block_form' && user_access('administer custom search')) {
    $element['#links']['custom_search'] = array(
      'title' => t('Custom Search configuration'),
      'href' => 'admin/config/search/custom_search',
      'query' => drupal_get_destination(),
    );
  }
}

/**
 * Filter the types.
 */
function _custom_search_filter_keys($val) {
  return strlen($val) > 2 && $val[1] == '-' ? drupal_substr($val, 2) : $val;
}

/**
 * Function used to filter node_type array to only filter
 * those that are configured in Custom Search Form.
 */
function custom_search_filter_array($value = FALSE) {
  return $value !== 0;
}