<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

    <channel>
    
    <title><![CDATA[StudioForty9 Blog]]></title>
    <link>http://www.studioforty9.com/blog</link>
    <description />
    <dc:language>en</dc:language>
    <dc:creator>info@studioforty9.com</dc:creator>
    <dc:rights>Copyright 2011</dc:rights>
    <dc:date>2011-03-08T23:02:21+00:00</dc:date>
    <admin:generatorAgent rdf:resource="http://expressionengine.com/" />
    

    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/studioforty9" /><feedburner:info uri="studioforty9" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
      <title><![CDATA[An Irish Module for Magento]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/7EJDotFjUA0/an_irish_module_for_magento</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/an_irish_module_for_magento#When:23:02:21Z</guid>
      <description>Just in time for St. Patrick's Day!&lt;p&gt;
	I had been meaning to write a small &amp;quot;Ireland&amp;quot; module for Magento for a while but only got around to it last week.&lt;br /&gt;
	&lt;br /&gt;
	It has 2 pieces of functionality:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;
		It adds the counties of Ireland (including Northern Ireland), into the &amp;#39;directory_country_region&amp;#39; table of the Magento database so the list of Irish counties appears when you change the country to Ireland on any of the forms in Magento (checkout, cart, etc.)&lt;/li&gt;
	&lt;li&gt;
		It adds a shipping method for An Post, the national postal carrier of Ireland.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
	There&amp;#39;s nothing much to say about part 1, but there&amp;#39;s a few points I&amp;#39;d like to mention about part 2:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;
		The code is based on WebShopApps MatrixRate module (&lt;a href="http://www.magentocommerce.com/magento-connect/webshopapps/extension/604/webshopapps-matrixrate--the-original-multiple-table-rate-solution--certified-bug-free"&gt;http://www.magentocommerce.com/magento-connect/webshopapps/extension/604/webshopapps-matrixrate--the-original-multiple-table-rate-solution--certified-bug-free&lt;/a&gt;). It&amp;#39;s a really great module and would recommend it for anyone who needs to use tablerates as their shipping method.&lt;/li&gt;
	&lt;li&gt;
		&amp;nbsp;The main advantage of this module is that it provided partial postcode matching out of the box. So it was easy to setup an &amp;quot;all--Ireland&amp;quot; rate since all Northern Ireland postcodes start with &amp;quot;BT&amp;quot;. Just give all &amp;quot;GBR&amp;quot; shipping destinations with postcode starting with &amp;quot;BT&amp;quot; the same cost as the Irish rate.&lt;/li&gt;
	&lt;li&gt;
		&amp;nbsp;The next issue, which I&amp;#39;ve come across a number of times, is the concept of an EU rate and a non-EU European rate. Rather than having to put in the same rates 27 times to account for each EU country, and another 10 or 20 times for the non-EU countries, I decided to custom code things. I put the value of &amp;quot;EUR&amp;quot; and &amp;quot;!EU&amp;quot; into the database to denote EU and non-EU respectively. When retrieving rates, I check to see if the country code (e.g., &amp;#39;DE&amp;#39; for Germany) is in an array which contains all the country codes for EU and non-EU countries respectively. If so, I return the EU/non-EU shipping rate. 5-10 lines of code saving thousands of lines in the database/CSV.&lt;/li&gt;
	&lt;li&gt;
		&amp;nbsp;Matrixrate is based on importing a CSV with the desired rates. So first I created a CSV for all the different zones (Ireland, UK, EU, Non-EU, Rest of the World) with all the different shipping options An Post offers (Standard Post, Registered Post, Express Post, Courier Post) and imported that. I then made a backup of the resulting database table and put the SQL for this table into the installer script for the module.&lt;/li&gt;
	&lt;li&gt;
		&amp;nbsp;Finally, I should point out that An Post has different rates based on what type of package is being sent (Envelope, Large Envelope, Packet, Package). Envelope and Large Envelope are ignored in this module. There is an assumption that Packets are used for the lightest shipments, and Packages are used thereafter. I think this is a reasonable assumption - take a look at the An Post rates on their website here - http://www.anpost.ie/AnPost/PostalRates/Standard+Post.htm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
	&lt;br /&gt;
	Anyway, if you&amp;#39;re interested in using the module, you can find it here: &lt;a href="http://www.magentocommerce.com/magento-connect/SF9/extension/5980/sf9_anpost"&gt;http://www.magentocommerce.com/magento-connect/SF9/extension/5980/sf9_anpost&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/7EJDotFjUA0" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[General,]]></dc:subject>
      <dc:date>2011-03-08T23:02:21+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/an_irish_module_for_magento#When:23:02:21Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[Taking Control of Product Options in Magento]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/w0He96iv5ms/taking_control_of_product_options_in_magento</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/taking_control_of_product_options_in_magento#When:12:05:41Z</guid>
      <description>&lt;p&gt;
	It&amp;#39;s about 18 months since I first grappled with custom options for products in Magento. This was for the &lt;a href="http://www.myblinds.ie"&gt;MyBlinds&lt;/a&gt; website which I&amp;#39;ve blogged about &lt;a href="http://www.studioforty9.com/blog/myblinds.ie"&gt;previously&lt;/a&gt;, and will do so again. A large number of products (2000), a number of different product types (7) as well a&amp;nbsp; reasonable number of options per product (on average 6) meant a complicated category setup. Ultimately, in this scenario, I built a custom import script that imported the custom options for each product type.&lt;/p&gt;
&lt;p&gt;
	Unfortunately, at the time, I wasn&amp;#39;t aware of &lt;a href="http://www.magentocommerce.com/magento-connect/AITOC%2C+Inc./extension/1431/custom-options-templates"&gt;Custom Option Templates&lt;/a&gt;. This module allows you to create a template of custom options, and apply it to whatever products you like. So there&amp;#39;s no need to import the custom options for the products, but just assign the appropriate template post-import.&lt;/p&gt;
&lt;p&gt;
	I&amp;#39;ve only come across one problem with this module. It has problems assigning more than 200 products to a particular template. This isn&amp;#39;t the end of the world, as we can just create a duplicate of a particular template, and assign the duplicate template to the products beyond 200. You need to be careful in doing this, as it can be easy to assign 2 or more templates to 1 product, and none to another, if you&amp;#39;re not careful about how you go about it.&lt;/p&gt;
&lt;p&gt;
	What&amp;#39;s also important, I think, in getting to grips with custom options for products in Magento, is to seriously consider scrapping the default product view template (/app/design/frontend/&amp;lt;your_interface&amp;gt;/&amp;lt;your_theme&amp;gt;/template/catalog/product/view.phtml). It&amp;#39;s very restricting in how it renders custom options. There&amp;#39;s no flexibility in terms of more sophisticated validation, tooltips to explain the meaning/importance of certain options, etc.&lt;/p&gt;
&lt;p&gt;
	As an example of the restrictions in the rendering of custom options in the default template, the input fields have ids something like &amp;quot;option_728&amp;quot;. What is the use of a unique identifier that I have no way of knowing what it is in advance, so that I can not target it using Javascript or CSS?&lt;/p&gt;
&lt;p&gt;
	Instead I find it better to create a custom view template for each of your product types where you can hand-craft the HTML to fit your user experience needs. This gives you complete control over how the page looks and you can create radically different product view pages based on the product type or category. In hand-crafting the HTML, it can become a little more complex to put in the appropriate option ids and names on the input fields. Thus far, I&amp;#39;ve been updating the options with the appropriate names using AJAX on product load. This isn&amp;#39;t ideal and I will be working on some custom functions to do this as part of the page rendering on a current project. But ultimately you can add the necessary ids and classes to your custom options so you can target them to your heart&amp;#39;s content.&lt;/p&gt;
&lt;p&gt;
	The only problem in this approach, is that the &amp;quot;custom layout update&amp;quot; field needs to be filled in for each product with the appropriate update to use the custom template rather than the default template:&lt;/p&gt;
&lt;pre class="syntax brush-xml"&gt;
&amp;lt;reference name=&amp;quot;product.info&amp;quot;&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;action method=&amp;quot;setTemplate&amp;quot;&amp;gt;&amp;lt;template&amp;gt;catalog/product/custom.phtml&amp;lt;/template&amp;gt;&amp;lt;/action&amp;gt;
	&amp;lt;/reference&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
	Obviously, if you want to make a change to the name of the template being used, you can use the mass update attributes action in the product grid in the Magento backend. It does seem like overkill however. Wouldn&amp;#39;t it be nice to be able to simply set the product page template at the category level. This is possible with a small piece of custom code. By default, Magento will let you set the page layout or custom design of a category to be applicable to its subcategories and products. However, this doesn&amp;#39;t extend to &amp;quot;custom layout updates&amp;quot;. So that&amp;#39;s what the following code does. It means that when you set a custom layout update in a category, and set it to apply to all of its children, that it will be taken up by the products. In this way, we can set a custom product template for an entire category, in one place only.&lt;/p&gt;
&lt;pre class="syntax brush-xml"&gt;
&amp;lt;global&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;models&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;catalog&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;rewrite&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;category&amp;gt;SF9_Custom_Model_Category&amp;lt;/category&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;product&amp;gt;SF9_Custom_Model_Product&amp;lt;/product&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/rewrite&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/catalog&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/models&amp;gt;
	&amp;lt;/global&amp;gt;
&lt;/pre&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;?php
	class SF9_Custom_Model_Category extends Mage_Catalog_Model_Category
	{&amp;nbsp; &amp;nbsp;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; public function getCustomLayoutUpdate(){
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $customLayoutUpdate = $this-&amp;gt;getData(&amp;#39;custom_layout_update&amp;#39;);
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ($customLayoutUpdate == &amp;quot;&amp;quot;) {
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $parent = $this-&amp;gt;getParentCategory();
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if($parent){
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $customLayoutUpdate = $parent-&amp;gt;getCustomLayoutUpdate();
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return $customLayoutUpdate;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; }
	}
?&amp;gt;
&lt;/pre&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;?php
	class SF9_Custom_Model_Product extends Mage_Catalog_Model_Product
	{&amp;nbsp; &amp;nbsp;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; public function getCustomLayoutUpdate(){
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $customLayoutUpdate = $this-&amp;gt;getData(&amp;#39;custom_layout_update&amp;#39;);
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ($customLayoutUpdate == &amp;quot;&amp;quot;) {
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $parent = Mage::registry(&amp;#39;current_category&amp;#39;);
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if($parent){
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $customLayoutUpdate = $parent-&amp;gt;getCustomLayoutUpdate();
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return $customLayoutUpdate;
	&amp;nbsp;&amp;nbsp;&amp;nbsp; }
	}
?&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/w0He96iv5ms" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[General,]]></dc:subject>
      <dc:date>2011-02-21T12:05:41+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/taking_control_of_product_options_in_magento#When:12:05:41Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[jQuery in Magento made easy]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/HYVp1YuxkXk/jquery_in_magento_made_easy</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/jquery_in_magento_made_easy#When:15:03:15Z</guid>
      <description>(or sophisticated depending on your point of vew)&lt;p&gt;
	First of all I&amp;#39;d like to credit my colleague &lt;a href="http://www.studioforty9.com/our-team#eoghan-obrien"&gt;Eoghan&lt;/a&gt;. He&amp;#39;s the Javascript guru in the company, and really this blog post is based on a library he developed for use on our projects, adapted for Magento. I&amp;#39;m still feeling my way around Javascript, in terms of taking advantage of the existing frameworks (jQuery, Prototype, MooTools) to write modular code that is loosely coupled with the underlying HTML/CSS.&lt;/p&gt;
&lt;p&gt;
	For those of you who have used Magento, you will know that it comes packaged with Prototype and Scriptaculous. The entire functionality both frontend and backend is dependent on the 10 or so Javascript classes written on top of Prototype. While technically it is possible to strip back this Javascript to allow orders to be placed for users without Javascript enabled, it really depends on your setup and is a reasonable amount of work for a questionable pay-off.&lt;/p&gt;
&lt;p&gt;
	But of course, Prototype is somewhat limited as a framework. Not only does it not have the same amount of 3rd party modules written for it, in comparison with jQuery, but it also tends to be a bit more verbose in terms of getting it to do what you want. So it&amp;#39;s not surprising that Magento Connect is littered with modules that provide functionality (e.g., slideshows) that are written in jQuery.&lt;/p&gt;
&lt;p&gt;
	Of course, you can&amp;#39;t just throw the jQuery library and some custom code into a Magento template and expect it to work. There will be conflicts between Prototype and jQuery as both use the &amp;#39;$&amp;#39; sign notation. Fortunately, jQuery has the noConflict() method that you can use to allow Prototype and jQuery to function happily together.&lt;/p&gt;
&lt;p&gt;
	But as online shops become more sophisticated in terms of the user experience, there can be an increase in the number of jQuery modules being used on the store. For example, on a store I am building at the moment you have a sliding panel and a &lt;a href="http://leandrovieira.com/projects/jquery/lightbox/"&gt;lightbox&lt;/a&gt; on every page, as well as an image &lt;a href="http://www.mind-projects.it/projects/jqzoom/"&gt;zoom&lt;/a&gt;, a &lt;a href="https://github.com/mattfarina/farbtastic"&gt;colour picker&lt;/a&gt; and another sliding panel on the product page. If we start putting &amp;lt;script&amp;gt; tags into the Magento template files where each particular functionality is needed, we soon end up with code that is difficult to maintain. Not only that, but including Javascript inline like that, &lt;a href="http://developer.yahoo.com/performance/rules.html#external"&gt;slows down page loads&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
	So rather than having each piece of jQuery in the appropriate template, remembering to wrap it with noConflict() each time, let&amp;#39;s put it in one file for the entire site. Here&amp;#39;s the example I&amp;#39;ll be using:&lt;/p&gt;
&lt;pre class="syntax brush-js"&gt;
(function($){

     $.studioforty9= {
          version: &amp;#39;0.1&amp;#39;,
          website: &amp;#39;http://dev.studioforty9.com/&amp;#39;,
          sections: {
               &amp;#39;cms-index-index&amp;#39; : &amp;#39;this.initHome()&amp;#39;,
               &amp;#39;cms-page-view&amp;#39; : &amp;#39;this.initCMS()&amp;#39;,
               &amp;#39;catalog-category-view&amp;#39; : &amp;#39;this.initCategory()&amp;#39;,
               &amp;#39;catalog-product-view&amp;#39; : &amp;#39;this.initProduct()&amp;#39;,
               &amp;#39;checkout-cart-index&amp;#39; : &amp;#39;this.initCart()&amp;#39;,
               &amp;#39;checkout-onepage-index&amp;#39; : &amp;#39;this.initCheckout()&amp;#39;
          },
          init: function()
          {
               this.TopPanel();
               this.LightBox();
          },
          initSiteSection: function(section){
               var section = $(&amp;#39;body&amp;#39;).attr(&amp;#39;class&amp;#39;).split(&amp;#39; &amp;#39;)[1];
               eval(this.sections[section]);
          },
          initHome: function(){},
          initCMS: function(){},
          initCategory: function(){},
          initProduct: function(){
               this.ProductOptions();
               this.ProductZoom();
               this.ColourPicker()
          },
          initCart: function(){},
          initCheckout: function(){},
          Utilities:
          {
               external: function() {
                    $(&amp;#39;A[rel*=&amp;quot;external&amp;quot;]&amp;#39;).click(function(e) {
                         var url = $(this).attr(&amp;#39;href&amp;#39;);
                         window.open(url);
                         e.preventDefault();
                    });
               }
          },
          Forms:
          {
               focus: function() {
                    var prevLabel = &amp;#39;&amp;#39;;
                    $(&amp;#39;.focus&amp;#39;).focus(function() {
                         if ( $.trim($(this).val()) == $(this).attr(&amp;#39;title&amp;#39;) ) {
                              prevLabel = $(this).val();
                              $(this).val(&amp;#39;&amp;#39;);
                         }
                    });
                    $(&amp;#39;.focus&amp;#39;).blur(function() {
                         if ( $(this).val() == &amp;#39;&amp;#39; ) {
                              $(this).val(prevLabel);
                         }
                    });
               }
          },
          TopPanel: function() {
               $(&amp;#39;#lightbox-link&amp;#39;).bind(&amp;#39;click&amp;#39;, function(event){
                    event.preventDefault();
                    $(&amp;#39;.lightbox&amp;#39;).slideDown(&amp;#39;slow&amp;#39;);
                    $(&amp;#39;#close-link&amp;#39;).show();
               });
              
               $(&amp;#39;#login-link&amp;#39;).bind(&amp;#39;click&amp;#39;, function(event){
                    event.preventDefault();
                    $(&amp;#39;.login&amp;#39;).slideDown(&amp;#39;slow&amp;#39;);
                    $(&amp;#39;#close-link&amp;#39;).show();
               });
              
               $(&amp;#39;#close-link&amp;#39;).bind(&amp;#39;click&amp;#39;, function(event){
                    event.preventDefault();
                    $(&amp;#39;.login&amp;#39;).slideUp(&amp;#39;slow&amp;#39;);
                    $(&amp;#39;.lightbox&amp;#39;).slideUp(&amp;#39;slow&amp;#39;);
                    $(&amp;#39;#close-link&amp;#39;).fadeOut(&amp;#39;slow&amp;#39;);
               });
          },
          LightBox: function(){
               $(&amp;#39;.lightbox-img&amp;#39;).lightBox({
                    containerResizeSpeed: 800,
                    imageLoading: &amp;#39;http://dev.studioforty9.com/skin/frontend/default/modern/img/lightbox-ico-loading.gif&amp;#39;,
                    imageBtnClose: &amp;#39;http://dev.studioforty9.com/skin/frontend/default/modern/img/lightbox-btn-close.gif&amp;#39;,
                    imageBtnPrev: &amp;#39;http://dev.studioforty9.com/skin/frontend/default/modern/img/lightbox-btn-prev.gif&amp;#39;,
                    imageBtnNext: &amp;#39;http://dev.studioforty9.com/skin/frontend/default/modern/img/lightbox-btn-next.gif&amp;#39;,
               });
          },    
          ProductOptions: function(){
               if($(&amp;#39;#choose-options&amp;#39;).length &amp;gt; 0){
                    $(&amp;#39;#choose-options&amp;#39;).bind(&amp;#39;click&amp;#39;, function(event){
                         event.preventDefault();
                         $(&amp;#39;.options&amp;#39;).slideToggle(&amp;#39;slow&amp;#39;);
                    });
               }
          },
          ProductZoom: function(){    
               var options = {
                             zoomWidth: 300,
                             zoomHeight: 260,
                           xOffset: 122,
                           yOffset: -82,
                           position: &amp;quot;right&amp;quot;,
                           title: false
               };

               $(&amp;#39;.product-image-zoom a&amp;#39;).jqzoom(options);
          },
          ColourPicker: function(){    
               $(&amp;#39;#picker-link a&amp;#39;).bind(&amp;#39;click&amp;#39;, function(event){
                    event.preventDefault();
                    $(&amp;#39;#colour-picker&amp;#39;).fadeToggle();
               });                    
              
               $(&amp;#39;#colour-picker&amp;#39;).farbtastic({callback : &amp;#39;.product-essential&amp;#39;, width: 150});
          }
     }

     $(function() {
          $.studioforty9.init();
          $.studioforty9.initSiteSection();
     });

})(jQuery.noConflict());
&lt;/pre&gt;
&lt;p&gt;
	There&amp;#39;s a few things I&amp;#39;d like to point out about this code.&lt;/p&gt;
&lt;p&gt;
	First of all, there&amp;#39;s only one call to noConflict(). The entire code is wrapped as an anonymous function, and noConflict() applied to this. Easy!&lt;/p&gt;
&lt;p&gt;
	Second, also at the bottom of the code is the equivalent of the onDomReady function. This is the code that is run when the page is finished loading. 2 lines. Easy to see what&amp;#39;s going on. There&amp;#39;s the init() function that calls other functions that we want to run on every page on the site. So in our case this is the TopPanel that slides down when particular links are clicked and the LightBox for particular images.&lt;/p&gt;
&lt;p&gt;
	The other function is initSiteSection(). As we&amp;#39;ve said already, we want certain code to only be run on certain pages. Rather than introduce a raft of if...else statements, we can leverage Magento to figure this out in a more seamless manner. Each Magento page has particular classes on the&lt;/p&gt;
&lt;p&gt;
	tag. The main ones are listed in the sections object. We associate these classes with a particular function to run (e.g., when the&lt;/p&gt;
&lt;p&gt;
	tag has a class of &amp;#39;catalog-product-view&amp;#39; we want to run the initProduct() function). This way it&amp;#39;s very easy to find out exactly what code from the class is running on any given page.*&lt;/p&gt;
&lt;p&gt;
	* I should point out that it&amp;#39;s also necessary to include the relevant libraries in the appropriate layout XML file. So for example, we would want to add the following lines of code to catalog.xml file of our theme to add the jqZoom library to&lt;/p&gt;
&lt;p&gt;
	of the page:&lt;/p&gt;
&lt;pre class="syntax brush-xml"&gt;
&amp;lt;catalog_product_view translate=&amp;quot;label&amp;quot;&amp;gt;
          ...
        &amp;lt;reference name=&amp;quot;head&amp;quot;&amp;gt;
          ...  
          &amp;lt;action method=&amp;quot;addItem&amp;quot;&amp;gt;&amp;lt;type&amp;gt;skin_js&amp;lt;/type&amp;gt;&amp;lt;name&amp;gt;js/jquery.jqzoom1.0.1.js&amp;lt;/name&amp;gt;&amp;lt;/action&amp;gt;
          &amp;lt;action method=&amp;quot;addItem&amp;quot;&amp;gt;&amp;lt;type&amp;gt;skin_css&amp;lt;/type&amp;gt;&amp;lt;name&amp;gt;css/jqzoom.css&amp;lt;/name&amp;gt;&amp;lt;/action&amp;gt;
          ...
        &amp;lt;/reference&amp;gt;

        ...
&amp;lt;/catalog_product_view&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/HYVp1YuxkXk" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Magento,]]></dc:subject>
      <dc:date>2011-02-13T15:03:15+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/jquery_in_magento_made_easy#When:15:03:15Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[Restricting Product Purchase to Authorised Users in Magento]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/KeXXFfgy0l0/restricting_product_purchase_to_authorised_users_in_magento</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/restricting_product_purchase_to_authorised_users_in_magento#When:10:44:06Z</guid>
      <description>Quick ways to exend Magento's default functionality&lt;p&gt;
	I haven&amp;#39;t written about e-commerce for quite a while now. Magento has been keeping me busy and now I&amp;#39;ve a list of thoughts and insights that I hope to share in the coming weeks.&lt;/p&gt;
&lt;p&gt;
	So first off, I&amp;#39;d like to describe a recent module I wrote that might seem reasonably complex. However, I&amp;#39;d like to show how easy it can be when taking advantage of Magento&amp;#39;s features.&lt;/p&gt;
&lt;p&gt;
	The idea behind the module is that a customer may only purchase a particular product by entering a code. There&amp;#39;s 4 parts to the module:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;
		The product view page where the customer can enter their code.&lt;/li&gt;
	&lt;li&gt;
		An override of the default Add to Cart functionality in Magento to validate the given Code&lt;/li&gt;
	&lt;li&gt;
		A section in the Magento backend for managing Codes.&lt;/li&gt;
	&lt;li&gt;
		An event listener to observe when a customer places an order so that the code can be marked as &amp;quot;used&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
	&lt;img alt="" src="http://www.studioforty9.com/assets/uploads/page/Screen shot 2011-02-06 at 6 February 21_01_09.jpg" style="width: 600px; height: 283px; border-width: 0px; border-style: solid; margin: 5px;" /&gt;&lt;/p&gt;
&lt;p&gt;
	The basics of the module can be setup using ModuleCreator (&lt;a href="http://www.magentocommerce.com/magento-connect/Daniel+Nitz/extension/1108/modulecreator"&gt;http://www.magentocommerce.com/magento-connect/Daniel+Nitz/extension/1108/modulecreator&lt;/a&gt;). The module doesn&amp;#39;t really install properly in Magento 1.4.x but I&amp;#39;ve used it enough times at this stage to be able to copy the files over manually and do some search and replace over them to get it the way I want it.&lt;/p&gt;
&lt;p&gt;
	Once the files, are in place, the most important thing is to design the table structure in the database and write the SQL installation script. The fields I needed were:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;
		code_id&lt;/li&gt;
	&lt;li&gt;
		country_id&lt;/li&gt;
	&lt;li&gt;
		customer_ip&lt;/li&gt;
	&lt;li&gt;
		valid_to&lt;/li&gt;
	&lt;li&gt;
		valid_from&lt;/li&gt;
	&lt;li&gt;
		used_timestamp&lt;/li&gt;
	&lt;li&gt;
		status&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
	Once installed in Magento, you can start fixing up the grid and add/edit screens to show you the fields for your particular module (rather than the default ModuleCreator fields). Having useful field types in the grid is a topic I intend to return to in a future post.&lt;/p&gt;
&lt;p&gt;
	After that, it&amp;#39;s just a matter of creating a test product and giving it a custom option where the customer can enter the code.&lt;/p&gt;
&lt;p&gt;
	We then override the Add to Cart functionality. So I override /app/code/core/Mage/Checkout/Model/Cart.php. To do this I add the following lines to the config.xml file of my module:&lt;/p&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;models&amp;gt;
	&amp;nbsp;&amp;nbsp; ...
	&amp;nbsp;&amp;nbsp; &amp;lt;checkout&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;rewrite&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;cart&amp;gt;SF9_Codes_Model_Cart&amp;lt;/cart&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/rewrite&amp;gt;
	&amp;nbsp;&amp;nbsp; &amp;lt;/checkout&amp;gt;
	&amp;lt;/models&amp;gt;&lt;/pre&gt;
&lt;p&gt;
	and I create my own Cart.php file&lt;/p&gt;
&lt;pre class="syntax brush-php"&gt;
class SF9_Codes_Model_Cart extends Mage_Checkout_Model_Cart
{
     public function addProduct($product, $info=null){
        $code_title = Mage::getStoreConfig(&amp;#39;codes/codes/custom_option_title&amp;#39;, 1);
        $error_message = Mage::getStoreConfig(&amp;#39;codes/codes/invalid_code_error_message&amp;#39;, 1);
    
          $options = array();
         
          foreach ($product-&amp;gt;getOptions() as $_option) {
               $options[$_option-&amp;gt;getId()] = $_option-&amp;gt;getTitle();
          }
         
          if(!in_array($code_title, $options)){
               parent::addProduct($product, $info);
               return;
          }         
         
          foreach($info[&amp;#39;options&amp;#39;] as $key =&amp;gt; $value){
               if(in_array($key, array_keys($options)) ){
                    $code = $value;
               }
          }         
    
          $timestamp = date(&amp;#39;Y-m-d H:i:s&amp;#39;);
         
          $codes = Mage::getModel(&amp;#39;codes/codes&amp;#39;)-&amp;gt;getCollection()
                         -&amp;gt;addFieldToSelect(&amp;#39;*&amp;#39;)
                         -&amp;gt;addFieldToFilter(&amp;#39;code&amp;#39;, $code)
                         -&amp;gt;addFieldToFilter(&amp;#39;status&amp;#39;, 0)
                         -&amp;gt;addFieldToFilter(&amp;#39;valid_from&amp;#39;, array(&amp;#39;date&amp;#39; =&amp;gt; true, &amp;#39;to&amp;#39; =&amp;gt; $timestamp))
                         -&amp;gt;addFieldToFilter(&amp;#39;valid_to&amp;#39;, array(&amp;#39;date&amp;#39; =&amp;gt; true, &amp;#39;from&amp;#39; =&amp;gt; $timestamp))
                         -&amp;gt;setPageSize(1);
         
          if(count($codes) &amp;gt; 0){
               parent::addProduct($product, $info);    
          }else{
               Mage::throwException($error_message);
          }
         
     }
}
&lt;/pre&gt;
&lt;p&gt;
	Finally, I create an observer for the order_placed event. To do this, I add the following lines to config.xml&lt;/p&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;events&amp;gt;
	&amp;nbsp;&amp;nbsp; &amp;lt;checkout_type_onepage_save_order_after&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;observers&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;sf9_codes_observer&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;type&amp;gt;singleton&amp;lt;/type&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;class&amp;gt;SF9_Codes_Model_Observer&amp;lt;/class&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;method&amp;gt;update_used_codes&amp;lt;/method&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/sf9_codes_observer&amp;gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/observers&amp;gt;
	&amp;nbsp;&amp;nbsp; &amp;lt;/checkout_type_onepage_save_order_after&amp;gt;
	&amp;lt;/events&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
	and create the following Observer.php file&lt;/p&gt;
&lt;pre class="syntax brush-php"&gt;
class SF9_Codes_Model_Observer{
        
          //runs when order is saved in Onepage Checkout
          public function update_used_codes($observer){
               $event = $observer-&amp;gt;getEvent();
               $order = $event-&amp;gt;getOrder();
              
               $code_title = Mage::getStoreConfig(&amp;#39;codes/codes/custom_option_title&amp;#39;, 1);
              
               $items = $order-&amp;gt;getAllItems();
               foreach($items as $item){
                    $_options = $item-&amp;gt;getProductOptions();
                    foreach($_options[&amp;#39;options&amp;#39;] as $_option){
                         $options[$_option[&amp;#39;label&amp;#39;]] = $_option[&amp;#39;value&amp;#39;];
                    }
                    if(isset($options[$code_title])){
                         $code = $options[$code_title];
                         $codes = Mage::getModel(&amp;#39;codes/codes&amp;#39;)-&amp;gt;getCollection()
                                             -&amp;gt;addFieldToSelect(&amp;#39;*&amp;#39;)
                                             -&amp;gt;addFieldToFilter(&amp;#39;code&amp;#39;, $code)
                                             -&amp;gt;setPageSize(1);
              
                         $update = $codes-&amp;gt;getFirstItem();
                         $timestamp = date(&amp;#39;Y-m-d H:i:s&amp;#39;);                             
                         $update-&amp;gt;setStatus(1)
                                   -&amp;gt;setUsername($order-&amp;gt;getBillingAddress()-&amp;gt;getName())
                                   -&amp;gt;setUserIp($_SERVER[&amp;#39;REMOTE_ADDR&amp;#39;])
                                   -&amp;gt;setUsedTimestamp($timestamp)
                                   -&amp;gt;save();
                    }
               }
          }
     }

&lt;/pre&gt;
&lt;p&gt;
	&lt;img alt="" src="http://www.studioforty9.com/assets/uploads/page/Screen shot 2011-02-06 at 6 February 20_59_27.jpg" style="width: 600px; height: 280px; border-width: 0px; border-style: solid; margin: 5px;" /&gt;&lt;/p&gt;
&lt;p&gt;
	What&amp;#39;s nice about the module is how it exemplifies in a very succinct way the different ways to extend Magento&amp;#39;s core functionality. You can extend a core PHP file when you want to alter the default behaviour or create an observer that listens to one of the approximately 280 events that Magento fires off when you want to do something extra at a particular time (in this case, update the code&amp;#39;s status to &amp;quot;used&amp;quot; and write its &amp;quot;used timestamp&amp;quot;.&lt;/p&gt;
&lt;p&gt;
	Now, let&amp;#39;s hope I can make blogging about Magento more of a habit!!&lt;/p&gt;
&lt;p&gt;
	&lt;img alt="" src="http://www.studioforty9.com/assets/uploads/page/Screen shot 2011-02-06 at 6 February 21_00_04.jpg" style="width: 601px; height: 279px; border-width: 0px; border-style: solid; margin: 5px;" /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/KeXXFfgy0l0" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Magento,]]></dc:subject>
      <dc:date>2011-02-07T10:44:06+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/restricting_product_purchase_to_authorised_users_in_magento#When:10:44:06Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[West Cork Homeless]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/Xkq1XyDPYh0/west_cork_homeless</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/west_cork_homeless#When:18:22:00Z</guid>
      <description>A little search engine boost for a good cause&lt;p&gt;
	I just set up a teeny tiny brochure site for &lt;a href="http://www.westcorkhomeless.com"&gt;West Cork Homeless&lt;/a&gt;&amp;nbsp;and now I want to give it a small shove into the Search Engine&amp;#39;s spotlights.&lt;/p&gt;
&lt;p&gt;
	The Tenancy Sustainment and Support Service is run by Novas Initiatives in partnership with Cork County Council and the HSE South. The TSS role is to aid people who are homeless or at risk of homelessness. There are a number of &lt;a href="http://www.westcorkhomeless.com/services.php"&gt;Tenancy Support and Advice Clinics&lt;/a&gt; run as part of the service across West Cork.&lt;/p&gt;
&lt;p&gt;
	&lt;strong&gt;Useful Services for Really Small Sites&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
	This little New Year&amp;#39;s Eve job was done on a &lt;em&gt;&amp;quot;favour for a good cause&amp;quot;&lt;/em&gt; basis, but I still wanted to provide some level of functionality in terms of Content Mangement and Contact Forms. Obviously our standard tool of choice when it comes to a CMS, &lt;em&gt;Expression Engine&lt;/em&gt;, is too full-on and industrial strength for such a small job so I was in the unusual position of looking for a very small and handy CMS for the site. I quickly whittled the candidates down to &lt;a href="http://grabaperch.com/"&gt;Perch&lt;/a&gt; and&amp;nbsp;&lt;a href="http://www.cushycms.com/"&gt;CushyCMS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
	&lt;strong&gt;Perch&lt;/strong&gt; has the advantage of being run off your own server, is brandable, and is yours for a once-off small fee (35 GBP).&lt;/p&gt;
&lt;p&gt;
	&lt;strong&gt;CushyCMS&lt;/strong&gt; is also brandable for a monthly charge (29 USD), it does CMS via FTP so realistically there&amp;#39;s no set up, and if you don&amp;#39;t mind the CushyCMS branding (which in this case I didn&amp;#39;t) it&amp;#39;s free.&lt;/p&gt;
&lt;p&gt;
	Otherwise, the two are relatively similar in how they operate: within the HTML you identify the regions of the site you want to edit and the system will allow your client / editor to edit them in a simple interface. In fairness, both systems would have been ideal for this job - but at no cost and no setup I decided to go for CushyCMS for this particular job. If I needed branding and management on the site&amp;#39;s own server, I would certainly have preferred to pay a once-off fee for Perch rather than the monthly charge for CushyCMS (although it should be noted that the monthly charge is for unlimited sites under your control).&lt;/p&gt;
&lt;p&gt;
	For simple-to-setup (and free) forms I go for the incomparable and incredible powerful &lt;a href="http://wufoo.com/"&gt;Wufoo&lt;/a&gt;. It&amp;#39;s pretty stunning what you can do with this service now, and in fairness we do have one or two clients who pay the monthly fee to Wufoo for the more advanced features - but if you need a simple form, with notifications (both to you and your client), as well as online storage of entries you really can&amp;#39;t beat Wufoo - a fantastic service.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
	Best wishes to West Cork Homeless and their new services and clinics.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/Xkq1XyDPYh0" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[General,]]></dc:subject>
      <dc:date>2010-12-31T18:22:00+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/west_cork_homeless#When:18:22:00Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[Fota Wildlife wins Best Tourism &amp; Travel Website&#8230; and also takes the Eircom Spiders Grand Prix]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/30dDQFFZXQs/fota-wildlife-wins-eircom-spiders-grand-prix-prize</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/fota-wildlife-wins-eircom-spiders-grand-prix-prize#When:10:05:16Z</guid>
      <description>Congratulations to Fota Wildlife Park who won the Best Tourism &amp; Travel Website 2010 and then won the Eircom Spiders Grand Prix for Best Overall Website 2010.&lt;p&gt;
	Which, by one measure at least, means we built this year&amp;#39;s best Irish website. Wow.&lt;/p&gt;
&lt;p&gt;
	&lt;img alt="Fota Wildlife Park wins the Eircom Spider Grand Prix Award 2010 - woohoo!" src="http://www.studioforty9.com/assets/uploads/page/fota-golden-spider.jpg" style="width: 600px; height: 200px;" /&gt;&lt;/p&gt;
&lt;p&gt;
	But that&amp;#39;s just the icing on the cake, it&amp;#39;s always been an honour to be the company who built the Fota Wildlife website. We&amp;#39;ve had some inspirational clients over the past number of years - and Fota are definitely on that list. They&amp;#39;re outstanding to work with, forward thinking - and a really nice bunch of people! So huge congratulations to everybody over there on winning the two awards!&lt;/p&gt;
&lt;p&gt;
	The sms text I got from Fota&amp;#39;s marketing manager Stephen Ryan after Fota Wildlife were announced as Grand Prix winners was &amp;quot;I&amp;#39;m in shock I nearly fell off my chair&amp;quot;. Well congratulations Stephen - a fully deserved award for all your effort in keeping the site and associated social networks current, lively and active!&lt;/p&gt;
&lt;p&gt;
	From our side, I&amp;#39;d like to give credit to the super-talented web developer Eoghan O&amp;#39;Brien for doing trojan work on the website and also thank Alan Morkan for his moral support (we&amp;#39;ll get an e-commerce site nominated next year Alan!).&lt;/p&gt;
&lt;p&gt;
	Here&amp;#39;s the opinion of the Grand Prix judges:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
	&lt;em&gt;Well developed, rich in content, visually appealing with good navigation. The site makes good use of images and interactive tools, building up a strong relationship with its users. It has also grown a strong online community encouraging repeat visits. There is also good integration with social media tools which are constantly updated and always have something new to offer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
	That&amp;#39;s pretty cool! Actually that&amp;#39;s really cool, the brief from day one was all about &amp;#39;building the community&amp;#39;.&lt;/p&gt;
&lt;p&gt;
	Well now that there&amp;#39;s a reputation to maintain - let&amp;#39;s get to work!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/30dDQFFZXQs" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[General,]]></dc:subject>
      <dc:date>2010-11-19T10:05:16+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/fota-wildlife-wins-eircom-spiders-grand-prix-prize#When:10:05:16Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[Realex Redirect with PHP]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/VJBu2s4ivJE/realex-redirect-with-php</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/realex-redirect-with-php#When:15:38:01Z</guid>
      <description>Automatically submit Realex Redirect form&lt;p&gt;
	Recently, we&amp;#39;ve been working with Realex and the Redirect method for simple once off payments which also require custom data (such as name, email address and a dynamic amount value) taken from user input.&lt;/p&gt;
&lt;p&gt;
	This can be awkward when using the Redirect method as you must first handle the user input before sending the user to pay. Usually, you would need to display a new page showing a form with hidden fields for the data which needs to be passed to Realex and a button such as &amp;#39;Proceed to Secure Server&amp;#39;. This two step process seems a bit cumbersome so we&amp;#39;ve tried to make it easier for people to go from our custom form straight to payment at the Realex server.&lt;/p&gt;
&lt;p&gt;
	In an effort to cut down on the amount of code, we&amp;#39;ve put together a small library of PHP code to do just that and help speed up the development process in future. You can buy our library for &amp;euro;25 excluding VAT.&lt;/p&gt;
&lt;p&gt;
	The library requires PHP version 5.1.4 and includes the following files:&lt;/p&gt;
&lt;pre class="syntax brush-plain"&gt;
documentaion.html
example.html
library
    Studioforty9
        HtmlPage.php
        Realex
            Redirect
                Form.php
                Response.php
                Request.php
&lt;/pre&gt;
&lt;p&gt;
	&lt;a href="http://pul.ly/b/10604" id="purchase-realex-redirect-library" title="Buy SF9 Realex Redirect Library"&gt;Buy Now&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
	Here is an example of how you can create a HTML page dynamically, pass your Request variables to a Realex Form class and submit the form automatically.&lt;/p&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;?php
$formIsValid = FALSE;

function __autoload($class)
{
	$classfile = str_replace(&amp;#39;_&amp;#39;, &amp;#39;/&amp;#39;, $class).&amp;#39;.php&amp;#39;;
	$path_to_library = &amp;#39;/path/to/library/&amp;#39;;
	require_once $path_to_library.$classfile;
}

# Validate User Input Here
if (isset($_POST[&amp;#39;amount&amp;#39;]) {
	$amount = clean($_POST[&amp;#39;amount&amp;#39;]);
	$formIsValid = TRUE;
}

# Check that all the initial User Input data is valid
if (TRUE === $formIsValid) {

	# You can now store the user input or email it to an administrator

	# Create Request
	$Request = new Studioforty9_Realex_Redirect_Request;
	$Request-&amp;gt;setMerchant_ID(&amp;#39;merchant_id&amp;#39;);
	$Request-&amp;gt;setSecret(&amp;#39;secret&amp;#39;);
	$Request-&amp;gt;setAccount(&amp;#39;internet&amp;#39;);
	$Request-&amp;gt;setOrder_ID(&amp;#39;123&amp;#39;);
	$Request-&amp;gt;setCurrency(&amp;#39;EUR&amp;#39;);
	$Request-&amp;gt;setTimestamp(strftime(&amp;quot;%Y%m%d%H%M%S&amp;quot;));
	$Request-&amp;gt;setCust_num(&amp;#39;123&amp;#39;);
	$Request-&amp;gt;setProd_ID(&amp;#39;012345&amp;#39;);
	$Request-&amp;gt;setVar_Ref(&amp;#39;0123456789&amp;#39;);
	$Request-&amp;gt;setAmount($amount * 100);
	$Request-&amp;gt;setSha1Hash($Request-&amp;gt;generateHash());
	
	# Create Form
	$Form = new Studioforty9_Realex_Redirect_Form;
	$Form-&amp;gt;setRequest($Request);
	$Form-&amp;gt;setAttributes(array(&amp;#39;id&amp;#39; =&amp;gt; &amp;#39;realex&amp;#39;, &amp;#39;name&amp;#39; =&amp;gt; &amp;#39;secureserver&amp;#39;));
	
	# Create Page
	$Page = new Studioforty9_HtmlPage();
	$Page-&amp;gt;html();
	$Page-&amp;gt;head(); // Must be called to allow for title, meta, styles and scripts to be added, render() method will not run without it
	$Page-&amp;gt;title(&amp;#39;Realex Redirect Payment&amp;#39;);
	$Page-&amp;gt;addMeta(array(&amp;#39;http-equiv&amp;#39; =&amp;gt; &amp;#39;content-type&amp;#39;, &amp;#39;content&amp;#39; =&amp;gt; &amp;#39;text/html; charset=UTF-8&amp;#39;));
	$Page-&amp;gt;addMeta(array(&amp;#39;name&amp;#39; =&amp;gt; &amp;#39;robots&amp;#39;, &amp;#39;content&amp;#39; =&amp;gt; &amp;#39;nofollow,noindex&amp;#39;));
	$Page-&amp;gt;addStyleToHead(array(&amp;#39;href&amp;#39; =&amp;gt; &amp;#39;/css/realex.css&amp;#39;));
	$Page-&amp;gt;addScriptToHead(array(&amp;#39;src&amp;#39; =&amp;gt; &amp;#39;/js/realex.js&amp;#39;));
	
	# Attach Loading paragraph, 
	$loading = &amp;#39;&amp;lt;p class=&amp;quot;loading&amp;quot;&amp;gt;Please wait while we redirect you to our secure server.&amp;lt;/p&amp;gt;&amp;#39;;
	$Page-&amp;gt;body(
		array(&amp;#39;onload&amp;#39; =&amp;gt; &amp;#39;document.secureserver.submit();&amp;#39;),
		$loading.$Form-&amp;gt;render()
	);
	
	echo $Page-&amp;gt;render();
} else {
	# Redirect the user back the initial form and show errors
}

?&amp;gt;&lt;/pre&gt;
&lt;h2&gt;
	Lets break this down&lt;/h2&gt;
&lt;p&gt;
	Firstly, we&amp;#39;re automatically loading the needed classes on demand with our &lt;code&gt;__autoload()&lt;/code&gt; function, if you decide to use our library make sure you set the correct path to the library folder. If you are on a windows server be sure to change forward slashes to backslashes.&lt;/p&gt;
&lt;p&gt;
	Next, you should validate the user input from the initial form, once we know the user input is valid, we can then store the data to a file or database or just send it out to an administrator.&lt;/p&gt;
&lt;h3&gt;
	The Request Class&lt;/h3&gt;
&lt;p&gt;
	Here&amp;#39;s where it gets interesting, we know the data is valid, we&amp;#39;ve stored it and now we want to send our eager customer to Realex to relieve them of some of their hard-earned cash. Using the Studioforty9_Relex_Redirect library we can create a new Request object like so:&lt;/p&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;?php

$Request = new Studioforty9_Realex_Redirect_Request;

?&amp;gt;&lt;/pre&gt;
&lt;p&gt;
	We can pass in any variables to this object using the &lt;code&gt;setVariable_Name&lt;/code&gt; methods. These method names map to request variables provided by Realex. Notice the underscores in the variables are also present in the method names. (e.g. &lt;code&gt;$Request-&amp;gt;setAuto_Settle_Flag(TRUE);&lt;/code&gt;)&lt;/p&gt;
&lt;pre class="syntax brush-plain"&gt;
merchant_id
secret
account
order_id
currency
timestamp
cust_num
prod_id
var_ref
amount
sha1hash
shipping_code
shipping_co
billing_code
billing_co
return_tss
auto_settle_flag
&lt;/pre&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;?php

$Request-&amp;gt;setMerchant_ID(&amp;#39;your_merchant_id&amp;#39;);
$Request-&amp;gt;setSecret(&amp;#39;your_shared_secret&amp;#39;);
$Request-&amp;gt;setAccount(&amp;#39;internet&amp;#39;);
$Request-&amp;gt;setOrder_ID(&amp;#39;123&amp;#39;);
$Request-&amp;gt;setCurrency(&amp;#39;EUR&amp;#39;);
$Request-&amp;gt;setTimestamp(strftime(&amp;quot;%Y%m%d%H%M%S&amp;quot;));
$Request-&amp;gt;setCust_num(&amp;#39;123&amp;#39;);
$Request-&amp;gt;setProd_ID(&amp;#39;012345&amp;#39;);
$Request-&amp;gt;setVar_Ref(&amp;#39;0123456789&amp;#39;);
$Request-&amp;gt;setAmount($amount * 100);

?&amp;gt;&lt;/pre&gt;
&lt;p&gt;
	The last thing you need to do with the &lt;code&gt;Studioforty9_Realex_Redirect_Request&lt;/code&gt; object is generate the Realex sha1 hash, our Request class provides an easy method for this so that all you need to do is call:&lt;/p&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;?php

$Request-&amp;gt;setSha1Hash($Request-&amp;gt;generateHash());

?&amp;gt;&lt;/pre&gt;
&lt;h3&gt;
	The Form Class&lt;/h3&gt;
&lt;p&gt;
	Once we have passed all our variables to the Request, we can then create a new Form object to dynamically build the form that will send the customer to Realex.&lt;/p&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;?php

$Form = new Studioforty9_Realex_Redirect_Form;
$Form-&amp;gt;setRequest($Request);
$Form-&amp;gt;setAttributes(array(&amp;#39;id&amp;#39; =&amp;gt; &amp;#39;realex&amp;#39;, &amp;#39;name&amp;#39; =&amp;gt; &amp;#39;secureserver&amp;#39;));

?&amp;gt;&lt;/pre&gt;
&lt;p&gt;
	All we need to do is create a new instance of &lt;code&gt;Studioforty9_Realex_Redirect_Form&lt;/code&gt; and pass the Request object with the &lt;code&gt;setRequest()&lt;/code&gt; method. Then I&amp;#39;ve added two attributes, and &lt;code&gt;id&lt;/code&gt; for styling purposes and a &lt;code&gt;name&lt;/code&gt; so that I can submit the form automatically when the page loads. The Form object also has a &lt;code&gt;render()&lt;/code&gt; method which we will use later.&lt;/p&gt;
&lt;h3&gt;
	The HtmlPage Class&lt;/h3&gt;
&lt;p&gt;
	The &lt;code&gt;Studioforty9_HtmlPage&lt;/code&gt; class provides a simple interface to create a HTML page without writing a single line of HTML. It uses the built in &lt;a href="http://ie2.php.net/manual/en/class.domdocument.php"&gt;DOMDocument&lt;/a&gt; class to programatically create and render a valid HTML page. We will use it to build a page for our Realex form on the fly and pass attributes to our &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag to send the form automatically.&lt;/p&gt;
&lt;pre class="syntax brush-php"&gt;
&amp;lt;?php

$Page = new Studioforty9_HtmlPage();
$Page-&amp;gt;html();
$Page-&amp;gt;head(); // Must be called to allow for title, meta, styles and scripts to be added, render() method will not run without it
$Page-&amp;gt;title(&amp;#39;Realex Redirect Payment&amp;#39;);
$Page-&amp;gt;addMeta(array(&amp;#39;http-equiv&amp;#39; =&amp;gt; &amp;#39;content-type&amp;#39;, &amp;#39;content&amp;#39; =&amp;gt; &amp;#39;text/html; charset=UTF-8&amp;#39;));
$Page-&amp;gt;addMeta(array(&amp;#39;name&amp;#39; =&amp;gt; &amp;#39;robots&amp;#39;, &amp;#39;content&amp;#39; =&amp;gt; &amp;#39;nofollow,noindex&amp;#39;));
$Page-&amp;gt;addStyleToHead(array(&amp;#39;href&amp;#39; =&amp;gt; &amp;#39;/css/realex.css&amp;#39;));
$Page-&amp;gt;addScriptToHead(array(&amp;#39;src&amp;#39; =&amp;gt; &amp;#39;/js/realex.js&amp;#39;));
$loading = &amp;#39;&amp;amp;lt;p class=&amp;quot;loading&amp;quot;&amp;gt;Please wait while we redirect you to our secure server.&amp;lt;/p&amp;gt;&amp;#39;;
$Page-&amp;gt;body(
	array(&amp;#39;onload&amp;#39; =&amp;gt; &amp;#39;document.secureserver.submit();&amp;#39;),
	$loading.$Form-&amp;gt;render()
);
?&amp;gt;&lt;/pre&gt;
&lt;p&gt;
	This class is fairly straight forward, we create an instance of &lt;code&gt;Studioforty9_HtmlPage&lt;/code&gt; and call its constructor method, which automatically creates a new &lt;acronym title="eXtensible Hypertext Markup Language"&gt;XHTML&lt;/acronym&gt; Strict Document, we call the &lt;code&gt;html&lt;/code&gt; method to create the root HTML node, we must also call the &lt;code&gt;head&lt;/code&gt; so we have a parent node for &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;meta&lt;/code&gt;, &lt;code&gt;style&lt;/code&gt; and &lt;code&gt;script&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
	You set the title of the document using the &lt;code&gt;title&lt;/code&gt; method, the &lt;code&gt;addMeta&lt;/code&gt; meta simply takes an array of attributes, the &lt;code&gt;addStyleToHead&lt;/code&gt; and &lt;code&gt;addScriptToHead&lt;/code&gt; methods will figure out whether to link to a resource or embed the code based on the attributes you provide, so for example, if you don&amp;#39;t pass an &lt;code&gt;src&lt;/code&gt; attribute to &lt;code&gt;addScriptToHead&lt;/code&gt; it will assume you wish to embed javascript in the head which you can do like so &lt;code&gt;$Page-&amp;gt;addScriptToHead(array(), &amp;quot;var greeting = &amp;#39;Hello World!&amp;#39;;&amp;quot;);&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
	Next, we need to create a loading message to show the customer while the browser attempts to automatically submit your form, if you want to show a spinner/animated gif, you can either add to image in directly here or add a &lt;acronym title="Cascading StyleSheet"&gt;CSS&lt;/acronym&gt; class hook to allow for more control. Lastly you need to pass some variables to the &lt;code&gt;body&lt;/code&gt; method, the &lt;code&gt;onload&lt;/code&gt; attribute needs some simple javascript code to submit the form and we also need to pass in our loading content as well as our &lt;code&gt;Studioforty9_Realex_Redirect_Form&lt;/code&gt; object&amp;#39;s &lt;code&gt;render&lt;/code&gt; method&lt;/p&gt;
&lt;p&gt;
	Finally, we run &lt;code&gt;echo $Page-&amp;gt;render();&lt;/code&gt; which sends everything to the browser for display. You should now have a simple, re-usable, programmatic approach to using the Realex Redirect method.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/VJBu2s4ivJE" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[General, PHP, Realex,]]></dc:subject>
      <dc:date>2010-09-15T15:38:01+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/realex-redirect-with-php#When:15:38:01Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[Blinds &amp; Magento]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/y2Yba-x3HXY/myblinds.ie</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/myblinds.ie#When:10:16:02Z</guid>
      <description>Percentage Price Changes and Free Samples&lt;p&gt;
	We&amp;#39;ve just finished quite a lengthy job for &lt;a href="http://www.myblinds.ie"&gt;MyBlinds.ie&lt;/a&gt;. This is a company that sells a wide variety of &lt;a href="http://www.myblinds.ie" title="Blinds in Ireland"&gt;window blinds&lt;/a&gt; with free delivery in Ireland. In the process, we had to address a number of interesting issues in Magento relating to percentage price changes on configuarble products and an easy way to handle free product samples.&lt;/p&gt;
&lt;p&gt;
	&lt;img alt="MyBlinds: Window Blinds With Free Delivery in Ireland" src="http://www.studioforty9.com/assets/uploads/page/myblinds.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;
	I had said this in my previous post about curtains, but the importance of custom product order forms can&amp;#39;t be stressed enough in some cases. When there are 6 or 7 different ordering processes, with different interdependent custom options, it becomes extremely painful very quickly if static forms aren&amp;#39;t used (being updated by AJAX with appropriate names/values).&lt;/p&gt;
&lt;p&gt;
	Another interesting issue that cropped up in this project was the issue of percentage price changes. Custom options can have a price related to them, be it a &amp;euro;5 increase or a 20% decrease. Unfortunately, Magento doesn&amp;#39;t apply percentages in a very intuitive way in terms of configurable products. Instead of applying them to the currently chosen option, it applies the percentage to the base price. Now, the base price of configurable products is often zero, so the percentage change becomes defunct. To get around this we need to set the price of the configurable product to &amp;euro;1 and then do some tricky maths in the background so that it all appears as expected in the cart.&lt;/p&gt;
&lt;p&gt;
	When initially faced with supplying fabric samples, it seemed like it could be done as a glorified contact form. But why lose out on the order management, shipping, etc that Magento provides by default. So we set up a product sample as a &amp;euro;0 virtual product. In the checkout, we can enable the Zero-Total payment method so we can skip through the necessity of payment details. So the only thing to check for is to change the &amp;quot;billing address&amp;quot; to &amp;quot;shipping address&amp;quot; if the cart subtotal is &amp;euro;0. I&amp;#39;m quite happy with how that worked out.&lt;/p&gt;
&lt;p&gt;
	Finally, some online shops really are only intended for a domestic market. So we know in advance where we are going to be shipping the products. Unfortunately, Magento doesn&amp;rsquo;t provide any default indication of shipping costs in the cart - waiting until the checkout to calculate the shipping costs or for the user to generate a shipping estimate and update the quote (2 clicks). So when loading the cart we set the current shipping address country to be Ireland and automatically add into the quote the appropriate shipping amount so it shows up straight away. Nice!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/y2Yba-x3HXY" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Magento,]]></dc:subject>
      <dc:date>2009-11-17T10:16:02+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/myblinds.ie#When:10:16:02Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[Fota Wildlife shortlisted for Golden Spider Award]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/V_348Lo0UBE/fota-wildlife-shortlisted-for-golden-spider-award-online-membership-and-ado</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/fota-wildlife-shortlisted-for-golden-spider-award-online-membership-and-ado#When:12:13:35Z</guid>
      <description>Online Membership and Adoption Process Launched&lt;p&gt;
	Great to hear that &lt;a href="http://www.fotawildlife.ie"&gt;Fota Wildlife Park&lt;/a&gt; was shortlisted for a Golden Spider in the category of Best Community &amp;amp; Charity website. To celebrate we&amp;#39;ve launched their brand new &lt;a href="http://www.fotawildlife.ie/membership-adoption/" title="Fota Wildlife Park - Become a Member Online"&gt;Membership and Adoption Process&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;
	&lt;img alt="Fota Wildlife - Adopt an Animal" src="http://www.studioforty9.com/assets/uploads/page/golden-spider.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;
	Firstly, warm congratulations to Fota Wildlife Park for getting shortlisted in the &lt;a href="http://www.goldenspiders.ie/"&gt;2009 Golden Spider Awards&lt;/a&gt;. For those who don&amp;#39;t know what this is, the Golden Spider awards are the Irish internet industry&amp;#39;s answer to the Oscars. Competition for a Golden Spider is fierce, and Fota is in extremely good company in the &lt;em&gt;Best Community &amp;amp; Charity Website&lt;/em&gt; category.&lt;/p&gt;
&lt;p&gt;
	&lt;a href="http://www.fotawildlife.ie"&gt;Fota Wildlife Park&lt;/a&gt; is a favourite destination in Cork. A wildlife park where the animals roam freely - the monkey island at Fota is one of the delights of a childhood in Cork.&lt;/p&gt;
&lt;p&gt;
	Fota Wildlife has always had a loyal community of visitors and supporters who are members of the park and visit regularly or who like to support what the park does by adopting an animal for a year.&lt;/p&gt;
&lt;p&gt;
	&lt;a href="http://www.fotawildlife.ie/membership-adoption" title="Membership and Adoption"&gt;Membership&lt;/a&gt; makes a lovely gift, particularly for families with kids as it gives free access to the park for the year - and comes with all sorts of additional benefits including free access to Dublin Zoo.&lt;/p&gt;
&lt;p&gt;
	Now on their new website, you can make use of the easy online process to become a member and to adopt an animal - and get your certificate and packages in the post. You can also purchase membership and adoption packages as gifts - Christmas presents anyone?!&lt;/p&gt;
&lt;p&gt;
	Fingers crossed for the Golden Spider!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/V_348Lo0UBE" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Expression Engine, Portfolio,]]></dc:subject>
      <dc:date>2009-11-09T12:13:35+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/fota-wildlife-shortlisted-for-golden-spider-award-online-membership-and-ado#When:12:13:35Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[Curtains &amp; Magento]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/vRqYq_8RaeI/curtains-magento-complex-forms-and-related-products</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/curtains-magento-complex-forms-and-related-products#When:13:10:54Z</guid>
      <description>Complex Forms and Related Products&lt;p&gt;
	Every Magento build is a learning experience. Very few products are straightforward enough to not need some customization of the default Magento setup. Perfect Curtains was no different in this regard.&lt;/p&gt;
&lt;p&gt;
	Curtains create two complications. Firstly, there is the potential for an exponential explosion in the number of simple products, if the number of size intervals aren&amp;#39;t kept to a minimum. (Fortunately, the price matrix was kept down to a size of 15 - much more manageable than a previous experience with 400!) Each curtain is a configurable product with the various intervals being the simple products. The customer inputs his/her exact dimensions and an AJAX call selects the next appropriate size interval. Fairly straightforward once you know what you&amp;#39;re doing.&lt;/p&gt;
&lt;p&gt;
	Secondly, curtains have a lot of interdependent custom options. There are headings and poles and rails, etc. Many of them can affect the final dimensions that the merchant needs to know and can also affect the price in other ways. So a very customized product order form needed to be created to bring the customer gradually through the ordering process, ensuring that nothing was too complicated, whilst ensuring that all of the necessary information was provided.&lt;/p&gt;
&lt;p&gt;
	With some experience in complex Magento order forms of late, I&amp;#39;ve decided that building them via static HTML to the point where the user experience is satisfactory before dealing with how they will integrate with Magento is the best way to go. In the case of curtains, where the heading chosen by the customer determined which product would be purchased (and hence which product ID etc, should be sent to the cart) it was always going to be necessary to do an AJAX call to determine the exact product ID. So if we&amp;#39;re going to do an AJAX call at this point, why not pull out all the custom option IDs at the same time, dynamically putting them into the names and values of the input fields of the static HTML form?!&lt;/p&gt;
&lt;p&gt;
	The other learning area on this project was Related Products. Two things:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;
		It&amp;#39;s pretty useless having a configurable product as a related product in Magento. You can&amp;#39;t configure them by default in the related products box so you can&amp;#39;t add them automatically at the same time as the main product. In the example of the Roman Blinds Rail in Perfect Curtains, I had to add in the appropriately sized Roman Blind Rail at the time when the customer updates the quote for their Roman Blind after they have input their desired dimensions. It&amp;#39;s not perfect, as the customer could simply click &amp;quot;add to cart&amp;quot;.&lt;/li&gt;
	&lt;li&gt;
		Related Products don&amp;#39;t have to be related in the Magento backend. It&amp;#39;s not possible by default to import related products via a CSV. So the thought of going through the Magento backend and associating all the related products didn&amp;#39;t inspire me. Until I found out that any product can be added to the shopping cart as a &amp;quot;related product&amp;quot;. All that is required is an input field with a name of &amp;quot;related_products&amp;quot; and the product ID as the value! Sweet.&lt;/li&gt;
&lt;/ol&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/vRqYq_8RaeI" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Magento,]]></dc:subject>
      <dc:date>2009-11-02T13:10:54+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/curtains-magento-complex-forms-and-related-products#When:13:10:54Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[What is 3-D Secure?]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/WxWu84aHacc/what-is-3-d-secure</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/what-is-3-d-secure#When:16:12:03Z</guid>
      <description>&lt;p&gt;
	There&amp;#39;s been plenty of talk about 3-D Secure over the course of the last few years. Recently, however, we&amp;#39;ve been hearing a lot more about it as banks move to require that merchants offer this service to customers of their E-Commerce websites. Nevertheless, many merchants are still wondering what 3-D Secure is exactly and what it will mean for their online business.&lt;/p&gt;
&lt;p&gt;
	Originally developed by Visa as &lt;em&gt;Verified by Visa&lt;/em&gt; and since adopted by MasterCard, 3-D Secure is an additional layer of security for online credit card and debit card transactions.&lt;/p&gt;
&lt;p&gt;
	Everybody remembers when the Card Security Code (a.k.a. Card Verification Value, CVV, CV2, CVC, CVVC etc...) came in. These are the three digits on the back of your credit card required to verify a transaction when you use a card online or over the phone. The idea is that it verifies the credit card in &lt;strong&gt;Card Holder Not Present&lt;/strong&gt; transaction situations.&lt;/p&gt;
&lt;p&gt;
	3-D Secure is the latest such security measure. Each cardholder will create a password which is associated with the card. When a transaction is underway online, the cardholder will be redirected to a third-party site representing the Card Issuing Authority, and asked for this password to authenticate the online transaction.&lt;/p&gt;
&lt;p&gt;
	The obvious advantage to the cardholder is the added layer of security that a password brings. While card numbers and expiry dates etc may still be copied by fraudsters - they will also need the cardholder&amp;#39;s password to use the card.&lt;/p&gt;
&lt;h4&gt;
	But how do you, the merchant, benefit?&lt;/h4&gt;
&lt;p&gt;
	Without 3-D Secure, if a fraudster on the other side of the globe orders a grand&amp;#39;s worth of merchandise from you, and you unwittingly send it off, you are liable for this fraudulent transaction. This is the case even if the transaction is fully authorised by the CVV Number. When the legitimate cardholder complains that a fraud has taken place and demands a chargeback you must return the money paid to you as part of the transaction. So you&amp;#39;re out of pocket and your merchandise is lost.&lt;/p&gt;
&lt;p&gt;
	However, if you have used 3-D Secure to authorize the transaction you will not be liable in the case of a fraud. Your goods are gone - but you keep the money paid for them.&lt;/p&gt;
&lt;p&gt;
	At StudioForty9, we will be rolling out the 3-D Secure ready version of our &lt;a href="http://www.magentocommerce.com/extension/652" title="HSBC Payment Gateway Module for Magento"&gt;HSBC Payment Gateway Module for Magento&lt;/a&gt;. If you have any questions about this module, or if you would like to be notified of its release (estimated as Dec. 1st, 2009) &lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/WxWu84aHacc" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Magento,]]></dc:subject>
      <dc:date>2009-10-20T16:12:03+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/what-is-3-d-secure#When:16:12:03Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[A rewrite.script file to replace .htaccess files for Expression Engine users on Register365]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/6aE_AWJYBlE/a-rewrite.script-file-to-replace-.htaccess-files-for-expression-engine-user</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/a-rewrite.script-file-to-replace-.htaccess-files-for-expression-engine-user#When:15:02:46Z</guid>
      <description>&lt;p&gt;
	Namesco a.k.a. Register365 are soon to begin the process of moving their users from a &amp;#39;legacy&amp;#39; H-Sphere system to a new hosting platform. Annoyingly, they don&amp;#39;t really mention that the new platform runs on Zeus server software rather than Apache. This is set to cause headaches for a lot of users as urls which are rewritten using the mod_rewrite module will no longer work.&lt;/p&gt;
&lt;p&gt;
	&lt;img alt="" src="http://www.studioforty9.com//assets/uploads/page/register-365.jpg" style="width: 600px; height: 200px;" /&gt;&lt;/p&gt;
&lt;p&gt;
	Although users will be automatically moved at some point in the future, you can choose to manually move your data and reconfigure any settings now should you so wish.&lt;/p&gt;
&lt;p&gt;
	Which is what we did for one of our clients over the weekend. Only to find that the &amp;quot;Linux Web Hosting&amp;quot; package is on a Zeus server. Whoever heard of the LZMP stack?&lt;/p&gt;
&lt;p&gt;
	Anyhow, the first casualty was our SEO and human friendly URLs. So if you&amp;#39;re using Expression Engine on a Names.co.uk or Register365.ie Zeus server, and you&amp;#39;ve been dropping the index.php from URLs by using mod_rewrite in a .htaccess file, then this is for you:&lt;/p&gt;
&lt;p&gt;
	Create a rewrite.script file - this goes into the same directory as your old .htaccess file.&lt;/p&gt;
&lt;p&gt;
	Copy the following code into the file:&lt;/p&gt;
&lt;pre class="syntax brush-plain"&gt;
RULE_0_START:
	# get the document root
	map path into SCRATCH:DOCROOT from /
	# initialize our variables
	set SCRATCH:ORIG_URL = %{URL}
	set SCRATCH:REQUEST_URI = %{URL}
	
	# see if theres any queries in our URL
	match URL into $ with ^(.*)\?(.*)$
	if matched then
		set SCRATCH:REQUEST_URI = $1
		set SCRATCH:QUERY_STRING = $2
	endif
RULE_0_END:

RULE_1_START:
	# prepare to search for file, rewrite if its not found
	set SCRATCH:REQUEST_FILENAME = %{SCRATCH:DOCROOT}
	set SCRATCH:REQUEST_FILENAME . %{SCRATCH:REQUEST_URI}
	
	# check to see if the file requested is an actual file or
	# a directory with possibly an index.  don&amp;#39;t rewrite if so
	look for file at %{SCRATCH:REQUEST_FILENAME}
	
	if not exists then
		look for dir at %{SCRATCH:REQUEST_FILENAME}
		if not exists then
			# check it&amp;#39;s not webmail or controlpanel or tech_support
			match SCRATCH:ORIG_URL into % with ^/webmail|^/tech_support|^/controlpanel
			if matched then
				goto END
			else
				set URL = /index.php%{SCRATCH:REQUEST_URI}
				goto QSA_RULE_START
			endif
		endif
	endif
	
	# if we made it here then its a file or dir and no rewrite
	goto END
RULE_1_END:

QSA_RULE_START:
	# append the query string if there was one originally
	# the same as [QSA,L] for apache
	match SCRATCH:ORIG_URL into % with \?(.*)$
	if matched then
		set URL = %{URL}&amp;amp;%{SCRATCH:QUERY_STRING}
	endif
	goto END
QSA_RULE_END:&lt;/pre&gt;
&lt;p&gt;
	Please note, this code is almost entirely based on work found in this post: &lt;a href="http://drupal.org/node/46508" rel="external" title="Rewrite Script for Zeus Server"&gt;http://drupal.org/node/46508&lt;/a&gt; which was customised for Names.co.uk so as not to break the &lt;em&gt;/controlpanel&lt;/em&gt; and &lt;em&gt;/webmail&lt;/em&gt; urls. We just added a tiny bit of extra customisation to get it working properly for &lt;a href="http://www.expressionengine.com" rel="external"&gt;Expression Engine&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
	You should also note that for the most part a .htaccess file will still run smoothly on Zeus.&lt;/p&gt;
&lt;p&gt;
	Finally, I&amp;#39;ve had it confirmed by support at Namesco / Register365 that CRON jobs are &lt;strong&gt;not&lt;/strong&gt; supported on Zeus servers - although they might help you out if you plead your case.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/6aE_AWJYBlE" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Expression Engine, General, SEO,]]></dc:subject>
      <dc:date>2009-06-22T15:02:46+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/a-rewrite.script-file-to-replace-.htaccess-files-for-expression-engine-user#When:15:02:46Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[A super clean, professional-looking start for CACM Accountants]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/hspPAFTYKRU/a-super-clean-professional-looking-start-for-cacm-accountants</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/a-super-clean-professional-looking-start-for-cacm-accountants#When:14:49:09Z</guid>
      <description>&lt;p&gt;
	Another extremely quick turnaround. &lt;a href="http://www.cacmaccountants.ie" rel="external" title="CACM Accountants"&gt;CACM Accountants&lt;/a&gt; launches with a satisfyingly clean and crisp design - built on a light CMS.&lt;/p&gt;
&lt;p&gt;
	&lt;img alt="image" class="blog-image" height="356" src="/assets/uploads/blog/CACM-Accountants.gif" width="600" /&gt;&lt;/p&gt;
&lt;p&gt;
	CACM Accountants is a brand new practice opened this month in the Atrium Business Centre, Blackpool, Cork by Carla Manning A.D.C.A C.P.A.&lt;/p&gt;
&lt;p&gt;
	What we really liked about this project is the speed at which we were able to turnaround a simple, clean design built on top of a light Content Management System so easy to use almost no training is required before the client is stuck-in and tweaking the content and SEO for each webpage.&lt;/p&gt;
&lt;p&gt;
	Nearly every web project starts with &amp;quot;&lt;i&gt;I want something really simple...&lt;/i&gt;&amp;quot;! Much of the time, this encouraging opening is followed by a litany of feature requirements and marketing goals which would strain the ingenuity of the most resourceful web developer. In this case, however, Carla knew from the outset what she wanted - which made the design, build and deployment of this website an extremely satisfying exercise for us.&lt;/p&gt;
&lt;p&gt;
	Visit &lt;a class="external" href="http://www.cacmaccountants.ie" title="CACM Accountants"&gt;CACM Accountants&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/hspPAFTYKRU" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Portfolio,]]></dc:subject>
      <dc:date>2009-06-08T14:49:09+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/a-super-clean-professional-looking-start-for-cacm-accountants#When:14:49:09Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[Payment Modules: A Beginning]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/CIFq2TUdLvI/payment-modules-a-beginning</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/payment-modules-a-beginning#When:12:45:44Z</guid>
      <description>Realex Payment Module for Magento&lt;p&gt;
	Getting a commission from &lt;a href="http://www.realex.ie/"&gt;Realex&lt;/a&gt;, Ireland&amp;#39;s biggest payment gateway, to produce a custom-built module for Magento to integrate with its services, was an exciting step in our ongoing exploration of the world of Magento extensions.&lt;/p&gt;
&lt;p&gt;
	Knowing that it would be immediately used by online shops, even if only on our small little island, was an added encouragement to get things right.&lt;br /&gt;
	&lt;br /&gt;
	The module provides 2 modes of use for the client. Realex Redirect transfers the customer from the Magento merchant site to Realex&amp;#39;s server for credit card payment. Realex Remote, takes the credit card details on the Magento site and communicates seamlessly with Realex to verify or refuse payment. It allows customers to use a number of different credit cards and currencies and clients can defer settlement of payment or settle immediately.&lt;br /&gt;
	&lt;br /&gt;
	We have subsquently extended the module to enable 3D Secure authentication. This module is currently undergoing rigorous testing and we hope to release it to the world soon. Watch this space for further developments.&lt;br /&gt;
	&lt;br /&gt;
	For more information visit: &lt;a href="http://www.magentocommerce.com/extension/699/realex-payment-module"&gt;http://www.magentocommerce.com/extension/699/realex-payment-module&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/CIFq2TUdLvI" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Magento,]]></dc:subject>
      <dc:date>2009-02-13T12:45:44+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/payment-modules-a-beginning#When:12:45:44Z</feedburner:origLink></item>

    <item>
      <title><![CDATA[Bestselling T-Shirts]]></title>
      <link>http://feedproxy.google.com/~r/studioforty9/~3/yrqXjqEWfLA/bestselling-t-shirts</link>
      <guid isPermaLink="false">http://www.studioforty9.com/blog/bestselling-t-shirts#When:12:30:11Z</guid>
      <description>&lt;p&gt;
	&lt;a href="http://www.nerdyshirts.com"&gt;Nerdyshirts&lt;/a&gt; is a successful online shop selling quirky t-shirts based in California. As a company that had a level of Magento prominence due to its inclusion as a test case in the first ever Magento webinar, we were delighted to take on the challenge of customising the look and feel of the shop.&lt;/p&gt;
&lt;p&gt;
	First up was the homepage. Unlike many online shops, Nerdyshirts homepage is it&amp;#39;s direct point of sale. Many users may never browse the categories or other products, instead adding items to their shopping cart straight from the homepage. So, getting it right, was clearly important.&lt;br /&gt;
	&lt;br /&gt;
	Nerdyshirts wanted a tiered list of all of the available t-shirts. Each week, new t-shirts would be made available, so a simple and as automated as possible a way to display both the current week&amp;#39;s and last week&amp;#39;s t-shirts at the top of the homepage was required. Following on from the newbies, the big boys, the bestsellers were to be shown. These were made configurable both in terms of the number to be displayed and also in terms of the timeframe over which they sold. Finally, all other t-shirts, not in the previous two categories, are displayed.&lt;br /&gt;
	&lt;br /&gt;
	The other major piece of customisation was in the area of the checkout. Magento, by default, doesn&amp;#39;t provide a multipage checkout - something which early on in its development caused a lot of frustration amongst some users due to the complete dependence on javascript and AJAX for the onepage checkout. Magento, does, however, provide a multishipping checkout - which acts like a multipage checkout but allows you (or forces you to - depending on your point of view) to specify an address for each item in your cart. So rather than try to create a multipage checkout from scratch, we adapted the multishipping checkout to mimic the functionality of a multipage checkout.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/studioforty9/~4/yrqXjqEWfLA" height="1" width="1"/&gt;</description>
      <dc:subject><![CDATA[Magento,]]></dc:subject>
      <dc:date>2009-01-30T12:30:11+00:00</dc:date>
    <feedburner:origLink>http://www.studioforty9.com/blog/bestselling-t-shirts#When:12:30:11Z</feedburner:origLink></item>

    
    </channel>
</rss>

