4

Is there any way to find node content (e.g., articles, pages, etc.) by username using Drupal's (version 7.x) core site search (i.e., the search end users can use)?

The installation that I'm working on currently indexes usernames only if they occur within the body of the node content; however, the users' respective articles will not show up.

I've attempted to write a small module to update the index to use the username (modifying this example for 7.x). I had no luck with this.

I've also attempted to write a small module that hooks into the search; however, it seems to be only accessible to the core node and user modules, which implement the hooks already.

For the time being, I have edited the core search module (in search.pages.inc) to call my small module. Then I grab the search keywords and see if they resembles an author name. If so, I grab some recent articles.

It works for now, but it's obviously not a good idea to edit the core.

Anyway, thanks for any help!

4

Here's my Core Drupal search based solution for the same. The code below would be responsible for indexing the node author in a custom module badly named My custom module ('my_module.module'). Most of the code is heavily inspired by the core search module's search.api.php.

Once the module is in place ensure that its name (again My custom module) is checked in Active search modules.

/**
 * Implements hook_search_info().
 * This ensures that the Search Content by author tab is present in your Search result
 * and available in the path site/byauthor/<searchterm>
 */
function my_module_search_info() {
  return array(
    'title' => 'Search Content by author',
    'path' => 'byauthor',
    'conditions callback' => 'callback_search_conditions',
  );
}

Following this click and confirm re-index content and run cron for the actual indexing The hook_update_index is written such that for each node the author name is retrieved and stored in the search index as a type 'nodebyauthor'.

/**
 * Implements hook_update_index().
 *
 * To actually index the nodes based on the uid
 * "Inspired" by search.api.php from drupal core search
 */
function my_module_update_index() {
  watchdog('my_module', 'entered my module update index');
  $limit = (int)variable_get('search_cron_limit', 100);
  $result = db_query_range("SELECT n.nid FROM {node} n 
            LEFT JOIN {search_dataset} d ON d.type = 'nodebyauthor' 
            AND d.sid = n.nid WHERE d.sid IS NULL OR d.reindex <> 0 
            ORDER BY d.reindex ASC, n.nid ASC", 0, $limit);
  foreach ($result as $node) {
    // simple query seemed a better option than loading the node and author object
    $author = db_query("SELECT `uid` FROM {node} WHERE `nid` = :nid", 
              array(':nid' => $node->nid))->fetchField();
    watchdog("my_moduleupdateidx", "Node is {$node->nid} and uid is {$author}");
    if ($author !== FALSE) {
      $author_name = db_query("SELECT `name` FROM {users} 
                     WHERE `uid` = :uid", 
                     array(':uid' => $author))->fetchField();
      search_index($node->nid, 'nodebyauthor', $author_name);
    }
  }
}

A helper hook hook_search_reset to mark content for reindexing when re-index option is triggered

/**
 * Implements hook_search_reset().
 *
 * Reset the indexed item timestamp for being reindexed on subsequent cron runs.
 */
function my_module_search_reset() {
  db_update('search_dataset')
    ->fields(array('reindex' => REQUEST_TIME))
    ->condition('type', 'nodebyauthor')
    ->execute();
}

The hook_search_execute is where the actual newly indexed content (after enabling our custom module and running cron) will provide results based on the user when a search is triggered:

/**
 * Implements hook_search_execute().
 *
 * To provide matching node results based on the node author when searched, again blatantly copied from search.api.php
 */
function my_module_search_execute($keys = NULL, $conditions = NULL) {
  $query = db_select('search_index', 'i', 
           array('target' => 'slave'))
           ->extend('SearchQuery')
           ->extend('PagerDefault');
  $query->join('node', 'n', 'n.nid = i.sid');
  $query
    ->condition('n.status', 1)
    ->addTag('node_access')
    ->searchExpression($keys, 'nodebyauthor');

  // Insert special keywords.
  $query->setOption('type', 'n.type');
  $query->setOption('language', 'n.language');
  if ($query->setOption('term', 'ti.tid')) {
    $query->join('taxonomy_index', 'ti', 'n.nid = ti.nid');
  }
  // Only continue if the first pass query matches.
  if (!$query->executeFirstPass()) {
    return array();
  }

  // Add the ranking expressions.
  _node_rankings($query);
  /*drupal_set_message((string) $query);
  drupal_set_message(var_dump($query->arguments()));
  drupal_set_message((string)$query->countQuery());*/
  // Load results.
  $find = $query
    ->limit(10)
    ->execute();
  $results = array();


  foreach ($find as $item) {
    // Build the node body.
    $node = node_load($item->sid);
    node_build_content($node, 'search_result');
    $node->body = drupal_render($node->content);

    // Fetch comments for snippet.
    $node->rendered .= ' ' . module_invoke('comment', 'node_update_index', $node);
    // Fetch terms for snippet.
    $node->rendered .= ' ' . module_invoke('taxonomy', 'node_update_index', $node);

    $extra = module_invoke_all('node_search_result', $node);

    $results[] = array(
      'link' => url('node/' . $item->sid, array('absolute' => TRUE)),
      'type' => check_plain(node_type_get_name($node)),
      'title' => $node->title,
      'user' => theme('username', array('account' => $node)),
      'date' => $node->changed,
      'node' => $node,
      'extra' => $extra,
      'score' => $item->calculated_score,
      'snippet' => search_excerpt($keys, $node->body),
    );
  }
  return $results;
}

Image: Search result with our custom module derived tab result

Despite being huge even with some additional search hooks missing I believe anything is better an option than hacking core. Hope this helps.

  • Thanks for the detailed response. Forgive me if I misunderstood, but is the only way to accomplish this through a separate search field (different tabs in your example)? I inherited this project and I believe the designers are set on having only one search field (the one from the core). – doubleswirve Oct 23 '13 at 0:37
  • That as per my understanding of the core search seems to be the case, though I may be completely wrong. I haven't had any real experience in working with core search prior to coding the module for this question, so I fear I might not be able to answer that. However someone else with more knowledge on the subject matter would probably provider greater clarity and insight. – optimusprime619 Oct 23 '13 at 3:54
  • Thanks for all the help. I think (unfortunately?) I'm going to stick with hacking the core for now. The project has to go live early next week, so I don't think there's time to make a design adjustment. I'm going to select your answer because I appreciate the detail and will be able to use it in the future as a reference. Thanks again! – doubleswirve Oct 24 '13 at 1:58
2

I always just created a views search (using the Views module) with an exposed filter for the user search field. It was also nice because I could output the exact fields that I wanted to show without having to edit any TPL files.

  • But of course! KISS – Dan Mantyla Jun 3 '15 at 19:58
  • can you tell me how to create search using views? I am looking to allow users to search for users as well as nodes from one search box – Umair Aug 14 '16 at 10:53

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.