Imtech Content Query Web Part for SharePoint 2010

If you are running a publishing site in SharePoint, then you know the name Waldek Mastykarz. If you don’t, you should. His blog is filled with many posts on SEO, Content Query Web Parts, and much more. I had a client request to add some paging into the Content Query Web Part, and stumbled upon Waldek’s Imtech Content Query Web Part for SharePoint 2010. This was the perfect solution for my client, but I needed to make a few modifications… this post will go over the modifications and issues we encountered and resolved.

The Issues and Modifications

  • My client had many customized item styles they still wanted to use, so using the example ImtechContentQueryMain.xsl and ImtechItemStyle.xsl sheets was out of the question, so I had to retro-fit their existing XSL files with the paging controls.
  • The paging control appeared at the top of the CQWP, we needed it at the bottom.
  • We encountered an error relating to trusted XSL files in a sub-site, we did not want to have duplicate XSL files all over the place.
  • Limiting the number of records returned on large lists, so the paging controls did not stretch out the page size.

Retro-fitting existing XSL Stylesheets with the Paging Controls

As mentioned, we wanted to use our existing stylesheets, other than the ones available from the Codeplex project page: http://imtech.codeplex.com/releases/view/39782#DownloadId=104110

To do this, I loaded up a default ItemStyle.xsl file (without any changes), as well as the ImtechItemStyle.xsl file in Beyond Compare, and copied the differences out into our custom ItemStyle.xsl.

The first step, is to copy the PagingControls template into your ItemStyle.xsl – it can be placed anywhere.

  <xsl:template name="PagingControls">
    <xsl:param name="Page" />
    <xsl:param name="NumPages" />
    <xsl:if test="$Page = 1">
      <xsl:text disable-output-escaping="yes"><![CDATA[<div>]]></xsl:text>
      <xsl:if test="$PageNumber &gt; 1">
        <xsl:variable name="PreviousPageNo" select="$PageNumber - 1"/>
        <a href="?{$PagingParameterName}={$PreviousPageNo}">
          <xsl:text disable-output-escaping="yes"><![CDATA[&laquo;]]></xsl:text> Prev
        </a>
        <xsl:text disable-output-escaping="yes"><![CDATA[&nbsp;]]></xsl:text>
      </xsl:if>
    </xsl:if>
    <xsl:choose>
      <xsl:when test="$Page = $PageNumber">
        <strong>
          <xsl:value-of select="$Page"/>
        </strong>
      </xsl:when>
      <xsl:otherwise>
        <a href="?{$PagingParameterName}={$Page}">
          <xsl:value-of select="$Page"/>
        </a>
      </xsl:otherwise>
    </xsl:choose>
    <xsl:text disable-output-escaping="yes"><![CDATA[&nbsp;]]></xsl:text>
    <xsl:if test="$Page &lt; $NumPages">
      <xsl:call-template name="PagingControls">
        <xsl:with-param name="Page" select="$Page + 1"/>
        <xsl:with-param name="NumPages" select="$NumPages" />
      </xsl:call-template>
    </xsl:if>
    <xsl:if test="$Page = $NumPages">
      <xsl:if test="$PageNumber &lt; $NumPages">
        <xsl:variable name="NextPageNo" select="$PageNumber + 1"/>
        <a href="?{$PagingParameterName}={$NextPageNo}">
          Next
          <xsl:text disable-output-escaping="yes"><![CDATA[&raquo;]]></xsl:text>
        </a>
      </xsl:if>
      <xsl:text disable-output-escaping="yes"><![CDATA[</div>]]></xsl:text>
    </xsl:if>
  </xsl:template>

Then, once that was in there, we need to modify the item template(s) we are using to support paging. To do this, we will use the Default template for ease of use…

Locate the start of the template

<xsl:template name="Default" match="*" mode="itemstyle">

Next, add in the following parameter right after that line in your XSL item template

<xsl:param name="CurPos" />

Your item template should now look like this:

  <xsl:template name="Default" match="*" mode="itemstyle">
    <xsl:param name="CurPos" />
    <xsl:variable name="SafeLinkUrl">
     ...

This adds in a parameter which gets the current position (row) from the list(s), we need this.

Next, we want to add in the paging. We’ll add it in its default location here, at the top of the CQWP, and show you how to move it to the bottom later in this article. Within your Default template, locate the following two lines

    </xsl:variable>
    <div class="item">

Now, we will paste in the following BEFORE <div class=”item”> and after </xsl:variable>

    <xsl:if test="$CurPos = 1 and $PageSize &gt; 0">
      <xsl:variable name="NumPages" select="ceiling($TotalRecords div $PageSize)"/>
      <xsl:if test="$NumPages &gt; 1">
        <xsl:call-template name="PagingControls">
          <xsl:with-param name="Page" select="1" />
          <xsl:with-param name="NumPages" select="$NumPages" />
        </xsl:call-template>
      </xsl:if>
    </xsl:if>

