Easily reorder search results

The general search page (?search_type=all) returns results grouped by type/subtype, and the code that generates these is not designed to be extensible at all. Thankfully the ability to rewrite view output via hooks makes this a breeze.

Each section of the search results is output by the search/list view. So let's just capture all these view strings into an array, reorder the array, and put it back into the page. We can do this by dropping a unique token during the first call of the search/list view, then filter the page/default view to replace the token with the array.

Note: In the code below I use anonymous functions as hook handlers, and I reorder the list by capturing the content of h2.search-heading-category element. Then a clever algorithm allows us to move keys to the top of an array (PHP could really use native functions to reorder keys). Below I move Pages, Files, and Bookmarks to the top of the results. Your ordering spec must match the HTML: If a heading has an "&" you must use an "amp" entity.

$lists = array();
$token = md5('reorder_search');

// capture each search/list output into $lists, and replace the first one with a token
elgg_register_plugin_hook_handler('view', 'search/list',
	function ($h, $t, $v, $p) use (&$lists, $token) {
		if (preg_match('~<h2 class="search-heading-category">(.*?)</h2~', $v, $m)) {
			$lists[$m[1]] = $v;
		} else {
			return;
		}
		// change the output
		if (count($lists) === 1) {
			return $token;
		}
		return '';
	}
);

// replace the token with the reordered contents of $lists
elgg_register_plugin_hook_handler('view', 'page/default',
	function ($h, $t, $v, $p) use (&$lists, $token) {
		if (!$lists) {
			return;
		}

		// headings (content of H2 tags)
		$order = array('Pages', 'Files', 'Bookmarks');

		// move keys to top in reverse order.
		$rev_order = array_reverse($order);
		foreach ($rev_order as $heading) {
			if (isset($lists[$heading])) {
				$lists = array($heading => $lists[$heading]) + $lists;
			}
		}

		// replace the token
		$v = str_replace($token, implode('', $lists), $v);
		return $v;
	}
);

Navigation