Logo
  • Contact form
  • Events & slides
  • Buy me a snack
πŸ‘‹πŸ»
Extending search with with PNP Search webpart

Extending search with with PNP Search webpart

Table of contents

  • Components of PNP Search
  • Before you start
  • Search schema
  • Turning crawled into managed properties
  • How to map properties
  • Using verticals as search query placeholder
  • Examples for search/filter queries
  • Dynamically filter based on a calculated date
  • Filter based on a multi value column
  • Only allow search box terms to search specific columns
  • Search for news within the current hub site and its associated hub sites
  • Examples to customize displayed data or their function
  • Show the parent folder name as a clickable link of a file
  • Replace text
  • If - statements
  • Link to a filtered view instead of the item itself
  • Format various data formats
  • Divide and round the size property of files
  • Mathematical expressions
  • Changelog
☝
TL;DR - Microsoft Search is quite powerful but lacks a fully customizable user interface. PNP Search is a well maintained and free webpart for SharePoint Online that you can use to customize the search experience for your users.
β€£

Components of PNP Search

Before you start

Search schema

The search schema is an inventory of all columns and metadata you have in a site collection in SharePoint. It will also contains SharePoint Online user attributes like department or office. The search schema has two categories of metadata:

  1. Crawled properties are all metadata and site columns, that you create. The crawling happens frequently and should show your columns quickly after filling an example item or document with that metadata.
  2. Managed properties are mapped to certain crawled properties to expose them to the search. With a mapped property the column becomes available as searchable, filterable and sortable. All default SharePoint columns, e.g. Title, Modified, Modified By, are already managed and can be used out-of-the-box.

Turning crawled into managed properties

This step is important since only managed properties are exposed to the search in a way where you can search or filter them. To turn crawled properties into managed properties you have to map them to the so called β€œRefinables”. Depending on the data type you should choose the refinable property. There are plenty available, that you can map at a tenant or site collection level.

Managed property type
Managed property name range
When to use
Date Multi-valued
RefinableDate00 to RefinableDate19
Columns: Date
Date Single-valued
RefinableDateSingle00 to RefinableDateSingle04
Stores multiple dates. Columns: Date
Decimal Multi-valued
RefinableDecimal00 to RefinableDecimal09
Columns: Decimal Numbers, that have fixed decimals
Double Multi-valued
RefinableDouble00 to RefinableDouble09
Columns: Decimal Numbers, that need more decimals points for higher precision
Integer Multi-valued
RefinableInt00 to RefinableInt49
Columns: Whole Numbers
String Multi-valued
RefinableString00 to RefinableString199
General purpose Columns: Text, Person, Managed Metadata, Choice, Lookup
String Multi-valued
RefinableStringFirst00 to RefinableStringFirst39
If you are mapping multiple properties to it, it will take the first that is not empty in a specific order. Columns: Text, Person, Managed Metadata, Choice, Lookup
String Multi-valued
RefinableStringLn00 to RefinableStringLn09
Use for searching language-specific contents. Columns: Text, Person, Managed Metadata, Choice, Lookup
String Single-valued
RefinableStringWbOff00 to RefinableStringWbOff49
When refining search results based on exact matches. Columns: Text, Person, Managed Metadata, Choice, Lookup
String Multi-valued
RefinableStringWbOffFirst00 to RefinableStringWbOffFirst49
When refining search results based on exact matches. If you are mapping multiple properties to it, it will take the first that is not empty in a specific order. Columns: Text, Person, Managed Metadata, Choice, Lookup

See the full list here: https://learn.microsoft.com/en-us/sharepoint/manage-search-schema#default-unused-managed-properties

πŸ’‘

You can map properties on the tenant-level, which pre-maps those properties for all site collections in your tenant. You can choose to overwrite the pre-mapping with your own values per site collection. If possible, don’t do that.

β€£

How to map properties

Using verticals as search query placeholder

Lets say you use three verticals that each use a result web part with the exact same layout and columns. You can combine all queries into one result web part by using the selected verticals tab value.

Add the complete search query (except the searchTerms or InputQueryText) to the tab value property of your vertical:

image

Then add {verticals.value} to search query in the filter results web part. It should look something like this:

{inputQueryText}
{verticals.value}

Examples for search/filter queries

Dynamically filter based on a calculated date

RefinableDate01 < {today+180}

Filter based on a multi value column

