- Applies to Joomla 2.5.x +, 3.4.x

What?
So I can't stand the way the default "Search" component in Joomla works. The default is to sort the results by popularity (hits) or by most recently added (depending on your version) which I have never seen in any other system.

I've googled and binged but could not find anything that documents how to bring it into line with other search systems. So here we go, hope this helps you.


Why?
I've created search systems for a plethora of other systems. The aim of this article is to enhance the Joomla search into par with Google and Wikipedia (or near enough).


How?
I'd like to use various techniques, and the first part of this article (Stage 1) is the only part you need to modify as this will improve your Joomla search results by giving priority to articles where the search term is in the article title.

In the stages thereafter, I'm going to simply enhance the relevance factor:

  • Soundex: Built-in function to list matches that sound like the search term.
  • Levenshtein: Allows for typos and matches to words that are 1 or 2 letters mistyped.
  • Grammar: Account for singular/plural, past/present, and noun/adjective/verb forms.
  • Referencing: If this is a search system for a technical database, and there is one specific article you visit a lot, it would be nicer just to type a number like "1234" and this returns that specific article. In the case of Joomla, we'll use the article ID.

Pre-Notes:
This article consists of instructions to hard-code some core files in Joomla. As a precaution, you may want to back up all your website files and its database. Or, if space is limited, you can backup the files I have listed here (the ones we will be modifying):
  1. \plugins\search\content\content.php
  2. \components\com_search\views\search\tmpl\default.xml
  3. \components\com_search\views\search\view.html.php
  4. \language\en-GB\en-GB.com_search.ini
  5. [IfExists] \modules\mod_rokajaxsearch\mod_rokajaxsearch.xml

