Display a user’s picture in the content query web part

As I detailed in my last post, it’s possible to display a user’s profile photo in a data form web part. I attempted to use a similar technique to display a photo in some custom XSL for a content query web part (CQWP) and unfortunately ran into a brick wall. After exploring many options, and digging through the XML files on the server to see if I could replicate how it was returned out of the box, I came to the conclusion that it may well be quicker to try this through the (new to SharePoint 2010) client object model.

This post shows one possible way of using ECMAScript to display a user’s photo with custom XSL for the content query web part.

First I created a new XSL template for my Extended Content Query Web Part as I detail in a previous post. Then I replicate the majority of an out of the box template to create a HTML output which has the appropriate identifiers for me to update via script. Importantly, I also reference my custom .js file in this template and jquery, with a bit of check/ hack to make sure it’s only loaded once. The finished XSL template looks like this:

  <xsl:template name="TitleWithAuthorImage" match="Row[@Style='TitleWithAuthorImage']" mode="itemstyle">  	  	
  	<!-- Load my custom script, stored in XSL Style Library, and JQuery from Google -->
  	<script type="text/javascript">
  		if (document.getElementById('JQuery') == null) {
  			var jq = document.createElement('script');
  			jq.type = 'text/javascript';
  			jq.id = 'JQuery';
  			jq.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js';
  			var sc = document.getElementsByTagName('script')[0];
  			sc.parentNode.insertBefore(jq, sc);
  		}
  		if (document.getElementById('ExternalJS') == null) {
  			var extjs = document.createElement('script');
  			extjs.type = 'text/javascript';
  			extjs.id = 'ExternalJS';
  			extjs.src = '/Style%20Library/XSL%20Style%20Sheets/ExtendedItemStyleJS.js';
  			var s = document.getElementsByTagName('script')[0];
  			s.parentNode.insertBefore(extjs, s);
  		}
   	</script>  	  	
  	<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="DisplayTitle">
        <xsl:call-template name="OuterTemplate.GetTitle">
            <xsl:with-param name="Title" select="''"/>
            <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
            <xsl:with-param name="UseFileName" select="1"/>
        </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="AuthorID">
    	<xsl:value-of select="ddwrt:UserLookup(string(@Author) ,'ID')" />
  	</xsl:variable>
	<div class="item link-item">
       <div class="image-area-left">
           <img alt="{@Author}">
				<xsl:attribute name="class">image author-image</xsl:attribute>
				<xsl:attribute name="rel"><xsl:value-of select="$AuthorID"/></xsl:attribute>
			</img>               
       </div>
       <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>
	</div>
  </xsl:template>

The script that I’ve used (thanks to this post from Ton Stegeman and to Ben Gallienne for patiently answering my noddy scripting questions!) looks like this:

$(document).ready(function() {
	// Create an array of unique user id's scraped from img rel tags
	var IDs = new Array();
	$('.author-image').each( function() {
		if($.inArray($(this).attr('rel'),IDs ) == -1) {
			IDs.push($(this).attr('rel'));		
		} 
	});
	
	// When sp.js is loaded run our function to display images
	ExecuteOrDelayUntilScriptLoaded(function() {DisplayAuthorImage(IDs);}, 'sp.js')	
});

function DisplayAuthorImage(userIds)
{
	// Grab the user information list and pass in first element of the IDs array
	var clientContext = new SP.ClientContext.get_current();
	var web = clientContext.get_web();
	var userInfoList = web.get_siteUserInfoList();
	var camlQuery = new SP.CamlQuery();
	camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'ID\'/>' +
							'<Value Type=\'Number\'>' + userIds[0] + '</Value></Eq>' +
							'</Where></Query><RowLimit>1</RowLimit></View>');
	this.userId = userIds[0];
	this.userIds = userIds;
	this.collListItem = userInfoList.getItems(camlQuery);
	clientContext.load(collListItem);
	clientContext.executeQueryAsync(
		Function.createDelegate(this, this.onQuerySucceeded),
		Function.createDelegate(this, this.onQueryFailed));	
}

function onQuerySucceeded(sender, args)
{
	// Grab the picture value and set an images with the matching rel tag to the source
	var item = collListItem.itemAt(0);
	var pictureUrl = (item.get_item('Picture') != null) ? item.get_item('Picture').get_url() : '/_layouts/images/person.gif';	
	var imageTags = $('div.image-area-left	 img[rel='+userId+']').attr('src',pictureUrl);

	// Recurse into the DisplayAuthorImage function after removing first elementof IDs array
	if (userIds.length > 1)
	{
		userIds.shift();
		DisplayAuthorImage(userIds);
	}
}

function onQueryFailed(sender, args)
{
	alert('Failed to display author images. \nError: ' + args.get_message() + '\nStackTrace: ' + args.get_stackTrace());
}

As you can see it’s a fairly straight forward piece of script which simply gets the appropriate data from the user information list and then finds and sets the source of all the images appropriately. I’ve used JQuery to help make things a bit easier for me and I’m currently loading that from Google, but it could be stored locally easily. As I’m restricting myself to working within ItemStyle.xsl I’m also not loading the scripts in exactly the place I think I would choose too – hence the check to see if it’s already in the page before loading.

Using this script in a CQWP to return a simple list of documents results in something like this. As you can see we now have (in this case) the author’s profile picture coming through! And if there is no picture then it drops in a nice placeholder image from the layouts folder.

CQWP COM User Photo Screenshot

Challenge: It still feels like it should be possible to get the value back as a field in the content query web part without having to resort to script. I can’t work it out but maybe somebody else out there can?

share and enjoy
  • Print
  • Twitter
  • Digg
  • del.icio.us
  • StumbleUpon
  • Yahoo! Buzz
  • Google Bookmarks
  • Facebook

