Tracking SharePoint Popular Items Accessed through JavaScript

Applies to: SharePoint 2013+

A while back I wrote an AngularJS app running in SharePoint 2013 and using lists as the backing store for some components. Without getting into the reasons this particular architecture was chosen, let’s look at an issue that came up.

The client asked us to show the popular items. There is a standard web part for this, but you can also query the search API directly by sorting by ViewsLifeTime:descending which is what we did so that we could display it in a custom Angular directive. No problem! Right?

It wasn’t until some time later that the client asked about the results we were displaying. The most “popular” items appeared to be the ones they had had trouble with behind the scenes and didn’t match their expectations about what users would be viewing.

Unpopular

When you view a list item (dispform.aspx?id=X) this view is tracked in SharePoint’s Usage Analytics (assuming you’ve configured this correctly). It’s this information that is used by search to determine an item’s popularity.

Unfortunately, it turns out pulling items from the REST API triggers no such view event. This seems obvious in retrospect, but until we really thought about it, usage tracking is just one of those magical behind the scenes things SharePoint does and we just assumed it would work.

This explains the results the client was seeing. The items they were having trouble with are the ones they were viewing directly (outside of the Angular app). While this wasn’t a ton of traffic, it was far more than any other list item was getting since they were only being viewed via the REST API inside a custom application. Ugh.

Fortunately, the fix for this isn’t too complicated, it’s just not very obvious.

Spoofing Item Views in JavaScript

You can log a View event using the SP.Analytics.AnalyticsUsageEntry.logAnalyticsEvent2 method. I had trouble finding any helpful documentation on this method or what the parameters should be. Fortunately, after some experimentation (and patience as the entries are not immediately available), I got it working.

Here’s the basic JS code which you can then adapt and make smarter:


