Lee Kelleher’s Weblog

random posts on code, .NET, Umbraco and WordPress

WordPress Plugin Development: Beginner’s Guide, by Vladimir Prelovac

with one comment

wordpress-plugin-development-book 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”!

Written by Lee Kelleher

October 20, 2009 at 11:34 pm

Putting your ASP.NET Web Application in Maintenance Mode (using ISAPI_Rewrite)

with one comment

Prompted by @slace’s tweet:

Aaron Powell 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!

Written by Lee Kelleher

September 29, 2009 at 1:22 pm

How to convert NameValueCollection to a (Query) String [Revised]

with 2 comments

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());
}

Written by Lee Kelleher

September 19, 2009 at 11:08 pm

Posted in blog

Tagged with , , , , ,

Umbraco: Ultimate Picker XSLT Example

with 7 comments

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.

Ultimate Picker Data Type settings

Ultimate Picker Data Type settings

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).

Adding Ultimate Picker to a Document Type

Adding Ultimate Picker to a Document Type

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.

Selecting related content

Selecting related content

For the next part we get to the real meat of this blog post… the XSLT!

Create a new XSLT

Create a new 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.

Copy-n-paste the XSLT

Copy-n-paste the XSLT

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#xA0;"> ]>
<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.

Insert the macro into the template

Insert the macro into the template

Save the template and view the front-end page. We can now see the Related Content pages. Tada!

The end result! Related Content

The end result! Related Content

Written by Lee Kelleher

September 8, 2009 at 10:38 pm

Robots.txt Editor for Umbraco

leave a comment »

Following up on my recent post of using Robots.txt with Umbraco, I decided that it would be nice to be able to edit the robots.txt directly from the Umbraco back-end.  (Also I wanted to play a bit more with the BaseTree/ITree classes).

This afternoon I had a few hours to spare – actually I was procrastinating on another job, (don’t tell my client – I’ll finish it off later tonight) – so I got down to some coding.

The source-code is available on the Umbraco Extensions project (on CodePlex) and created a project page on the new Our Umbraco community website. (Don’t forget to give it some karma points! ;-p)

A direct download to the package installer (zip) is available here.

Very special thanks to Dave Kinsella for providing the Robot icon robot icon – although I know Dave, it was great proof that Twitter really does work! (Thanks to Dan too for his Johnny 5 attempt! 18480255 – Here was my attempt too!  18484040)

If you have any bugs, comments, feedback or suggestions – please feel free to get in touch with me via the Our Umbraco forums.

Written by Lee Kelleher

July 20, 2009 at 10:18 pm

Posted in blog

Tagged with , , , , , ,

Add YouTube Plug-in to Umbraco/TinyMCE

with 13 comments

Update: Following on from Dirk and Ismail’s comments, I found out that this YouTube plug-in does not work with TinyMCE v3 (which is the default richtext editor in Umbraco v4). This guide is written to works  for Umbraco v3 only, (using TinyMCE v2).

If you are looking for similar functionality in Umbraco v4, (TinyMCE v3), then all you need to do is enable the ‘Flash/media’ button in your Richtext editor data-type and embed the YouTube video like any other Flash movie (swf) – more details in my comment below.

/End of update.


Recently one of my clients wanted the ability to insert YouTube video clips directly into the TinyMCE editor within Umbraco.  My initial thought was to create a macro that would take a YouTube video URL, parse it and display it on the rendered (front-end) page.  Tim G has a blog post on how to do this on his Nibble blog, (love the Surfin’ Bird reference).

This approached worked fine, but we ran into problems trying to edit the YouTube video URL, along with that, my client had an additional step of selecting a macro, then entering the YouTube URL.

After a little researching, I eventually found a native YouTube plug-in for TinyMCE, (direct link to ZIP download).

Here is how I integrated in Umbraco:

  1. Extract the contents of the youtube.zip archive to your /umbraco_client/tinymce/plugins/youtube/
  2. In your /config/ folder, open the tinyMceConfig.config file.
  3. Insert the following lines:
    After the last <command /> entry, add…
    <command>
    	<umbracoAlias>mceYoutube</umbracoAlias>
    	<icon>../umbraco_client/tinymce/plugins/youtube/images/youtube.gif</icon>
    	<tinyMceCommand value="" userInterface="true" frontendCommand="youtube">youtube</tinyMceCommand>
    <priority>75</priority>
    </command>

    Then after the last <plugin /> entry, add…

    <plugin loadOnFrontend="false">youtube</plugin>
  4. Once the XML config entries are in place, you will need to restart the  Umbraco application – the quickest way of doing this is by modifying your Web.config, (literally open it, add a space, remove it, hit save).
  5. The YouTube button is now available in Umbraco. However, it’s not quite ready yet, there is still one more step!
  6. In your Umbraco back-end, go to the “Developer” section, expand the “DataTypes” folder and then select “Richtext editor”. In the “Buttons” section you should see a YouTube icon. Check the box next to the icon, and you’re done! If you don’t see the YouTube icon, then check that the did the config steps above, and/or check that the read permissions are set correctly on your /umbraco_client/ folder, (re-apply them if needs be).

