“Code-easy” modifications for SharePoint 2010: Part 2, the custom Content Query Web Part Item Style

I always wanted to do a series about easy to build, real life customer requests for SharePoint modifications. And as with most ideas, never really found the time to do it. Well, now’s as good a time as any!

Other parts:

So here is part 2, the custom Content Query Web Part Item Style

Aaahh, the Content Query Web Part, or CQWP for short. The Swiss Army Knife no real SharePoint solution architect can do without. If you are not familiar with the Content Query Web Part in SharePoint, here is a small introduction. I won’t go in depth on all the different advanced options you might have configuring the CQWP, because there are lots of good articles about that out there. I do focus on how you would package and deploy such a customization using Visual Studio 2010.

Introduction

The Content Query Web Part (CQWP) was first introduced in SharePoint MOSS 2007. It allows for querying and presenting SharePoint data in a very flexible and customizable way and is considered one of the most important Web Parts in SharePoint. It can roll up SharePoint items:

  • Throughout your site collection.
  • In one specific site and all of its sub sites.
  • In one specific list.

As an example, say you want to do an aggregation (“roll up”) of all news articles from your news site and show the latest 3 with a thumbnail image on your home page? Easy with the help of the CQWP:

1

You start with configuring the CQWP through the settings in the Web Part toolbox.

2 3 4

The Query part determines where you will get your items from:

  • Source: the scope of the query.
  • List Type: choose the list type your items are in. In this case we pick Pages Library because our news articles are based on Publishing Pages stored in the default Pages library.
  • Content Type: we only want to return Article Pages and not Web Part pages.

The Presentation part determines how the items will be presented on the page:

  • Grouping and Sorting: speaks for itself. We pick 3 items, sorted by Article Date Descending.
  • Styles: the group style is used when we group the items and is not used in this example. The Item style is the most interesting part and controls how the items are rendered. There are several options, so be sure to check them all out. For now we pick the default “Image on left”.

Fields to display:

This part is a new feature of the CQWP in SharePoint 2010. These fields are called “Slots” and are used to bind item fields to XSL properties. Every item style template can have its own set of configurable fields.

Customization

This post is about configuring and customizing the CQWP if you are not *that* happy with the standard behavior of the available Item Styles. My most requested style for instance, is not available out of the box:

15

  • the title on top
  • the image on the left, just beneath the title
  • the byline to the right of the image
  • the first 200 characters of the article content, beneath the byline
  • a read more link

The standard CQWP gets its configuration from files in the Site Collection Style Library. These files are shared among all default Content Query Web Parts in your site. Let’s take a closer look at these files and the best way to do this is using SharePoint Designer. Just open up your site and navigate to the All Files section. Here you will find the Style Library with the XSL Style Sheets:

5

The file we are interested in is the ItemStyle.xsl. If you take a peek at the contents of this file, you will find several <xsl:template> elements which correspond to the different Style options you see configuring the CQWP. The names of the template should mostly speak for themselves. One exception, the “Image Left” is called “Default”.

Important:If you are not familiar with XSL you might want to read up on the subject. We keep our customization fairly simple, so you will just need a basic understanding.

We could of course modify the OOTB file using SharePoint Designer and create our customization that way. And that is a perfectly supported scenario, but with three major downsides:

  • This is an OOTB file and if it is modified it is saved to the content database. If someone chooses to reset it to the site definition all your changes would be lost.
  • Coexistence with other applications could be hard since you would have to share the default ItemStyle.xsl among them.
  • If you mess up the default ItemStyle.xsl it could affect other Content Query Web Parts in the Site Collection.

So the best way around these issues is to supply our own style sheet with our Web Part.

To start, create a Visual Studio 2010 Empty SharePoint solution. Since we don’t have an assembly that needs Full Trust (see my earlier post about Sandbox solutions), we select a sandboxed solution.

8

Add a SharePoint module:

9

After the module is added to the project, delete the Sample.txt

Next we add the XSLT Style Sheet: Add New Item/ Data / Style Sheet. Remember to give it a .xsl extension instead of .xslt to be in line with OOTB SharePoint files.

Your Solution should now look like this:

10

My next step is to copy the content of the OOTB file in my new file to start off with.

Open the default file in SharePoint Designer and answer “No” to the question if you want to check the file out (see downside no. 1). Copy and Paste the contents in your new file in Visual Studio, clearing the current contents of the file.

You now effectively made a copy of the OOTB file and are ready to create your own rendering template (the actual CQWP Item Style customization).

To give yourself a head start, it is easiest to copy a similar one. In this case that would be “Image Left”, which is called “Default” in the ItemStyle.xsl. Just copy and paste the complete template (everything between and including the <xsl:template name=”Default” match=”*” mode=”itemstyle”> and </xsl:template> tags).

