The Search Results Core web part is quite easy to customise with XSL, which makes it a good out of the box solution for displaying data that comes from multiple sites or even multiple farms.

Unfortunately specifying the query to use is not quite so easy, limiting you to a hardcoded query with the fixed keyword query properties or whatever the user can type in to the standard search box. Sometimes this is enough, but the keyword syntax is too limited if you want to do something like return results newer than a certain date. For that you need to be using the SQL search syntax.

The advanced search web part uses SQL syntax and can get just about any result set you want. However, the UI is not really simple enough for the average user and isn’t that convenient for searching lookup fields. Time to try customising the advanced search interface.

My first thought was to override the Advanced Search webpart. However, I on looking through the code in reflector I noticed that the advanced search webpart doesn’t contain any code to build the query. That happens in a control called SearchResultHiddenObject, which is marked internal so there is no way to modify the construction of queries in code. On the other hand, the fact that the Advanced Search webpart doesn’t do any special processing means that it can be safely removed.

Copying the html source for the webpart into a content editor webpart works quite well, or at least it did once I removed some of the table structure - “?Contents=1” is a very useful query string if your html breaks the menus. Note that you probably shouldn’t edit the html directly in the cewp source editor, as it is difficult to get at the editor again if it is wrong, and you probably don’t want to delete all your code, which is the only option the recovery interface gives you.

As well as the web part itself, you need to copy some script and hidden fields - the script block starts with the function DisplayNextProp and the hidden fields are ASB_TextDTProps, ASB_DateTimeDT_Props and ASB_ResType_Query.

Next step is to make a cut down version, getting rid of the table structure, giving me a relatively easy to modify form with all the original fields. The javascript can also be safely removed as it is only for updating the UI, and the whole point of the customisation is to replace that UI. I’m not sure what ResetPageHashCode does, but removing it doesn’t seem to have any effect.

What we are left with is a set of html controls that can be modified as needed. There is no need to register the controls anywhere and the first part of the name is ignored - the SRHO just checks the part of the name starting with “ASB”. All of the fields are optional, and the SRHO will ignore any missing values. The numbering of the controls with multiple instances such as the property controls has no special requirements - as long as they match the pattern ASB_PS_ they will work.

ASB_TextDT_Props and ASB_DateTimeDT_Props Are lists separated by “#;#” which specify the properties which will be treated as text and datetimes respectively when building the query. All others are treated as numbers.

ASB_ResType_Query is set by the result type dropdown and can be used to include some raw SQL. However, the SRHO requires at least one other piece of the query to be used.

ASB_PS_lolb_0 is the operator to use between properties - either “And” or “Or”. This is required if multiple properties are checked and the same operator is used for all properties.

ASB_TQS_AndQ_tb is the “All of these words” search box.

ASB_TQS_PhraseQ_tb is for an exact phrase.

ASB_TQS_OrQ_tb is for “Any of these words”.

ASB_TQS_NotQ_tb is for words to exclude. It can only be used if another search term is also specified.

The language checkboxes are named in the format ASB_SS_lcb_0_12 with a value of “on”. The first number is a zero based index, while the last number corresponds to langdef values in the properties of a default search box. I’m not sure where those values come from.

Search Scope checkboxes are similar, with the format ASB_SS_scb_0_16 but no value set. The last number is the scope ID, which you can find in shared service administration.

Finally there are the property selectors. You can have as many of these as you want - just change the number at the end.

ASB_PS_plb_1 is the internal name of the property to search

ASB_PS_olb_1 is the operator, which will be one of the following values:

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorContain)

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorNotContain)

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorEqual)

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorNotEqual)

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorLater)

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorGreater)

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorEarlier)

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorLess)

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorTrue)

  • WebPartPlatform.Current.GetLocResourceString(LocStringId.AdvancedSearch_OperatorFalse)

or in English:

  • Contains

  • Does not contain

  • Equals

  • Does not equal

  • Later than

  • Greater than

  • Earlier than

  • Less than

  • Is true

  • Is false

ASB_PS_pvtb_1 is the value to search for.

Putting this all together, we get the following code which when placed in a content editor webpart will provide a dropdown to choose from a list of known authors and display the results in a search core results web part on the same page (assuming the url in the submit button is set to the current page).

<input type="hidden" name="ASB_TextDT_Props" id="Hidden4"  value="Title#;#Author#;#Region" />
<input type="hidden"  name="ASB_DateTimeDT_Props" id="Hidden5" value="Write#;#Created" />

<input name="nameprefix$ASB_PS_plb_1"  type="hidden" value="Author" />
<input  name="nameprefix$ASB_PS_olb_1" type="hidden" value="Contains" />
<SELECT name="nameprefix$ASB_PS_pvtb_1">
<input name="nameprefix$ASB_PS_lolb_0" type="hidden" value="And"  />

<INPUT id="Submit1"  onclick='WebForm_DoPostBackWithOptions(new  WebForm_PostBackOptions("nameprefix$ASB_BS_SRCH_1", "", false, "",  "/sites/home/SearchTest/default.aspx", false, false))' type="submit"  name="nameprefix$ASB_BS_SRCH_1" value="Search" />