Written by Lee Kelleher

July 16, 2009 at 3:07 pm

Posted in blog

Tagged with , , ,

Robots.txt for use with Umbraco

with 10 comments

I originally posted this over at the Our Umbraco community wiki. [Robots.txt for use with Umbraco] I am only posting it on my blog as a cross-reference. The Our Umbraco wiki version will evolve with the community’s experience and knowledge.

The Robots Exclusion Protocol has been around for many years, yet there are a lot of web-developers who are unaware of the reasons for having a robots.txt file in the root of their websites.

There have been many rumours around whether the bigger search engine crwalers (i.e. Googlebot) consider your website amateurish if you didn’t have a robots.txt – and if handled badly, could lead to your site being invisible on SERPs.

If you are happy for a crawler to crawl/index all of your website’s content, then you can use the following:

User-agent: *
Disallow:

However, when using Umbraco to power my websites, it is preferable to define which folders are accessible by the crawler. Personally, I would not like to see the contents of my /umbraco/ folder to be returned in Google’s SERPs.

Here is an example of the robots.txt that I have used on several Umbraco-powered websites.

# robots.txt for Umbraco
User-agent: *
Disallow: /aspnet_client/
Disallow: /bin/
Disallow: /config/
Disallow: /css/
Disallow: /data/
Disallow: /scripts/
Disallow: /umbraco/
Disallow: /umbraco_client/
Disallow: /usercontrols/
Disallow: /xslt/

From my perspective, there is no reason for a search engine crawler to be crawling/indexing files from any of the above folders – you may have a different perspective, to which you can amend your robots.txt accordingly.

For more information about the robots.txt standard, please refer to the official website: http://www.robotstxt.org/robotstxt.html

Written by Lee Kelleher

July 7, 2009 at 4:10 pm

Posted in blog

Tagged with , ,

Source Code Released for User Control File Tree Umbraco Package

leave a comment »

A few months ago I released the User Control File Tree package for Umbraco, this allowed developers to edit the front-end code/mark-up in their ASCX user-controls from the Umbraco back-end, (remotely), rather than editing them directly on the server via a text-editor.

Today I have released the source-code on the Umbraco Extensions project (on CodePlex) and created a project page on the new Our Umbraco community website.

If you have any comments, feedback or suggestions – please feel free to get in touch with me via the Our Umbraco forums.

Written by Lee Kelleher

June 29, 2009 at 10:55 pm

Posted in blog

Tagged with , , , ,

MySql data-source support for ELMAH

leave a comment »

Following on from my last post (a couple of months ago) about Integrating ELMAH with Umbraco, I received a comment if it was possible for ELMAH to use MySQL as a back-end data-source.

After a few emails back and forth between myself and Rajiv, (as well as Rajiv’s requests over at the ELMAH support group), the advice was to simpily develop some code that implemented the ErrorLog class, (making use of the 3 core methods: Log, GetError and GetErrors). Rajiv make a start with this code, but ran into a few problems, (mostly because he was trying to reference methods/properties that were internal to the core Elmah.dll).

Given that I’d said it was quick and easy to develop this code, I best put my money (or time in this case) where my mouth was. Fifteen minutes later the code was written… and then another hour later, the code was tested and bugs fixed.

For the MySQL connectivity, I used the MySql.Data.MySqlClient connector. For the MySqlErrorLog, I followed the code/design patterns that Atif had used in both the core SqlErrorLog and SQLiteErrorLog classes.

I have uploaded the Visual Studio (2008) solution to the ELMAH support group file repo (here is a direct link to the ZIP) – you will need to compile the DLL from the solution. If you need a pre-compiled DLL, then give me a shout, I’ll sort something out.

Once you have the compiled Elmah.MySql.dll, you will need to add following to your Web.config file:

In your <elmah> section, change the <errorLog> to: (if you haven’t installed ELMAH before, please see the WebBase)

<errorLog type="Elmah.MySqlErrorLog, Elmah.MySql" />

In the VS2008 solution, there is a script called MySql.sql – run this against your database to create the new table (called “elmah”) needed to log the errors/exceptions.

Then add your MySql connection string in the <connectionStrings> section:

<add name="ELMAH_MySql" connectionString="SERVER=localhost;DATABASE=elmah;USER=XXXX;PASSWORD=XXXX;" />

It is very important that you call the connection string “ELMAH_MySql” – as this is hard-coded in the backend. (Let me know if this is a problem, I think it could be moved to the <errorLog> section?)