Rename our template to something like “ImageWithArticleContent” and replace the wildcard match (“*”) with our specific style.

<xsl:template name=”ImageWithArticleContent” match=”Row[@Style=’ImageWithArticleContent’]” mode=”itemstyle”>

The next step is to reorganize the template to match our requested design. Basically it just starts with the title and the image and finally the Byline (“description”). We then add a new property “Content” and display the first 200 characters and the Read More link. Because we add a property a new slot will be created in the CQWP toolbox as we’ll see later.

 

<xsl:template name="ImageWithArticleContent" match="Row[@Style='ImageWithArticleContent']" mode="itemstyle">
    <xsl:variable name="SafeLinkUrl">
      <xsl:call-template name="OuterTemplate.GetSafeLink">
        <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="SafeImageUrl">
      <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
        <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="DisplayTitle">
      <xsl:call-template name="OuterTemplate.GetTitle">
        <xsl:with-param name="Title" select="@Title"/>
        <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
      </xsl:call-template>
    </xsl:variable>
    <div class="item">
      <div class="link-item">
        <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
        <a href="{$SafeLinkUrl}" title="{@LinkToolTip}">
          <xsl:if test="$ItemsHaveStreams = 'True'">
            <xsl:attribute name="onclick">
              <xsl:value-of select="@OnClickForWebRendering"/>
            </xsl:attribute>
          </xsl:if>
          <xsl:if test="$ItemsHaveStreams != 'True' and @OpenInNewWindow = 'True'">
            <xsl:attribute name="onclick">
              <xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>
            </xsl:attribute>
          </xsl:if>
          <xsl:value-of select="$DisplayTitle"/>
        </a>
      </div>
      <xsl:if test="string-length($SafeImageUrl) != 0">
        <div class="image-area-left">
          <a href="{$SafeLinkUrl}">
            <xsl:if test="$ItemsHaveStreams = 'True'">
              <xsl:attribute name="onclick">
                <xsl:value-of select="@OnClickForWebRendering"/>
              </xsl:attribute>
            </xsl:if>
            <xsl:if test="$ItemsHaveStreams != 'True' and @OpenInNewWindow = 'True'">
              <xsl:attribute name="onclick">
                <xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>
              </xsl:attribute>
            </xsl:if>
            <img class="image" src="{$SafeImageUrl}" title="{@ImageUrlAltText}">
              <xsl:if test="$ImageWidth != ''">
                <xsl:attribute name="width">
                  <xsl:value-of select="$ImageWidth" />
                </xsl:attribute>
              </xsl:if>
              <xsl:if test="$ImageHeight != ''">
                <xsl:attribute name="height">
                  <xsl:value-of select="$ImageHeight" />
                </xsl:attribute>
              </xsl:if>
            </img>
          </a>
        </div>
      </xsl:if>
      <div class="description">
        <xsl:value-of select="@Description" />
      </div>
      <div class="content">
        <xsl:value-of select="substring(@Content, 0, 200)" disable-output-escaping="yes"/>
        <a href="{$SafeLinkUrl}">...Read More</a>
      </div>
    </div>
  </xsl:template>
  

Important: Because we are cutting off the output rendering we potentially leave open HTML tags! See this post about a solution.

Unfortunately, there is no SharePoint GUI way to link our custom Item Style to the Content Query Web Part. The way around this, is to deploy a pre-configured Web Part file with our solution.

Add a Web Part to our project:

12

Delete the Web Part class file, since we are only interested in the .webpart file.

Add an empty (unconfigured) CQWP to your SharePoint Page and export this Web Part.

Open the exported file in notepad or Visual Studio and copy the contents.

Paste this in the .webpart file in our Visual Studio project.

  • Set the Title and Description to the required values.
  • Set the ItemLimit to 3

Modify the ItemXslLink property to link our custom style sheet:

<property name="ItemXslLink" type="string" >/Style%20Library/Xsl/CustomItemStyle.xsl</property>

Modify the ItemStyle property to match our custom style:

<property name="ItemStyle" type="string">ImageWithArticleContent</property>

Save the file.

Important: since our solution doesn’t need an assembly, we need to exclude it from the package. Select your project and set the “Include Assembly In Package” to false.

We can now deploy our solution and test our work.

13

14

You can download the Visual Studio 2010 solution here.

Advertisements