Stage 1: Add Relevance [Mandatory Stage]
We want to order by more than just popularity and/or date, but also by our own relevance heuristics. The following change would give radically high relevance to articles where the search term is found in the title.
  1. \plugins\search\content\content.php: Insert this between the if ($sContent && $limit > 0){ and before the from part of the query $query->from('#__content AS a');
    1.  // Add "Relevance" column 
    2.  // + 1000 pts if in title x1 (eg. if word is twice then 2000pts) 
    3.  // + 60 pts if in introtext 
    4.  // + 40 pts if in fulltext 
    5.   
    6.  $sql_keyword = strtolower(trim($db->Quote($db->escape($text, true), false))); 
    7.  $query->select(' 
    8.  (1000*((LENGTH(TRIM(a.title)) - LENGTH(REPLACE(LOWER(TRIM(a.title)), '.$sql_keyword.',\'\'))) / LENGTH('.$sql_keyword.'))) + 
    9.  (60*((LENGTH(TRIM(a.introtext)) - LENGTH(REPLACE(LOWER(TRIM(a.introtext)), '$sql_keyword.',\'\'))) / LENGTH('.$sql_keyword.'))) + 
    10.  (40*((LENGTH(TRIM(a.`fulltext`)) - LENGTH(REPLACE(LOWER(TRIM(a.`fulltext`)), '.$sql_keyword.',\'\'))) / LENGTH('.$sql_keyword.'))) AS relevance 
    11.  '); 
    « Show Me »

  2. [Same file again and optional if your search opts to search archived articles] \plugins\search\content\content.php: Insert this between the if ($sArchived && $limit > 0){ and before the from part of the query $query->from('#__content AS a');
    1.  $sql_keyword = strtolower(trim($db->Quote($db->escape($text, true), false))); 
    2.  $query->select(' 
    3.  (1000*((LENGTH(TRIM(a.title)) - LENGTH(REPLACE(LOWER(TRIM(a.title)), '.$sql_keyword.',\'\'))) / LENGTH('.$sql_keyword.'))) + 
    4.  (60*((LENGTH(TRIM(a.introtext)) - LENGTH(REPLACE(LOWER(TRIM(a.introtext)), '.$sql_keyword.',\'\'))) / LENGTH('.$sql_keyword.'))) + 
    5.  (40*((LENGTH(TRIM(a.`fulltext`)) - LENGTH(REPLACE(LOWER(TRIM(a.`fulltext`)), '.$sql_keyword.',\'\'))) / LENGTH('.$sql_keyword.'))) AS relevance 
    6.  '); 
    « Show Me »

  3. [Same file again] \plugins\search\content\content.php: Add the option to select by relevance to the CASE order statement:
    1.  switch ($ordering) { 
    2.   
    3.  // BEGIN: joes new ordering option 
    4.    case 'relevance': 
    5.  $order = 'relevance DESC'; 
    6.  break; 
    7.  // END: joes new ordering option 
    8.   
    9.  case 'oldest': 
    10.  $order = 'a.created ASC'; 
    11.  break; 
    12.   
    13.  case 'popular': 
    14.  $order = 'a.hits DESC'; 
    15.  break; 
    16.   
    17.  case 'alpha': 
    18.  $order = 'a.title ASC'; 
    19.  break; 
    20.   
    21.  case 'category': 
    22.  $order = 'c.title ASC, a.title ASC'; 
    23.  $morder = 'a.title ASC'; 
    24.  break; 
    25.   
    26.  case 'newest': 
    27.  default: 
    28.  $order = 'a.created DESC'; 
    29.  break; 
    « Show Me »

  4. To add it to the frontend as option in advanced search: OPTION FOR SITE VISITORS \components\com_search\views\search\tmpl\default.xml:
    1.  <field  
    2.                  name="ordering"  
    3.                  type="list" 
    4.                  default="relevance" 
    5.                  description="COM_SEARCH_ORDERING_DESC
    6.                  label="COM_SEARCH_ORDERING_LABEL" 
    7.          > 
    8.                  <option value="newest">COM_SEARCH_NEWEST_FIRST</option> 
    9.                  <option value="oldest">COM_SEARCH_OLDEST_FIRST</option> 
    10.                  <option value="popular">COM_SEARCH_MOST_POPULAR</option> 
    11.                  <option value="alpha">COM_SEARCH_ALPHABETICAL</option> 
    12.                  <option value="category">JCATEGORY</option> 
    13.                    <option value="relevance">COM_SEARCH_MOST_RELEVANT</option> 
    14.          </field> 
    « Show Me »

  5. To add it to the frontend as option in advanced search: FUNCTIONALITY \components\com_search\views\search\view.html.php:
    1.  // built select lists 
    2.  $orders = array(); 
    3.  $orders[] = JHtml::_('select.option',  'newest', JText::_('COM_SEARCH_NEWEST_FIRST')); 
    4.  $orders[] = JHtml::_('select.option',  'oldest', JText::_('COM_SEARCH_OLDEST_FIRST')); 
    5.  $orders[] = JHtml::_('select.option',  'popular', JText::_('COM_SEARCH_MOST_POPULAR')); 
    6.  $orders[] = JHtml::_('select.option',  'alpha', JText::_('COM_SEARCH_ALPHABETICAL')); 
    7.  $orders[] = JHtml::_('select.option',  'category', JText::_('JCATEGORY')); 
    8.    $orders[] = JHtml::_('select.option',  'relevance', JText::_('COM_SEARCH_MOST_RELEVANT')); 
    « Show Me »

  6. To add it to the frontend as option in advanced search: LANGUAGE FILE \language\en-GB\en-GB.com_search.ini:
    1.  COM_SEARCH_MOST_POPULAR="Most Popular" 
    2.    COM_SEARCH_MOST_RELEVANT="Most Relevant" 
    3.  COM_SEARCH_NEWEST_FIRST="Newest First" 
    4.  COM_SEARCH_OLDEST_FIRST="Oldest First" 
    « Show Me »


Third-party AJAX Search modules?
  1. To add it to ROKAJAXSEARCH: \modules\mod_rokajaxsearch\mod_rokajaxsearch.xml:
    1.  <field name="ordering" type="list" default="newest" label="Ordering"> 
    2.  <option value="alpha">Alphabetical</option> 
    3.  <option value="category">Section/Category</option> 
    4.  <option value="newest">Newest first</option> 
    5.  <option value="oldest">Oldest first</option> 
    6.  <option value="popular">Most popular</option> 
    7.  <option value="relevance">Most relevant</option> 
    8.  </field> 
    « Show Me »

    Don't forget to change the setting in Joomla Admin Panel > Module Manager > RokAjaxSearch > Basic Options > Advanced Search > Ordering (no functionality to add if you followed Stage 1 above)

Lastly and optionally
I add the following to the core joomla search module PHP template so that the first search is based on the above heuristics:
  1.  <input type="hidden" name="ordering" id="ordering" value="relevance" /> 
This needs to be put alongside the other hidden variables in the module, core joomla file is at /modules/mod_search/tmpl/default.php and I put it just before the closing form tag "</form>". Note that if you are using a 3rd-party template which has it's own login module, you will need to find the file specific to that template (eg. /templates/<name_of_template>/html/mod_login/default.php)

Stage 2: More than Title relevance
So I could stop here as Stage 1 substantially improves your Joomla search, but the above files are enough to start adding your own code to make the "relevance" ordering more relevant.

... ok still to come as I'm really happy with what the above already improves!

Download the above modified files.
The following ZIP file contains the default Joomla v3.4.x core files and then a copy with my modifications above. I use this to quickly add the relevance option to clients websites as it should work for all Joomla installations version 3.4.x.

Download demo files

Comments   

+1 christophe Wednesday, 13th January 2016, 7:58 pm
I added this functionnality to my website, but there is some problems. The most important is that the joomla search engine add '%' to the word. EG : %joel%
So, you have to delete all the % if you want the word be take in account. :
You have to replace every '.
$sql_keyword.'
by
(TRIM(BOTH "%" FROM '.$sql_keyword.'))

With that, it's working very well !
0 Bobby E Monday, 16th November 2015, 3:48 pm
Is there a way to make the search browse the navigation menu titles? I have iframes that are dynamically generated from converted word.doc that are part of a 5th child navigation menu...
0 Bobby E Monday, 16th November 2015, 3:43 pm
Saraeee - I returned the same blank page:
On stage 1:a - there is a typo $sql_keyword. - change to: $.sql_keyword.
0 Saraee Sunday, 18th October 2015, 7:29 am
Thank you dear Joel. With demo files at the end of the article I could do so.
0 Saraeee Tuesday, 25th August 2015, 1:40 pm
I did what you explained on my joomla 3 website but had error and no result shown.
Any idea?
-2 pankaj Tuesday, 3rd September 2013, 9:32 am
what to do for titel name search? done all the changes according to u .but the the no sultion for the titel search. if the the article is new it will shown.but if it is old date article then the result is shown in differnt article body in there content. :cry: :cry:

Add comment


Send