Once you have saved the changes to your Web.config, you are all set to use MySql as your ELMAH back-end data-source!

Known issues:

  • The “Sequence” column in the “elmah” table should be auto-incremental, but it isn’t! (I don’t claim to know enough about MySql to have multiple auto-incremental columns) – any suggestions?
  • The MySql connection string is hard-coded as “ELMAH_MySql
  • The code will only compile with .NET 2.0 and above (no support for .NET 1.0 or 1.1 – sorry)

I have mentioned to Atif about the possibility of including MySql support to the ELMAH core – to which he is willing to do, only if I support it. Which I will be happy to do – but only if there is a need for it.  So my suggestion would be, if you would like to see MySql support in the ELMAH core – then raise a feature request on the ELMAH Google Code site. Once it gains momentum, we’ll take it from there.

Written by Lee Kelleher

June 29, 2009 at 11:28 am

Posted in blog

Tagged with , , , , , ,

Integrating ELMAH with Umbraco

with 17 comments

I have a few Umbraco projects that have a lot of custom .NET code, mostly in they are in the form of user-controls and XSLT extensions.  As far as I’m aware Umbraco doesn’t have an extendable mechanism for exception handling and sending out notification emails, (there is the umbraco.BusinessLogic.Log, which writes to the umbracoLog table in the database, but that’s all).

Initially I looked at Tim Gaunt’s Advanced Error Reporting – a great drop-in solution that does exactly what it says on the tin!  Whilst reading the comments on Tim’s blog, Simon Dingley reminded me of the ELMAH project – which has been one of those web-applications that you keep meaning to try out, but never get around to.

What is ELMAH?

ELMAH (Error Logging Modules and Handlers) is an application-wide error logging facility that is completely pluggable. It can be dynamically added to a running ASP.NET web application, or even all ASP.NET web applications on a machine, without any need for re-compilation or re-deployment.

So I decided to see how nicely it plays with Umbraco… the result, it plays very nicely indeed.

If you are interested, here’s how…

  1. Download the latest ELMAH binary release (1.0 Beta 3 at the time of writing [direct link]) from the Google Code project page. (http://code.google.com/p/elmah/)
  2. Extract the files from the ZIP.
  3. Select the DLLs from the “/bin/” folder, for Umbraco you’ll be using the DLL from “/bin/net-2.0/Release/“.  For the benefit of this post, I decided to use the SQLite option to store the error logs in a database. I could easily have used the SQL Server or VistaDB options.
  4. Drop the DLLs into the “/bin/” folder of your Umbraco installation.
  5. Open the web.config of your Umbracoo installation and add the following lines:

Add the following to your <configSections> section:

<sectionGroup name="elmah">
	<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah"/>
	<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah"/>
	<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah"/>
	<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah"/>
</sectionGroup>

Add the following just after the </configSections> section:

<elmah>
	<security allowRemoteAccess="yes" />
	<errorLog type="Elmah.SQLiteErrorLog, Elmah" connectionStringName="ELMAH.SQLite" />
	<errorMail from="no-reply@domain.com" to="webmaster@domain.com" />
</elmah>

Add the following to your <connectionStrings> section, (if you have one, otherwise create one):

<add name="ELMAH.SQLite" connectionString="Data Source=~/data/errors.s3db"/>

In the <httpModules> section, add this:

<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah"/>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah"/>

… and finally, in the <httpHandlers> section, add this:

<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah"/>

If you run into any trouble, there is a more detailed guide on Setting Up ELMAH from DotNetSlackers.

By now you should have ELMAH up and running.  Open up your web-browser and go to http://localhost/elmah.axd, (obviously replace “localhost” with whatever your hostname is). You should see the ELMAH Error Log page.  Since this is open to the public, you may want to secure it, see the Securing Error Log Pages article for further details.

The last part is to integrate the ELMAH Error Log page into the Umbraco back-end.  I created a new user-control in the “/usercontrols/” folder called “ELMAH.ascx”, using the following HTML:

<%@ Control Language="C#" %>
<iframe height="98%" width="100%" scrolling="auto" src="elmah.axd" style="margin-top:5px;"></iframe>

Then in the “/config/Dashboard.config” configuration file, I added a new section for the developer area.

<section>
	<areas>
		<area>developer</area>
	</areas>
	<tab caption="Error Logging Modules and Handlers for ASP.NET">
		<control>/usercontrols/ELMAH.ascx</control>
	</tab>
</section>

Now in the Umbraco back-end the developer area looks like this.

ELMAH in Umbraco

I have been very impressed with how well ELMAH functions.  Aside from the essential email notifications, the RSS feeds are a great bonus!

kick it on DotNetKicks.com

Written by Lee Kelleher

April 23, 2009 at 9:13 pm

Posted in blog

Tagged with , , , ,