4

I only want to have certain content types indexed, for the default Drupal 7 search. And I would like to do this without installing any other modules.

I would like to do this by hooking into the query (using hook_query_alter) that grabs all the nodes from the search_dataset. This query is found in the node_update_index function (node.module):

$result = db_query_range("SELECT n.nid FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE d.sid IS NULL OR d.reindex <> 0 ORDER BY d.reindex ASC, n.nid ASC", 0, $limit, array(), array('target' => 'slave'));

The problem is I never get the ability to alter this query in the hook, my code is as following:

function mymodule_query_alter(&$query) {
  var_dump((string)$query);
}

At some point it should print the db_query_range query. I've also tried printing my debugging to a file so I could catch those queries running ajax time.

Any ideas on what I might be doing wrong?

  • Is your function really named HOOK_query_alter()? If so, then is your module named HOOK? – kekkis Jun 11 '12 at 8:39
  • no my function is called main_query_alter main being my module name, I'll edit the answer so it's more clear. – Birk Jun 11 '12 at 8:45
6

You can only modify SQL queries that are tagged, which this one is not. Therefore you cannot use HOOK_query_alter() to do what you are trying to accomplish.

This is hacky, but the easiest way to do this might be to implement hook_module_implements_alter() and prevent the Node module's hook_update_index() implementation from firing. You can then copy the node_update_index() function to your custom module, obviously replacing "node" in the function name with the name of your custom module, and modifying only the query to exclude whatever node types you want.

/**
 * Implements hook_module_implements_alter().
 */
function mymodule_module_implements_alter(&$implementations, $hook) {
  if ('update_index' == $hook) {
    unset($implementations['node']);
  }
}

/**
 * Implements hook_update_index().
 * 
 * @see node_update_index().
 */
function mymodule_update_index() {
  $limit = (int)variable_get('search_cron_limit', 100);

  $result = db_query_range( /* Your custom query here */ );

  foreach ($result as $node) {
    _node_index_node($node);
  }
}
| improve this answer | |
  • Is this Drupal 7 or 8? When I try this with Drupal 7, the hook's value is 'node_update_index', not 'update_index'. And, $implementations key is 'search' not 'node'. Regardless, I can not unset it and node_update_index() still fires and indexes the content. – Jason Jan 2 '14 at 18:34
  • @Jason - hook_node_update_index() is an unrelated hook for this particular task. Please see my answer for the fix. – jamix Apr 8 '14 at 10:07
  • I think an equivalent, maybe cleaner, way for D8 is to implement a @SearchPlugin in your module, probably inheriting from the NodeSearch plugin class, and override the updateIndex() or indexNode() method to skip the unwanted content types, and use that search instead of the core one. It still leverages most of the core code and logic, just altering the node selection to avoid the ones you don't want. – FGM May 18 '17 at 21:04
2

Well, you can borrow what Custom Search does, which is:

function custom_search_query_alter(QueryAlterableInterface $query) {
  if ($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');
        }
      }
    }
  }
}

You would just need to edit the $excluded_types = ... line for your content types.

| improve this answer | |
  • 3
    The difference is that you are still indexing the content types you are excluding, so that adds a lot of unnecessary processing during indexing and inserts a lot of extra data in the database. The core Search module does full table scans during most searches, so reducing the amount of data here is advantageous. – Chris Pliakas Jun 13 '12 at 17:33
  • 2
    @ChrisPliakas, true. I normally accept that penalty so I don't have to index a ton of nodes if I need to adjust the content types in the future. – mpdonadio Jun 13 '12 at 23:25
  • 1
    understood. For sites with a more fluid data model, I can definitely see how the Custom Search solution might be less processing in the long run. Like everything in Drupal, it comes down to your specific use-case :-) – Chris Pliakas Jun 14 '12 at 13:51
0

Chris Pliakas's answer no longer works, presumably due to changes in core. Here's how we managed to do it in Drupal 7.22:


/**
 * Implements hook_module_implements_alter().
 */
function my_module_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'cron') {
    unset($implementations['search']);
  }
}

/**
 * Implements hook_cron().
 *
 * @see search_cron()
 */
function my_module_cron() {
  // We register a shutdown function to ensure that search_total is always up
  // to date.
  drupal_register_shutdown_function('search_update_totals');

  foreach (variable_get('search_active_modules', array('node', 'user')) as $module) {
    // Update word index
    $module == 'node' ? module_invoke('my_module', 'update_index') : module_invoke($module, 'update_index');
  }
}

/**
 * Implements hook_update_index().
 * 
 * @see node_update_index()
 */
function my_module_update_index() {
  $limit = (int)variable_get('search_cron_limit', 100);

  // Only index the artist and label content types.
  $result = db_query_range("SELECT n.nid FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE (d.sid IS NULL OR d.reindex  0) AND n.type IN (:types) ORDER BY d.reindex ASC, n.nid ASC", 0, $limit, array(':types' => array('artist', 'label')), array('target' => 'slave'));

  foreach ($result as $node) {
    _node_index_node($node);
  }
}

Basically, we plug in our own my_module_cron() implementation instead of search_cron(), where we replace the node_update_index() call with my_module_update_index(). In my_module_update_index(), we have a modified query that only selects nodes of certain types for indexing.

| improve this answer | |
  • your code looks good, however the admin/config/search/settings page still shows the total number of nodes to index including all types of nodes: 0% of the site has been indexed. There are 27 items left to index. when in fact I've limited the query to the content type, which has only 5 nodes. – Nick Mar 23 '18 at 0:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.