How to use umbraco.library GetMedia in XSLT for Umbraco v4.5
This is a quick follow-up on my previous blog post: “How to use umbraco.library GetMedia in XSLT“. At the request of fellow Umbraco South-West UK developer, Dan, that I should update the code snippets for the new XML schema in Umbraco v4.5+
First a quick notice; if you are using v4.5.0, then please upgrade to v4.5.1, as there was a tiny bug in GetMedia that caused great confusion and headaches – you have been advised!
Without further ado, the updated XSLT snippet that you came here for…
<xsl:template match="/">
<xsl:variable name="mediaId" select="number($currentPage/mediaId)" />
<xsl:if test="$mediaId > 0">
<xsl:variable name="mediaNode" select="umbraco.library:GetMedia($mediaId, 0)" />
<xsl:if test="$mediaNode/umbracoFile">
<img src="{$mediaNode/umbracoFile}" alt="[image]" height="{umbracoHeight}" width="{umbracoWidth}" />
</xsl:if>
</xsl:if>
</xsl:template>
Any questions? Come join us over at Our Umbraco… we are a friendly bunch!
ASP.NET System Information for Umbraco
Released a new Umbraco package today, that integrates the ASP.NET System Information Prober into the Umbraco back-office.
What is the ASP.NET System Information Prober? It is a single page that tries to get as much useful hosting information about your web-server. The concept is similar to PHP’s native phpinfo() function.
Installing the package will add a new node tree to the developer section.
Here is a quick demo video: http://screenr.com/2YC
Installing this package will add a new node tree to the developer section.
You can download the ASP.NET System Information for Umbraco package from the Our Umbraco community site.
Working with XSLT using new XML schema in Umbraco 4.1
Most of the Umbraco community are aware that the XML schema in the upcoming Umbraco 4.1 release has changed.
Instead of each document being a node element, the element name is the node-type alias, same with property values; they no longer use data elements with alias attributes. Here is a quick example, comparing the old/legacy with the new:
<node id="1066" parentID="-1" level="1" nodeName="Home" ... nodeTypeAlias="Homepage" path="-1,1066"> <data alias="bodyText"><![CDATA[<p>Welcome to my homepage.</p>]]></data> </node>
<Homepage id="1066" parentID="-1" level="1" ... nodeName="Home" path="-1,1066" isDoc="">
<bodyText><![CDATA[<p>Welcome to my homepage.</p>]]></bodyText>
</Homepage>
Obviously for long-time Umbraco developers this will require a small shift in mindset, as we are way too familiar with writing XPath queries like;
$currentPage/descendant-or-self::node[string(data[@alias='umbracoNaviHide']) != '1']
… which will need to be rewritten to;
$currentPage/descendant-or-self::*[umbracoNaviHide != '1']
Not that it’s a difficult thing to change/update, but I can see a lot of questions being asked on the Our Umbraco forum.
Since there are a lot of existing Umbraco packages that use the current, (soon to be legacy) XML schema, it might be worthwhile making use of XSLT itself to convert the new back to the old – in order to keep the existing XSLT templates working. Here’s a quick example:
<!-- ROOT element --> <xsl:template match="root"> <xsl:element name="root"> <xsl:apply-templates select="child::*" /> </xsl:element> </xsl:template> <!-- NODE elements --> <xsl:template match="*[count(@isDoc) = 1]"> <xsl:element name="node"> <xsl:attribute name="nodeTypeAlias"> <xsl:value-of select="local-name()"/> </xsl:attribute> <xsl:copy-of select="@*" /> <xsl:apply-templates select="child::*" /> </xsl:element> </xsl:template> <!-- DATA elements --> <xsl:template match="*[count(parent::*) > 0 and count(@isDoc) = 0]"> <xsl:element name="data"> <xsl:attribute name="alias"> <xsl:value-of select="local-name()"/> </xsl:attribute> <xsl:copy-of select="text()" /> </xsl:element> </xsl:template>
These templates would be used to transform the new schema/structure back to the old legacy schema/structure, like so:
<xsl:variable name="legacyFragment"> <xsl:apply-templates select="$currentPage/ancestor::root" /> </xsl:variable> <xsl:variable name="legacyRoot" select="msxml:node-set($legacyFragment)/root" /> <xsl:variable name="legacyCurrentPage" select="$legacyRoot/descendant-or-self::node[@id = $currentPage/@id]" />
Since you can’t modify a variable’s value in XSLT, it would be a case of replacing all the “$currentPage” references with “$legacyCurrentPage” (or whatever you decided to call it). But in all honesty, if you are going to start modifying your XSLT, then it would be better to refactor the XPath statements to use the new schema!
Personally, I’m looking forward to using the new XML schema in Umbraco 4.1, the structure makes more sense from a semantic perspective – and I am told it will have performance gains on the XSLT processor.
Bit.ly Url Shortener DataType for Umbraco
Over the weekend, I coded up a little treat… a Bit.ly Url Shortener data-type for Umbraco!
The new data-type lets you shorten your Umbraco page URLs using the Bit.ly API service.
For more information, go to the project page over on Our Umbraco.
Updated Robots.txt Editor for Umbraco
Last night I released version 2 of the Robots.txt Editor for Umbraco.
Changes & new features:
- Restructured the package files, they all live in a folder called “robots-txt” (still under the /umbraco folder – but self-contained)
- Errors are now displayed using the Feedback control (as opposed to the Speech Bubble in the bottom-right corner).
- Robots.txt editor has buttons for adding new User-Agent and Disallow rules, as well as comment/uncomment functionality.
- Changed the Robot icon… courtesy of Mozilla Firefox’s “about:robots” favicon.
Hope you all enjoy the update… if you come across any bugs or ideas for a future release, please let me know via the our.umbraco forum.
How to use umbraco.library GetMedia in XSLT
From time to time I notice a reoccurring post over at the Our Umbraco forum; how to display an image (from the Media section) in XSLT?
A quick answer can be found on the Our Umbraco wiki for the umbraco.library GetMedia method.
For most uses, the last example in the wiki works great. But I want to show you a “super safe” way of dealing with GetMedia in XSLT.
Where I find a lot of the examples go wrong is that they make the assumption that a media node (XML) is returned from the GetMedia call, e.g.
<xsl:value-of select="umbraco.library:GetMedia($currentPage/data[@alias='mediaId'], 'false')/data[@alias='umbracoFile']" />
If the ‘mediaId’ property didn’t contain either a numeric value or a valid media node id, then it would return null … meaning that the following “/data” would throw an Exception! (Displaying “Error parsing XSLT file” message on the front-end.) Not what you or your users want to see!
In order to consider any user inputs, like media IDs not being selected, or even a referenced media node is deleted in the back-office, here is the “super safe” approach:
<xsl:template match="/">
<xsl:variable name="mediaId" select="number($currentPage/data[@alias='mediaId'])" />
<xsl:if test="$mediaId > 0">
<xsl:variable name="mediaNode" select="umbraco.library:GetMedia($mediaId, 0)" />
<xsl:if test="count($mediaNode/data) > 0">
<xsl:if test="string($mediaNode/data[@alias='umbracoFile']) != ''">
<img src="{$mediaNode/data[@alias='umbracoFile']}" alt="[image]">
<xsl:if test="string($mediaNode/data[@alias='umbracoHeight']) != ''">
<xsl:attribute name="height">
<xsl:value-of select="$mediaNode/data[@alias='umbracoHeight']" />
</xsl:attribute>
</xsl:if>
<xsl:if test="string($mediaNode/data[@alias='umbracoWidth']) != ''">
<xsl:attribute name="width">
<xsl:value-of select="$mediaNode/data[@alias='umbracoWidth']" />
</xsl:attribute>
</xsl:if>
</img>
</xsl:if>
</xsl:if>
</xsl:if>
</xsl:template>
Here’s what happens:
- The “mediaId” is pulled from a property of the “currentPage” and cast as a number. Optionally the “mediaId” could be passed in via a macro parameter, or somewhere else?
- The first condition checks the the “mediaId” is numeric, and greater-than zero.
- The “mediaId” is passed through to “GetMedia”, along with the false flag to only pull-back the required node (not it’s children, for Folder media items).
- We check if the media node has any child “data” elements – which contain the data about the image/media.
- Then we check if the “umbracoFile” property has any data – if not, then there is no point displaying an image.
- There are extra conditions for the “height” and “width” properties – these are optional.
Personally, I add an “altText” property to the Image media-type … and use that in the XSLT – again this is optional, but strongly recommended!
I can see how this “super safe” approach is overkill – especially compared with a single line of XSLT … but from my experience, it’s better to be safe than sorry – especially when dealing with user data-input – your assumptions and expectations of how users will use the system aren’t always correct!
Update: OK, I agree the extra “if” statements are overkill… so here’s a condensed version – assuming that the “umbracoHeight” and “umbracoWidth” properties are always there…
<xsl:template match="/">
<xsl:variable name="mediaId" select="number($currentPage/data[@alias='mediaId'])" />
<xsl:if test="$mediaId > 0">
<xsl:variable name="mediaNode" select="umbraco.library:GetMedia($mediaId, 0)" />
<xsl:if test="count($mediaNode/data) > 0 and string($mediaNode/data[@alias='umbracoFile']) != ''">
<img src="{$mediaNode/data[@alias='umbracoFile']}" alt="[image]" height="{$mediaNode/data[@alias='umbracoHeight']}" width="{$mediaNode/data[@alias='umbracoWidth']}" />
</xsl:if>
</xsl:if>
</xsl:template>
WordPress Plugin Development: Beginner’s Guide, by Vladimir Prelovac
I have recently finished reading Vladimir Prelovac book on WordPress plug-in development, (WordPress Plug-in Development: Beginner’s Guide, Packt Publishing, 2009).
As an experienced WordPress plug-in developer, I was pessimistic at the start – there is already a wealth of documentation and detailed tutorials on the web, who would need a book? However with Vladimir being a well-respected WordPress plug-in developer, I was curious to see his approach on the subject, and you never know – I may learn a thing or two? (hint: I did!)
WordPress Plug-in Development (Beginner’s Guide) is a great introduction to the WordPress platform, the plug-in architecture and the ever-growing community surrounding it.
The first thing I noticed was that the book is centred around WordPress 2.6, (at the time of writing the latest version is 2.8.4, with 2.9 due out very soon), unfortunately all of the screenshots for the admin back-end are outdated, since there was a complete overhaul to the design in version 2.7. This is no fault of the author, but an example of how fast paced the WordPress developer community is. Luckily, the principles that Vladimir explains are focused on the core WordPress functionality, which are solid and stable.
Throughout the book, Vladimir encourages you to “hack” around with code, which for me is a great experience – it’s how I learnt to code! As the tagline of the book states: “Learn by doing: less theory, more results“.
There is also a great awareness of 3rd-party applications, libraries and resources, (like Digg, jQuery, Poedit, etc), which is fine for experienced web-developers, but for beginners – it will open up a world of exciting developments! Thinking back to when I first played with jQuery… or pulling my photos back from Flickr’s API… so cool!
The very nice people at Packt Publishing have a sample chapter available on-line; Chapter 2: Social Bookmarking, covers how to develop your own Digg button for your blog.
Vladimir covers all areas of WordPress development, from action and filter hooks to shortcodes and widgets to localisation (i18n & L10n). Even I didn’t know about the “wp_localize_script” function!
The mantra of the book is to leverage WordPress whenever you can, try not to re-invent the wheel. Which reminds me of Peteris Krumins‘ blog quote: “good coders code, great reuse”!
As the book progresses, each chapter’s example plug-in becomes more challenging and complex. The focus on localisation over the last few chapters was most interesting for me, as it is (probably) the least understood concept in WordPress plug-in development!
Often it is easy for WordPress users to take plug-in functionality for granted, this book exposes the amount of thought, planning, design and skill that goes into every (popular) WordPress plug-in.
In summary, WordPress Plug-in Development (Beginner’s Guide) is perfect for anyone who is interested in extending the functionality of WordPress – it goes without saying that a little PHP knowledge is required, but that isn’t a show-stopper, you can learn whilst you “hack”!
Putting your ASP.NET Web Application in Maintenance Mode (using ISAPI_Rewrite)
Prompted by @slace’s tweet:
i wish there was a way to use app_offline but still view from certain ip’s
I replied with a suggestion that we’ve used in the past. Aaron said I should blog about it… so here I am (again)!
A while ago we needed to do an Umbraco upgrade (from v3 to v4) on a production server – in my opinion it was a pretty major upgrade on a live site, we had done a couple of test upgrades on dev and staging, all was successful. But since there was various parts of the site that we need to regression test, I felt it best to take the entire site offline whilst we upgraded.
Usually creating an “App_Offline.htm” page in the root of your web app is enough to take it offline. However that was no good for testing… so what to do?
This is where ISAPI_Rewrite is your best friend, (or .htaccess to be precise). We needed to configure the site to allow access for us and redirect everyone else to a “Site under maintenance” page. I found a few examples across the web, but to save you all that hassle, here are the .htaccess rules that we use:
# BEGIN Maintanence Mode
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !/offline.html$
RewriteCond %{REMOTE_ADDR} !^82\.13\.23\.230$
RewriteRule ^(.*)$ /offline.html [R=302,L]
</IfModule>
# END Maintanence Mode
What does it do? The first “RewriteCond” rule checks that you are not requesting the “offline.html” page (otherwise you would end up in a constant loop!) The second “RewriteCond” checks the IP address of the visitor – in my case it was “82.13.23.230″ (remember to escape the dots). If those two rules aren’t satisfied, then the “RewriteRule” is used, redirecting the visitor to the “offline.html” page.
As always, I am open to any suggestions or improvements!
How to convert NameValueCollection to a (Query) String [Revised]
Following on from a comment on my previous post about converting a NameValueCollection to a (query) string – I have finally got around to revising my code snippet. Now the method will handle same key multiple values, (it no longer comma-separates them).
I have also added extra parameters so that you can define your own delimiter (since the HTTP specification says that you can use both ampersands & and semicolons ;) and there is an option for omitting keys with empty values.
/// <summary>
/// Constructs a NameValueCollection into a query string.
/// </summary>
/// <remarks>Consider this method to be the opposite of "System.Web.HttpUtility.ParseQueryString"</remarks>
/// <param name="parameters">The NameValueCollection</param>
/// <param name="delimiter">The String to delimit the key/value pairs</param>
/// <returns>A key/value structured query string, delimited by the specified String</returns>
public static String ConstructQueryString(NameValueCollection parameters, String delimiter, Boolean omitEmpty)
{
if (String.IsNullOrEmpty(delimiter))
delimiter = "&";
Char equals = '=';
List<String> items = new List<String>();
for (int i = 0; i < parameters.Count; i++)
{
foreach (String value in parameters.GetValues(i))
{
Boolean addValue = (omitEmpty) ? !String.IsNullOrEmpty(value) : true;
if (addValue)
items.Add(String.Concat(parameters.GetKey(i), equals, HttpUtility.UrlEncode(value)));
}
}
return String.Join(delimiter, items.ToArray());
}
Umbraco: Ultimate Picker XSLT Example
Chatting with Dan (my partner-in-code at Bodenko) about the Ultimate Picker data-type in Umbraco, we realised that we couldn’t find any examples of how to use the data in XSLT. So obviously needing an excuse to write-up a new blog post, here we go.
If you need a quick overview about the Ultimate Picker data-type, see Tim Geyssens’ blog post.
For my example, using a default Umbraco install (with Runway), we will create a new data-type using the Ultimate Picker, (let’s call it “Runway Textpage Picker“), we select the ‘Database datatype‘ to be “Nvarchar”; the ‘Type‘ as a “List Box”; The ‘Parent nodeid‘ is “1048″ and the ‘Document Alias‘ filter is “RunwayTextpage” – we also tick the ‘Show grandchildren‘ checkbox.
Next, we will assign the new “Runway Textpage Picker“ data-type to a property of the Runway Textpage, we will call it “Related Content“. For more information about working with document types, please refer to the our.umbraco.org wiki page, (Working with document types).
Once the document-type is saved, we move on to the ‘Content‘ section. Select any of the Runway Textpages. You should now see the ‘Related Content‘ property panel, containing a list of all the other Runway Textpages. To select multiple items, hold-down the CTRL (or Command on the Mac) button. When you have finished, click the ’Save and publish‘ button.
For the next part we get to the real meat of this blog post… the XSLT!
Create a new XSLT called “RelatedContent” (without the .xslt extension), keep it ‘Clean’ and tick the ‘Create Macro‘ checkbox. Next a quick short-cut for you; copy-n-paste the following XSLT into the main editor window.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library"
exclude-result-prefixes="msxml umbraco.library">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<xsl:template match="/">
<xsl:variable name="preNodes">
<xsl:variable name="relatedContent" select="$currentPage/data[@alias='RelatedContent']" />
<xsl:variable name="nodeIds" select="umbraco.library:Split($relatedContent, ',')" />
<xsl:for-each select="$nodeIds/value">
<xsl:copy-of select="umbraco.library:GetXmlNodeById(.)"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="nodes" select="msxml:node-set($preNodes)/node" />
<xsl:if test="count($nodes) > 0">
<div class="related-content">
<h3>Related Content</h3>
<ul>
<xsl:for-each select="$nodes">
<li>
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:value-of select="@nodeName" />
</a></li>
</xsl:for-each></ul>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Here’s a quick explanation of what is happening in the XSLT. We are provided with a list of comma-separated nodeIds from the Ultimate Picker, which we need to parse/split – then pull back the XML node data, then we can transform it however we like!
The way we do this is 2-tiered, first we must loop through the comma-separated list, pulling back the XML node for each nodeId, adding it to an XSLT variable. Doing this will cause the XSLT variable to be a fragmented node-tree, which means that we need to convert the node-tree fragment into a node-set. (*Note: there are a gazillion ways to skin a cat – suggestions are welcome – this method works for me).
Once we have the complete XML node-set, we can transform into whatever HTML we like.
Now that we are done with the XSLT, we can edit our template in the ‘Settings‘ section. Select the “Runway Textpage” template. Somewhere after the ‘bodyText‘ property item, click on the ‘Insert Macro’ button. From the ‘Choose a macro‘ drop-down, select the ‘Related Content‘ option – this will add the macro code to the template.
Save the template and view the front-end page. We can now see the Related Content pages. Tada!