This will call the PagingControls template we added earlier, if the $CurPos = 1 (this is the first row in our CQWP), and the $PageSize is greater than 0 (meaning that we are using the paging feature in this web part).

Save your ItemStyle.xsl, and we need to next compare ImtechContentQueryMain.xsl, and ContentQueryMain.xsl.

In the ContentQueryMain.xsl file, locate this line towards the top of the file:

<xsl:param name="ClientId" />

Found it? Awesome. Paste in the following lines below that line:

    <xsl:param name="PageSize" />
    <xsl:param name="PagingParameterName" />
    <xsl:param name="TotalRecords" />
    <xsl:param name="PageNumber" />
    <xsl:param name="WebPartTitle" />
    <xsl:param name="WebPartDescription" />
    <xsl:param name="WebPartTitleUrl" />
    <xsl:param name="Locale" />
    <xsl:param name="GroupStyle" />
    <xsl:param name="ItemStyle" />

The next thing we have to do is include the CurPos (current row position) in the template OuterTemplate.CallItemTemplate. Search for that in the file, and then find <xsl:otherwise> within that template. After

<xsl:apply-templates select="." mode="itemstyle">

Add in

<xsl:with-param name="CurPos" select="$CurPosition" />

So the full template should look like this

  <xsl:template name="OuterTemplate.CallItemTemplate">
    <xsl:param name="CurPosition" />
    <xsl:value-of disable-output-escaping="yes" select="$BeginListItem" />
    <xsl:choose>
      <xsl:when test="@Style='NewsRollUpItem'">
        <xsl:apply-templates select="." mode="itemstyle">
          <xsl:with-param name="EditMode" select="$cbq_iseditmode" />
        </xsl:apply-templates>
      </xsl:when>
      <xsl:when test="@Style='NewsBigItem'">
        <xsl:apply-templates select="." mode="itemstyle">
          <xsl:with-param name="CurPos" select="$CurPosition" />
        </xsl:apply-templates>
      </xsl:when>
      <xsl:when test="@Style='NewsCategoryItem'">
        <xsl:apply-templates select="." mode="itemstyle">
          <xsl:with-param name="CurPos" select="$CurPosition" />
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="." mode="itemstyle">             

<xsl:with-param name="CurPos" select="$CurPosition" />  </xsl:apply-templates> </xsl:otherwise> </xsl:choose> <xsl:value-of disable-output-escaping="yes" select="$EndListItem" /> </xsl:template>

With the bolded line above being what we’ve added to it from the Imtech file. You can now save and close the ContentQueryMain.xsl file. And that is it for the modifications required on both the ItemStyle.xsl and ContentQueryMain.xsl files! You should now be able to use paging using your item styles and the Imtech Content Query Web Part.

Moving the Paging Control to the Bottom

Now, with the above in place, or using the Imtech XSL stylesheets, you will notice that the paging control is at the top. Well… if we want to keep in line functionality similar to SharePoint, we want to move the paging control to the bottom of the page. To do so, open up your ItemStyle.xsl file. Locate your default item style template (same one used in the last section), and locate this code, which appears after </xsl:variable> and before the starting DIV tag

    <xsl:if test="$CurPos = 1 and $PageSize &gt; 0">
      <xsl:variable name="NumPages" select="ceiling($TotalRecords div $PageSize)"/>
      <xsl:if test="$NumPages &gt; 1">
        <xsl:call-template name="PagingControls">
          <xsl:with-param name="Page" select="1" />
          <xsl:with-param name="NumPages" select="$NumPages" />
        </xsl:call-template>
      </xsl:if>
    </xsl:if>

Just cut that out. We will be moving it to the bottom of the template. now, locate the following, which ends the item style

        </div>
    </xsl:template>

Just before the closing DIV, paste the above code back in. If you save the file (and check it in – needs to be checked in to be viewable), you will see that it appears AFTER the first row returned by the CQWP. We need to add a little logic into here so we can determine if we are on the last row, and in the case of the last page where we might not have a full page, determine what the last item number is for that last page, and then display the paging controls. So the code below would be used instead of the default we just added in here.

