<?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>Damian Gostomski &#124; Freelance Web Development</title>
	<atom:link href="http://www.gostomski.co.uk/feed" rel="self" type="application/rss+xml" />
	<link>http://www.gostomski.co.uk</link>
	<description></description>
	<lastBuildDate>Tue, 31 Jan 2012 21:24:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<item>
		<title>Adding product to basket in Ubercart causes checkout bug</title>
		<link>http://www.gostomski.co.uk/drupal/adding-product-to-basket-in-ubercart-causes-checkout-bug</link>
		<comments>http://www.gostomski.co.uk/drupal/adding-product-to-basket-in-ubercart-causes-checkout-bug#comments</comments>
		<pubDate>Tue, 31 Jan 2012 21:24:25 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Drupal]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=95</guid>
		<description><![CDATA[As part of a site I&#8217;ve recently been developing using Ubercart, I needed the ability to be able to add an item to the basket via a URL. Getting a URL to trigger an event was trivial, using the following code. First, you setup the URL pattern to trigger a callback function: $items['product/%/add'] = array(<a href="http://www.gostomski.co.uk/drupal/adding-product-to-basket-in-ubercart-causes-checkout-bug" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<p>As part of a site I&#8217;ve recently been developing using Ubercart, I needed the ability to be able to add an item to the basket via a URL. Getting a URL to trigger an event was trivial, using the following code.</p>
<p>First, you setup the URL pattern to trigger a callback function:</p>
<pre class="brush: php; title: ;">
$items['product/%/add'] = array(
	'page callback'		=&gt;'djg_add_product_to_basket',
	'type'			=&gt;MENU_CALLBACK,
	'access arguments'	=&gt;array('access content'),
);
</pre>
<p>Next, I setup a simple callback function, which would get the Node ID from the URL, and pass it to the <em>uc_cart_add_item</em> function and then redirect the user to the checkout.</p>
<pre class="brush: php; title: ;">
function djg_add_product_to_basket() {
	$parts	= explode('/', $_GET['q']);
	$nid	= $parts[1];

	uc_cart_add_item($nid, 1);
	drupal_goto('cart/checkout');
}
</pre>
<p>I tried this, and it seemed to work, however I later realised that the delivery pane had been removed from the checkout. Several searches later, and all I could find were people with similar problems, but in their case it was because the product they wanted to buy wasn&#8217;t shippable.</p>
<p>Some more digging around, and I found that when you add a product pragmatically using uc_cart_add_item, it doesn&#8217;t pick up the shippable status from the product node.</p>
<p>The solution is to explicitly set the product as shippable using the third parameter, which is attributes, so the line of code should look like:</p>
<pre class="brush: php; title: ;">
uc_cart_add_item($nid, 1, array('shippable'=&gt;true));
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/drupal/adding-product-to-basket-in-ubercart-causes-checkout-bug/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting pages with a certain template</title>
		<link>http://www.gostomski.co.uk/wordpress/getting-pages-with-a-certain-template</link>
		<comments>http://www.gostomski.co.uk/wordpress/getting-pages-with-a-certain-template#comments</comments>
		<pubDate>Sun, 22 Jan 2012 12:26:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=91</guid>
		<description><![CDATA[I&#8217;d originally posted this on the WordPress StackExchange site, but thought I&#8217;d share it here as well. If you ever need to get pages which use a certain template, you can use the following query. You can then use the loop as normal to iterate over the pages, as well as expanding on the above<a href="http://www.gostomski.co.uk/wordpress/getting-pages-with-a-certain-template" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;d <a href="http://wordpress.stackexchange.com/a/39657/756">originally posted this on the WordPress StackExchange</a> site, but thought I&#8217;d share it here as well. If you ever need to get pages which use a certain template, you can use the following query. You can then use the loop as normal to iterate over the pages, as well as expanding on the above query, such as setting the order.</p>
<pre class="brush: php; title: ;">
query_posts(array(
	'post_type' =&gt;'page',
	'meta_key'  =&gt;'_wp_page_template',
	'meta_value'=&gt;'page-portfolio.php',
));
</pre>
<p>It may have once been useful to be able to just specify the page template in the query with an additional parameter, but I feel the widespread need for this is now gone, as many cases which would use this can be done better using Custom Post Types and a custom archive page.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/wordpress/getting-pages-with-a-certain-template/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Better auto updating copyright date</title>
		<link>http://www.gostomski.co.uk/snippet/better-auto-updating-copyright-date</link>
		<comments>http://www.gostomski.co.uk/snippet/better-auto-updating-copyright-date#comments</comments>
		<pubDate>Sun, 08 Jan 2012 13:34:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Snippet]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=88</guid>
		<description><![CDATA[At the start of every year, there always seem to be several blog posts about how to automatically update the copyright date in the footer of your site. These all seem to rely on using the date function in PHP to output the current year. Although this works fine in most cases, it falls apart<a href="http://www.gostomski.co.uk/snippet/better-auto-updating-copyright-date" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<p>At the start of every year, there always seem to be several blog posts about how to automatically update the copyright date in the footer of your site. These all seem to rely on using the date function in PHP to output the current year. Although this works fine in most cases, it falls apart if in the first year you want it to say just 2012, but next year you want it to say 2012-2013 instead of just 2013.</p>
<p>If we wrap this logic up in a function, it will be able to automatically display either just the single, current year, or a range from set year to the current one. Below is such a code snippet and examples of how to use it.</p>
<pre class="brush: php; title: ;">
/**
 * Return the given copyright string, with an auto updating year
 * Will either return the single, current year, or a range if a start is supplied that's not the current year
 *
 * Examples:
 * echo dg_copyright(&quot;&amp;copy; Copyright Damian Gostomski %s&quot;);
 * Output: &amp;copy; Copyright Damian Gostomski 2012
 * echo dg_copyright(&quot;&amp;copy; Copyright Damian Gostomski %s&quot;, 2012);
 * Output: &amp;copy; Copyright Damian Gostomski 2012
 * echo dg_copyright(&quot;&amp;copy; Copyright Damian Gostomski %s&quot;, 2008);
 * Output: &amp;copy; Copyright Damian Gostomski 2009-2012
 *
 * @link http://www.gostomski.co.uk/snippet/better-auto-updating-copyright-date
 * @param String $text - The text using sprintf notation. Use %s as the placeholder
 * @param Integer $year - The start year
 * @return String - The input string with the correct year in the placeholder
 */
function dg_copyright($text, $year = '') {
	// We need to know the current year so we can compare it to the start
	$current	= date('Y');

	// Figure out what the year part of the message should be
	if(empty($year)) {
		$year	= $current;
	} else if($year != $current) {
		$year	= &quot;$year-$current&quot;;
	}

	return sprintf($text, $year);
}
</pre>
</pre>
<p>The above code snippet is well commented, but if you have any questions or suggestions for improvements, post them in the comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/snippet/better-auto-updating-copyright-date/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Estimates or “How to dig your own grave”</title>
		<link>http://www.gostomski.co.uk/event/phpnw2011-project-estimation</link>
		<comments>http://www.gostomski.co.uk/event/phpnw2011-project-estimation#comments</comments>
		<pubDate>Mon, 07 Nov 2011 20:57:57 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Event]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=78</guid>
		<description><![CDATA[This is part of the series covering the PHP Nw 2011 conference. View the rest of the posts on this event here. This was one of the best talks that I’d attended, despite not being about PHP, but about the problems with estimates and how to avoid them. Rowan wasn’t even shaken by the multitude<a href="http://www.gostomski.co.uk/event/phpnw2011-project-estimation" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<p>This is part of the series covering the PHP Nw 2011 conference. <a href="http://www.gostomski.co.uk/event/phpnw-2011-review">View the rest of the posts on this event here</a>.</p>
<p>This was one of the best talks that I’d attended, despite not being about PHP, but about the problems with estimates and how to avoid them. Rowan wasn’t even shaken by the multitude of technical issues which delayed it, but I’m sure he’d factored in the risk of that happening.</p>
<p>The talk was split into two main parts, starting off with the possible mistakes, and then how to spot problems and resolve them. It’s certainly making a difference in the way that I now handle estimates (something I’ve always disliked doing). At the end of the day, it comes down to a few common sense rules for making estimates and managing risks and estimating appropriately.</p>
<h3>Problem – The sales team creates estimates</h3>
<p>This is something that everyone who’s ever worked in any sort of commercial environment can relate to, and it was most certainly true for me. I’m not sure if the sales team are just overly optimistic when quoting timescales and costs for a project, or if they think the only way to win the work is to massively underestimate, but it never works out.</p>
<p>The solution to this however is simple, let the person who will be doing the work, and has a much better idea of how long it will take, give the estimate.</p>
<h3>Problem – Estimates from a single developer</h3>
<p>Even when you give an “educated” estimate as a developer, it’s still easy to get it wrong, which is why you should ideally not get an estimate from just one developer. Ideally the estimates would be made independently and then an average would be taken (although any outliers would be investigated), but if that’s not possible, they should always be reviewed.</p>
<p>Now not everyone is fortunate enough to have other developers with which to review their estimates, but even with just the other tips, you’ll still improve your estimates.</p>
<h3>Problem – Estimates from a detailed list of tasks</h3>
<p>One of the common guidelines given when estimating for a large job is to break it down into smaller chunks and estimate each chunk. If this gives us more accurate estimates, logic would dictate that further breaking these down to very detailed tasks would yield even more accurate estimates, but unfortunately not.</p>
<p>If you get down to this level, your estimate is almost immediately void, as things always change, but you have misplaced confidence in your estimates as you think they’re accurate to the nearest 30 seconds. This also has the side effect of encouraging micromanagement, which no one wants!</p>
<h3>Problem – Estimate in hours</h3>
<p>Leading on from the above, estimating in hours not only encourages too much granularity but also doesn’t map to days conveniently (see next point). Think in terms of days, using an increment relative to the size of the project, but no smaller than a quarter of a day, up to a week at a time on larger projects.</p>
<h3>Problem – Estimate work in 8 hour days</h3>
<p>If you created a detailed list of tasks and durations as mentioned above and then divide the number of hours by 8 to get the duration of a project, you have a problem (or several):</p>
<p>1.       Taking a 9-5 job, you have an 8 hour day, but take out an hour for lunch, and you’re left with 7 hours of “work” time</p>
<p>2.       Of these 7 hours, you can’t work on a single task without any interruptions, breaks or context switches. Every time you switch task or get interrupted, you need to get up to speed again</p>
<p>A developer can expect to get about 6 hours of actual work done on a good day, and a lead developer just 4 hours.</p>
<h3>Problem – Just estimating coding time</h3>
<p>It’s far too easy to get caught up and just think about coding time, but unfortunately we need to deal with numerous other tasks including documentation (both internal API documentation and end user documentation), testing, deployment etc. On top of this, there will <strong>always</strong> be bugs and amends (no matter how perfect you think you are) as well as the overhead of running a team project (communication, management etc).</p>
<h3>Problem – Waterfall estimates are next to useless</h3>
<p>Although most projects involve some amount of boilerplate functionality which is easy to estimate, as you’ve done it a million times over, there’s still a lot you don’t know. With the Waterfall model, there is the “Cone of Uncertainty”. This means that at the start of the project, your estimates will likely be wildly inaccurate, and as you progress closer towards the end, the cone starts to close, and your estimates get more and more accurate. This has led to the growth of agile over the last few years, but unfortunately people using agile think they can’t estimate a whole project at the start.</p>
<h3>Solution &#8211; The holy triangle</h3>
<p>The holy triangle is based on 3 axis, where adjusting 2 affects the value of the third. The possible combinations are:</p>
<ul>
<li>Good, fast and expensive</li>
<li>Good, cheap and slow</li>
<li>Fast, cheap and bad</li>
</ul>
<p>Although it is possible to have high quality and quickly, it will be expensive – Something most clients will fail to comprehend.</p>
<h3>Solution – MoSCoW</h3>
<p>This stands for <strong>M</strong>ust, <strong>S</strong>hould, <strong>C</strong>ould, <strong>W</strong>on’t and help the client to understand that not all functionality is created equally. Unfortunately a client will initially think that everything is a must, so hopefully the following will clear up what’s a must versus a should, could or won’t:</p>
<ul>
<li><strong>Must – </strong>Critical to the project, which would be a failure without it. The project could not launch without all the must features implemented</li>
<li><strong>Should – </strong>Most things that the client thinks is a must will actually fall into this category. Although you can launch without these, it’s best to do them if you can, as they will often help improve the usability or make it unique</li>
<li><strong>Could –</strong> These are the nice to have extras, but in no way, shape or form crucial to the project. If there’s enough resource left once all the must and should features are done, you can work on these</li>
<li><strong>Won’t –</strong> No, just say no to these features</li>
</ul>
<p>So how does this help? Well, you’ll likely have just halved your workload as it turns out you don’t need all the bells and whistles the client thought they needed. It also helps to manage client expectations, because as long as you have all the musts implemented, you can still launch without the rest, reducing the risk of overrunning (for the initial release).</p>
<h3>Mistake – Lose track of time</h3>
<p>Unfortunately, we’re all terrible at tracking time for 2 main reasons:</p>
<p>1.       We dislike anything that’s not actual coding, so time tracking is seen as a chore</p>
<p>2.       If we’re switching between tasks regularly, the time tracking becomes very fragmented (although in this case, context changes are the bigger problem)</p>
<p>Despite this, it’s important to track time, so that you know where you are relative to your estimates and if they’re accurate. The sooner you can identify a problem, the better.</p>
<h3>Mistake – Estimate bugs</h3>
<p>By their very definition, it’s impossible to estimate how long it will take to fix a bug, as the exact cause is unknown. I’m sure we’ve all spent numerous hours, if not days, to find a trivial, one line fix. As you can’t estimate the duration of finding the cause of the bug, you need to have this buffer factored into the overall estimate.</p>
<h3>Mistake – Not learning from mistakes</h3>
<p>At the end of every project, we should review everything that went well, but more importantly, what didn’t go so well. If estimate were under, identify the cause so you won’t make the mistake again. If there was something that took considerable time that wasn’t factored in, make a note do you remember last time etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/event/phpnw2011-project-estimation/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP North West 2011 Review</title>
		<link>http://www.gostomski.co.uk/event/phpnw-2011-review</link>
		<comments>http://www.gostomski.co.uk/event/phpnw-2011-review#comments</comments>
		<pubDate>Mon, 07 Nov 2011 20:57:52 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Event]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=79</guid>
		<description><![CDATA[I was fortunate enough to attend the recent PHP conference in Manchester for the second consecutive year a few weeks ago, and this series of posts summarises my thoughts and what I learnt. It’s safe to say I’ll be going again next year! I will write up all the talks I attended in the next<a href="http://www.gostomski.co.uk/event/phpnw-2011-review" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<p>I was fortunate enough to attend the recent PHP conference in Manchester for the second consecutive year a few weeks ago, and this series of posts summarises my thoughts and what I learnt. It’s safe to say I’ll be going again next year!</p>
<p>I will write up all the talks I attended in the next few days, and the list so far is below:</p>
<ul>
<li><a href="http://www.gostomski.co.uk/event/phpnw2011-project-estimation">Estimates, or &#8220;How to dig your own grave&#8221;</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/event/phpnw-2011-review/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Reader modifications using GreaseMonkey</title>
		<link>http://www.gostomski.co.uk/general/google-reader-modifications-using-greasemonkey</link>
		<comments>http://www.gostomski.co.uk/general/google-reader-modifications-using-greasemonkey#comments</comments>
		<pubDate>Tue, 01 Nov 2011 20:44:20 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=74</guid>
		<description><![CDATA[Google Reader has recently received the visual update which has been available for most Google Services over the last few months. On the whole, I like the style and think it’s much cleaner than the old one. Despite this, it’s not perfect in my opinion, with my biggest complaint being how it styles the collapsed<a href="http://www.gostomski.co.uk/general/google-reader-modifications-using-greasemonkey" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<p>Google Reader has recently received the visual update which has been available for most Google Services over the last few months. On the whole, I like the style and think it’s much cleaner than the old one. Despite this, it’s not perfect in my opinion, with my biggest complaint being how it styles the collapsed list of items. As this is the main way I consume content via Google Reader (and then click through to read the full article on the original website), it’s reduced how quickly I can scan a large list of content.</p>
<p>I <a href="http://twitter.com/#%21/damiangostomski/statuses/131144806079537152">tweeted about this frustration</a> and a few people responded with possible suggestions (<a href="http://twitter.com/#%21/iamfriendly/statuses/131145031443689473">here</a> and <a href="http://twitter.com/#%21/nocataractshere/statuses/131145847298723840">here</a>), but neither was quite right for me, but it did give me an idea. If all I want to do, is change one CSS rule to reduce the height of the row, I can use the excellent GreaseMonkey extension for Firefox.</p>
<p>I set about learning how to make a GreaseMonkey script, and it’s incredibly simple, as it’s just plain JavaScript. Within 5 minutes I had a working script which done what I wanted.</p>
<p><a href="http://userscripts.org/scripts/show/116877">The GreaseMonkey script can be downloaded here</a>, and the full code is shown below. All it does is create an inline style tag in the header and add the single rule. If I was doing more complex CSS I could load an external stylesheet, but for something this simple, the overhead of an extra request wasn’t required.</p>
<pre class="brush: jscript; title: ;">
// ==UserScript==
// @name           Compressed Reader
// @namespace      http://gostomski.co.uk
// @include        http://www.google.com/reader/view/
// ==/UserScript==

(function() {
var head, style;
head                   = document.getElementsByTagName('head')[0];
style                  = document.createElement('style');
style.type             = 'text/css';
style.innerHTML = &quot;#entries.list .entry .collapsed {line-height: 2.2ex; height: 12px}&quot;;
head.appendChild(style);
})();
</pre>
<p>The above script will allow you to fit as much as 33% more posts in the screen at once.</p>
<p>What else would you want to change with the new Google Reader, as I may carry on developing this script to make Google Reader even better.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/general/google-reader-modifications-using-greasemonkey/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Goodbye And, Hello MC2</title>
		<link>http://www.gostomski.co.uk/work/goodbye-and-hello-mc2</link>
		<comments>http://www.gostomski.co.uk/work/goodbye-and-hello-mc2#comments</comments>
		<pubDate>Fri, 26 Aug 2011 09:00:25 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=69</guid>
		<description><![CDATA[Goodbye And! Today marks my last day at And Digital. I&#8217;ve been here for 15 months, having joined right out of University. At the time, I wasn&#8217;t actively seeking employment, as I was freelancing so that I did&#8217;t have to settle for &#8220;any old job&#8221;. After a few jobs at And Digital, they offered me<a href="http://www.gostomski.co.uk/work/goodbye-and-hello-mc2" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<h2>Goodbye And!</h2>
<p>Today marks my last day at <a href="http://weareand.co.uk/digital/" target="_blank">And Digital</a>. I&#8217;ve been here for 15 months, having joined right out of University. At the time, I wasn&#8217;t actively seeking employment, as I was freelancing so that I did&#8217;t have to settle for &#8220;any old job&#8221;. After a few jobs at And Digital, they offered me the job, and shortly afterwards, I was a full time employee there.</p>
<p>In my time here, I&#8217;ve worked on a wide range of projects and moved from being &#8220;just a developer&#8221; to having a wide range of roles, and become very competent with WordPress. I&#8217;d also started to take on a much more client facing role and been involved in the early, cenceptual phases on many projects?</p>
<p><em>So, if things are going so well, why move on?</em></p>
<h2>Hello MC2</h2>
<p>As of the first of September, I&#8217;ll be taking on the role of lead developer at <a href="http://mcmc.co.uk/" target="_blank">MC2</a>. Just as before, I was never actively seeking new employment, but every one in a while, a great opportunity presents itself &#8211; This was such a case.</p>
<p>As well as an element of client work to begin with, there is a lot more to this new role than just developing websites for clients. There will be a heavy emphasis on using the latest technologies and having a much more R&amp;D driven role.</p>
<p>This continual learning and being able to develop to solve both internal needs as well as just building cool stuff for the sake of it appeals to me a lot more than a role in a traditional client service agency.</p>
<p>Due to the nature of the work I&#8217;ll be doing, I should also have lots of interesting things to write about, and maybe even the time to write them, so be sure to look out for lots of new, fresh content coming up.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/work/goodbye-and-hello-mc2/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web app lock in &#8211; Getting your data out</title>
		<link>http://www.gostomski.co.uk/web/web-app-lock-in-getting-your-data-out</link>
		<comments>http://www.gostomski.co.uk/web/web-app-lock-in-getting-your-data-out#comments</comments>
		<pubDate>Sun, 05 Jun 2011 12:54:03 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[activecollab]]></category>
		<category><![CDATA[beanstalk]]></category>
		<category><![CDATA[codebase]]></category>
		<category><![CDATA[lighthouse]]></category>
		<category><![CDATA[vendor lock-in]]></category>
		<category><![CDATA[web appp]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=66</guid>
		<description><![CDATA[As more and more desktop applications are being replaced with their web counterparts, data ownership is becoming an increasing concern &#8211; At least it should be. The problem is, the more you invest into a system, in terms of time and data, the more you tie yourself to it, until one day, you want to<a href="http://www.gostomski.co.uk/web/web-app-lock-in-getting-your-data-out" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<p>As more and more desktop applications are being replaced with their web counterparts, data ownership is becoming an increasing concern &#8211; At least it should be. The problem is, the more you invest into a system, in terms of time and data, the more you tie yourself to it, until one day, you want to leave.</p>
<p>The reasons for wanting to leave can vary from cost, a change in your requirements, or simply a better product/service elsewhere. Whenever you need to switch, there is always a cost associated, be it money, time or both.</p>
<p>At work (<a href="http://weareand.co.uk" target="_blank">And Digital</a>), we&#8217;re currently going through a significant change in terms of the services we&#8217;re using. These changes include:</p>
<ol>
<li>Condensing all our servers to one, fully managed server from <a href="http://uk.layershift.com/" target="_blank">Layershift</a></li>
<li>Migrating issue tracking from Lighthouse and Codebase to activeCollab</li>
<li>Migrating our SVN repositories from Beanstalk and Codebase to self hosted repositories</li>
</ol>
<p>I&#8217;ll be focusing on the last 2 tasks, as that&#8217;s where the issue lies. Lighthouse allows you to export your entire account as a directory structure with a JSON and CSVfile for each ticket. Although activeCollab can&#8217;t natively import this, we have the data in a usable format, and the primary need for this data is archive/backup, as 99% of the tickets are completed.</p>
<p>Beanstalk allows us to download an SVN dump of each repository which we can then load into a new repository using the svnadmin load command.</p>
<p>Codebase on the other hand, doesn&#8217;t provide an automated way to export projects or code repositories. I even contacted support who suggested a few tools/scripts which would help, but confirmed there is no official way to do this. And it&#8217;s not like Codebase is a new application either, as it&#8217;s soon to have version 4 released!</p>
<p>I&#8217;ll end with this plea to all web application developers:</p>
<blockquote><p>The last interaction your users will have with your application is when they leave. You can&#8217;t force them to stay with you any longer by locking down all their data. Make it easy for them to leave and make their last impression a good one. This way, they can become your evangelists, as even though you may no longer meet their needs, they will know plenty of people for whom you&#8217;d be perfect.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/web/web-app-lock-in-getting-your-data-out/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New site launch</title>
		<link>http://www.gostomski.co.uk/general/new-site-launch-under-construction</link>
		<comments>http://www.gostomski.co.uk/general/new-site-launch-under-construction#comments</comments>
		<pubDate>Sun, 12 Dec 2010 22:14:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=11</guid>
		<description><![CDATA[UPDATE: I&#8217;ve now replaced the &#8220;Lorem Ipsum&#8221; with actual content, but everything else below is still valid. Today I launched my new site, but unlike most site launches, it’s half missing. Currently, the only real content is on the homepage and the blog. There are some screenshots of a few websites in the portfolio section, but the text is all “Lorem ipsum”, as is the about page. So why have I done it? Why would I take down my existing site and replace it with this one? Firstly, this version has no less content as the old site has almost nothing for the about and portfolio sections. If anything, this site now has more content, as there are an additional 2 blog posts. But that’s not the real reason for launching my site just yet, it comes down to the key benefits of agile/iterative/release early, release often/call it what you<a href="http://www.gostomski.co.uk/general/new-site-launch-under-construction" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<p><strong>UPDATE: I&#8217;ve now replaced the &#8220;Lorem Ipsum&#8221; with actual content, but everything else below is still valid.</strong></p>
<p>Today I launched my new site, but unlike most site launches, it’s half missing. Currently, the only real content is on the homepage and the blog. There are some screenshots of a few websites in the portfolio section, but the text is all “Lorem ipsum”, as is the about page.</p>
<p>So why have I done it? Why would I take down my existing site and replace it with this one? Firstly, this version has no less content as the old site has almost nothing for the about and portfolio sections. If anything, this site now has more content, as there are an additional 2 blog posts.</p>
<p>But that’s not the real reason for launching my site just yet, it comes down to the key benefits of agile/iterative/release early, release often/call it what you will.</p>
<p>1.       Get user feedback<br />
2.       Changing needs<br />
3.       No such thing as a perfect version 1.0<br />
4.       Time<br />
5.       Motivation</p>
<h2>User feedback</h2>
<p>User feedback is one of the most important aspects of any project. Without this valuable feedback, anything you do is purely a guess as to what you think the user wants. This may traditionally apply more to software/web applications but I think it works with a web site as well.</p>
<p>So what do you think works well and what doesn’t? What sort of content do you want to see in the coming months? Tutorials? Articles? Code?</p>
<h2>Changing needs</h2>
<p>Not only would I be second guessing what a users goals are with this site, I would also be second guessing what I want to achieve from it long term. If I wanted to release a perfect version 1.0 and then my needs significantly changed, I would either delay version 1.0, or I would probably have to build version 2.0 while leaving the existing site to stagnate.</p>
<p>This way, I can make lots of small revisions to the site and keep releasing them helping me to change direction quicker if need be and making sure the site is always fresh.</p>
<h2>Perfection &amp; Time constraints</h2>
<p>I can be a bit of a perfectionist, so much so, that it makes me cringe to have to put a hack in place to meet a tight deadline. I could easily find 100 things that need doing/improving before launching this, and then a hundred more. The problem with this is that it would never be 100% perfect – This, coupled with the fact I have no actual deadline for the launch of this site is a huge issue, one that can be solved by releasing it now and constantly iterating it to make it better.</p>
<h2>Motivation</h2>
<p>One of the reasons my old site stagnated is because there was never any urgency to do anything with it. It was performing well and generating leads. This lack of urgency means I didn’t find the time to do the things I wanted with it, be it more content, promotion or design tweaks.</p>
<p>Now, I will have to make time, not only for the content but also design tweaks. One thing I plan to do more in the future is split testing so as to get a better understanding of what works well and what doesn’t.</p>
<h2>Going forward</h2>
<p>Now that this site is up, I can just sit here. First, I’ll be replacing all the “Lorem ipsum” throughout the site, then I have a couple of ideas for some interesting articles/tutorials I’ll be publishing in the next few weeks and also some design tweaks to experiment with, including some more colour options (I have a total of 50 colour options to experiment with).</p>
<p>So, what do you think of the site and my reasoning for launching it in this state? Let me know your thoughts in the comments or contact me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/general/new-site-launch-under-construction/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Removing fields for logged in users in Gravity Forms</title>
		<link>http://www.gostomski.co.uk/wordpress/removing-fields-for-logged-in-users-in-gravity-forms</link>
		<comments>http://www.gostomski.co.uk/wordpress/removing-fields-for-logged-in-users-in-gravity-forms#comments</comments>
		<pubDate>Sun, 12 Dec 2010 20:32:52 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.gostomski.co.uk/?p=10</guid>
		<description><![CDATA[Gravity Forms is one of my favourite WordPress plug-ins due to it&#8217;s ease of use, flexability and extensibilty. In a recent project I needed to be able to show or hide a set of fields dependant on if the user was logged in. Although Gravity Forms allows for conditional fields, these are dependant on other<a href="http://www.gostomski.co.uk/wordpress/removing-fields-for-logged-in-users-in-gravity-forms" class="more-info">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.gravityforms.com/" target="_blank">Gravity Forms</a> is one of my favourite WordPress plug-ins due to it&#8217;s ease of use, flexability and extensibilty. In a recent project I needed to be able to show or hide a set of fields dependant on if the user was logged in. Although Gravity Forms allows for conditional fields, these are dependant on other form fields.</p>
<p>As part of the registtration process, we collected numerous pieces of information, and many of the same fields would appear in other forms within the site. Why should users who have already registered and given all that infoamtion once have to do it again. In that case, there where up to 8 fields, dependant on the form, which we could hide for logged in users, but in these examples, so as to keep things nice and simple, I&#8217;ll be focusing on a single field &#8211; The users email address.</p>
<h2>The form</h2>
<p>To start with, you will need to create a form with at least two fields &#8211; An email address and something else (just so we know everything still works and can test it). Embed this form into a test page and test it all working. Also, make both of these fields required.</p>
<h2>Hiding the field</h2>
<p>To do this, we will need to add some code to the functions.php file found in your theme. If you haven&#8217;t got this file, just create it. I&#8217;ll start off by showing the code for removing the field, and I&#8217;ll then go through it and explain each part.</p>
<pre class="brush: php; title: ;">
function remove_fields_for_logged_in_users($form) {
	if(!is_user_logged_in()) return $form;

	$fields_to_hide = array('Email');

	foreach($form['fields'] as $key=&gt;$field) {
		if(in_array($field['label'], $fields_to_hide)) {
			unset($form['fields'][$key]);
		}
	}

	return $form;
}
add_filter('gform_pre_render', 'remove_fields_for_logged_in_users');
</pre>
<p>We start off by adding a filter to hook into the Gravity Forms core. In this case, we&#8217;re using the gform_pre_render filter, which is called nearthe start of the get_form method, which gets and renders the form. This has one parameter, which is the form object we&#8217;ll be modifying.</p>
<pre class="brush: php; title: ;">
if(!is_user_logged_in()) return $form;
</pre>
<p>As we want to remove fields for users which are already logged in, the first thing we need to do, is check the user is actually logged in. If they&#8217;re not logged in, then we don&#8217;t have this information so we leave the form object as is.</p>
<pre class="brush: php; title: ;">
$fields_to_hide = array('Email');
</pre>
<p>Next up, we need to declare a list of all the fields which we want to remove for logged in users. The values in this list need to correspond to the labels of the fields you used when creating the form. If you called the email field something other then &#8220;Email&#8221; you will need to change the above.</p>
<pre class="brush: php; title: ;">
foreach($form['fields'] as $key=&gt;$field) {
	if(in_array($field['label'], $fields_to_hide)) {
		unset($form['fields'][$key]);
	}
}

return $form;
</pre>
<p>Lastly, we need to check if any of the fields in this form match up the ones we want to remove for logged in users. As part of the $form array passed in, there is a sub array called fields, which contains all the fields which make up this form. For each field, we check if it&#8217;s in our array of fields to remove, and if so, we remove it.</p>
<p>Lastly, we need to remember to return the form object.</p>
<h2>Testing it</h2>
<p>If you now view the form and are logged in, the email field should not be there, where as if you view the form when not logged in, both fields will be there. If you fill out both forms, they will both submit (even though the email, which is a required field wasn&#8217;t filled in for logged in users).</p>
<p>However, there is a problem. If you view the entries, you will see we obviously have some missing information, as the email field wasn&#8217;t shown.</p>
<h2>Filling in the gaps</h2>
<p>So now we need some additional functionality to fill in the missing fields, so we have all the information when viewing the form entries. To do this, we need to following code.</p>
<pre class="brush: php; title: ;">
function add_missing_fields_for_logged_in_users($lead, $form) {
	global $current_user, $wpdb;

	if(!is_user_logged_in()) return;

	get_current_user();

	$original_form = RGFormsModel::get_form_meta($form['id']);

	foreach($original_form['fields'] as $key=&gt;$field) {
		if($field['label'] == 'Email') {
			$lead_detail_data = array(
				'lead_id'=&gt;$lead['id'],
				'form_id'=&gt;$form['id'],
				'field_number'=&gt;$field['id'],
				'value'=&gt;$current_user-&gt;user_email
			);

			$wpdb-&gt;insert(&quot;{$wpdb-&gt;prefix}rg_lead_detail&quot;, $lead_detail_data);
		}
	}
}
add_action('gform_post_submission', 'add_missing_fields_for_logged_in_users', 10, 2);
</pre>
<p>As before, we need to hook into the Gravity Forms core, this time using the gform_post_submission action. By the time this is executed, the form submission has already been saved. The function takes two parameters, the lead, which is the users answers to the form (plus some additional data) and the form, which is the same as before, however the form may have been modified using the above filter.</p>
<p>We need to start by making sure the user is logged in, as there would only be missing fields for logged in users, and we then get all the user details for the current logged in user.</p>
<pre class="brush: php; title: ;">
$original_form = RGFormsModel::get_form_meta($form['id']);
</pre>
<p>As the form which is passed in has gone through the gform_pre_render filter, it may be missing certain fields for logged in users, in this case, the email address field. So that we have the original form, we need to get it directly, using the form ID we&#8217;re passed in as part of the form.</p>
<pre class="brush: php; title: ;">
foreach($original_form['fields'] as $key=&gt;$field) {
	if($field['label'] == 'Email') {
		$lead_detail_data = array(
			'lead_id'=&gt;$lead['id'],
			'form_id'=&gt;$form['id'],
			'field_number'=&gt;$field['id'],
			'value'=&gt;$current_user-&gt;user_email
		);

		$wpdb-&gt;insert(&quot;{$wpdb-&gt;prefix}rg_lead_detail&quot;, $lead_detail_data);
	}
}
</pre>
<p>For each field, check if it&#8217;s one of the one we removed. If it is, we need to manually add it to the database linking it to the users lead. Each lead detail as linked to the form and the lead, we then have the ID of the field and the value, we we get from the user object.</p>
<h2>Making this more flexible</h2>
<p>Soon, I will update this to show you how to make it even more flexible.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gostomski.co.uk/wordpress/removing-fields-for-logged-in-users-in-gravity-forms/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>