24 comments to Display a user’s picture in the content query web part

  • […] Web Part, and in the end had to settle for using some javascript and the client object model as explained in a different post. share and enjoy Tags: DVWP, […]

  • Awesome stuff Glyn! That’s conceptually how I thought it would be done based on our earlier discussions but great work to get it working!

  • Sai

    Hi Glyn,

    I have to show logged in user photo in site home page. Is it possible with contenet query webpart? We are suing sharepoint 2010.

    Thanks in advance.

    Sai

    • Hi Sai,

      Unfortunately I don’t think the CQWP is what you need to do this – because if a user has not added/ modified something on the site then there will be nothing to query…

      I can’t think of any of the OOB web parts that are going to let you do this either – but I do think this would be possible using the client object model if you wished. I’ve never done it but I imagine it’s not too hard to get the current user and then their properties (e.g. photo) and write them out to the screen.

      HTH

  • Ruben

    I was looking for something like this but I have a question, how can I resize the profile photo?

    • Hi Ruben – the profile photos are available in a few different sizes that are automatically generated when a new photo is uploaded. Here’s a good post on the Microsoft Social Computing Team Blog on how they are managed and how to access them.

      • Ruben

        Thanks for the reply and by the way, how can I do when the picture is taken in ‘var pictureUrl’ to resizing it [onQuerySucceeded(sender, args)]? -either of the images (person.gif/profile picture)-

  • Ruben

    I solved my problem for now, only with add an “xsl:attribute” — width: 72px; height: auto; — in the tag

  • Why not use the People Search Core Results webpart and customize the XSL.
    There’s no need for the script then.

    Look for useful xsl templat at: http://spxslt.codeplex.com/documentation

  • Hi Hans – I agree that the People Search Core Results web part would be the right way to go about this if you were simply interested in the people. However, this is example is more for ‘regular’ uses of the CQWP, such as aggregating a list of documents, and then integrating the person image alongside the results.

    HTH

  • jagadeesh

    i want print attachment image directly in data view web part.

    i used the below code snippet, it is displayed image name, but i need to print image here.

    server
    Attachments
    Display
    true

    I tried upto my level but it’s not getting displayed…

  • Dattatraya Bandgar

    Hi Glyn,

    I can directly display user pic. in my dataview using following code.

    I think there is no need to too much of Jquery code. This is working for me.

    • Tanuja

      I am using CQWP Userlookup login name is blank and hence not able to fetch user picture.
      Also picture loading is slow and random. What is the solution to display user profile picture?

  • Dattatraya Bandgar

    In previous post i cant see my code posted hence added below

    <img border="0" src="{@Author.picture}" />

    note : please replace < with and " with “

  • I solved the problem in another way, by overriding the CQWP; I added a custom XSLT function in order to be called by the XSLT. The function get the user ID and the property to be retrieved. If anyone is interested in this solution, I’ll be glad to share the details.

    • Hi Roberto – that sounds good. Feel free to link to a blog post or whatever on here if you want to share!

    • Hi Roberto,

      I’m much interested in the solution you’ve indicated – custom XSLT function to get Picture of Author’s post (i.e. Picture of some User) within CQWP.

      BTW, I’ve used the solution suggested by Glyn Clough in this post and it worked fine for a while until I’ve activated User Profile Sync Service to import Pictures (and other users’ info) from AD. Then the call for:
      item.get_item(‘Picture’)
      (that appears within code of the above solution in this post) always(!) returns NULL. Do you, or anybody else reading this reply, have any clue or whatsoever why that happens or how to solve it.

      Any help will be much appreciated.

      Thanks

      Itzik

      Any help will be much appreciated.

  • Andrew Foster

    Hi Glyn (or other users of this solution!)

    using this solution to provide simple links through to a users profile based on their name as well as display a picture.

    However,occastionally a picture is not found, or a link blank even though that user exists, has a profile picture and is present in the site hidden user list.

    This appears to be random and not isolated to one particular user property, but the method that we are using is the one highlighted above where the ID of a user is utilised.

    Is this an issue with the user lookup function or something that you or others have discovered in the above solution?

    any help would be greatly appreciated

  • Andrew – great post – can you suggest how this can be done via Content By Search?

    I’m interested in displaying the profile picture associated with the user who posted the list item or a blog post (e.g. the picture of the user that created the object.) If I were to follow the display template route, what is your recommendation on how this can be achieved? This is what I get now.

  • Matthew Cornish

    Hi Glyn,

    Relatively new to SharePoint. I understand most of what you’re doing above with the exception of the camlQuery / DisplayAuthorImage() stuff. Am I able to use this method to get other information such as department, phone number etc? If so, can you point me in the right direction as to how please? I’m assuming all this would happen in onQuerySucceeded()? Going to have a play on a test server…

    Many thanks.

  • Matthew Cornish

    Hi Glyn,

    As an update (and perhaps useful for others) I was able to add the following into you onQuerySucceeded() function:

    var userDepartment = item.get_item(‘Department’);
    var userTitle = item.get_item(‘JobTitle’);

    …and these values were given to me, which was awesome 🙂 I’m using the following page as a reference for field names (although removing “SPS-” from those affixed with that):

    http://technet.microsoft.com/en-us/library/hh147513(v=office.14).aspx

    …and of course I can use jQuery to move these values into the parts of my template as required.

    The main issue I’m having now is that calling jQuery within the template like you are isn’t working every time. Annoyingly half the time it just doesn’t load (be it from google api or from locally on the server). Any thoughts as to why? For now I’m loading jQuery from a content editor web part above my CQWP while testing.

    Thank you.

  • Saran

    I have used this. I am getting an error on the extendedstyle.js – “Object Expected”… am I missing something?

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>