Now, I am also going to center mine as well, so it looks a little better than just being left justified.

            <center>
              <xsl:if test="$PageSize &gt; 0">
                  <xsl:variable name="NumPages" select="ceiling($TotalRecords div $PageSize)"/>
                  <xsl:variable name="PageBeforeLast" select="$NumPages - 1"></xsl:variable>
                  <xsl:variable name="CountBeforeLastPage" select="$PageBeforeLast * $PageSize"></xsl:variable>
                  <xsl:variable name="LastPageCount" select="$TotalRecords - $CountBeforeLastPage"></xsl:variable>
                      <xsl:if test="$PageNumber = $NumPages and $CurPos = $LastPageCount">
                            <br/>
                            <xsl:call-template name="PagingControls">
                              <xsl:with-param name="Page" select="1" />
                              <xsl:with-param name="NumPages" select="$NumPages" />
                            </xsl:call-template>
                      </xsl:if>
                      <xsl:if test="$CurPos = $PageSize and $NumPages &gt; 1 and $PageNumber != $NumPages">
                        <br/>
                        <xsl:call-template name="PagingControls">
                          <xsl:with-param name="Page" select="1" />
                          <xsl:with-param name="NumPages" select="$NumPages" />
                        </xsl:call-template>
                  </xsl:if>
              </xsl:if>
            </center>

A little explanation on the above… I’ve added 3 new variables.

  • PageBeforeLast – this variable calculates the second to last page by taking the total number of pages NumPages, and then subtracts one.
  • CountBeforeLastPage – this variable gets the count of items before the last page by taking the PageBeforeLast variable, and multiplying it by the PageSize, which is the count of items per page.
  • LastPageCount – this variable gets the count of the number of items on the last page, which takes the TotalRecords variable and subtracts the CountBeforeLastPage, so if we have 23 items on the last page instead of 25, we know exactly when to implant the paging control.

Now there are two if conditions after that. The first determines if we are on the last page, and the last count. If we are at the last item on the last page, we will add in the paging control. The second if statement is used for every other page but the last one.

The web part references an untrusted XSL file.

Take a look at this discussion thread for the Extended CQWP by Imtech (the original version for 2007) – http://imtech.codeplex.com/discussions/53870. They are referencing the following error:

image

Now, this is in regards to the XSL options of the Presentation section of the Imtech Content Query Web Part properties.

image

This is very handy – so you can change these on the fly, instead of modifying the Item and Main XSL links in the XML of the web part itself. The bad news – if it is not local to the site, the following code will not work. The assembly for the Imtech CQWP is put into the GAC (if you look at the manfiest.xml file in the WSP), and, the site I was doing this on WAS in full trust mode. However, you will still get this error. To overcome this, you will need to modify the XML of the web part itself to point to your custom XSL stylesheets, if you are not using the out-of-the-box ones, which I do not recommend doing. Keep those as-is, and create new ones. To do this, export the Imtech Content Query Web Part, and open the .webpart file in a text editor. Search for: ItemXslLink and place the link to your customized Item Style XSL there:

<property name="ItemXslLink" type="string">/Style Library/XSL Style Sheets/ImtechItemStyle.xsl</property>

And the same goes for the Main XSL link, locate MainXslLink, and put in the relative URL to your ContentQueryMain XSL file:

<property name="MainXslLink" type="string">/Style Library/XSL Style Sheets/ImtechContentQueryMain.xsl</property>

Then save the file, and you can use it by uploading it to a page, or, make it re-usable by placing it in the web part gallery of your site collection(s).

Limiting the Number of Records Returned

This part is simple, but, I did want to include it. If you have thousands of items in a list, when you enable paging, and if you have your paging set at 25 or 50, you are going to see a lot of page numbers showing up, stretching out the width of your web part if you do not have a fixed width set… so, it does not look so great. Chances are, you do not need to show ALL of the items, just the most recent 50, 100, or a couple of hundred. The way to do this? In addition to using paging, if you limit the number of records returned within the default Content Query Web Part Properties, the only items page will be the number you are returning.

Resources

Microsoft has compiled some great resources on customizing the Content Query Web Part, so I want to share those with you…

And I of course need to add a link here to Heather Solomon’s article on customizing the Content Query Web Part…

Customizing the Content Query Web Part and Custom Item Styles

About Geoff Varosky
Geoff Varosky is a Senior Architect for Insight, based out of Watertown, MA. He has been architecting and developing web based applications his entire career, and has been working with SharePoint for the past 15 years. Geoff is an active member of the SharePoint community, Co-Founder and Co-Organizer of the Boston Area SharePoint Users Group, co-founder for the Boston Office 365 Users Group, co-organizer for SharePoint Saturday Boston and speaks regularly at SharePoint events and user groups.

6 Responses to Imtech Content Query Web Part for SharePoint 2010

  1. Pingback: modery.net -- Share - Manage - Govern

  2. Rene says:

    Many thanks for this! Gave me a very good start during our upgrade to SharePoint 2010 combined with intranet rebranding, saved me some work

  3. Bart Kuppens says:

    Great article!!! Included the paging controls in my custom ItemStyle.xsl and it works like a charm! However, I did notice that your code where you centered the paging controls generates the tags even if no paging is needed. So, I optimized it a bit and also included an extra test so the controls are only rendered when there’s > 1 page.

  4. Zako says:

    I made exact changes as mentioned above but cannot see paging in Imtech CQWP

Leave a comment