Now this is quite amazing and I only found that out recently. Lets say you have a multi-value choice column and you want to show all results based on those values. Usually you would combine these values with the operator β€œOR”. While that's fine for one or two fixed values, providing the query for dynamic values is not easy.

Example: You have a site page (page A) with a lookup multi-value for other side pages. You do that, because you want to provide a high level relation between site pages. You have mapped the lookup column to a refinable, which will store the site pages id. The site page you created has two other site pages in its lookup column.

On the initial page (page A), you setup a PNP search result displaying all site pages of its lookup column. For this, you can use this syntax:

{|RefinableString01:{Page.myLookupColumn.lookupid}}

Only allow search box terms to search specific columns

Usually, a search box will always look through all properties and contents of files. You can restrict the search box input by specifying one or more columns.

(RefinableString197: {inputQueryText}* OR Title: {inputQueryText}*)

Search for news within the current hub site and its associated hub sites

//News within the hub and its associated sites
PromotedState:2
DepartmentID:{{Site.id._guid}}
//All elements within the current Site, without the site object itself
path:{Site}
-contentclass="STS_Site"

Examples to customize displayed data or their function

Using handlebar expressions you can customize the format of the data in the results, like formatting dates or links. You can use handlebar expressions: https://github.com/helpers/handlebars-helpers?tab=readme-ov-file#helpers

Show the parent folder name as a clickable link of a file

The number at the end of the handlebar expression shows what folder level you want to show. In my case I have only one folder inside the library.

1 = direct parent, 2 = library , 3 = site

<a href="{{ParentLink}}" target="_blank" style="color: {{@root.theme.semanticColors.link}}">
	{{itemAt (split ParentLink "/")  (subtract (length (split ParentLink "/")) 1)}}
</a>

Replace text

In the example with the parent folder as a clickable link I had one issue where users used the β€œ#” in the name of the folder or document set. That cause the link to break, so I went in and replaced the β€œ#” with its encoded value.

{{replace ParentLink "#" "%23" }}

//full expression
<a href="{{replace ParentLink "#" "%23" }}" target="_blank" style="color: {{@root.theme.semanticColors.link}}">
	{{itemAt (split ParentLink "/")  (subtract (length (split ParentLink "/")) 1)}}
</a>

If - statements

You can use if expressions to show content based on conditions.

//Show a default value if the column filled or else when empty
{{#if SPTranslationLanguage}}
{{SPTranslationLanguage}}
{{else}}
en-us
{{/if}}

//Show a value if the path, in this case, contains a specific word
{{#if (contains item.Path "Archive")}}
Archive
{{else}}
Active
{{/if}}

Link to a filtered view instead of the item itself

Often you reach a situation where users click on links and instead of being redirected into a word document, the users wants to see the document within the library. You can manipulate the link so the users sees a filtered library or list.

Format various data formats

Case-sensitive, use value separators as needed.

//Date only
{{getDate RefinableDate01 "DD.MM.yyyy"}}
//Date and Time in 24h format
{{getDate LastModifiedTime "DD.MM.yyyy HH:mm"}}

Divide and round the size property of files

Size is a managed property. Make sure to add it to the selected properties on the first page of the result web part. The size is usually displayed as KB, therefore, a division is necessary to get the equivalent size in MB.

{{round (divide Size 1048576)}} MB

Mathematical expressions

//round numbers
{{divide NumberProperty 10)}}

//division
{{round DecimalNumberProperty}}

Changelog

Date
Changes
01.01.2025
Initial creation
28.11.2025
Added link to handlebar expressions Added replace expression example
Logo

Events & slides

Buy me a snack

Contact form

Data privacy policy

About

This blog is made with β™₯️ on Notion and made public with Super.so. Rocket icon created by RIkas Dzihab - Flaticon.

RedditLinkedIn
//based on its list item id
<a href="{{ParentLink}}?FilterField1=ID&FilterValue1={{ListItemID}}&FilterType1=Counter&useFiltersInViewXml=1" target="_blank" style="color: {{@root.theme.semanticColors.link}}">
	Edit in list
</a>

//based on a refinablestring that is connected with "empWorkerName"
<a href="{{ParentLink}}?FilterField1=empWorkerName&amp;FilterValue1={{RefinableString198}}&amp;FilterType1=Text" target="_blank" style="color: {{@root.theme.semanticColors.link}}">
    {{RefinableString198}}
</a>