function logItemUsage(itemId, listName) {
SP.SOD.executeOrDelayUntilScriptLoaded(function() {
var stuff = {
ctx: SP.ClientContext.get_current()
};
stuff.user = stuff.ctx.get_web().get_currentUser();
stuff.ctx.load(stuff.user);
stuff.scope = "{00000000-0000-0000-0000-000000000000}";
stuff.site = stuff.ctx.get_site();
stuff.ctx.load(stuff.site);
this.stuff.ctx.executeQueryAsync(
function () {
stuff.siteId = stuff.site.get_id();
var itemUrl = _spPageContextInfo.webAbsoluteUrl + "/Lists/" + listName + "/DispForm.aspx?ID=" + itemId;
SP.Analytics.AnalyticsUsageEntry.logAnalyticsEvent2(
stuff.ctx,
1,
itemUrl,
stuff.scope,
stuff.siteId,
stuff.user
);
stuff.ctx.executeQueryAsync(
function() {
console.log("Logged: " + itemUrl);
}, function (s, a) {
console.log(a.get_message());
}
}, function (s, a) {
console.log(a.get_message());
}
);
}, "SP.js");
}

view raw

LogItemUsage.js

hosted with ❤ by GitHub

For instance, I adapted the above into an AngularJS service and wrapped the call to get the site Id and user into a promise so that I only had to pull that once in my app, but all of that is up to you.

One nice thing about doing this manually is you can control when it fires. For instance, you might want to only log usage during reads but not during edits or exclude administrative accounts, etc.

That’s it! Now your custom interface can participate in the internal popularity contest!

Scroll SharePoint Search Results Back to the Top on Paging

Applies To: SharePoint 2013+

By default, when you click on a different page using SharePoint’s Search Results web part’s paging links (shown underneath the search results) the next page of results is shown but you remain at the bottom of the page. This is super dumb.

Paging

This is really easy to fix and requires no custom code at all! There is a property (not exposed in the UI for some reason) called ScrollToTopOnRedraw that is False by default.

To apply this setting to your Search Results web part, simply export the web part. You can do this by choosing to Edit the page and choosing Export… in the web part dropdown menu:

ExportWP

Now, open the .webpart file in a text editor like Notepad and do a quick find for ScrollToTopOnRedraw. Then change the value from False to True and save the file:

ScrcollToTopOnRedraw

Now, choose Delete in that same web part dropdown menu on the current Search Results web part. Then click the Add a Web Part button. Choose Upload a Web Part under the list of categories, then click Choose File and pick the .webpart file we saved a minute ago. Finally click the Upload button:

UploadWebPart

You’ll probably be asked if you want to leave the site. It’s safe to choose Leave.

Click the Add a Web Part button again. Choose the Imported Web Parts category and find your newly uploaded Search Results web part and click Add. You’ll likely have to update the Refinement Target for any refinement web parts on the page as well.

Now, when you page results you’ll be taken back to the top of the results each time!

Refinement Panel Customization Saving Woes

Applies To: SharePoint 2010

Editing the Filter Category Definition of a Refinement Panel web part can make your search result pages so much better. This is one of the first things we customize and every time we do, I get tripped up by a really annoying setting in the web part.

Problem Scenario

I replace the XML in the Filter Category Definition property in the Refinement properties section of the web part. I hit Apply and everything validates. I save the page and run the results – No custom refinements! In fact, when I open the web part back up for editing, my custom Filter Category Definition is totally wiped out! Why isn’t it saving!?!?!?! Why am I weeping ever so softly?!?!! Why would I confess that on the internets?!?!?!?!

Solution

There’s a checkbox at the bottom of the Refinement properties section labeled, Use Default Configuration. This is checked by default. Unless you uncheck this when you place your custom XML in the property, it is going to completely ignore you and replace it with the default XML.

RefinementSettings

I can see why things work this way, but it is extremely unintuitive. It would seem that the web part should recognize there is custom XML in the Filter Category Definition and understand that’s what it should use. Then a button (NOT a checkbox) that says something along the lines of “Revert to Default Configuration” would be used to reset that XML when needed.

Oh well, nobody is asking my opinion anyway. So do yourself a favor and remember to uncheck that box whenever customizing the Filter Category Definition.

PDF Search Results Direct Link (Eliminating DispForm.aspx Results) Without an iFilter

Applies To: SharePoint

We are utilizing our search functionality much more in SharePoint and one of the more annoying things we found was how PDF files are treated by default. In the search results, the link goes to the DispForm.aspx for the item rather than directly to the item.

The obvious fix is to install an iFilter. Unfortunately, this isn’t always an option. For us, the performance and crawl delay issues didn’t make up for the benefit of having these documents indexed. Fortunately, I came across this answer by daver306 on SharePoint SE that didn’t get a lot of attention but worked perfectly for me.

I wanted to write it up with some added detail and share my experiences. Not only does this allow you to link directly to your PDFs within the search without the use of XSL and allows KnowledgeLake queries to open PDFs directly within the KnowledgeLake Viewer, it’s actually pretty simple to do.

1. Add PDF as a File Type

Within Central Admin, go to your Search Administration (Manage Service Applications > Search Service). From there click on the File Types link under Crawling on the left:

If pdf is not listed, click the New File Type button and type pdf (no period needed) in the File extension box and click OK:

2. Restart the Search Service

This is a very important step. I originally tried to skip it to spare myself some hassle and ended up having to repeat the crawl below. You will need to go to each server running the SharePoint Server Search service and stop it. You can do this through the command line or the Services panel under Administrative Tools:

Once off on all boxes, just go back through and start it again.

3. Reset Your Index

Back on the Search Administration page within Central Administration you will want to click on the Index Reset link under Crawling on the menu on the left:

Press the Reset Now button. Remember that this should be done at a time when your environment is not under heavy use or when search won’t be needed since search results will not be available until after a full crawl completes.

4. Perform a Full Crawl

If you have a pretty standard search setup, then you probably only have one content source. If not, then you already know how to start the full crawls for each of them. If you’ve just got the one, then from the Search Administration page within Central Administration click on the Content Sources link under Crawling on the menu on the left. Hover over your content source and choose Start Full Crawl in the dropdown menu:

After the crawl completes (This could be hours depending on the size of your farm), things should be working as expected. No more DispForm.aspx links in your search results!