Customizing DNN 7 Search and Search Results
DNN 7 has introduced a new, Lucene-powered indexing and search results retrieval mechanism. This means that all techniques you knew are not in effect any more. No more SQL queries and/or tables, data get returned in JSON format and rendered via Javascript. For more details, please read this post on DNNSofware.com
This adds a whole lot of new functionality but also a lot of limitations in the way Search Results are presented. Actually, there never was a straightforward way to customize Search Results, but until now you could just edit SearchResults.ascx and its corresponding code-behind file and have your desired result.
Things are still ugly regarding customization. The default Search Results layout includes a link guiding you to advanced search concepts, an "Advanced" form that asks you to provide various information such as where you want to search (categorized by module type) and so forth.
This doesn't always make sense to end users, and some elements have to be removed in specific scenarios. Users don't always want advanced search options, nor do they need to know what type of modules your site contains. In some cases they don't give a damn about the author, or the last modified date too. But there's no immediate way to configure what will be displayed and what will be not.
Moreover, until now you could face the problem of default module titles (which users usually leave as is because they are using containers that didn't include the module title) by tweaking the way module titles were inserted in the SearchItem table (see this older post for more). Since no SQL tables are used any more, you're left with ugly "Text/HTML" and other default titles in Search Results. The JSON returned for each search result item just contains a title that is often made of a concatenation of the tab's name and the module's title (or, in the case of grouped results, just the module's title).
Moreover, having a module with a BLANK title is no longer an option since modules with blank titles are not indexed(!). For more info, see my question here: http://www.dnnsoftware.com/answers/cid/420779
So le't see how we can address all of the above with some modifications on specific files. Be warned that what I'm saying here applies to version 7.1 and may or may not be in effect for future DNN versions, as well as that those changes are not upgrade-proof, meaning that if you upgrade your site to a higher DNN version you may lose them. But, it's better than nothing. :)
Be sure to get a backup of all the files you are going to modify in case something goes wrong!
Let's start.
Hiding the "advanced" link
File: dnn.SearchResult.js
Location: DesktopModules\Admin\SearchResults
Go to line 343, you will see a call to the DnnSearchBox like the following
dnn.searchResult.searchInput = $('#dnnSearchResult_dnnSearchBox').dnnSearchBox({
id: 'dnnSearchResult_dnnSearchBox',
filterText: dnn.searchResult.defaultSettings.advancedText,
showAdvanced: true,
advancedId: 'dnnSearchResultAdvancedForm',
...
Locate this line:
showAdvanced: true,
And change it to
showAdvanced: false,
This is an option that you can't access via the module settings and it hides the "advanced" link. Unfortunately, the form that would pop up will still be visible at the bottom of the page so you have to take an extra step:
File: SearchResults.ascx
Location: DesktopModules\Admin\SearchResults
Go to around line 55 and you'll see a DIV element surrounding the elements of the Advanced form, like the following:
<div id="dnnSearchResultAdvancedForm" class="dnnForm">
<div class="dnnFormItem">
<dnn:Label ID="lblAdvancedTags" runat="server" ResourceKey="lblAdvancedTags" />
<input type="text" id="advancedTagsCtrl" />
</div>
<div class="dnnFormItem">...
Add a style="display:none;" attribute to the outer div to hide the whole form.
If you need the advanced form but do not need to show specific controls, you can just skip the steps above, go at this point and just add a style="display:none;" attribute to any of the DIVs nested inside to hide the specific control you don't need (e.g. Scope)
Hide Advanced Tips link
File: dnn.SearchResult.js
Location: DesktopModules\Admin\SearchResults
Go to line 359 (it's empty), just above this piece of code:
$('a.dnnSearchResultAdvancedTip').on('click', function () {
$('#dnnSearchResult-advancedTipContainer').slideToggle('fast');
return false;
});
And insert the following line:
$('a.dnnSearchResultAdvancedTip').hide();
Alternatively, you can achieve the same result by adding a style="display:none;" attribute at the A tag in SearchResults.ascx, line 6:
<a href="javascript:void(0)" class="dnnSearchResultAdvancedTip"><%= LinkAdvancedTipText %></a>
Hide Results by Page / Sort section
File: SearchResults.ascx
Location: DesktopModules\Admin\SearchResults
Go to line 13 and add a style="display:none;" attribute to the outer DIV element there (first element in code snippet below):
<div class="dnnSearchResultPanel">
<div class="dnnRight">
<ul class="dnnSearchResultSortOptions">
<li class="active"><a href="#byRelevance"><%= RelevanceText %></a></li>
<li><a href="#byDate"><%= DateText %></a></li>...
If you hide this section but you need to specify a different sort order and/or results per page setting, you can alter the Javascript call at the same file, line 116 onwards, by altering the sortOption and pageSize initial values:
$(function () {
if(typeof dnn != 'undefined' && dnn.searchResult){
dnn.searchResult.moduleId = <%= ModuleId %>;
dnn.searchResult.queryOptions = {
searchTerm: '<%= SearchTerm %>',
sortOption: 0,
pageIndex: 1,
pageSize: 15
};
sortOption can be 0 for date, 1 for relevance.
pageSize can be anything you need.
Hide various elements on Search Results
Well, some people don't like the "last updated" information. Others don't like the "author" info. So let's see how we get rid of anything we don't need:
File: dnn.SearchResult.js
Location: DesktopModules\Admin\SearchResults
Start from about line 112,where you'll see code like this:
markup += '<div class="dnnSearchResultItem-Others">';
markup += '<span>' + dnn.searchResult.defaultSettings.lastModifiedText + ' </span>';
markup += data.DisplayModifiedTime;
markup += '</div>';markup += '<div class="dnnSearchResultItem-Others">';
markup += '<span>' + dnn.searchResult.defaultSettings.sourceText + ' </span>';
Comment lines 112 to 115 to get rid of the "last updated" text
Comment lines 117 to 119 to get rid of the "source" text and link
Comment lines 121 to 123 to get rid of author info
Comment lines 126 to 135 to get rid of 'tags" info
Hide default HTML module titles (if any)
As mentioned earlier, you may not want module titles to appear in search results, but they do, even if your container doesn't display the module's title. The most common is "Text/HTML" and we'll see how to get rid of it in Search Results.
File: dnn.SearchResult.js
Location: DesktopModules\Admin\SearchResults
Scroll down to the bottom of the file and append this function at the end:
function fixTitle (s) {
if (s=='Text/HTML') {
return ('...');
}
var s1;
var s2;
s1=s.substring(0,s.indexOf('>')-1);
s2=s.substring(s.indexOf('>')+2, s.length);
if (s2=='Text/HTML' || s2==s1) {
return (s1);
}
else
{
return (s);
}
}
This function accepts a search result item title and first checks if the title is "Text/HTML". If so, it returns three dots ("...") instead. You will find this in grouped results, where the module title is displayed on its own.
If the title does not belong to a group subset, it'll be in the format "xxx > yyy" where xxx is the page's name and yyy is the module's title. The code breaks the string in its two parts and checks if the second part is equal to "Text/HTML". If so, it returns only the first part (the page's name). Also, if both parts are the same it once more returns the first part. Useful when a module has the same title as the page and you don't want to see this in search results.
This is not the best possible solution, but it's a decent workaround, provided that you don't have the character ">" anywhere in your module titles or page names. I know it can get better, but this is only to demonstrate how you can do it.
In order to put our function into effect, we have to go to line 107:
markup += '<a href="' + data.DocumentUrl + '"' + dnn.searchResult.defaultSettings.linkTarget + '>' + data.Title + '</a></div>';
and replace data.Title with fixTitle(data.Title):
markup += '<a href="' + data.DocumentUrl + '"' + dnn.searchResult.defaultSettings.linkTarget + '>' + fixTitle(data.Title) + '</a></div>';
Hide subsets (grouped results)
If, for some reason, you don't want to have any grouped results then you can comment out the code that is generating them. Be adviced that the result that was supposed to be grouped won't display a description underneath, just the title and link.
File: dnn.SearchResult.js
Location: DesktopModules\Admin\SearchResults
Go to line 159 and comment the code there until line 161:
// render subsets
for (var j = 0; j < result.Results.length; j++) {
markup += '<div class="dnnSearchResultItem-Subset">' + dnn.searchResult.renderResult(result.Results[j]) + '</div>';
}
Finally, if you tamper with the way search results are rendered, you may not want to have auto-search (search-as-you-type) get in your way by rendering everything in a different way (e.g. using default text/html module titles). There is no option for disabling it, but we can always hack the code a little more:
File: SearchSkinObjectPreview.js
Location: Resources\search
Go to line 137 and comment out this piece of code (until line 155):
throttle = setTimeout(function() {
var service = $.dnnSF ? $.dnnSF(-1) : null;
var url = makeUrl(val, service);
if (url) {
$.ajax({
url: url,
beforeSend: service ? service.setModuleHeaders : null,
success: function(result) {
if (result)
generatePreviewTemplate(result);
},
error: function() {
},
type: 'GET',
dataType: 'json',
contentType: "application/json"
});
}
}, self.settings.delayTriggerAutoSearch);
This will prevent the Search skin object from auto-searching.
Well, that's all! Even if line numbers change with an upgrade, you have a reference point on what to seek in code. I know this is not the prettiest or the most accurate and bullet-proof solution in the world, but until DNN Corp. decides to add more configuration settings to its Search subsystem, it will have to do. In the meantime, you can vote for my relevant suggestion in Community Voice here:
http://www.dnnsoftware.com/voice/cid/420823
Oh, and please feel free to suggest any other improvements / hacks to Search and Search Results! I know I didn't cover the whole range of possible modifications, but these are, IMHO, the most common ones.
Until next time!
8 comments:
We worked around the title-problem with a really neat trick, because we also often need to get a module from another page (which is very hard when all modules have the same name).
Since almost everything we do uses 2SexyContent we programmed the module to automatically rename the module based on the title the user adds to the content. Slick - it even works with multilingual scenarios.
An important question: Search without documents is sooo 1990. Is there a quick trick to enable pdfs on the community edition?
I'm glad to see I'm not the only person frustrated with the DNN Search Module. These are actually good tidbits, so thank you for taking the time to figure them out and share them with others.
I'm trying to figure out how to customize the configuration of a search module, so that it searches only for pages (which can already be done in the module as is) that have been tagged with a specific tag (such as "products"). I know an end user can do this by going through the Advanced link, but I'm trying to make this the default behavior of the search module when the page is first loaded.
If you have any advice that you'd care to share, I'd love to hear it.
The problem around Html module's default title "text/html" or "Enter Title" has been resolved in 7.3.2. https://dnntracker.atlassian.net/browse/DNN-5639
Excellent write-up. I absolutely appreciate this website. I'm extremely pleased to uncover this site. I need to to thank you for ones time due to this wonderful read!! I definitely loved every bit of it and i also have you book-marked to check out new stuff in your site.
What about the dnn new versions? Please share the updates. Thanks
Thanks so much for posting this. It got me started to find what I needed to do in the newer versions of DNN.
I'm using DNN 9.3.2 and it would take an even longer article to explain everything I did to get a good looking search output. A lot of CSS tweaks. But the JS was hardest part to crack.
In the module settings I put Show Snippet and Show Source to false, everything else to true. I wanted a single title link, Description if found and the most inclusive Author, Last UPdated, etc....using CSS I just hid Subset > Title lines
.dnnSearchResultItem-Subset > .dnnSearchResultItem-Title {
display:none;
}
and looped through to find a description if exists and the longest of the -Others subset elements.
This code replace what is commented at the bottom. (dov = div) It was around line 215 in dnn.SearchResults.js...
var idOfLongest = 0;
var lenOfLongest = 0;
for (var g = list.length -1; g >= 0; g--) {
if (list[g].indexOf("-Others") > -1) {
var len = list[g].length;
if (len > lenOfLongest) {
if (idOfLongest > 0) {
list.splice(idOfLongest, 1);
}
idOfLongest = g;
lenOfLongest = len;
}
else {
list.splice(g, 1);
}
}
}
for (var y = 0; y < list.length; y++) {
markup += '' + list[y] + '';
}
//// render subsets
//for (var j = 0; j < result.Results.length; j++) {
// markup += '' + dnn.searchResult.renderResult(result.Results[j]) + '';
//}
So sorry, I left off the top of the new code...
// only want the longest of -others:
var list = []
// render subsets
for (var j = 0; j < result.Results.length; j++) {
var item = '' + dnn.searchResult.renderResult(result.Results[j]) + '';
list.push(item);
}
Post a Comment