26 comments

  • ehh…how do i deploy it to sharepoint 2010 – do I need to compile the solution or ?

    • There is no need to compile this, since there is no code behind/ assembly. You just need to package and deploy the solution from Visual Studio or deploy the wsp itself.

  • the second news article are listed in bold…..

  • Pingback: “Code-easy” modifications for SharePoint 2010: Part 1, the Validating Email Field | All Things SharePoint

  • Pingback: Output Escaping Rich Text in a Content Query Web Part | All Things SharePoint

  • Hi Yuriburger…

    But how do I make the WSP? – I DL the.zip file..and there’s no .WSP in it..

    Could be that the article are the cause – …I think it was displaying fine on the page though..

  • Ok thanks …I first need to install SP on my local machine then..only have it in VM without Visual studio ….

    Mayby you could upload the wsp file to skydrive?

  • Hi,
    This is an interesting post, I have been building xsl files to get a similar effect in SPD. Do you have any idea how to automatically generate the “Add new item” link using XSL?

    • Hi, well this is something you probably do not want to do in the ItemStyle.xsl (since this would be rendered for every item in your query). You could however do this in the other xsl files or in a CEWP just beneath the CQWP. You can construct this link using javascript for instance, but the actual code depends on the type of item. This code I used for creating new Article Pages:


      var options =
      {
      url: "/sitename/_layouts/CreatePublishingPageDialog.aspx?IsDlg=1",
      title: "New Page",
      allowMaximize: false,
      showClose: true,
      width: 450,
      height: 200,
      dialogReturnValueCallback: silentCallback
      };

      function openDialogToCreatePage()
      {
      SP.UI.ModalDialog.showModalDialog(options);
      }

      function silentCallback(dialogResult, returnValue)
      {
      }

      function refreshCallback(dialogResult, returnValue)
      {
      SP.UI.Notify.addNotification('Operation Successful!');
      SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK);
      }

      Add Item

      • I see, I suppose you could create the newitem URL using the client object model to pick up the site site collection/subsite, etc…
        It’s interesting, I can see so much potential to customise SharePoint without using server-side code. Thanks for your post.

  • Hi there,

    I need to skip first item from the list. I use Content Query Web Part to show the list of all iems from the site Pages folder. I need the item published last newer show. Please help

    • Hi Sergiy,

      first you have to be sure there is no other way to accomplish this task, maybe through sorting/ filtering? If you really need to skip the first item during XSLT processing, it would mean you would also have to supply a custom ContentQueryMain.xslt. This piece of XSLT is responsible for the general markup of the CQWP and is aware of what row is being processed.

      If it is just costmetics, maybe you could hide the first row clientside?

      Hope this helps,

      Yuri

  • Does this .wsp support Blog posts for SP 2010?

    • Sure, just select the Content Type “Post” from the Web Part properties. You might have to adjust the XLST to your liking if you need a different layout. You would also have to decide what the rollup image needs to be. Hope this helps,

      Yuri

  • What would I need to alter in the above to get the same results rolling up blog posts from subsites? I have been searching for this solution for quite some time, and everything I find online doesn’t seem to work (I think most are more valid for 2007 and not so much SP2010). Every example of xsl templates and mods to webpart file I have tried just throughs errors for any and all CQWP). None seem to work; please help!

    • Not sure why your webpart would throw errors, if the XSL is correct. Does a normal (unmodified) CQWP work, because that should be able to roll up from subsites just fine?

  • Hi I got a error saying that OuterTemplate.GetSafeLink doesnot exist.
    Anyone can help on this?

  • Hello, I have a problem. When I deploy this solution to the GAC, I have the error saying: “The Web Part references an untrusted XSL file. Only XSL files contained in this site’s Site Library may be references.”
    I have found out one solution for this: “The final thing to do, is add a feature event receiver. Why? Because for some reason at least a publishing site collection otherwise refuses to let the custom CQWP use the custom xsl file, informing that it is not trusted. So this feature receiver corrects this problem by specifically assigning the sitecollection url for the webpart.”

    Did you use team site in this example? Is there any other solution for this problem?

    Thanks for posting this article, it is very helpfull 🙂

    • Marijana,

      this could be caused by the way you reference the XSLT file in your .webpart file. Make sure you use a relative path to the XSLT file like this: /Style%20Library/Xsl/CustomItemStyle.xsl

      A feature receiver should not be needed, so hopefully this helps.

      Y.

  • Hey yuriburger

    This is exactly what I want but my site needs to have 4 thumbnail images. I’m really new to sharepoint and struggling on my own. I appreciate I need to add more instances of “safeimageurl”, so “safeimageurl2”?? but what else?

  • Does your blog have a contact page? I’m having a tough time locating it but, I’d like to send you an email.
    I’ve got some suggestions for your blog you might be interested in hearing. Either way, great blog and I look forward to seeing it improve over time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s