<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Keith's Blog</title>
	<atom:link href="http://www.keithlawless.com/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.keithlawless.com</link>
	<description>Random thoughts on a variety of subjects</description>
	<lastBuildDate>Fri, 19 Mar 2010 01:43:10 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Ubertwitter Beta 7.1 Mini-Review</title>
		<link>http://www.keithlawless.com/?p=181</link>
		<comments>http://www.keithlawless.com/?p=181#comments</comments>
		<pubDate>Fri, 19 Mar 2010 01:32:49 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=181</guid>
		<description><![CDATA[I've been playing with Ubertwitter for the last few days and wanted to share some first impressions. 
Pros:

Tons of features.
Support for photo and video uploads. 
Location awareness. 
A good looking and readable GUI even on my wee Pearl.

Cons:

The application setup presents you with a seemingly endless series of screens, with no indication of when you're [...]]]></description>
			<content:encoded><![CDATA[<p>I've been playing with <a href="http://www.ubertwitter.com/">Ubertwitter</a> for the last few days and wanted to share some first impressions. </p>
<p>Pros:
<ul>
<li>Tons of features.</li>
<li>Support for photo and video uploads. </li>
<li>Location awareness. </li>
<li>A good looking and readable GUI even on my wee Pearl.</li>
</ul>
<p>Cons:
<ul>
<li>The application setup presents you with a seemingly endless series of screens, with no indication of when you're going to be done.</li>
</ul>
<p>Recommended. Free download with ads, or ad-free with a paid annual subscription. BlackBerry only.
<p><a href="http://www.keithlawless.com/wp-content/uploads/2010/03/Capture16_24_38.jpg"><img class="alignnone size-full" src="http://www.keithlawless.com/wp-content/uploads/2010/03/Capture16_24_38.jpg" alt="" title="Capture16_24_38.jpg" width="138" height="150" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=181</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wordpress for BlackBerry 1.1 Released</title>
		<link>http://www.keithlawless.com/?p=178</link>
		<comments>http://www.keithlawless.com/?p=178#comments</comments>
		<pubDate>Fri, 19 Mar 2010 01:18:25 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=178</guid>
		<description><![CDATA[ The open source project Wordpress for BlackBerry has released version 1.1 of it's mobile blogging platform. The official announcement covers the list of new features - I'm personally excited about this release because I contributed some code that makes it's debut in version 1.1.

]]></description>
			<content:encoded><![CDATA[<p> The open source project <a href="http://blackberry.wordpress.org/2010/03/17/version-1-1/"  alt="">Wordpress for BlackBerry</a> has released version 1.1 of it's mobile blogging platform. The official announcement covers the list of new features - I'm personally excited about this release because I contributed some code that makes it's debut in version 1.1.
<p><a href="http://www.keithlawless.com/wp-content/uploads/2010/03/wp_icon_big.png"><img class="alignnone size-full" src="http://www.keithlawless.com/wp-content/uploads/2010/03/wp_icon_big.png" alt="" title="wp_icon_big.png" width="234" height="208" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=178</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wordpress for BlackBerry</title>
		<link>http://www.keithlawless.com/?p=137</link>
		<comments>http://www.keithlawless.com/?p=137#comments</comments>
		<pubDate>Wed, 17 Feb 2010 20:25:28 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[wordpress]]></category>
		<category><![CDATA[meta wordpress]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=137</guid>
		<description><![CDATA[A quick post using the new WP for BB application. I don't think I could write a full post using this app, especially on my wee BB Pearl. However, this could be handy for event blogging or a similar short-form use case. Sending a picture along with a post is handy as well.

]]></description>
			<content:encoded><![CDATA[<p>A quick post using the new WP for BB application. I don't think I could write a full post using this app, especially on my wee BB Pearl. However, this could be handy for event blogging or a similar short-form use case. Sending a picture along with a post is handy as well.
<p><a href="http://www.keithlawless.com/wp-content/uploads/2010/02/IMG00055.jpg"><img class="alignnone size-full" src="http://www.keithlawless.com/wp-content/uploads/2010/02/IMG00055.jpg" alt="" title="IMG00055.jpg" width="320" height="240" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=137</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wordpress 2.9 and a New Look</title>
		<link>http://www.keithlawless.com/?p=135</link>
		<comments>http://www.keithlawless.com/?p=135#comments</comments>
		<pubDate>Mon, 28 Dec 2009 13:12:08 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=135</guid>
		<description><![CDATA[This site has been upgraded to Wordpress 2.9. If you see any oddities, please post a comment to this post. Also, the theme of this site has been changed from my custom theme to a much more simpler one that should load much faster. My custom theme was the test bed for some posts I [...]]]></description>
			<content:encoded><![CDATA[<p>This site has been upgraded to Wordpress 2.9. If you see any oddities, please post a comment to this post. Also, the theme of this site has been changed from my custom theme to a much more simpler one that should load much faster. My custom theme was the test bed for some posts I wrote on Wordpress themes last year, and was never really finished. I went back and reread those posts, and found that they stood on their own pretty well, so hopefully removing the sample code from this sites template won’t reduce their value.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=135</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using PHPUnit with Eclipse PDT (PHP Development Tools)</title>
		<link>http://www.keithlawless.com/?p=128</link>
		<comments>http://www.keithlawless.com/?p=128#comments</comments>
		<pubDate>Fri, 02 Jan 2009 19:17:54 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[Eclipse]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[phpunit]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=128</guid>
		<description><![CDATA[Eclipse PHP Developer Tools (PDT) is a very capable and mature platform for developing PHP applications. For those that develop only in PHP, an integrated installation is available that includes the Eclipse platform and any dependencies. For developers that may already be using Eclipse for development in another language, PDT can be installed using Eclipse's [...]]]></description>
			<content:encoded><![CDATA[<p>Eclipse <a href="http://www.eclipse.org/pdt/">PHP Developer Tools</a> (PDT) is a very capable and mature platform for developing PHP applications. For those that develop only in PHP, an integrated installation is available that includes the Eclipse platform and any dependencies. For developers that may already be using Eclipse for development in another language, PDT <a href="http://wiki.eclipse.org/PDT/Installation#Eclipse_3.4_.2F_Ganymede_.2F_PDT_2.0">can be installed</a> using Eclipse's software update facility. </p>
<p>The one feature that PDT lacks is integration with PHPUnit. This can be a real hindrance for teams using Test Driven Development, and discourages everyone from frequently running their unit test suite while developing. </p>
<p>Luckily, the Eclipse platform has a mechanism for adding external tools to a project, and makes it very easy to call these tools once they are configured. In this post, I'll outline the steps I took to add PHPUnit support to my installation of PDT.</p>
<p>This post assumes that you have already installed Eclipse, and have a local development environment for PHP and PHPUnit. Jonathan Tran <a href="http://usingzendframework.blogspot.com/2007/12/setting-up-phpunit.html">has a handy tutorial</a> on installing PHPUnit on a Windows machine that I found very helpful.</p>
<p>In my PHP projects, I keep my unit tests in a directory called /tests. To start, select any unit test file - I chose AllTests.php, which executes a test suite containing all my unit tests for the project.  Once the file is selected, select the menu item Run->External Tools->External Tools Configurations... That brings up a dialog box similar to this.</p>
<p><a href="http://www.keithlawless.com/wp-content/uploads/2009/01/jan2screen1.png"><img src="http://www.keithlawless.com/wp-content/uploads/2009/01/jan2screen1-220x300.png" alt="jan2screen1" title="jan2screen1" width="220" height="300" class="alignnone size-medium wp-image-129" /></a></p>
<p>Select the Program configuration category, and click on the first icon - New Launch Configuration. Name your new configuration PHPUnit. </p>
<p>The location field should contain the full path to your phpunit shell script. On windows, this will be called phpunit.bat. On my computer, the correct location is c:\pear\phpunit.bat; however, this will vary by system.</p>
<p>The Working Directory should be set to the base location of your unit test files. In my case, this is the fully qualified \tests path. </p>
<p>For the Arguments list, you should have one entry - ${resource_name}. This tells Eclipse to pass the name of the currently highlighted unit test to phpunit.bat. To add this, click on the Variables... button and find resource_name in the displayed list.</p>
<p>The remainder of the tabs can be left with their default values. Your finished configuration should look like this:</p>
<p><a href="http://www.keithlawless.com/wp-content/uploads/2009/01/jan2screen2.png"><img src="http://www.keithlawless.com/wp-content/uploads/2009/01/jan2screen2-247x300.png" alt="jan2screen2" title="jan2screen2" width="247" height="300" class="alignnone size-medium wp-image-130" /></a></p>
<p>Press Apply to save your changes. You can now press the Run button to execute PHPUnit immediately, or press Close to exit this dialog box.</p>
<p>After the first time you run PHPUnit using the External Tools Configurations dialog box, your PHPUnit configuration will be associated with the Run External Tools icon on you Eclipse workspace - this is the green Play Button icon decorated with a little red toolbox. To execute any unit test script as you develop, simply select the script in the PHP Explorer and press the Run External Tools icon. </p>
<p><a href="http://www.keithlawless.com/wp-content/uploads/2009/01/jan2screen3.png"><img src="http://www.keithlawless.com/wp-content/uploads/2009/01/jan2screen3-300x225.png" alt="jan2screen3" title="jan2screen3" width="300" height="225" class="alignnone size-medium wp-image-131" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=128</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Writing a last.fm plug-in for Wordpress &#8211; Part Three: The Plug-In</title>
		<link>http://www.keithlawless.com/?p=114</link>
		<comments>http://www.keithlawless.com/?p=114#comments</comments>
		<pubDate>Mon, 29 Dec 2008 22:19:54 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[last.fm]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=114</guid>
		<description><![CDATA[This is the third and final post describing how to write a plug-in to last.fm for Wordpress. In the first post, we looked at the last.fm API. In the second post, we took this information and made a PHP application to create a weekly Album Chart using the API. In this post, we use the [...]]]></description>
			<content:encoded><![CDATA[<p>This is the third and final post describing how to write a plug-in to last.fm for Wordpress. In <a href="http://www.keithlawless.com/?p=51">the first post</a>, we looked at the last.fm API. In <a href="http://www.keithlawless.com/?p=52">the second post</a>, we took this information and made a PHP application to create a weekly Album Chart using the API. In this post, we use the PHP appication as the basis for a Wordpress plugin.</p>
<p><span id="more-114"></span>The first step to create a Wordpress plug-in is to create a directory for it to live. Although you can write a plug-in as a single PHP file and just drop it into your plug-in directory, this is not recommended. Ideally, each plug-in will live in it's own directory, and will use sub-directories to organize whatever additional files are needed for the plug-in to work.</p>
<p>For our plug-in, we'll create a directory structure that looks like this:</p>
<pre>
/wp-content
    /plugins
       /lastfm-album-chart
</pre>
<p>Within the lastfm-album-chart directory, create a subdirectory called PHP. Into this directory, copy the Album.php and AlbumChart.php files that we created in the last post. The next step is to write a plug-in that uses these two PHP classes to construct our last.fm Album Chart. </p>
<p>The code for the first draft of our plug-in is here:</p>
<pre name="code" class="php">
&lt;?php
/*
Plugin Name: last.fm Album Chart
Plugin URI: http://www.keithlawless.com/
Description: Displays a last.fm user's Weekly Album Chart as a sidebar item.
Version: 0.1
Author: Keith Lawless
Author URI: http://www.keithlawless.com/
*/
include 'php/AlbumChart.php';

/* Create a Wordpress template tag to allow Album Chart to appear on blog
  wherever the lastfm_album_chart() template is called.
*/
function lastfm_album_chart( $username, $apikey, $maxentries ) {
    print "&lt;h2&gt;last.fm Recent Albums&lt;/h2&gt;";

    $chart = new AlbumChart( $username, $apikey, $maxentries );
    print $chart-&gt;render();
}
?&gt;
</pre>
<p>The first thing to note in this script are the comments at the top. This comment block is used to identify this code as a Wordpress plug-in. Even without any implementing code, you can create a PHP script that will be recognized by Wordpress and that will show up in the administration panel. Here is ours:</p>
<p><a href="http://www.keithlawless.com/wp-content/uploads/2008/12/dec29screen1.png"><img src="http://www.keithlawless.com/wp-content/uploads/2008/12/dec29screen1-300x259.png" alt="dec29screen1" title="dec29screen1" width="300" height="259" class="alignnone size-medium wp-image-116" /></a></p>
<p>The remainder of the plug-in script is a single function called lastfm_album_chart() that closely follows the logic of the PHP application we wrote in the last post. To use this plugin, the Wordpress site owner simply activates the plug-in, then inserts a call to lastfm_album_chart() wherever in the theme the owner wants the Album Chart to appear - usually in the sidebar.php script. Then, the theme's stylesheet is updated as needed to make the Album Chart blend in with the rest of the site.</p>
<p>The final step before we are finished is to create an options panel for our plug-in. In the current implementation, the site owner has to specify their last.fm username, api, and chart size in the call to the lastfm_album_chart() method. This means that if any of these values change, the owner has to update a php script and FTP the new script to the Wordpress web server. Not a very user-friendly solution.</p>
<p>Creating a Wordpress options panel isn't very difficult; however, you do have to pay attention to detail to make sure your option panel is recognized by the Wordpress administration console. Here is the script above, modified to use an options panel:</p>
<pre name="code" class="php">
&lt;?php
/*
Plugin Name: last.fm Album Chart
Plugin URI: http://www.keithlawless.com/
Description: Displays a last.fm user's Weekly Album Chart as a sidebar item.
Version: 1.0
Author: Keith Lawless
Author URI: http://www.keithlawless.com/
*/
include 'php/AlbumChart.php';

/* Create a Wordpress template tag to allow Album Chart to appear on blog

  wherever the lastfm_album_chart() template is called.
*/
function lastfm_album_chart() {
    print "&lt;h2&gt;last.fm Recent Albums&lt;/h2&gt;";

    $username = get_option( "lastfm_albumchart_username" );
    $apikey = get_option( "lastfm_albumchart_apikey" );
    $maxentries = get_option( "lastfm_albumchart_maxentries" );

    $chart = new AlbumChart( $username, $apikey, $maxentries );
    print $chart-&gt;render();
}

function lastfm_albumchart_plugin_menu() {
    add_options_page( 'last.fm Album Chart Options',
        'last.fm Album Chart',
        8,
        __FILE__,
        'lastfm_albumchart_plugin_page' );
}

function lastfm_albumchart_plugin_page() {
    // This is the standard class for Wordpress option pages
    echo '&lt;div class="wrap"&gt;';

    echo '&lt;h2&gt;last.fm Album Chart&lt;/h2&gt;';

    echo '&lt;form method="post" action="options.php"&gt;';

    // Add some hidden fields needed for proper page flow.
    echo wp_nonce_field('update-options');

    // Create a form to gather input values for our option fields. This
    // format will give you the "standard" Wordpress look.
    echo '&lt;table class="form-table"&gt;';
    echo '&lt;tr valign="top"&gt;';
    echo '&lt;th scope="row"&gt;last.fm username&lt;/th&gt;';
    echo '&lt;td&gt;&lt;input type="text" name="lastfm_albumchart_username" value="';
    echo get_option('lastfm_albumchart_username');
    echo '"/&gt;&lt;/td&gt;&lt;/tr&gt;';
    echo '&lt;tr valign="top"&gt;';
    echo '&lt;th scope="row"&gt;last.fm API key&lt;/th&gt;';
    echo '&lt;td&gt;&lt;input type="text" name="lastfm_albumchart_apikey" value="';
    echo get_option('lastfm_albumchart_apikey');
    echo '"/&gt;&lt;/td&gt;&lt;/tr&gt;';
    echo '&lt;tr valign="top"&gt;';
    echo '&lt;th scope="row"&gt;Number of entries&lt;/th&gt;';
    echo '&lt;td&gt;&lt;input type="text" name="lastfm_albumchart_maxentries" value="';
    echo get_option('lastfm_albumchart_maxentries');
    echo '"/&gt;&lt;/td&gt;&lt;/tr&gt;';
    echo '&lt;/table&gt;';

    // Hidden field to pass a command to options.php
    echo '&lt;input type="hidden" name="action" value="update"/&gt;';

    // Enumerate the option fields on this page in a hidden field. Needed
    // by options.php for processing.
    echo '&lt;input type="hidden" name="page_options" value="';
    echo 'lastfm_albumchart_username,';
    echo 'lastfm_albumchart_apikey,';
    echo 'lastfm_albumchart_maxentries';
    echo '"/&gt;';

    // Add a submit button.
    echo '&lt;p class="submit"&gt;';
    echo '&lt;input type="submit" name="Submit" value="';
    echo _e( 'Save Changes?' );
    echo '"/&gt;';
    echo '&lt;/p&gt;';

    echo '&lt;/form&gt;';
    echo '&lt;/div&gt;';
}

add_action( 'admin_menu', 'lastfm_albumchart_plugin_menu' );

?&gt;
</pre>
<p>The first change to note is that our lastfm_album_chart() method no longer requires any parameters. Instead, the three values are obtained by calling the standard Wordpress method get_options(). Note that we chose some long and descriptive names for our three options (eg. lastfm_albumchart_username). This is to make sure our option names do not conflict with any other plug-ins, or with the core set of Wordpress options.</p>
<p>To create and activate the options page, we add two functions. lastfm_albumchart_plugin_menu() is called whenever the options main menu is created. The line line of this script contains a call to add_action() that registers this method with the Administration menu. Within the lastfm_albumchart_plugin_menu function, we make a call to the Wordpress function add_options_page(). This is the trickiest part of the process - it creates a new option page called 'last.fm Album Chart Options', which is invoked by a menu item called 'last.fm Album Chart'. The value 8 specifies that <a href="http://codex.wordpress.org/User_Levels#User_Level_8">only site editors</a> can access this menu item. This is part of Wordpress' security system for multi-user sites. The __FILE__ parameter specifies that the method for creating the options page is in this PHP script. The final parameter is the name of the method to use to create the option page. </p>
<p>The lastfm_albumchart_plugin_page() method uses the PHP echo command to output the HTML needed to build the options page. Note that this isn't a complete HTML page with &lt;head&gt; and &lt;body&gt; tags - this is just the markup needed to display our option form within the larger Wordpress administration console. </p>
<p>When creating your own options pages, you should copy another page to make sure you are following the <a href="http://codex.wordpress.org/Creating_Options_Pages">Wordpress guidelines for option pages</a>. An option page contains both CSS styles to make sure the option page is displayed correctly, as well as hidden fields used to inform the Administration console what options you are updating, and what values to change. </p>
<p>The administration panel that is created after our revised plug-in script is uploaded and activated looks like this:</p>
<p><a href="http://www.keithlawless.com/wp-content/uploads/2008/12/dec29screen2.png"><img src="http://www.keithlawless.com/wp-content/uploads/2008/12/dec29screen2-300x254.png" alt="dec29screen2" title="dec29screen2" width="300" height="254" class="alignnone size-medium wp-image-122" /></a></p>
<p>This is a very basic options page that just shows the three field names and their current values. By making the lastfm_albumchart_plugin_page() method more elaborate we could add additional refinements like detailed instructions for each field, or friendlier form elements like a drop down list.</p>
<p>That's the final step in creating our last.fm plugin. Once the sidebar.php script is updated to call the plug-in, and some CSS styling is applied, the final product looks like this.</p>
<p><a href="http://www.keithlawless.com/wp-content/uploads/2008/12/dec29screen3.png"><img src="http://www.keithlawless.com/wp-content/uploads/2008/12/dec29screen3-300x191.png" alt="dec29screen3" title="dec29screen3" width="300" height="191" class="alignnone size-medium wp-image-123" /></a></p>
<p>I hope you found this series helpful. Please feel free to leave a comment or contact me <a href="http://www.facebook.com/people/Keith-Lawless/1132293918">via Facebook</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=114</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Writing a last.fm plug-in for Wordpress &#8211; Part Two: The PHP Application</title>
		<link>http://www.keithlawless.com/?p=89</link>
		<comments>http://www.keithlawless.com/?p=89#comments</comments>
		<pubDate>Fri, 26 Dec 2008 19:22:21 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=89</guid>
		<description><![CDATA[This is the second post in a three part series on writing last.fm plug-in for Wordpress. In the first part of this series, we explored the last.fm API and wrote some simple PHP scripts to demonstrate two of the last.fm API methods. In this post, we'll create a complete PHP application that creates the last.api [...]]]></description>
			<content:encoded><![CDATA[<p>This is the second post in a three part series on writing last.fm plug-in for Wordpress. In the first part of this series, we explored the last.fm API and wrote some simple PHP scripts to demonstrate two of the last.fm API methods. In this post, we'll create a complete PHP application that creates the last.api widget. This application will be generic enough to use in any web page. In the third post in this series, we'll convert the generic application into a Wordpress plug-in. </p>
<p>Before getting started, we should decide what we want to the widget to look like, and what information it should display. Since we'll be pulling in the weekly Album Chart, it makes sense for our widget to display the top five albums that the user has listened to over the past week - that is, the first five entries in the Album Chart. Once we have the list, we'll pull in additional information about each album. This will allow us to display a little thumbnail image of the album's CD cover if one is available. </p>
<p><span id="more-89"></span>The finished widget should look something like this:</p>
<p><a href="http://www.keithlawless.com/wp-content/uploads/2008/12/dec26screen1.png"><img src="http://www.keithlawless.com/wp-content/uploads/2008/12/dec26screen1-300x195.png" alt="dec26screen1" title="dec26screen1" width="300" height="195" class="alignnone size-medium wp-image-90" /></a></p>
<p>At the end of the last post we took a look at the API method to retrieve information about a specific album. Using an object-oriented design, we can create a PHP script that encapsulates information about an album. The script is shown here:</p>
<pre name="code" class="php">
&lt;?php
class Album {

    private $artist = "";
    private $name = "";
    private $apikey = "";
    private $albumurl = "";
    private $imageurl = "";

    public function __construct( $p_artist, $p_name, $p_apikey ) {
        $this-&gt;artist = $p_artist;
        $this-&gt;name = $p_name;
        $this-&gt;apikey = $p_apikey;

        $this-&gt;fetchAlbum();
    }

    public function render() {
        $ret = "&lt;li&gt;";

        if( $this-&gt;imageurl != "" ) $ret = $ret .
            "&lt;a href=\"" . $this-&gt;albumurl . "\"&gt;" .
            "&lt;img width=\"34\" height=\"34\" src=\"" .
            $this-&gt;imageurl . "\"&gt;&lt;/a&gt;&nbsp;";

        $ret = $ret . "&lt;a href=\"" .
            $this-&gt;albumurl . "\"&gt;" .
            $this-&gt;artist . " - " . $this-&gt;name . "&lt;/a&gt;";

        return $ret;
    }

    private function fetchAlbum() {
        $url = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo" .
            "&#038;artist=" . urlencode($this-&gt;artist) .
            "&#038;album=" . urlencode($this-&gt;name) .
            "&#038;api_key=" . $this-&gt;apikey;
        $input = file_get_contents($url)
            or die('Could not access file: ' . $url );
        $xmlobj = simplexml_load_string($input);

        $return_code_array = $xmlobj-&gt;xpath("@status");
        $return_code = $return_code_array[0];

        if( $return_code != "ok" )
            die('Last.fm returned an error: ' . $xmlobj-&gt;error );

        $this-&gt;albumurl = $xmlobj-&gt;album-&gt;url;
        $imageurl_array = $xmlobj-&gt;xpath("//image[@size='small']");
        $this-&gt;imageurl = $imageurl_array[0];
    }
}
?&gt;
</pre>
<p>The class Album performs two functions - it fetches the album information using the last.fm API, and it provides a render() method that creates and returns a &lt;li&gt; element for the album. The user of this class only has to provide the artist and album name, along with a valid last.fm API key. The mechanics of fetching and rendering the album information is hidden within the class. </p>
<p>In the fetchAlbum() method, we added some error checking to make sure we found a match for our album. Since last.fm is providing the list of albums to us, we should never encounter an "Album not found" error - however, having the error checking gives you a nice piece of reusable code you can use in other applications. Also in fetchAlbum() we use this statement to fetch the album image URL:</p>
<pre>$imageurl_array = $xmlobj-&gt;xpath("//image[@size='small']");</pre>
<p>Xpath is a standard way of querying XML documents, and is supported in many different programming languages. This query says to find all of the &lt;image&gt; elements that have an attribute of "size" with a value of "small." That is, an element that looks like this:
<pre>&lt;image size="small"&gt;</pre>
<p>Now that we have the code to build an individual album's list item, we need to build the overall Album Chart. We developed some rudimentary code in the last post to accomplish this. Here is a more refined version of that code, implemented an AlbumChart class:</p>
<pre name="code" class="php">
include_once 'Album.php';

class AlbumChart {
    private $user = "keithlawless";
    private $apikey = "14d5668dc30efbc02489d78dfc32da26";
    private $max = 5;

    private $albums;

    public function __construct( $p_user="", $p_apikey="", $p_max=5 ) {
        if( $p_user != "" ) {
            $this-&gt;user = $p_user;
        }

        if( $p_apikey != "" ) {
            $this-&gt;apikey = $p_apikey;
        }

        if( $p_max != "" ) {
            $this-&gt;max = $p_max;
        }

        $this-&gt;fetchChart();
    }

    public function render() {
        $ret = "&lt;ul&gt;";

        foreach( $this-&gt;albums as $album ) {
            $ret = $ret . $album-&gt;render();
        }

        $ret = $ret . "&lt;/ul&gt;";
        return $ret;
    }

    private function fetchChart() {
        $url = "http://ws.audioscrobbler.com/2.0/?method=user.getweeklyalbumchart" .
            "&#038;user=" . $this-&gt;user .
            "&#038;api_key=" . $this-&gt;apikey;

        $input = file_get_contents($url) or die('Could not access file:' . $url);
        $xmlobj = simplexml_load_string($input);

        $return_code_array = $xmlobj-&gt;xpath("@status");
        $return_code = $return_code_array[0];

        if( $return_code != "ok" )
            die('Last.fm returned an error: ' . $xmlobj-&gt;error );

        $count = 0;
        foreach( $xmlobj-&gt;weeklyalbumchart-&gt;album as $album ) {
            $artist = $album-&gt;artist;
            $name = $album-&gt;name;

            $album = new Album( $artist, $name, $this-&gt;apikey );
            $this-&gt;albums[$count] = $album;

            // If we've hit the maximum number of albums requested,
            // break the loop.
            $count++;
            if( $count == $this-&gt;max ) break;
        }
    }
}
?&gt;
</pre>
<p>After getting the AlbumChart from last.fm, we iterate through the array of album elements are returned. For each album, we parse out the artist and title, and create a new Album object, which we store in an array. Once we reach the maximum number of albums we want to display - or run out of albums - we stop the loop. To display the Album chart, we simply create an unordered list, an iterate over the array of Album objects, calling each object's render method. </p>
<p>All that's left now is to create the widget script itself. Here is the code:</p>
<pre name="code" class="php">
&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;last.fm Widget Test&lt;/title&gt;
    &lt;body&gt;
        &lt;h2&gt;last.fm Recent Albums&lt;/h2&gt;
        &lt;?php
            include 'AlbumChart.php';
            $chart = new AlbumChart();
            print $chart-&gt;render();
        ?&gt;
    &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>We simply create an AlbumChart object, and call it's render() method to display the widget. To customize this widget for your site, you can select a different last.fm username and API key by passing parameters when creating the AlbumChart object - for example:</p>
<pre>
$chart = new AlbumChart( "YourUserName", "Your API Key" );
</pre>
<p>This code can be used "as is" in your Wordpress blog - you simply drop the code above into your sidebar.php script for your current template, and make any needed adjustments. In the next post, we'll go one step further, and create a Wordpress plug-in that makes it even easier to use this code for your blog.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=89</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Writing a last.fm plug-in for Wordpress &#8211; Part One: The last.fm API</title>
		<link>http://www.keithlawless.com/?p=51</link>
		<comments>http://www.keithlawless.com/?p=51#comments</comments>
		<pubDate>Tue, 23 Dec 2008 22:04:06 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[last.fm]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=51</guid>
		<description><![CDATA[last.fm is an online music listening and recommendation service that began life as a University project by one of it's cofounders,  Richard Jones. In addition to generating custom online "radio stations", users can create a profile that keeps track of the music they listen to. This process is called scrobbling and is used as a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://last.fm">last.fm</a> is an online music listening and recommendation service that began life as a University project by one of it's cofounders,  <a href="http://www.metabrew.com/">Richard Jones</a>. In addition to generating custom online "radio stations", users can create a profile that keeps track of the music they listen to. This process is called scrobbling and is used as a baseline for generating recommendations and custom playlists. To keep the data flowing, last.fm provides an easy-to-use API based on passing XML over HTTP.</p>
<p>This post is the first in a series of three exploring this API, and showing how the API can used to create a Wordpress plug-in for displaying information from your last.fm profile on your blog. In this first post, we'll take a look at the last.fm API, and create some simple PHP scripts to test out the API. In the second post, we'll turn our simple scripts into a complete PHP application. In the third post, we'll create a Wordpress plug-in that leverages our PHP application to display our last.fm data on a blog.</p>
<p><span id="more-51"></span>The <a href="http://www.last.fm/api">last.fm API</a> is accessed in two ways. For querying data, a simple HTTP GET is used, passing any variables as part of the request URL. This method does not require authentication, and returns data as an XML document in response to GET. All of the examples in this series of posts use this method. For API methods that modify a user's data, HTTP POSTs are used along with an authentication callback to the originating web site. Each type method requires <a href="http://www.last.fm/api/account">a freely available API key</a>. The examples here use my API key - I recommend that you sign up for your own, although all of the examples here will work with any recognized API key.</p>
<p>For our Wordpress plug-in, we are going to display the last.fm user's Album Chart. This is a personalized Weekly Top Album list for each user, showing the albums that received the greatest number of plays during the previous week. The URL to call to get the Album Chart looks like this:</p>
<pre>http://ws.audioscrobbler.com/2.0/?method=user.getweeklyalbumchart&#038;
user=keithlawless&#038;api_key=14d5668dc30efbc02489d78dfc32da26</pre>
<p>This URL is very similar to the rest of the query API's: a method name is passed which takes the form <i>object.action</i>, followed by a user name (if needed) and the caller's API key. The call returns an XML document. You should be able to be paste the URL above into your browser and see the most recent Album Chart for my last.fm account.</p>
<pre name="code" class="xml">
<lfm status="ok">
    <weeklyalbumchart user="keithlawless" from="1229256000" to="1229860800">
        <album rank="1">
            <artist mbid="092b9bb2-c774-4b95-8251-d5cd337a536e">The Tangent</artist>
            <name>Not As Good As The Book</name>
            <mbid></mbid>
<playcount>10</playcount>
            <url>http://www.last.fm/music/The+Tangent/Not+As+Good+As+The+Book</url>
        </album>
        <album rank="2">
            <artist mbid="169c4c28-858e-497b-81a4-8bc15e0026ea">Porcupine Tree</artist>
            <name>The Sky Moves Sideways</name>
            <mbid>61b42968-ed19-45cd-a56e-43f5f3fa0d71</mbid>
<playcount>7</playcount>
            <url>http://www.last.fm/music/Porcupine+Tree/The+Sky+Moves+Sideways</url>
        </album>
        <album rank="3">
            <artist mbid="169c4c28-858e-497b-81a4-8bc15e0026ea">Porcupine Tree</artist>
            <name>Fear of a Blank Planet</name>
            <mbid></mbid>
<playcount>6</playcount>
            <url>http://www.last.fm/music/Porcupine+Tree/Fear+of+a+Blank+Planet</url>
        </album>
        <album rank="3">
            <artist mbid="898b645e-eed2-490a-8ce2-0e7a4d2d5bc8">Robert Fripp</artist>
            <name>Radiophonics Soundscapes vol.1: Live in Argentina</name>
            <mbid></mbid>
<playcount>6</playcount>
            <url>http://www.last.fm/music/Robert+Fripp/Radiophonics+Soundscapes+vol.1%3A+Live+in+Argentina</url>
        </album>
        <album rank="5">
            <artist mbid="bf6c29f5-b69f-4842-9031-37f9645d365d">Carole King</artist>
            <name>Carole King - Her Greatest Hits: Songs Of Long Ago</name>
            <mbid></mbid>
<playcount>2</playcount>
            <url>http://www.last.fm/music/Carole+King/Carole+King+-+Her+Greatest+Hits%3A+Songs+Of+Long+Ago</url>
        </album>
    </weeklyalbumchart>
</lfm>
</pre>
<p>Each returned XML document will contain a status attribute in the lfm element. If the call was successful, there will be one child element containing the result - in this case a weeklyalbumchart element. This element contains a series of album elements - one for each album on our Chart. </p>
<p>Accessing the last.fm API from a PHP script is easy because of two nice features of PHP. First, PHP will accept a URL in most places where a local file name is called for. This allows you to quickly get the result of an HTTP call as if the result was a file on your hard drive. Second, PHP contains a simple XML parsing library called SimpleXML that allows XML documents to be treated like native PHP objects. The following PHP script calls the same URL as above, and creates an HTML list of albums from the Album Chart.</p>
<pre name="code" class="php">
 &lt;html&gt;
 &lt;body&gt;
    &lt;?php
        $apikey = "14d5668dc30efbc02489d78dfc32da26";
        $user = "keithlawless";
        $url = "http://ws.audioscrobbler.com/2.0/?method=user.getweeklyalbumchart&#038;user=" .
            $user . "&#038;api_key=" . $apikey;

        $input = file_get_contents($url)
            or die('Could not access file: $url');

        $xmlobj = simplexml_load_string($input); 

        $return_code_array = $xmlobj-&gt;xpath("@status");

        print "&lt;h2&gt;Status code was: " . $return_code_array[0] . "&lt;/h2&gt;";

        print "&lt;ul&gt;";
        foreach( $xmlobj-&gt;weeklyalbumchart-&gt;album as $album ) {
            print "&lt;li&gt;&lt;a href=\"" . $album-&gt;url . "\"&gt;" .
                $album-&gt;artist . " - " . $album-&gt;name . "&lt;/a&gt;";
        }
        print "&lt;/ul&gt;";
    ?&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>In line 6 of this example, we assemble the URL to pass to last.fm. In line 9, we use the php function file_get_contents to call the URL and return the resulting XML document as a string. A call is made to simplexml_load_string() on line 12 - this converts the XML document to a PHP object. The simplexml class allows xpath expressions - this is demonstrated on line 14, where we use the xpath expression "@status" to return all status attributes in the XML document as an array. On line 16 we displayed the first (and only) occurrence of  status.  Lines 19-22 is a loop over all of the album elements that are children of the weeklyalbumchart element. Each of the album elements is a SimpleXML object as well - allowing the url, artist, and name elements to be accessed using the normal "arrow" notation. </p>
<p>The resulting page is shown here:<br />
<img src="http://www.keithlawless.com/wp-content/uploads/2008/12/dec23screen1-300x253.png" alt="dec23screen1" title="dec23screen1" width="400" height="337" class="alignnone size-medium wp-image-79" /></p>
<p>For the plug-in, it would be nice to display more information about each album in the Album Chart. To do that, we'll use the album.getInfo API method. A sample URL for this method is:</p>
<pre>http://ws.audioscrobbler.com/2.0/?method=album.getinfo&#038;
artist=Porcupine%20Tree&#038;album=The%20Sky%20Moves%20Sideways&#038;
api_key=14d5668dc30efbc02489d78dfc32da26</pre>
<p>Note that this URL does not require a username field in the request since the album information isn't specific to a user. However, a valid API key is required. The resulting XML document looks something like this (some elements are removed to save space).</p>
<pre name="code" class="xml">
<?xml version="1.0" encoding="utf-8"?>
<lfm status="ok">
<album>
    <name>The Sky Moves Sideways</name>
    <artist>Porcupine Tree</artist>
    <id>1429130</id>
    <mbid>61b42968-ed19-45cd-a56e-43f5f3fa0d71</mbid>
    <url>http://www.last.fm/music/Porcupine+Tree/The+Sky+Moves+Sideways</url>
    <releasedate>    5 Sep 1995, 00:00</releasedate>
    <image size="small">http://userserve-ak.last.fm/serve/34s/12007055.jpg</image>
    <image size="medium">http://userserve-ak.last.fm/serve/64s/12007055.jpg</image>
    <image size="large">http://userserve-ak.last.fm/serve/174s/12007055.jpg</image>
    <image size="extralarge">http://userserve-ak.last.fm/serve/300x300/12007055.jpg</image>
<listeners>26561</listeners>
<playcount>250718</playcount>
</album>
</lfm>
</pre>
<p>Of particular interest in this XML are the image tags. In the next post when we create a complete PHP application, we'll use this information to put a little image next to each entry on our chart. At this point, you should note that not all of the album elements will be present for every album. last.fm will record each album and track that you listen to based on the tagging information contained in the track. However, not all artists are in last.fm's internal databases.</p>
<p>That's it for this post - keep an eye out for Part 2 where we'll put all of this together into a complete PHP application.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=51</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Now Running Wordpress 2.7</title>
		<link>http://www.keithlawless.com/?p=44</link>
		<comments>http://www.keithlawless.com/?p=44#comments</comments>
		<pubDate>Sat, 13 Dec 2008 01:59:34 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=44</guid>
		<description><![CDATA[Upgraded the site tonight to Wordpress 2.7. I've been running Release Candidate 1 on my test server since it came out, and have been putting it through it's paces - so I don't expect any issues.
]]></description>
			<content:encoded><![CDATA[<p>Upgraded the site tonight to Wordpress 2.7. I've been running Release Candidate 1 on my test server since it came out, and have been putting it through it's paces - so I don't expect any issues.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=44</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My Vote is In</title>
		<link>http://www.keithlawless.com/?p=42</link>
		<comments>http://www.keithlawless.com/?p=42#comments</comments>
		<pubDate>Tue, 04 Nov 2008 14:06:42 +0000</pubDate>
		<dc:creator>Keith</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Politics]]></category>

		<guid isPermaLink="false">http://www.keithlawless.com/?p=42</guid>
		<description><![CDATA[I voted in the U.S. elections today. I was at my local polling station at 6:30am for the early start that some locations in Massachusetts are trying. When the doors opened, I was number 18 in line with another ten or so people behind me. In previous elections, I have been as close to the [...]]]></description>
			<content:encoded><![CDATA[<p>I voted in the U.S. elections today. I was at my local polling station at 6:30am for the early start that some locations in Massachusetts are trying. When the doors opened, I was number 18 in line with another ten or so people behind me. In previous elections, I have been as close to the front of the line as number five - not sure how statistically relevant the "long" line is. The poll workers were ready for a big turnout and were very organized. Plenty of voting machines set up, and enough room so that a long line of people could queue up indoors out of the cold. There were ushers at the front doors and a few other places to help out people and keep things organization - the first time I've seen that, and pretty comical considering the number of voters waiting in line that early.</p>
<p>Despite being my sixth presidential election, I don't remember ever being this excited to vote. I was shaking with excitement - hopefully the machine can read my slightly wobbly arrows.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keithlawless.com/?feed=rss2&amp;p=42</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
