<?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>Inchoo</title>
	<atom:link href="http://inchoo.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://inchoo.net</link>
	<description>Magento Design and Magento Development Professionals - Inchoo</description>
	<lastBuildDate>Mon, 20 May 2013 06:56:29 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5</generator>
		<item>
		<title>Newsletter auto-subscribe on create account and place order in Magento</title>
		<link>http://inchoo.net/ecommerce/magento/newsletter-auto-subscribe-create-account-place-order-magento/</link>
		<comments>http://inchoo.net/ecommerce/magento/newsletter-auto-subscribe-create-account-place-order-magento/#comments</comments>
		<pubDate>Mon, 20 May 2013 06:19:54 +0000</pubDate>
		<dc:creator>Marko Martinovic</dc:creator>
				<category><![CDATA[Events & Observers]]></category>
		<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[newsletter]]></category>
		<category><![CDATA[observer]]></category>
		<category><![CDATA[subscribe]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18762</guid>
		<description><![CDATA[By default Magento provides a Newsletter feature, which enables store administrators to send newsletters to customers who have registered to receive them. Since most customers tend not to opt-in to &#8230;]]></description>
				<content:encoded><![CDATA[<p>By default Magento provides a Newsletter feature, which enables store administrators to send newsletters to customers who have registered to receive them. Since most customers tend not to opt-in to any email subscription related services, you might need to automatically subscribe customers when they register or place an order. In this article I&#8217;ll present code and simple Magento extension to make it easier for you to accomplish this task.</p>
<p><span id="more-18762"></span></p>
<p>Since complete Magento extension named Inchoo_AutoSubscribe is available from its <a href="https://github.com/Marko-M/Inchoo_AutoSubscribe/" title="Inchoo_AutoSubscribe" target="_blank">GitHub repository page</a>, here I&#8217;ll just include a few important code snippets. You can easily download code by clicking at ZIP icon inside GitHub repository page interface or using <a href="https://github.com/Marko-M/Inchoo_AutoSubscribe/archive/master.zip" title="Inchoo_AutoSubscribe ZIP package">this</a> link.</p>
<p>General idea is to create observers to capture sales_order_place_after and customer_register_success events, and there we can automatically subscribe customer to newsletter. One thing to note is that customers are left with option to manually unsubscribe using My Account -> Newsletter Subscriptions screen, and if they do unsubscribe, they wont be automatically subscribed next time they place an order. </p>
<p>First things first, the snippet from our config.xml file to register event observers:</p>
<p>app/code/community/Inchoo/AutoSubscribe/etc/config.xml</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;frontend&gt;
        &lt;events&gt;
            &lt;sales_order_place_after&gt;
                &lt;observers&gt;
                    &lt;inchoo_autosubscribe_sales_order_place_after&gt;
                        &lt;class&gt;Inchoo_AutoSubscribe_Model_Observer&lt;/class&gt;
                        &lt;method&gt;salesOrderPlaceAfter&lt;/method&gt;
                    &lt;/inchoo_autosubscribe_sales_order_place_after&gt;
                &lt;/observers&gt;
            &lt;/sales_order_place_after&gt;
            &lt;customer_register_success&gt;
                &lt;observers&gt;
                    &lt;inchoo_autosubscribe_customer_register_success&gt;
                        &lt;class&gt;Inchoo_AutoSubscribe_Model_Observer&lt;/class&gt;
                        &lt;method&gt;customerRegisterSuccess&lt;/method&gt;
                    &lt;/inchoo_autosubscribe_customer_register_success&gt;
                &lt;/observers&gt;
            &lt;/customer_register_success&gt;
        &lt;/events&gt;
    &lt;/frontend&gt;
&lt;/config&gt;
</pre>
<p>To hide Sign Up for Newsletter checkbox from Create an Account screen we must point customer_form_register block template to our own .phtml file using something like this inside our layout xml file:</p>
<p>app/design/frontend/base/default/layout/inchoo_autosubscribe.xml</p>
<pre class="brush: xml; title: ; notranslate">
&lt;layout version=&quot;0.1.0&quot;&gt;
    &lt;customer_account_create&gt;
        &lt;reference name=&quot;customer_form_register&quot;&gt;
            &lt;action method=&quot;setTemplate&quot;&gt;
                &lt;template&gt;inchoo/autosubscribe/customer/form/register.phtml&lt;/template&gt;
            &lt;/action&gt;
        &lt;/reference&gt;
    &lt;/customer_account_create&gt;
&lt;/layout&gt;
</pre>
<p>Last but not least snippet is our observers code:</p>
<p>app/code/community/Inchoo/AutoSubscribe/Model/Observer.php</p>
<pre class="brush: php; title: ; notranslate">
class Inchoo_AutoSubscribe_Model_Observer extends Varien_Object
{
    public function salesOrderPlaceAfter($observer)
    {
    	$email = $observer-&gt;getEvent()-&gt;getOrder()-&gt;getCustomerEmail();
        Mage::log('salesOrderPlaceAfter: '.$email);
        $this-&gt;_autoSubscribe($email);
    }
    public function customerRegisterSuccess($observer)
    {
        $email = $observer-&gt;getEvent()-&gt;getCustomer()-&gt;getEmail();
        Mage::log('customerRegisterSuccess: '.$email);
        $this-&gt;_autoSubscribe($email);
    }
    protected function _autoSubscribe($email)
    {
        Mage::log('_autoSubscribe: '.$email);
        $subscriber = Mage::getModel('newsletter/subscriber')-&gt;loadByEmail($email);
        if($subscriber-&gt;getStatus() != Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED &amp;&amp;
                $subscriber-&gt;getStatus() != Mage_Newsletter_Model_Subscriber::STATUS_UNSUBSCRIBED) {
            $subscriber-&gt;setImportMode(true)-&gt;subscribe($email);
        }
    }
}
</pre>
<p>I sincerely hope you&#8217;ll find this code useful. If you want to suggest any changes feel to leave your comment here or simply fork this code from its <a href="https://github.com/Marko-M/Inchoo_AutoSubscribe/" title="Inchoo_AutoSubscribe" target="_blank">GitHub repository page</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/newsletter-auto-subscribe-create-account-place-order-magento/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Go Responsive (or go home) &#8211; workshop about Responsive Web Design</title>
		<link>http://inchoo.net/fun-zone/go-responsive-or-go-home/</link>
		<comments>http://inchoo.net/fun-zone/go-responsive-or-go-home/#comments</comments>
		<pubDate>Thu, 16 May 2013 13:59:40 +0000</pubDate>
		<dc:creator>Maja Andracic</dc:creator>
				<category><![CDATA[Fun & Events]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[hrvoje jurisic]]></category>
		<category><![CDATA[inchoo]]></category>
		<category><![CDATA[responsive]]></category>
		<category><![CDATA[responsive web design]]></category>
		<category><![CDATA[web design]]></category>
		<category><![CDATA[workshop]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18688</guid>
		<description><![CDATA[Osijek’s Business Incubator BIOS was a host for Inchoo’s Go Responsive workshop, which had Responsive Web Design as a theme. Responsive Web Design is web design and development approach aimed &#8230;]]></description>
				<content:encoded><![CDATA[<p style="text-align: left;">Osijek’s <a title="BIOS" href="http://inkubator.hr/" target="_blank">Business Incubator BIOS</a> was a host for Inchoo’s <strong>Go Responsive</strong> workshop, which had <strong>Responsive Web Design</strong> as a theme. Responsive Web Design is web design and development approach aimed at crafting sites to provide an optimal page viewing experience across a wide range of devices and resolutions. <span id="more-18688"></span>Today, users view pages on mobile phones, desktop computer monitors, tablets and various devices, so we feel obligated to give them the best user experience we can.</p>
<h3>Whole-day workshop about Responsive Web Design</h3>
<p><strong>Whole-day workshop</strong> gathered 20 participants who had previous knowledge of Responsive Web Design and are aware that today’s users access content from mobile phones, desktop computer monitors, tablets and various devices, so they, as developers, need to respond to that challenge. <strong>Netgen</strong>, <strong>Betaware</strong>, <strong>Mono</strong>, <strong>Gauss</strong>, <strong>Farmeron</strong>, <strong>N-lab</strong>, <strong>Kolektiva</strong>, <strong>Proodos</strong>, <strong>Anctu</strong> and <strong>Adcon</strong> decided to send their developers to pleasant working atmosphere of Go Responsive workshop in order to expand knowledge and stay in the loop with web trends.</p>
<p><strong><a href="http://inchoo.net/fun-zone/go-responsive-or-go-home/attachment/hrvoje/" rel="attachment wp-att-18696"><img class="size-full wp-image-18696 alignleft" alt="hrvoje" src="http://inchoo.net/wp-content/uploads/2013/05/hrvoje.jpg" width="150" height="149" /></a>Hrvoje Jurisic,</strong> a certified Magento frontend developer was in the role of the teacher. This was his <strong>first workshop as lecturer</strong> and we must say that participants were pleased with him. At Inchoo, Hrvoje is working as <strong>frontend developer, designer and illustrator</strong>. Do you know our comic <a title="The Inchooers" href="http://inchoo.net/tag/inchooers/" target="_blank">The Inchooers</a>? Well, he is the author. Working on some of Inchoos biggest projects, like <a title="Kolektiva" href="http://inchoo.net/portfolio/kolektiva-balka/" target="_blank">Kolektiva</a>, <a title="AEScripts" href="http://inchoo.net/portfolio/aescripts/" target="_blank">aescripts.com</a> and <a title="OzMattress" href="http://inchoo.net/portfolio/ozmattress-inchoo-australia/" target="_blank">OzMattress</a>, Hrvoje polished his experience.</p>
<p><strong>Not just</strong> talking about <strong>theory</strong>, but giving examples and problems from practice, Hrvoje taught attendees about the <strong>processes and techniques of RWD</strong>, <strong>“Mobile First”</strong> approach, how to get <strong>fluid layout</strong>, access to responsive images, tables or navigation and triggered a debate about <strong>future of web design</strong>.</p>
<h3>We asked Hrvoje to share his workshop experience</h3>
<h4>Hrvoje, Go Responsive is the first workshop you’ve experienced from a lecturers view. Tell us, how does it feel to be a lecturer and not an attendant?</h4>
<p>Good. I like the feeling of sharing the knowledge and positive energy that is generated around this kind of gatherings. I remember some of the workshops, where I was a student, and the inspiration and positive energy with which I left from those workshops. That enthusiasm kept me inspired for weeks. I hope Go Responsive workshop had the similar  effect on at least one participant.</p>
<h4>How did you decide to have a workshop about Responsive Web Design?</h4>
<p>RWD is something that will mark the next few years on the web. This is something in which I believe and I’m a huge upholder of RWD. It currently has a “buzz”, this is what developers and clients are interested in.</p>
<h4>How did the preparing go? It was a whole-day workshop&#8230;<a href="http://inchoo.net/fun-zone/go-responsive-or-go-home/attachment/464932_10200466249071481_1981946648_o/" rel="attachment wp-att-18692"><img class=" wp-image-18692 alignright" alt="464932_10200466249071481_1981946648_o" src="http://inchoo.net/wp-content/uploads/2013/05/464932_10200466249071481_1981946648_o.jpg" width="282" height="282" /></a></h4>
<p>Since Go Responsive was the first workshop I ran, it was difficult to estimate how much time will the presentation and tasks take. In the end it turned out that I judged well and kept Go Responsive for 15 minutes shorter than expected. And as for the preparation of presentation, well that took a lot more time then expected. Next time I’ll know better. <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h4>What have you set as the key takeaway from the workshop for the participants?</h4>
<p><em>I wanted them to understand the importance of RWD and not to do it because it’s fashionable.</em> Then we focused on workflow, because things have changed radically with the appearance of RWD. And at the end, it was important to understand techniques in RWD so we went through HTML and CSS.</p>
<h4>Are you satisfied how the workshop went? What would you do differently if you could re-do the workshop?</h4>
<p>I’m pleased. As far as I could gather from the feedback, the participants were satisfied as well, and that’s what’s most important. And if I can do better? I can. It can always be better. <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Now re-doing the same workshop, I wouldn‘t change much. Maybe just allocate time little differently to give some units more spotlight.</p>
<h4>What do you think, what is the future of Responsive Web Design?</h4>
<p><em>RWD is here to stay. It will soon be a standard in web design and we will not be talking about it like some kind of special type web development.</em> Just to be clear, I don’t think of RWD as the universal solution, it all depends from project to project. But, it’s probably the best solution for most projects.</p>
<h3>Go Responsive followed Go for a Drink (responsibly!)</h3>
<p style="text-align: center;"><a href="http://inchoo.net/fun-zone/go-responsive-or-go-home/attachment/17990301_hicnfurfbeeaenxvyc-1mgkvjcqyu4_5u-nolx7izk0/" rel="attachment wp-att-18721"><img class="wp-image-18721 aligncenter" alt="17990301_hICnFUrFBeeAenXvYc-1MgKvJcQyU4_5U-NOlX7izK0" src="http://inchoo.net/wp-content/uploads/2013/05/17990301_hICnFUrFBeeAenXvYc-1MgKvJcQyU4_5U-NOlX7izK0.jpg" width="408" height="408" /></a></p>
<p>After the workshop, the participants gathered for a drink in old part of Osijek called Tvrda (Fortress). Some of them weren’t from Osijek so it was a good opportunity to see the city, and they weren’t disappointed. Fascinated by the tranquility and greenery, they understood what we talked about relaxation in work and life in Osijek, unlike their more urban areas, like Croatia capital city. It was a hot day, but the drinks were cold and the band was playing, while no mosquitos were there to ruin the atmosphere.</p>
<h3>We think we did a good job</h3>
<p>Inchoo wanted to impart knowledge trough a new channel- a workshop, and we got feedback from attendants that we succeeded in that. Responsive Web Design is a hot topic in the world of web and we are pleased that Go Responsive workshop is recognized as a good blend of theory and practice.</p>
<p><strong><em>Tell us, how do you see Responsive Web Design in the future?</em></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/fun-zone/go-responsive-or-go-home/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Automatic Cross Related Products &#8211; CSV Import</title>
		<link>http://inchoo.net/ecommerce/magento/automatic-cross-related-products-csv-import/</link>
		<comments>http://inchoo.net/ecommerce/magento/automatic-cross-related-products-csv-import/#comments</comments>
		<pubDate>Thu, 16 May 2013 12:11:20 +0000</pubDate>
		<dc:creator>Ivan Galambos</dc:creator>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[check data]]></category>
		<category><![CDATA[cross related]]></category>
		<category><![CDATA[csv import]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[related products]]></category>
		<category><![CDATA[Upload]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18634</guid>
		<description><![CDATA[If you have configurable products that have been associated with simple products, you can assign configurable products to related products. You probably know how this task can be boring. To &#8230;]]></description>
				<content:encoded><![CDATA[<p>If you have configurable products that have been associated with simple products, you can assign configurable products to related products. You probably know how this task can be boring. To avoid that (in most cases) boring task, I created this module so you don&#8217;t need to lose lots of your precious time.</p>
<p><span id="more-18634"></span></p>
<p>You probably know how to associate related products in Magento, but let&#8217;s repeat for those who forgot or maybe don&#8217;t know.  Open Product_1 and assign Product_2, Product_3 and Product_4 as Related Products to Product_1. If you want to associate Product 2 to other (previously mentioned) Products 1, 3 and 4, you just follow the same procedure. If, perhaps, you don&#8217;t know what Related products, Up-sells or Cross-sells are,  check out related <a href="http://inchoo.net/ecommerce/magento/related-products-up-sells-cross-sells-in-magento/" title="related products - Inchoo" target="_blank">Inchoo</a> and/or <a href="http://www.magentocommerce.com/knowledge-base/entry/how-do-i-set-up-product-relations" title="Magento post" target="_blank">Magento</a> post. Those posts will certainly get you on the right track.</p>
<p>To avoid this boring <strong>additional work</strong>, I&#8217;ve created Magento module that will <strong>automatically link</strong> all products in <strong>one step</strong>! Not only that, you can <strong>exclude</strong> some of the products from a list of products (if you wish to do that) in just one step, so that excluded product will not be anymore associated to other products from the list. One more thing, you can also <strong>upload CSV</strong> file with your product ID#, where each row represents collection of related products. Everything will be much easier to explain through examples, so let&#8217;s start!</p>
<p>First things first,  let&#8217;s explain configuration options.</p>
<p><img src="http://inchoo.net/wp-content/uploads/2013/05/related-1.jpg" alt="Description options" width="600" height="400" /></p>
<h4>1. Enabled</h4>
<p>This configuration option will enable this enhancement to Magento Related Products functionality.</p>
<h4>2. Remove un-assigned Products From a Collection</h4>
<p>This is the interesting one&#8230; Imagine that you have products 1, 2, 3 and 4 and you want to associate them as Related Products (in a way that all of them are associated to each other &#8211; &#8220;cross related&#8221;). To avoid boring additional work, you&#8217;ve enabled this module. You would go in Magento administration to Catalog/Manage Products. Then select Product 1 and then click on <strong>Related Products</strong> tab.  After assigning products 2, 3 and 4, click on Save. And that&#8217;s it! If you select Product_2 you would see that products 1, 3 and 4 are all <strong>associated</strong> to Product_2. Similar is for products 3 and 4.</p>
<p>Now, for this configuration option, let&#8217;s say that you don&#8217;t want anymore Product_4 to be associated to collection of products 1, 2 and 3. Normally, in default Magento functionality you would need to select Product_1 and un-select Product_4. Then you would select Product_2 and un-select Product_4. Same for Product_3.  At the end, if you select Product_4 (which you want to exclude from your related collection of products 1, 2 and 3) you would see that Product_4 is connected to products 1, 2 and 3.</p>
<p>Let&#8217;s come back to our example &#8211; <strong>Cross Related</strong> enhancement. Firstly, we&#8217;ve associated products 2,3,4 to Product_1. Then we un-selected Product_4 from specified collection, so each products: 1, 2 and 3 would be associated with each other. In default Magento behaviour, Product_4 would be associated with products 1, 2 and 3. <strong>To remove</strong>, also in one step, Product_4 to be associated to products 1, 2 and 3 (we have had connected products 1, 2, 3, 4) you can enable this configuration option and system will automatically unassigned all &#8220;irrelevant&#8221; products from specified collection.<br />
So basically, imaging that <strong>connecting on Product_1 products 2, 3, 4 is the same as you are sending one row in CSV</strong> file: &#8220;1&#8243;, &#8220;2&#8243;, &#8220;3&#8243;, &#8220;4&#8243;.<br />
As the result, all of those products would be assigned to each other. Same, if you send (with this configuration option) again in next row &#8220;1&#8243;, &#8220;2&#8243;, &#8220;3&#8243; as a result you&#8217;ll have products 1, 2 and 3 associated to each other, BUT product 4 will be &#8220;alone&#8221; &#8211; more precisely, Product 4 <strong>will not have anymore</strong> associated products 1, 2 and 3.</p>
<h4>3. Enable CSV Import</h4>
<p>If this module is enabled and if this configuration option is enabled, you&#8217;ll see additional button in Magento <strong>Administration</strong> &#8211; <strong>Catalog</strong> / <strong>Manage Products</strong> &#8211; &#8220;<strong>Cross Related CSV Import</strong>&#8221;</p>
<p><img src="http://inchoo.net/wp-content/uploads/2013/05/related-2.jpg" alt="Upload CSV file button" width="600" height="300" /></p>
<p>If you click on &#8220;<strong>Cross Related CSV Import</strong>&#8221; you&#8217;ll see next screen:</p>
<p><img src="http://inchoo.net/wp-content/uploads/2013/05/related-3.jpg" alt="Import and check button" width="600" height="300" /></p>
<p>You can now Browse your csv file and click on &#8220;<strong>Check Data</strong>&#8221; button to upload and check your csv file, after which you&#8217;ll see &#8220;<strong>Import</strong>&#8221; button, if you have at least 1 row for insert. <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Otherwise you&#8217;ll see next message without Import button: &#8220;<em>File is totally invalid. Please fix errors and re-upload file</em>&#8220;.<br />
After you click on &#8220;Import&#8221;, you&#8217;ll see &#8220;<strong>Back</strong>&#8221; button so that you can re-upload some other file, if needed.</p>
<p><strong>Note</strong>. &#8220;Check&#8221; button will upload your file (on success) in <strong>[MAGENTO_ROOT]/var/crossrelated/crossrelated.csv</strong> and &#8220;Import&#8221; button will connect those items and delete the file.</p>
<h4>4. Exclude items from the cart</h4>
<p>In Magento, by default, you don&#8217;t see related items on front-end in case if you have them in cart. If you don&#8217;t want to hide them from Related Products block on front-end you can enable this option. We needed this, so I hope it might help someone&#8230;</p>
<h4>Code Snippets</h4>
<p>Now let see some snippets of the code. For full module you&#8217;ll need to download archive file from <a href="http://inchoo.net/wp-content/uploads/2013/05/aapp.tar.gz">here</a>.</p>
<p><strong>Model/Import.php</strong></p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
/**
 * Import model
 *
 * @category    Inchoo
 * @package     Inchoo_CrossRelated
 * @author      Ivan Galamboš &lt;ivan.galambos@inchoo.net&gt;
 */
class Inchoo_CrossRelated_Model_Import extends Inchoo_CrossRelated_Model_Abstract
{
    /**
     * Form field names (and IDs)
     */
    const FIELD_NAME_SOURCE_FILE = 'import_file';
    const FIELD_NAME_IMG_ARCHIVE_FILE = 'import_image_archive';
    /**
     * Validates source file and returns validation result.
     *
     * @param string $sourceFile Full path to source file
     * @return bool
     */
    public function validateSource($sourceFile)
    {
        $result = $this-&gt;isDataValid($sourceFile);
        return $result;
    }
    /**
     * Move uploaded file
     *
     * @throws Mage_Core_Exception
     * @return string Source file path
     */
    public function uploadSource()
    {
        $uploader  = Mage::getModel('core/file_uploader', self::FIELD_NAME_SOURCE_FILE);
        $uploader-&gt;skipDbProcessing(true);
        $result    = $uploader-&gt;save(self::getWorkingDir());
        $extension = pathinfo($result['file'], PATHINFO_EXTENSION);
        $uploadedFile = $result['path'] . $result['file'];
        if (!$extension) {
            unlink($uploadedFile);
            Mage::throwException(Mage::helper('crossrelated')-&gt;__('Uploaded file has no extension'));
        }
        $sourceFile = self::getWorkingDir() . 'crossrelated';
        $sourceFile .= '.' . $extension;
        if(strtolower($uploadedFile) != strtolower($sourceFile)) {
            if (file_exists($sourceFile)) {
                unlink($sourceFile);
            }
            if (!@rename($uploadedFile, $sourceFile)) {
                Mage::throwException(Mage::helper('crossrelated')-&gt;__('Source file moving failed'));
            }
        }
        return $sourceFile;
    }
    /**
     * Import/Export working directory (source files, result files, lock files etc.).
     *
     * @return string
     */
    public static function getWorkingDir()
    {
        return Mage::getBaseDir('var') . DS . 'crossrelated' . DS;
    }
    /**
     * Import &amp; unlink checked crossrelated csv file.
     *
     * @throws Mage_Core_Exception
     * @return void
     */
    public function importSource()
    {
        $sourceFile = self::getWorkingDir() . 'crossrelated';
        $sourceFile .= '.' . 'csv';
        if (file_exists($sourceFile)) {
            $io = new Varien_Io_File();
            $io-&gt;streamOpen($sourceFile, 'r');
            while ( $row = $io-&gt;streamReadCsv() ) {
                $checkThisRow = true;
                foreach ($row as $v) {
                    $v = trim($v);
                    if ( !ctype_digit($v) ) {
                        $checkThisRow = false;
                    }
                }
                if ( $checkThisRow ) {
                    $this-&gt;connectCsvDataToCrossRelated($row);
                }
            }
            unlink($sourceFile);
        } else {
            Mage::throwException(Mage::helper('crossrelated')-&gt;__('Source file does not exist'));
        }
    }
}
</pre>
<p><strong>controllers/Adminhtml/Catalog/ProductController.php</strong></p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
require_once 'Mage/Adminhtml/controllers/Catalog/ProductController.php';
/**
 * Catalog product controller
 *
 * @category    Inchoo
 * @package     Inchoo_CrossRelated
 * @author      Ivan Galamboš &lt;ivan.galambos@inchoo.net&gt;
 */
class Inchoo_CrossRelated_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Catalog_ProductController
{
    /**
     * Initialize layout.
     *
     * @return Inchoo_CrossRelated_Adminhtml_Catalog_ProductController
     */
    protected function _initAction()
    {
        $this-&gt;_title($this-&gt;__('Inchoo CrossRelated Products'))
            -&gt;loadLayout()
        ;
        return $this;
    }
    /**
     * Import CrossRelated CSV data
     */
    public function csvimportAction()
    {
        $maxUploadSize = Mage::helper('crossrelated')-&gt;getMaxUploadSize();
        $this-&gt;_getSession()-&gt;addNotice(
            $this-&gt;__('Total size of uploadable files must not exceed %s', $maxUploadSize)
        );
        $this-&gt;_initAction()
            -&gt;_title($this-&gt;__('CrossRelate CSV Import'))
            -&gt;_addBreadcrumb($this-&gt;__('CrossRelate CSV Import'), $this-&gt;__('CrossRelate CSV Import'));
        $this-&gt;_setActiveMenu('catalog/products');
        $this-&gt;renderLayout();
    }
    /**
     * Start validation process action.
     *
     * @return void
     */
    public function validatecsvimportAction()
    {
        $data = $this-&gt;getRequest()-&gt;getPost();
        if ($data) {
            $this-&gt;loadLayout(false);
            /** @var $resultBlock Inchoo_CrossRelated_Block_Adminhtml_Import_Frame_Result */
            $resultBlock = $this-&gt;getLayout()-&gt;getBlock('import.frame.result.crossrelated');
            try {
                /** @var $import Inchoo_CrossRelated_Model_Import */
                $import = Mage::getModel('crossrelated/import');
                $validationResult = $import-&gt;validateSource($import-&gt;setData($data)-&gt;uploadSource());
                if (!$import-&gt;getProcessedRowsCount()) {
                    $resultBlock-&gt;addError($this-&gt;__('File does not contain data. Please upload another one'));
                } else {
                    if (!$validationResult) {
                        if ($import-&gt;getProcessedRowsCount() == $import-&gt;getInvalidRowsCount()) {
                            $resultBlock-&gt;addNotice(
                                $this-&gt;__('File is totally invalid. Please fix errors and re-upload file')
                            );
                        } else {
                                $resultBlock-&gt;addNotice(
                                    $this-&gt;__('Please fix errors and re-upload file or simply press &quot;Import&quot; button to skip rows with errors'),
                                    true
                                );
                        }
                        $error = $this-&gt;__('Invalid data (non-digits) in rows:') . ' ' . implode(', ', $import-&gt;getErrors());
                        $resultBlock-&gt;addError($error);
                    } else {
                            $resultBlock-&gt;addSuccess(
                                $this-&gt;__('File is valid! To start import process press &quot;Import&quot; button'), true
                            );
                    }
                    $resultBlock-&gt;addNotice($this-&gt;__('Checked rows: %d, invalid rows: %d', $import-&gt;getProcessedRowsCount(), $import-&gt;getInvalidRowsCount()));
                }
            } catch (Exception $e) {
                $resultBlock-&gt;addNotice($this-&gt;__('Please fix errors and re-upload file'))
                    -&gt;addError($e-&gt;getMessage());
            }
            $this-&gt;renderLayout();
        } elseif ($this-&gt;getRequest()-&gt;isPost() &amp;&amp; empty($_FILES)) {
            $this-&gt;loadLayout(false);
            $resultBlock = $this-&gt;getLayout()-&gt;getBlock('import.frame.result.crossrelated');
            $resultBlock-&gt;addError($this-&gt;__('File was not uploaded'));
            $this-&gt;renderLayout();
        } else {
            $this-&gt;_getSession()-&gt;addError($this-&gt;__('Data is invalid or file is not uploaded'));
            $this-&gt;_redirect('*/*/csvimport');
            return;
        }
        return;
    }
    /**
     * Start import process action.
     *
     * @return void
     */
    public function startcrossrelatedimportAction()
    {
        try {
            $this-&gt;loadLayout(false);
            /** @var $resultBlock Inchoo_CrossRelated_Block_Adminhtml_Import_Frame_Result */
            $resultBlock = $this-&gt;getLayout()-&gt;getBlock('import.frame.result.crossrelated');
            /** @var $import Inchoo_CrossRelated_Model_Import */
            $import = Mage::getModel('crossrelated/import');
            $import-&gt;importSource();
            $resultBlock-&gt;addAction('show', 'import_validation_container')
                -&gt;addAction('innerHTML', 'import_validation_container_header', $this-&gt;__('Status'));
        } catch (Exception $e) {
            $resultBlock-&gt;addError($e-&gt;getMessage());
            $this-&gt;renderLayout();
            return;
        }
        $resultBlock-&gt;addAction('hide', array('edit_form', 'upload_button', 'messages'));
        $resultBlock-&gt;addSuccessRefresh($this-&gt;__('Import successfully done.'), true);
        $this-&gt;renderLayout();
        return;
    }
}
</pre>
<p>Note. For full module you&#8217;ll need to download archive file from <a href="http://inchoo.net/wp-content/uploads/2013/05/aapp.tar.gz">here</a>.</p>
<p>Feel free to create your own csv file with IDs of your desired products and let me know what do you think.</p>
<p>If you have any questions&#8230; we are here for you!</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/automatic-cross-related-products-csv-import/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Customer journey and multichannel shopping</title>
		<link>http://inchoo.net/ecommerce/customer-journey-and-multichannel-shopping/</link>
		<comments>http://inchoo.net/ecommerce/customer-journey-and-multichannel-shopping/#comments</comments>
		<pubDate>Thu, 16 May 2013 11:32:37 +0000</pubDate>
		<dc:creator>Vice Bozic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Online Marketing]]></category>
		<category><![CDATA[customer]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[journey]]></category>
		<category><![CDATA[multi-channel]]></category>
		<category><![CDATA[purchase]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18623</guid>
		<description><![CDATA[Last week my friend on Facebook recommended me a book that I should read, so I went to my local bookstore and tried to find it. Unfortunately, they didn&#8217;t have &#8230;]]></description>
				<content:encoded><![CDATA[<p>Last week my friend on Facebook recommended me a book that I should read, so I went to my local bookstore and tried to find it. Unfortunately, they didn&#8217;t have the book that I was looking for, so I went to their online shop and bought my book there.</p>
<p>The whole process got me thinking how gone are the days of a single channel shopping. We, as customers are using multiple channels and touchpoints before actually making a purchase, and what&#8217;s interesting is that often website or mobile phone are the first touchpoint of interaction with the brand.<span id="more-18623"></span></p>
<p>To help businesses understand this shift in consumer behavior, <a href="http://www.google.com/think/tools/customer-journey-to-online-purchase.html" target="_blank"><strong>Google recently launched a great tool</strong></a> that shows how different channels play different roles in customer journey. Tool is made up from data from 36,000 Google Analytics accounts from 11 industries in 7 countries.</p>
<p><img class="alignleft size-full wp-image-18643" alt="customerpurchase" src="http://inchoo.net/wp-content/uploads/2013/05/customerpurchase.jpg" width="609" height="435" /></p>
<p>Using this tool you can find out:</p>
<ul>
<li>How different marketing channels affect customer purchase decisions</li>
<li>How does the length of the customer journey impact purchase value</li>
<li>How to improve your marketing based on channel performance</li>
</ul>
<p>You can start working with the <strong><a href="http://www.google.com/think/tools/customer-journey-to-online-purchase.html" target="_blank">Customer Journey to Online Purchase here</a>.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/customer-journey-and-multichannel-shopping/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Per product meta robots tag control in Magento</title>
		<link>http://inchoo.net/ecommerce/magento/per-product-meta-robots-tag-control-in-magento/</link>
		<comments>http://inchoo.net/ecommerce/magento/per-product-meta-robots-tag-control-in-magento/#comments</comments>
		<pubDate>Wed, 08 May 2013 13:52:06 +0000</pubDate>
		<dc:creator>Marko Martinovic</dc:creator>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[install script]]></category>
		<category><![CDATA[module]]></category>
		<category><![CDATA[setup resource]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18576</guid>
		<description><![CDATA[My first Magento related task here at Inchoo was to assist our client to gain control over his meta robots tag on per product basis. In this article I&#8217;ll present &#8230;]]></description>
				<content:encoded><![CDATA[<p>My first Magento related task here at Inchoo was to assist our client to gain control over his meta robots tag on per product basis. In this article I&#8217;ll present simple Magento extension designed to do just that. I&#8217;ll also show you how to create custom product attribute programmatically trough setup resource installer script and how to retrieve this attribute later on.</p>
<p><span id="more-18576"></span></p>
<p>Magento extension at hand is available from its <a href="https://github.com/Marko-M/Inchoo_ProductMetaRobots/" title="Inchoo_ProductMetaRobots" target="_blank">GitHub repository page</a>, here I&#8217;ll just include a few important code snippets. First important thing is our setup class from Inchoo_ProductMetaRobots/app/code/community/Inchoo/ProductMetaRobots/Model/Resource/Setup.php file:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
class Inchoo_ProductMetaRobots_Model_Resource_Setup extends Mage_Eav_Model_Entity_Setup
{
    /**
     * Add our custom attributes
     *
     * @return Mage_Eav_Model_Entity_Setup
     */
    public function installCustomProductAttributes()
    {
        $attributes = $this-&gt;_getCustomProductAttributes();
        foreach ($attributes as $code =&gt; $attr) {
            $this-&gt;addAttribute('catalog_product', $code, $attr);
        }
        return $this;
    }
    /**
     * Remove custom attributes
     *
     * @return Mage_Eav_Model_Entity_Setup
     */
    public function removeCustomProductAttributes()
    {
        $attributes = $this-&gt;_getCustomProductAttributes();
        foreach ($attributes as $code =&gt; $attr) {
            $this-&gt;removeAttribute('catalog_product', $code);
        }
        return $this;
    }
    /**
     * Returns entities array to be used by
     * Mage_Eav_Model_Entity_Setup::installEntities()
     *
     * @return array Custom entities
     */
    protected function _getCustomProductAttributes()
    {
        return array(
            'inchoo_meta_robots' =&gt; array(
                'group'             =&gt; 'Meta Information',
                'label'             =&gt; 'Meta Robots',
                'type'              =&gt; 'varchar',
                'input'             =&gt; 'select',
                'default'           =&gt; '',
                'class'             =&gt; '',
                'backend'           =&gt; '',
                'frontend'          =&gt; '',
                'global'            =&gt; Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
                'visible'           =&gt; true,
                'required'          =&gt; false,
                'user_defined'      =&gt; false,
                'searchable'        =&gt; false,
                'filterable'        =&gt; false,
                'comparable'        =&gt; false,
                'visible_on_front'  =&gt; false,
                'visible_in_advanced_search' =&gt; false,
                'unique'            =&gt; false,
                'option' =&gt; array (
                    'value' =&gt; array(
                        'INDEX,FOLLOW' =&gt; array(0=&gt;'INDEX,FOLLOW'),
                        'NOINDEX,FOLLOW' =&gt; array(0=&gt;'NOINDEX,FOLLOW'),
                        'NOINDEX,NOFOLLOW' =&gt; array(0=&gt;'NOINDEX,NOFOLLOW'),
                        'INDEX,NOFOLLOW' =&gt; array(0=&gt;'INDEX,NOFOLLOW')
                    )
                )
            )
        );
    }
}
</pre>
<p>Inside _getCustomProductAttributes() function we can place new product attributes. In our case there&#8217;s just one attribute with &#8216;inchoo_meta_robots&#8217; code. This attribute will be used to construct dropdown menu (&#8216;input&#8217; with value &#8216;select&#8217;) with four options specified by the &#8216;option&#8217; array. This menu will be configurable at Product Information -> Meta Information -> Meta Robots as specified by the &#8216;group&#8217; and &#8216;label&#8217; array elements. Inside our setup class we also have two public functions, first one installCustomProductAttributes() is used for creating our custom product attributes and the second removeCustomProductAttributes() for removing them if necessary. These two functions are available inside our install script located at Inchoo_ProductMetaRobots/app/code/community/Inchoo/ProductMetaRobots/sql/inchoo_productmetarobots_setup/install-0.0.1.php. Here&#8217;s the code you&#8217;ll find there:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
$installer = $this;
// Install our custom attributes
$installer-&gt;installCustomProductAttributes();
// Remove our custom attributes
//$installer-&gt;removeCustomProductAttributes();
</pre>
<p>By default install script is adding custom product returned by _getCustomProductAttributes(). If you encounter any difficulties, the removal code is there to assist. If this happens also don&#8217;t forget to delete the &#8216;inchoo_productmetarobots_setup&#8217; row from &#8216;core_resource&#8217; table to trigger the install script again.</p>
<p>All that&#8217;s left to do is to rewrite Mage_Page_Block_Html_Head block using something like following inside global section of your config.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;global&gt;
        &lt;blocks&gt;
            &lt;page&gt;
                &lt;rewrite&gt;
                    &lt;html_head&gt;Inchoo_ProductMetaRobots_Block_Page_Html_Head&lt;/html_head&gt;
                &lt;/rewrite&gt;
            &lt;/page&gt;
        &lt;/blocks&gt;
    &lt;/global&gt;
&lt;/config&gt;
</pre>
<p>In our code we override Mage_Page_Block_Html::getRobots() function to inject our custom product attribute inside robots meta tag for product page view. The code is located at Inchoo_ProductMetaRobots/app/code/community/Inchoo/ProductMetaRobots/Block/Page/Html/Head.php and here&#8217;s the contents of that file:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
class Inchoo_ProductMetaRobots_Block_Page_Html_Head extends Mage_Page_Block_Html_Head
{
    /**
     * Customize meta robots tags when viewing product.
     *
     * @return string
     */
    public function getRobots()
    {
        parent::getRobots();
        if (($_product = Mage::registry('current_product')) &amp;&amp;
                ($robots = $_product-&gt;getAttributeText('inchoo_meta_robots'))) {
            $this-&gt;_data['robots'] = $robots;
        }
        return $this-&gt;_data['robots'];
    }
}
</pre>
<p>We simply call parent::getRobots() for the default behavior, and then override it if we are at the product page view, and if current product has meta robots value selected in its Meta Robots dropdown menu.</p>
<p>I hope you find this code snippets useful, if you have any suggestions feel free to leave your comment here or fork this code from its <a href="https://github.com/Marko-M/Inchoo_ProductMetaRobots/" title="Inchoo_ProductMetaRobots" target="_blank">GitHub repository page</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/per-product-meta-robots-tag-control-in-magento/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Easily manage LAMP name based virtual hosts</title>
		<link>http://inchoo.net/tools-frameworks/easily-manage-lamp-name-based-virtual-hosts/</link>
		<comments>http://inchoo.net/tools-frameworks/easily-manage-lamp-name-based-virtual-hosts/#comments</comments>
		<pubDate>Thu, 02 May 2013 05:42:22 +0000</pubDate>
		<dc:creator>Marko Martinovic</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[Tools & Frameworks]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[lamp]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[virtual host]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18530</guid>
		<description><![CDATA[I&#8217;ve been developing inside LAMP environment since the day one of my web development adventure. Reason for this is that all of the web development tools like web server, database &#8230;]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve been developing inside LAMP environment since the day one of my web development adventure. Reason for this is that all of the web development tools like web server, database management system, source code revision control systems are at home when I log into the Linux powered workstation. Of course there are some downsides to developing inside LAMP, most importantly the sheer complexity of LAMP environment configuration. With this in mind I&#8217;ve created tool designed to simplify management of name based virtual hosts on Debian based Linux operating systems. In this article I&#8217;ll give my best to provide an overview of this tool and present you with a few clear examples illustrating its usage.</p>
<p><span id="more-18530"></span></p>
<p>This tool is a bash shell script named lamp-vhost-manager released under GPLv2 open source license and available from it&#8217;s <a href="https://github.com/Marko-M/lamp-vhost-manager" title="LAMP Vhost manager" target="_blank">GitHub repository page</a>. Here are some of the features of this shell script:</p>
<ul>
<li>Two modes of operation, add project and remove project.</li>
<li>Can optionally create MySQL user and database for the project.</li>
<li>Has basic error checking built in. Also script will ask you before permanently removing any files or databases.</li>
<li>Project directories are created with proper user and group ownership depending on your base document root configuration.</li>
</ul>
<p>First things first, this is how to grab a copy of lamp-vhost-manager:</p>
<pre class="brush: bash; title: ; notranslate">
wget --no-check-certificate https://github.com/Marko-M/lamp-vhost-manager/tarball/master -O - | tar xz
cd Marko-M-lamp-vhost-manager-*
chmod +x lamp-vhost-manager.sh
</pre>
<p>I usually copy this type of scripts to /usr/bin so they could be accessed globally:</p>
<pre class="brush: bash; title: ; notranslate">
sudo cp lamp-vhost-manager.sh /usr/bin/
</pre>
<p>One note, before using this script please make sure name based virtual hosting has been enabled for your Apache installation. Also note that script requires root privileges to do its work.</p>
<p>After grabbing your copy of lamp-vhost-mangager you can use following command to create project accessible at vhost1.loc domain:</p>
<pre class="brush: bash; title: ; notranslate">
sudo /usr/bin/lamp-vhost-manager.sh -m add -n vhost1.loc
</pre>
<p>If you would like to also create MySQL user and database for your project you can provide your MySQL admin user credentials like this:</p>
<pre class="brush: bash; title: ; notranslate">
sudo /usr/bin/lamp-vhost-manager.sh -m add -n vhost1.loc -u mysqladminusername -p mysqladminuserpassword
</pre>
<p>Preceding command will configure virtual host and provide you with data like URL and file system path of your new project and database credentials so you can get right to work.</p>
<p>To remove the vhost1.loc project you can use similar command but this time change -m parameter from add to remove like this:</p>
<pre class="brush: bash; title: ; notranslate">
sudo /usr/bin/lamp-vhost-manager.sh -m remove -n vhost1.loc -u mysqladminusername -p mysqladminuserpassword
</pre>
<p>Script will then ask you for confirmation before removing any resources and then do its job accordingly.</p>
<p>There&#8217;s a few more parameters to adjust this script to your work environment at your disposal. You can use -h parameter to get detailed usage instructions like this:</p>
<pre class="brush: bash; title: ; notranslate">
sudo /usr/bin/lamp-vhost-manager.sh -h
</pre>
<p>If you would like to avoid having to provide some parameters each time you call the lamp-vhost-manager, you can edit corresponding bash variables at the beginning of the script.</p>
<p>I hope that lamp-vhost-manager works for you and that you find it useful. If you have any suggestions or encounter any difficulties just drop your comment here and I&#8217;ll see what can be done.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/tools-frameworks/easily-manage-lamp-name-based-virtual-hosts/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ultimate Google Analytics Dashboard for Ecommerce</title>
		<link>http://inchoo.net/ecommerce/ultimate-google-analytics-dashboard-for-ecommerce/</link>
		<comments>http://inchoo.net/ecommerce/ultimate-google-analytics-dashboard-for-ecommerce/#comments</comments>
		<pubDate>Mon, 29 Apr 2013 07:23:46 +0000</pubDate>
		<dc:creator>Vice Bozic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Online Marketing]]></category>
		<category><![CDATA[dashboard]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[google analytics]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18498</guid>
		<description><![CDATA[If you are an online store owner, then using custom Google Analytics dashboard is a must. It will save you time and effort of browsing through all these separate tabs &#8230;]]></description>
				<content:encoded><![CDATA[<p>If you are an online store owner, then using custom Google Analytics dashboard is a must. It will save you time and effort of browsing through all these separate tabs inside the Google Analytics interface. I decided to share with you one dashboard that I am using on a regular basis.<span id="more-18498"></span></p>
<p>This dashboard tracks key Ecommerce metrics and dimensions, including:</p>
<ul>
<li>Revenue from all sources</li>
<li>Revenue from AdWords campaigns</li>
<li>Average order value (AOV)</li>
<li>Ecommerce conversion rate</li>
<li>Transactions</li>
<li>Visits</li>
<li>Revenue by medium</li>
<li>Revenue by mobile (including tablet)</li>
<li>Best selling products</li>
<li>Top landing pages</li>
<li>Top search keywords</li>
<li>Visitors by city</li>
</ul>
<p><strong><a href="https://www.google.com/analytics/web/template?uid=DBWUpMfPT8-m7BEeFuA91w" target="_blank">Click this link</a> and save the dashboard to your own Google Analytics profile.</strong></p>
<p>Hope you will find it useful <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/ultimate-google-analytics-dashboard-for-ecommerce/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>301 redirects vs canonical links in Magento</title>
		<link>http://inchoo.net/ecommerce/magento/301vscanonicals/</link>
		<comments>http://inchoo.net/ecommerce/magento/301vscanonicals/#comments</comments>
		<pubDate>Sat, 27 Apr 2013 18:19:34 +0000</pubDate>
		<dc:creator>Ivan Galambos</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[Products]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[products]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[seo]]></category>
		<category><![CDATA[tips]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=17337</guid>
		<description><![CDATA[What can you do to prevent duplicated content of products from different stores? Recently we&#8217;ve received one inquiry to optimize an existing Magento website. Shortly, there are 2 stores with &#8230;]]></description>
				<content:encoded><![CDATA[<p>What can you do to prevent duplicated content of products from different stores?</p>
<p>Recently we&#8217;ve received one inquiry to optimize an existing Magento website.<br />
Shortly, there are 2 stores with codes: store1 and store2. Store code is included in the URL.</p>
<p>While we were working on the optimization, the client has reported that some of the products show in both: store1 and store2 but they should be visible only in one of those stores (imagine that you&#8217;re on store1 and you see there some related products but from store2).</p>
<p><span id="more-17337"></span></p>
<p>Additional problem in our case was that there were 2 categories, store1 and store2 (same names for categories as for store codes).</p>
<p>Our ICG (<strong>Inchoo Consulting Group</strong>) team was on top of the all things that we were doing. When they saw our problem, they instantly noticed what that could mean for client&#8217;s SEO!</p>
<p>Shortly, when you&#8217;re on one product you could manually change URL from /store1/ to /store2/ and you were able to see the same product, but now in different store (with different theme).</p>
<p>Because search engine could see the same product in store1 and store2 (2 same pages but with different URL &#8211; with the same content) it might think that you&#8217;re &#8220;cheating&#8221; and it could position you lower in search results. What search engine could do is to index all products on all stores &#8211; duplicated content. To avoid that we needed to &#8220;find&#8221; proper solution for that.</p>
<p>Basically what we could do here is: a) <strong>301 redirects</strong> or b) <strong>use canonical URLs</strong>. So we needed to ensure for some products from store1 not to be visible in store2.</p>
<p>At the end what we did is that we added 301 redirects for products that should be only visible in one store (if you try somehow to change URL), but if product exists in both stores we added canonical URLs to be on store1 (store1 in our case is more important).</p>
<p>What do you think about this approach for this specific issue?</p>
<p>If you have some similar situation here&#8217;s an idea how can you solve particular issue (bellow is sample code how can you solve it). Basically we&#8217;ve modified 2 files. One controller (for redirects) and one block (for canonical URLs).</p>
<p>Note: we&#8217;ve worked on CE ver.: 1.7.0.1. <strong>Don&#8217;t change the core files!</strong> But, because of simplicity I&#8217;ll show you the solution by modifying core files.</p>
<p>Open file <strong>app/code/core/Mage/Catalog/controllers/ProductController.php</strong> and replace <strong>viewAction()</strong> with the following content:</p>
<pre class="brush: php; title: ; notranslate">
public function viewAction()
    {
        // Get initial data from request
        $categoryId = (int) $this-&gt;getRequest()-&gt;getParam('category', false);
        $productId  = (int) $this-&gt;getRequest()-&gt;getParam('id');
        $specifyOptions = $this-&gt;getRequest()-&gt;getParam('options');
        /////////////////////////////////////// START WITH 301 REDIRECT
        $redirectURL =     Mage::getUrl('', array(
                '_current' =&gt; true,
                '_use_rewrite' =&gt; true,
        ));
        if ($productId) {
            $product = Mage::getModel('catalog/product')-&gt;load($productId);
        }
        $tmpStoreCode = false;
        $tmpStoreCode =  Mage::app()-&gt;getStore()-&gt;getCode();
        $expCatIdStore= false;
        switch ($tmpStoreCode) {
            case 'store1':
                $expCatIdStore = 1;
                break;
            case 'store2':
                $expCatIdStore = 100;
                break;
        }
        if ($expCatIdStore &amp;&amp; $productId) {
            $catIds = array();
            try {
                $catIds = $product-&gt;getCategoryIds();
            } catch (Exception $e) {
                //Mage::log or similar
            }
            $productIsInStore1 = false;
            $productIsInStore2 = false;
            // imagine that store code store1 represents category_id=1 and
            // store with code store2 represents category_id=100
            if (in_array(1, $catIds)) {
                $productIsInStore1 = true;
            }
            if (in_array(100, $catIds)) {
                $productIsInStore2 = true;
            }
            // if product should be in both stores don't do any redirect
            if ( !($productIsInStore1 &amp;&amp; $productIsInStore2) ) {
                if ($productIsInStore2 &amp;&amp; $tmpStoreCode === 'store1') {
                    $redirectURL = str_replace('example.com/store1/', 'example.com/store2/', $redirectURL);
                    header ('HTTP/1.1 301 Moved Permanently');
                    header ('Location: ' . $redirectURL);
                    exit;
                } elseif ($productIsInStore1 &amp;&amp; $tmpStoreCode === 'store2') {
                    $redirectURL = str_replace('example.com/store2/', 'example.com/store1/', $redirectURL);
                    header ('HTTP/1.1 301 Moved Permanently');
                    header ('Location: ' . $redirectURL);
                    exit;
                }
            }
        }
        /////////////////////////////////////// END WITH 301 REDIRECT
        // Prepare helper and params
        $viewHelper = Mage::helper('catalog/product_view');
        $params = new Varien_Object();
        $params-&gt;setCategoryId($categoryId);
        $params-&gt;setSpecifyOptions($specifyOptions);
        // Render page
        try {
            $viewHelper-&gt;prepareAndRender($productId, $this, $params);
        } catch (Exception $e) {
            if ($e-&gt;getCode() == $viewHelper-&gt;ERR_NO_PRODUCT_LOADED) {
                if (isset($_GET['store'])  &amp;&amp; !$this-&gt;getResponse()-&gt;isRedirect()) {
                    $this-&gt;_redirect('');
                } elseif (!$this-&amp;amp;gt;getResponse()-&gt;isRedirect()) {
                    $this-&gt;_forward('noRoute');
                }
            } else {
                Mage::logException($e);
                $this-&gt;_forward('noRoute');
            }
        }
    }
</pre>
<p>Additionally, to use canonical URLs for products that should be in both categories but, perhaps, show to search engine that it&#8217;s in only one (for example store1) category change <strong>_prepareLayout()</strong> method with the following content</p>
<p>Open file <strong>app/code/core/Mage/Catalog/Block/Product/View.php</strong></p>
<pre class="brush: php; title: ; notranslate">
    protected function _prepareLayout()
    {
        $this-&gt;getLayout()-&gt;createBlock('catalog/breadcrumbs');
        $headBlock = $this-&gt;getLayout()-&gt;getBlock('head');
        if ($headBlock) {
            $product = $this-&gt;getProduct();
            $title = $product-&gt;getMetaTitle();
            if ($title) {
                $headBlock-&gt;setTitle($title);
            }
            $keyword = $product-&gt;getMetaKeyword();
            $currentCategory = Mage::registry('current_category');
            if ($keyword) {
                $headBlock-&gt;setKeywords($keyword);
            } elseif($currentCategory) {
                $headBlock-&gt;setKeywords($product-&gt;getName());
            }
            $description = $product-&gt;getMetaDescription();
            if ($description) {
                $headBlock-&gt;setDescription( ($description) );
            } else {
                $headBlock-&gt;setDescription(Mage::helper('core/string')-&gt;substr($product-&gt;getDescription(), 0, 255));
            }
            if ($this-&gt;helper('catalog/product')-&gt;canUseCanonicalTag()) {
                $params = array('_ignore_category'=&gt;true);
                /////////////////////////////////////// START WITH CANONICAL
                $cannURL = $product-&gt;getUrlModel()-&gt;getUrl($product, $params);
                $productId  = (int) $this-&gt;getRequest()-&gt;getParam('id');
                $tmpStoreCode = false;
                $tmpStoreCode =  Mage::app()-&gt;getStore()-&gt;getCode();
                $expCatIdStore = false;
                switch ($tmpStoreCode) {
                    case 'store1':
                        $expCatIdStore = 1;
                        break;
                    case 'store2':
                        $expCatIdStore = 100;
                        break;
                }
                if ($expCatIdStore &amp;&amp; $productId) {
                    $catIds = array();
                    try {
                        $catIds = $product-&gt;getCategoryIds();
                    } catch (Exception $e) {
                        //die silently
                    }
                    $productIsInBoth = false;
                    if ( in_array(1, $catIds) &amp;&amp; in_array(100, $catIds) ) {
                        $productIsInBoth = true;
                    }
                    if ($productIsInBoth &amp;&amp; $tmpStoreCode === 'store2') {
                        $cannURL = str_replace('example.com/store2/', 'example.com/store1/', $cannURL);
                    }
                }
                $headBlock-&gt;addLinkRel('canonical', $cannURL);
                //////////////////////////////////// END WITH CANONICAL
                //$headBlock-&gt;addLinkRel('canonical', $product-&gt;getUrlModel()-&gt;getUrl($product, $params));
            }
        }
        return parent::_prepareLayout();
    }
</pre>
<p>And that&#8217;s about it.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/301vscanonicals/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Product Stock Alerts (not) working</title>
		<link>http://inchoo.net/ecommerce/product-stock-alerts-not-working/</link>
		<comments>http://inchoo.net/ecommerce/product-stock-alerts-not-working/#comments</comments>
		<pubDate>Fri, 26 Apr 2013 11:33:46 +0000</pubDate>
		<dc:creator>Ivan Galambos</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Email]]></category>
		<category><![CDATA[Events & Observers]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Products]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[iteration]]></category>
		<category><![CDATA[observer]]></category>
		<category><![CDATA[product]]></category>
		<category><![CDATA[product alert]]></category>
		<category><![CDATA[product alert price]]></category>
		<category><![CDATA[product alert stock]]></category>
		<category><![CDATA[stock]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18469</guid>
		<description><![CDATA[Recently one of our clients had contacted us and said that ProductAlert functionality doesn&#8217;t work any more. After I investigated the situation I saw that last email regarding to Stock &#8230;]]></description>
				<content:encoded><![CDATA[<p>Recently one of our clients had contacted us and said that ProductAlert functionality doesn&#8217;t work any more. After I investigated the situation I saw that last email regarding to Stock Alerts was sent several months ago. In the meantime we&#8217;ve upgraded the site to Magento EE and at first I thought that maybe during the upgrade something went wrong. Other thought was that maybe client has modified Transactional Email Template&#8230; After reviewing log files I couldn&#8217;t find anything related to those emails. System did send other emails though.</p>
<p>During the investigation I saw on forums that other developers have similar issue that weren&#8217;t resolved yet. After tracing and looking what might have gone wrong we&#8217;ve found&#8230; <span id="more-18469"></span></p>
<p>Shortly, the issue was in Magento approach to handling Product Stock Alert collection. Our client has more than 40.000 subscribers and more than 30.000 are waiting for status to be changed from &#8220;Out of Stock&#8221; to &#8220;In Stock&#8221;. So <strong>when Magento tries to load 40.000 records from table product_alert_stock to collection to foreach them because of memory limitation php fails</strong>. Probably if you have more than 20.000 records in table product_alert_stock your Product Stock Alert functionality doesn&#8217;t work anymore.</p>
<p>The solution was relatively simple. Divide collection by 1.000 and create several pages to iterate through more than 30.000 records, in same way Magento is doing in different places in its system. In our case we had around 35 pages, each with 1.000 records in collection. <strong>New functionality is iterating through all of them and for each record where status=0 (unprocessed) system checks for product to see if product is now in stock.</strong> If that&#8217;s true =&gt; set status=1 and send an notification email to customer.</p>
<p>So let&#8217;s create our module, Inchoo_ProductAlert, that will enhance Magento&#8217;s approach:</p>
<h3>1. Create file in app/etc/modules/ Inchoo_ProductAlert.xml with the following content:</h3>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_ProductAlert&gt;
            &lt;active&gt;true&lt;/active&gt;
            &lt;codePool&gt;local&lt;/codePool&gt;
        &lt;/Inchoo_ProductAlert&gt;
    &lt;/modules&gt;
&lt;/config&gt;
</pre>
<h3>2. Create file in app/code/local/Inchoo/ProductAlert/etc/ config.xml with the following content:</h3>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_ProductAlert&gt;
            &lt;version&gt;1.0.0.0&lt;/version&gt;
        &lt;/Inchoo_ProductAlert&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;models&gt;
            &lt;productalert&gt;
                &lt;rewrite&gt;
                    &lt;observer&gt;Inchoo_ProductAlert_Model_Observer&lt;/observer&gt;
                &lt;/rewrite&gt;
            &lt;/productalert&gt;
        &lt;/models&gt;
    &lt;/global&gt;
&lt;/config&gt;
</pre>
<p>You can see that we&#8217;ve rewritten Mage_ProductAlert_Model_Observer class</p>
<h3>3. Create file in /www/app/code/local/Inchoo/ProductAlert/Model/ Observer.php with the following content:</h3>
<pre class="brush: php; title: ; notranslate">
&lt;?php
/**
 * ProductAlert observer
 *
 * @category   Inchoo
 * @package    Inchoo_ProductAlert
 * @author     &lt;ivan.galambos@inchoo.net&gt;
 */
class Inchoo_ProductAlert_Model_Observer extends Mage_ProductAlert_Model_Observer
{
     /**
     * Process stock emails
     *
     * @param Mage_ProductAlert_Model_Email $email
     * @return Mage_ProductAlert_Model_Observer
     */
    protected function _processStock(Mage_ProductAlert_Model_Email $email)
    {
        $email-&gt;setType('stock');
        foreach ($this-&gt;_getWebsites() as $website) {
            /* @var $website Mage_Core_Model_Website */
            if (!$website-&gt;getDefaultGroup() || !$website-&gt;getDefaultGroup()-&gt;getDefaultStore()) {
                continue;
            }
            if (!Mage::getStoreConfig(
                self::XML_PATH_STOCK_ALLOW,
                $website-&gt;getDefaultGroup()-&gt;getDefaultStore()-&gt;getId()
            )) {
                continue;
            }
            try {
                $wholeCollection = Mage::getModel('productalert/stock')
                    -&gt;getCollection()
//                    -&gt;addWebsiteFilter($website-&gt;getId())
                    -&gt;addFieldToFilter('website_id', $website-&gt;getId())
                    -&gt;addFieldToFilter('status', 0)
                ;
//                $wholeCollection-&gt;getSelect()-&gt;order('alert_stock_id DESC');
                /*       table: !product_alert_stock!
                alert_stock_id: 1
                   customer_id: 1
                    product_id: 1
                    website_id: 1
                      add_date: 2013-04-26 12:08:30
                     send_date: 2013-04-26 12:28:16
                    send_count: 2
                        status: 1
                */
            }
            catch (Exception $e) {
                Mage::log('error-1-collection $e=' . $e-&gt;getMessage(), false, 'product_alert_stock_error.log', true);
                $this-&gt;_errors[] = $e-&gt;getMessage();
                return $this;
            }
            $previousCustomer = null;
            $email-&gt;setWebsite($website);
            try {
                $originalCollection = $wholeCollection;
                $count = null;
                $page  = 1;
                $lPage = null;
                $break = false;
                while ($break !== true) {
                    $collection = clone $originalCollection;
                    $collection-&gt;setPageSize(1000);
                    $collection-&gt;setCurPage($page);
                    $collection-&gt;load();
                    if (is_null($count)) {
                        $count = $collection-&gt;getSize();
                        $lPage = $collection-&gt;getLastPageNumber();
                    }
                    if ($lPage == $page) {
                        $break = true;
                    }
                    Mage::log('page=' . $page, false, 'check_page_count.log', true);
                    Mage::log('collection=' . (string)$collection-&gt;getSelect(), false, 'check_page_count.log', true);
                    $page ++;
                    foreach ($collection as $alert) {
                        try {
                            if (!$previousCustomer || $previousCustomer-&gt;getId() != $alert-&gt;getCustomerId()) {
                                $customer = Mage::getModel('customer/customer')-&gt;load($alert-&gt;getCustomerId());
                                if ($previousCustomer) {
                                    $email-&gt;send();
                                }
                                if (!$customer) {
                                    continue;
                                }
                                $previousCustomer = $customer;
                                $email-&gt;clean();
                                $email-&gt;setCustomer($customer);
                            }
                            else {
                                $customer = $previousCustomer;
                            }
                            $product = Mage::getModel('catalog/product')
                                -&gt;setStoreId($website-&gt;getDefaultStore()-&gt;getId())
                                -&gt;load($alert-&gt;getProductId());
                            /* @var $product Mage_Catalog_Model_Product */
                            if (!$product) {
                                continue;
                            }
                            $product-&gt;setCustomerGroupId($customer-&gt;getGroupId());
                            if ($product-&gt;isSalable()) {
                                $email-&gt;addStockProduct($product);
                                $alert-&gt;setSendDate(Mage::getModel('core/date')-&gt;gmtDate());
                                $alert-&gt;setSendCount($alert-&gt;getSendCount() + 1);
                                $alert-&gt;setStatus(1);
                                $alert-&gt;save();
                            }
                        }
                        catch (Exception $e) {
                            Mage::log('error-2-alert $e=' . $e-&gt;getMessage(), false, 'product_alert_stock_error.log', true);
                            $this-&gt;_errors[] = $e-&gt;getMessage();
                        }
                    }
                }
                Mage::log(&quot;\n\n&quot;, false, 'check_page_count.log', true);
            } catch (Exception $e) {
                Mage::log('error-3-steps $e=' . $e-&gt;getMessage(), false, 'product_alert_stock_error.log', true);
            }
            if ($previousCustomer) {
                try {
                    $email-&gt;send();
                }
                catch (Exception $e) {
                    $this-&gt;_errors[] = $e-&gt;getMessage();
                }
            }
        }
        return $this;
    }
    /**
     * Run process send product alerts
     *
     * @return Inchoo_ProductAlert_Model_Observer
     */
    public function process()
    {
        Mage::log('ProductAlert started @' . now(), false, 'product_alert_workflow.log', true);
        $email = Mage::getModel('productalert/email');
        /* @var $email Mage_ProductAlert_Model_Email */
        $this-&gt;_processPrice($email);
        $this-&gt;_processStock($email);
        $this-&gt;_sendErrorEmail();
        Mage::log('ProductAlert finished @' . now(), false, 'product_alert_workflow.log', true);
        return $this;
    }
}
</pre>
<p>You can see that we&#8217;ve overwritten 2 methods: process() and _processStock().<br />
In process() method we added Mage::log() for creating start&amp;end time in var/log/product_alert_workflow.log so we can know did script finish with it&#8217;s execution. Similarly to debug our enhancement in _processStock() method, we added few more Mage:log() calls so we can track if everything behave in the expected way.</p>
<p>For the end, if you don&#8217;t want to wait for your cron to be triggered, you can create a file in Magento root, let&#8217;s call it,</p>
<h3>inchoo_cron.php:</h3>
<pre class="brush: php; title: ; notranslate">
&lt;?php
/**
 * @author     &lt;ivan.galambos@inchoo.net&gt;
 */
require_once 'app/Mage.php';
Mage::app();
try {
    Mage::getModel('productalert/observer')-&gt;process();
} catch (Exception $e) {
    Mage::log('error-0-start $e=' . $e-&gt;getMessage() . ' @' . now(), false, 'product_alert_stock_error.log', true);
}
</pre>
<p>And that&#8217;s about it. Feel free after testing your functionality to remove/comment Mage::log() calls. And if you have similar issue with Product Alert Price functionality you can apply the same basic idea and everything should work fine.</p>
<p>3 log files are going to be created if you apply this enhancement without removing Mage::log() calls:</p>
<ul>
<li><strong>product_alert_workflow</strong>.log &#8211; log start&amp;end time for each call to script</li>
<li><strong>check_page_count</strong>.log &#8211; log #of pages and query that should be run</li>
<li><strong>product_alert_stock_error</strong>.log &#8211; error messages from 0-3 places in code</li>
</ul>
<p>Note that even Magento EE v. 1.13 has the same problem with big collection in ProductAlert module.</p>
<p>And that&#8217;s about it.</p>
<p>Have a nice day!</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/product-stock-alerts-not-working/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Magento 2 and Twig</title>
		<link>http://inchoo.net/ecommerce/magento/magento-2-and-twig/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-2-and-twig/#comments</comments>
		<pubDate>Wed, 24 Apr 2013 12:01:23 +0000</pubDate>
		<dc:creator>Branko Ajzele</dc:creator>
				<category><![CDATA[Frontend]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Front-End]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[twig]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18372</guid>
		<description><![CDATA[Recently there has been some buzz around Magento getting support for Twig template engine. Looking at the CHANGELOG.markdown file under the Magento2 GitHub repository for 2.0.0.0-dev44 version commit, this seems &#8230;]]></description>
				<content:encoded><![CDATA[<p>Recently there has been some buzz around Magento getting support for Twig template engine. Looking at the CHANGELOG.markdown file under the Magento2 GitHub repository for 2.0.0.0-dev44 version commit, this seems to be more than just a buzz.<span id="more-18372"></span> Here are the specific log entries mentioning the Twig:</p>
<ul>
<li>Introduced support for Twig templating</li>
<li>template rendering, including phtml, was abstracted into a Mage_Core_Block_Template_Engine to make support for other template engines easier</li>
<li>included Magento-specific Twig functions and filters</li>
<li>Converted product view page to demonstrate use of Twig templates and services</li>
</ul>
<p>So what exactly is Twig? Twig is a modern template engine for PHP, you can get it from <a href="http://twig.sensiolabs.org">http://twig.sensiolabs.org</a>. It is fast, secure and flexible, at least the “commercial” says so <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Twig is developed by Fabien Potencier, the creator of the Symfony framework, and it is released under the new BSD license. </p>
<p>Even today, in 2013, there are many developers that will argue how PHP itself is a template engine itself so adding something like specialised template engines on top of it is an overkill. When you look at the Magento 1.x series, it uses pure PHP mixed with HTML within its *.phtml files, and the whole thing works. Well, it works more or less, until you get your developer assembling collection objects and coding in hundred of lines of business logic within .phtml file, logic that needs to be shared across few controllers, etc. Then the whole thing gets bunch of duplicated code, etc.</p>
<p>There are strong arguments why use template engine with PHP. I would strongly recommend reading the <a href="http://fabien.potencier.org/article/34/templating-engines-in-php">Templating Engines in PHP</a> article written by Fabien Potencier himself. Be worn doe, author himself has an article intro starting with “<em>This blog post is not for the faint-hearted!</em>”. I personally agree with his views and comments on the modern template language feature requirements such as: concision, template oriented syntax, reusability, security, etc. With that said, I personally welcome the support for Twig within Magento2.</p>
<p>So where are we with Magento 2 + Twig implementation. If you <em>git clone https://github.com/magento/magento2.git</em> project and pull it into your favorite IDE (NetBeans) then do a Find for “twig” string, you will get a result of “<em>Found 4,944 matches of twig in 397 files.</em>”. There is no point in listing all those files here, this is just to get a glimpse on things. Since everything major and core in Magento start from Mage_Core, if you do a same search on the /app/code/Mage/Core/ folder you will get a result of “<em>Found 47 matches of twig in 4 files.</em>”. Now this is the number of files we can start tracing from.</p>
<p>You can clearly see that there is a <em>Mage_Core_Block_Template_Engine_Twig</em> class that implements the <em>Mage_Core_Block_Template_EngineInterface</em> interface. I must say, this is a nice surprise, seeing Magento using interfaces. You can take this as a bit of sarcasm from my side given that Magento 1.x was all about class extending. Surprisingly, <em>Mage_Core_Block_Template_EngineInterface</em> interface is ultimately simple, it only holds one method “<em>public function render(Mage_Core_Block_Template $block, $templateFile, $vars);</em>”. Looking further at the <em>Mage_Core_Block_Template_Engine_Factory</em> class and its “<em>public function get($name)</em>” method, seems like built in stuff will cover standard *.phtml and new Twig templates.</p>
<p>I won’t go into further details about implementation and usage, maybe in some of my later articles, when I actually get to play with it.</p>
<p>To conclude, what I am personally hoping that the Twig templating support will achieve for Magento 2 is slightly cleaner 3rd party extension code in a first place. Primarily hoping not to see any more collection and business logic code within yesterdays *.phtml files, etc.</p>
<p>Would be interesting to hear your thought about this Magento move?</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-2-and-twig/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How to pass Hubspot Inbound Marketing Certification Exam</title>
		<link>http://inchoo.net/ecommerce/how-to-pass-hubspot-inbound-marketing-certification-exam/</link>
		<comments>http://inchoo.net/ecommerce/how-to-pass-hubspot-inbound-marketing-certification-exam/#comments</comments>
		<pubDate>Tue, 23 Apr 2013 12:26:29 +0000</pubDate>
		<dc:creator>Vice Bozic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Online Marketing]]></category>
		<category><![CDATA[hubspot]]></category>
		<category><![CDATA[inbound marketing]]></category>
		<category><![CDATA[vicebozic]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18174</guid>
		<description><![CDATA[On April 2, 2013, Hubspot launched a new version of their free inbound marketing certification program. Since lots of things have changed from previous version, I decided to upgrade my &#8230;]]></description>
				<content:encoded><![CDATA[<p>On April 2, 2013, <strong><a href="http://www.hubspot.com/" target="_blank">Hubspot </a></strong>launched a new version of their free <strong><a href="http://academy.hubspot.com/certification/" target="_blank">inbound marketing certification program</a></strong>. Since lots of things have changed from previous version, I decided to upgrade my existing certification and to take the test again. I passed the test a couple of days ago and thought I’d share a few tips on how to prepare for – and most importantly pass – the exam. <span id="more-18174"></span></p>
<h3>1. About the exam</h3>
<p>Firstly, I must say that <strong>Hubspot</strong> did a really great job providing all the necessary information for you to pass the exam &#8211; 9 video classes with additional links to various blog posts, ebooks and guides. To pass the exam, you will need to answer 50 multiple choice and true/false questions within 60 minutes. I know that might seem like a short amount of time, but if you are prepared that&#8217;s more than enough. Also, you have three chances to pass the test, and if you do not pass, you will have to wait 48 hours before taking the test again.</p>
<h3>2. How to prepare</h3>
<p>Best way you can prepare for the exam is to go through a 9 video classses that are categorized by inbound marketing methodology &#8211; Attract, Convert, Close and Delight. I suggest that you watch all of them, as they are all very useful. I took approximately one week to go through all of them, plus couple of days for notes and preparation. Also, you can download a <strong><a href="http://cdn2.hubspot.net/hub/137828/file-24742226-pdf/inbound_marketing_certification/imc_study_guide.pdf" target="_blank">quick study guide</a></strong> to help you with your preparation. Before you can watch videos, you will need to <strong><a href="http://academy.hubspot.com/certification/" target="_blank">signup for a complimentary Hubspot account</a></strong>.</p>
<div id="attachment_18218" class="wp-caption aligncenter" style="width: 619px"><a href="http://academy.hubspot.com/certification/" target="_blank"><img class="size-full wp-image-18218 " alt="classes" src="http://inchoo.net/wp-content/uploads/2013/04/classes.jpg" width="609" height="493" /></a><p class="wp-caption-text">Inbound Marketing Certification &#8211; 9 Video Classes</p></div>
<h3>3. After the exam</h3>
<p>Once you have submitted your answers, you will know the results immediately, and hopefully if you passed the test you can show off your new certificate. Also, you will get a certification badge that you can embed onto your blog or website.</p>
<p>Good luck!</p>
<div id="attachment_18222" class="wp-caption alignleft" style="width: 619px"><img class="size-full wp-image-18222" alt="certificate" src="http://inchoo.net/wp-content/uploads/2013/04/certificate.jpg" width="609" height="493" /><p class="wp-caption-text">Inbound Marketing Certificate</p></div>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/how-to-pass-hubspot-inbound-marketing-certification-exam/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Magento Maximum Allowed Order Amount</title>
		<link>http://inchoo.net/ecommerce/magento/magento-maximum-allowed-order-amount/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-maximum-allowed-order-amount/#comments</comments>
		<pubDate>Mon, 22 Apr 2013 07:29:12 +0000</pubDate>
		<dc:creator>Branko Ajzele</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[Events & Observers]]></category>
		<category><![CDATA[order]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18159</guid>
		<description><![CDATA[Recently I have been working on a project that had its own set of small fraud prevention features. One such feature was maximum allowed order amount. While it may sound &#8230;]]></description>
				<content:encoded><![CDATA[<p>Recently I have been working on a project that had its own set of small fraud prevention features. One such feature was maximum allowed order amount. While it may sound strange at first; why would someone want to limit the maximum amount of order?! Given the nature of the product that shop was selling (cannot disclose that information) that feature request seemed pretty reasonable. <span id="more-18159"></span>If you look at the Magento admin configuration area, you will see that Magento offers the opposite feature called Minimum Order Amount. You can find it under <strong>System > Configuration > Sales > Sales > Minimum Order Amount</strong>.</p>
<p>Minimum Order Amount functions slightly different than our Maximum Allowed Order Amount. The main difference is that with Maximum Allowed Order Amount you are not suppose to add anything new to the cart itself if it exceeds the maximum limit. So how do we do that. Answer is simple, event/observer system. All we need to do is to find the right event in Magento and hook an observer on it. After careful tracing, few try and fail, and a tip from my coworker Matej, the most logical event for implementing Maximum Allowed Order Amount seemed to be <strong>sales_quote_save_before</strong>. Additionally, it makes sense to implement the Maximum Allowed Order Amount functionality only on the frontend area, since we do not want to limit the admin created orders. With that in mind, we only needed to add the following to our extension config.xml file:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;frontend&gt;
        &lt;events&gt;
            &lt;sales_quote_save_before&gt;
                &lt;observers&gt;
                    &lt;inchoo_maxorderamount_enforceSingleOrderLimit&gt;
                        &lt;class&gt;inchoo_maxorderamount/observer&lt;/class&gt;
                        &lt;method&gt;enforceSingleOrderLimit&lt;/method&gt;
                    &lt;/inchoo_maxorderamount_enforceSingleOrderLimit&gt;
                &lt;/observers&gt;
            &lt;/sales_quote_save_before&gt;
        &lt;/events&gt;
    &lt;/frontend&gt;
&lt;/config&gt;
</pre>
<p>And the following logic into our Observer.php model class file:</p>
<pre class="brush: php; title: ; notranslate">
class Inchoo_MaxOrderAmount_Model_Observer
{
    private $_helper;
    public function __construct()
    {
        $this-&gt;_helper = Mage::helper('inchoo_maxorderamount');
    }
    /**
     * No single order can be placed over the amount of X
     */
    public function enforceSingleOrderLimit($observer)
    {
        if (!$this-&gt;_helper-&gt;isModuleEnabled()) {
            return;
        }
        $quote = $observer-&gt;getEvent()-&gt;getQuote();
        if ((float)$quote-&gt;getGrandTotal() &gt; (float)$this-&gt;_helper-&gt;getSingleOrderTopAmount()) {
            $formattedPrice = Mage::helper('core')-&gt;currency($this-&gt;_helper-&gt;getSingleOrderTopAmount(), true, false);
            Mage::getSingleton('checkout/session')-&gt;addError(
                $this-&gt;_helper-&gt;__($this-&gt;_helper-&gt;getSingleOrderTopAmountMsg(), $formattedPrice));
            Mage::app()-&gt;getFrontController()-&gt;getResponse()-&gt;setRedirect(Mage::getUrl('checkout/cart'));
            Mage::app()-&gt;getResponse()-&gt;sendResponse();
            exit;
        }
    }
}
</pre>
<p>The real success with this approach lies in the single “<strong>Mage::getSingleton(&#8216;checkout/session&#8217;)->addError()</strong> &#8230;” line of code. Triggering this line of code here, within sales_quote_save_before event, makes Magento refuse to update (add new items) the shopping cart if the amount of new products exceeds the Maximum Allowed Order Amount. More or less thats it.</p>
<p>You can download <strong><a href="https://github.com/ajzele/Inchoo_MaxOrderAmount" title="Inchoo_MaxOrderAmount">Inchoo_MaxOrderAmount</a></strong> Magento extension from <a href="https://github.com/ajzele?tab=repositories" title="GitHub - Branko Ajzele">my GitHub account</a>. It adds a nice little configuration area for this extension under <strong>System > Configuration > Sales > Sales > Maximum Order Amount</strong>. On top of just limiting the maximum allowed order amount, there is also some extra functionality regarding the admin email notifications in case certain orders pass certain amount values. As I said, this extension is inspired by simple fraud prevention functionalities on a project we have been working on recently.</p>
<p>Hope you find it useful, if not for practical application then maybe for educational reasons.<br />
Cheers.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-maximum-allowed-order-amount/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Magento Event Driven Programming Tips &amp; Tricks</title>
		<link>http://inchoo.net/ecommerce/magento/magento-event-driven-programming-tips-tricks/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-event-driven-programming-tips-tricks/#comments</comments>
		<pubDate>Wed, 17 Apr 2013 10:05:25 +0000</pubDate>
		<dc:creator>Branko Ajzele</dc:creator>
				<category><![CDATA[Events & Observers]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[observer]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18143</guid>
		<description><![CDATA[One of the cool things about Magento from the application architectural point of view is its support for the event driven programming. That is, event &#8211; observer system. The whole &#8230;]]></description>
				<content:encoded><![CDATA[<p>One of the cool things about Magento from the application architectural point of view is its support for the event driven programming. That is, event &#8211; observer system. The whole idea is pretty simple. On one side you have an events getting fired, and on another side you have observers listening for specific events and executing certain logic when specific event is fired. What&#8217;s great about event driven programming is that it enables clear separation of your custom code from the core code.<span id="more-18143"></span></p>
<p>It allows you to hook into certain parts of the workflow and possibly change its behaviour or at the very least inject your additional custom logic alongside. Given the role Magento tries to fill in, the super modular and extendible eCommerce platform for growth, events play a significant role in its architecture. Not so surprisingly, this event &#8211; observer pattern is mostly used among extension developers, because it enables them clean injection of extensions functionality into Magento. For example, lets say you have a specific requirement of notifying a 3rd party system about each new order that gets created. In Magento, this is really easy, you would simply implement observer that observes sales_order_place_after event and place your logic within it.</p>
<p>There are several “types” or better to say kinds of event getting fired in Magento. For one, we can differentiate what I call:</p>
<ul>
<li>static events</li>
<li>dynamic events</li>
</ul>
<p>First of all, this is just my terminology. There is no special difference between the two, its just how I like to call them, so bare with me. </p>
<p>Let me explain what I mean by static event. Static events are all those events defined with full event name like:</p>
<ul>
<li>Mage::dispatchEvent(&#8216;admin_session_user_login_failed&#8217;, array(&#8216;user_name&#8217; => $username, &#8216;exception&#8217; => $e));</li>
<li>Mage::dispatchEvent(&#8216;cms_page_prepare_save&#8217;, array(&#8216;page&#8217; => $model, &#8216;request&#8217; => $this->getRequest()));</li>
<li>Mage::dispatchEvent(&#8216;catalog_product_get_final_price&#8217;, array(&#8216;product&#8217; => $product, &#8216;qty&#8217; => $qty));</li>
<li>Mage::dispatchEvent(&#8216;catalog_product_flat_prepare_columns&#8217;, array(&#8216;columns&#8217; => $columnsObject));</li>
<li>Mage::dispatchEvent(&#8216;catalog_prepare_price_select&#8217;, $eventArgs);</li>
<li>&#8230;</li>
</ul>
<p>Dynamic events are all those events defined with dynamically, at runtime, fetched event name like:</p>
<ul>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_load_before&#8217;, $params);</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_load_after&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_save_before&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_save_after&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent(&#8216;controller_action_layout_render_before_&#8217;.$this->getFullActionName());</li>
<li>&#8230;</li>
</ul>
<p>Once more, both type of events are absolutely the same, they function the same, this is just my terminology. If you are an extension developer, then chances are that most of the time you will be interested in dynamic events. For example, each time you wish to intercept a certain parameters passed to a controller action you could simply create an event observer that would observe “<strong>controller_action_predispatch_*</strong>” event triggered within Mage_Core_Controller_Varien_Action class file:</p>
<p><strong>Mage::dispatchEvent(&#8216;controller_action_predispatch_&#8217; . $this->getFullActionName(), array(&#8216;controller_action&#8217; => $this));</strong></p>
<p>Now, let us see how exactly do we define event observer and place some of our code to be executed upon certain event. First we need to create an entry within our modules config.xml file. Lets say we want to “examine” all of the parameters passed to controller action during customer registration process. When customer fills in the required registration fields and clicks “Submit”, form POST’s the data to http://{{shop.domain}}/index.php/customer/account/createpost/ url. Now, if you look at the previously mentioned “<strong>controller_action_predispatch_*</strong>” event, expression “<strong>$this->getFullActionName()</strong>” would return “<strong>customer_account_createpost</strong>” string. You can find that out easily by placing the “<strong>var_dump($this->getFullActionName()); exit;</strong>” expression right there under the “Mage::dispatchEvent(&#8216;controller_action_predispatch_&#8230;” expression. So, now that we now that, we can safely conclude that the full event name we need to observe in this case is “<strong>controller_action_predispatch_customer_account_createpost</strong>”.</p>
<p>Now let us create a required entry within our modules config.xml file:</p>
<pre class="brush: xml; title: ; notranslate">
    &lt;frontend&gt;
        &lt;events&gt;
            &lt;controller_action_predispatch_customer_account_createpost&gt;
                &lt;observers&gt;
                    &lt;inspectCustomerRegistrationData&gt;
                        &lt;class&gt;Inchoo_Test_Model_Observer&lt;/class&gt;
                        &lt;method&gt;inspectCustomerRegistrationData&lt;/method&gt;
                    &lt;/inspectCustomerRegistrationData&gt;
                &lt;/observers&gt;
            &lt;/controller_action_predispatch_customer_account_createpost&gt;
        &lt;/events&gt;
</pre>
<p>Value of <code>&lt;class></code> implies on using <strong>Inchoo_Test_Model_Observer</strong> class file and value of <method> implies on using the “<strong>inspectCustomerRegistrationData</strong>” method within that class. The <class> can be written slightly different, for example “<code>&lt;class>inchoo_test/observer</code></class>” where “<strong>inchoo_test</strong>” is your model class group. Its actually a better, more modular, approach to use class group (“inchoo_test”) for <code>&lt;class></code> definition here. Method “<strong>inspectCustomerRegistrationData</strong>” is where we will put our custom logic. In this case we will simply try to fetch the POST parametars passed to the controller action, so our inspectCustomerRegistrationData class file looks like:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
class Inchoo_Test_Model_Observer
{
    public function inspectCustomerRegistrationData($observer = null)
    {
        $event = $observer-&gt;getEvent();
        $controllerAction = $event-&gt;getControllerAction();
        Zend_Debug::dump($controllerAction-&gt;getRequest()-&gt;getParams(), 'PARAMS');
        exit;
    }
</pre>
<p>Line “<strong>$event = $observer->getEvent();</strong>” is a standard way to get the “event” object which then holds the data passed to the event. If you look above at the example where we outlined the dispatch of &#8216;controller_action_predispatch_*&#8217; event you will see that that event takes one parameter called “&#8217;controller_action&#8217;” with the value of “$this”. Since “$this” in that context came from Mage_Core_Controller_Varien_Action class file that means that our $this is actually an instance of Mage_Core_Controller_Varien_Action and that we can do stuff like “<strong>$this->getRequest()->getParams();</strong>” to get the parameters passed to controller action. Calling Zend_Debug as in example above would then output something like shown below to your browser:</p>
<p>PARAMS array(7) {<br />
  [&quot;success_url&quot;] =&gt; string(0) &quot;&quot;<br />
  [&quot;error_url&quot;] =&gt; string(0) &quot;&quot;<br />
  [&quot;firstname&quot;] =&gt; string(6) &quot;Branko&quot;<br />
  [&quot;lastname&quot;] =&gt; string(6) &quot;Ajzele&quot;<br />
  [&quot;email&quot;] =&gt; string(16) &quot;user@mail.com&quot;<br />
  [&quot;password&quot;] =&gt; string(8) &quot;test123&quot;<br />
  [&quot;confirmation&quot;] =&gt; string(8) &quot;test123&quot;<br />
}</p>
<p>The above is simple example of how to use event observer. The most important thing in the whole process is to simply “discover” the event you need, and then observer it. Sometimes the right event might not be there, so you might need to look for the second best. For example, if we did not had the “<strong>controller_action_predispatch_customer_account_createpost</strong>” event dispatched then the next best event would probably be:</p>
<p><strong>Mage::dispatchEvent(&#8216;controller_action_predispatch&#8217;, array(&#8216;controller_action&#8217; => $this));</strong></p>
<p>However, event “&#8217;controller_action_predispatch&#8217;” is pretty generic, which means it will get triggered for every controller action predispatch. In which case you would have to do a little IF logic within your event observer code.</p>
<p>Usually, next to the <em>controller</em> related events are <em>model</em> related events. If you open a class file like Mage_Catalog_Model_Product, you can see property definitions like &#8220;protected $_eventPrefix = &#8216;catalog_product&#8217;;&#8221; and &#8220;protected $_eventObject = &#8216;product&#8217;;&#8221;. Now, if you trace the code a little bit down to Mage_Core_Model_Abstract class file, you will see that properties $_eventPrefix and $_eventObject are used for &#8220;dynamic&#8221; events like (alongside with the generic events for the same action):</p>
<ul>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_load_before&#8217;, $params);</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_load_after&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_save_commit_after&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_save_before&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_save_after&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_delete_before&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_delete_after&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_delete_commit_after&#8217;, $this->_getEventData());</li>
<li>Mage::dispatchEvent($this->_eventPrefix.&#8217;_clear&#8217;, $this->_getEventData());</li>
</ul>
<p>Knowing this is extremely important, as it enables you to create all sort of event observers for specific models and their actions, like &#8220;Customer entity create/update/delete&#8221;, &#8220;Order entity create/update/delete&#8221;, &#8220;Invoice entity create/update/delete&#8221;, etc. As a matter of fact, defining $_eventPrefix and $_eventObject properties on your custom model classes is something you should adopt as a sign of good coding practice. Doing so enables the other guy to hook into your extension code in a clean way.</p>
<p>To conclude, writing observers is pretty easy. Most of the time issues pop out when you do not have an event dispatched for certain situations. In such cases, try looking around for “dynamic” events or the next best event you can hook into.</p>
<p>Hope this helps.<br />
Cheers.</method></p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-event-driven-programming-tips-tricks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>3 ways you can use videos on your E-commerce site</title>
		<link>http://inchoo.net/ecommerce/3-ways-you-can-use-videos-on-your-e-commerce-site/</link>
		<comments>http://inchoo.net/ecommerce/3-ways-you-can-use-videos-on-your-e-commerce-site/#comments</comments>
		<pubDate>Tue, 16 Apr 2013 15:15:37 +0000</pubDate>
		<dc:creator>Vice Bozic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Online Marketing]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[video]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18046</guid>
		<description><![CDATA[If you are not using video on your E-commerce site, it would be good to start thinking about it. 2013 is all about the content &#8211; and video is leading &#8230;]]></description>
				<content:encoded><![CDATA[<p>If you are not using video on your E-commerce site, it would be good to start thinking about it. 2013 is all about the content &#8211; and video is leading the way. Using video, whether in a form of simple product video or a full company presentation, can significantly impact the way how your customers are perceiving your brand. It can help you to increase conversion rate, relevant search traffic and customer loyalty. Here are 3 examples of various ways in which some of our clients are using video.<span id="more-18046"></span></p>
<h3>1. Oz Mattress &#8211; company presentation</h3>
<p><a href="http://www.ozmattress.com.au/" target="_blank">Ozmattress.com.au</a> is Australia’s first exclusive online mattress retailer. Australian Made, designed, engineered and offered exclusively online with warehousing in Sydney, Canberra, Melbourne and Brisbane. They are using this short video to present the company and their products.</p>
<p><strong>Check out their video here: <a href="http://youtu.be/HrYXsKlZXA4" target="_blank">http://youtu.be/HrYXsKlZXA4</a></strong></p>
<p><a href="http://youtu.be/HrYXsKlZXA4" target="_blank"><img class="size-full wp-image-18050 alignnone" alt="ozmattress_video" src="http://inchoo.net/wp-content/uploads/2013/04/ozmattress_video.jpg" width="609" height="350" /></a></p>
<h3>2. AE Scripts &#8211; demos</h3>
<p><a href="http://aescripts.com" target="_blank">aescripts + aeplugins</a> is a repository and marketplace of high-end scripts and plugins for many leading 2D and 3D software packages such as Adobe After Effects and Maxon Cinema 4D. They are using demo videos to showcase various effects that those scripts and plugins can produce.</p>
<p><strong>Check out their video here: <a href="http://aescripts.com/plexus/" target="_blank">http://aescripts.com/plexus/</a></strong></p>
<p><a href="http://aescripts.com/plexus/" target="_blank"><img class="size-full wp-image-18068 alignnone" alt="aescripts_video" src="http://inchoo.net/wp-content/uploads/2013/04/aescripts_video.jpg" width="609" height="350" /></a></p>
<h3>3. Teraflex &#8211; guides and events</h3>
<p><a href="http://www.teraflex.biz/" target="_blank">Teraflex</a> is a manufacturer of TeraFlex suspensions, body protection equipment, low range gearing and HD axles for Jeeps. They are a really good example on how a great video production combined with interesting storytelling can provide a unique value for the customer and the brand. Currently, they have 4,382 subscribers and 1,168,939 video views on their YouTube channel.</p>
<p><strong>Check out their video here: <a href="http://www.teraflex.biz/news/cat/teraflex-video/" target="_blank">http://www.teraflex.biz/news/cat/teraflex-video/</a><br />
</strong></p>
<p><a href="http://www.teraflex.biz/news/cat/teraflex-video/" target="_blank"><img class="alignleft size-full wp-image-18058" alt="teraflex_video" src="http://inchoo.net/wp-content/uploads/2013/04/teraflex_video.jpg" width="609" height="350" /></a>These are some of the ways you can use video to present your company, showcase your products and provide a much richer experience for your customers.</p>
<p>Have you been using video on your E-commerce sites? If you have some cool examples, please share them in the comments <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/3-ways-you-can-use-videos-on-your-e-commerce-site/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Recap of Magento Imagine 2013 &#8211; The Art of Commerce</title>
		<link>http://inchoo.net/ecommerce/recap-of-magento-imagine-2013-the-art-of-commerce/</link>
		<comments>http://inchoo.net/ecommerce/recap-of-magento-imagine-2013-the-art-of-commerce/#comments</comments>
		<pubDate>Mon, 15 Apr 2013 12:18:34 +0000</pubDate>
		<dc:creator>Aron Stanic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Fun & Events]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[conference]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[EE 1.13]]></category>
		<category><![CDATA[magento imagine]]></category>
		<category><![CDATA[Magento2]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=17999</guid>
		<description><![CDATA[3rd annual Magento Imagine eCommerce conference took place in early April and saw over 1500 Magento merchants, solution and industry partners and individual developers from the total of 44 countries &#8230;]]></description>
				<content:encoded><![CDATA[<p>3rd annual Magento Imagine eCommerce conference took place in early April and saw over 1500 Magento merchants, solution and industry partners and individual developers from the total of 44 countries meet for the biggest single Magento event ever. We were there as well, so check out our impressions and some interesting notes we made.<span id="more-17999"></span></p>
<p><img class=" wp-image-18020  alignleft" style="line-height: 24px; font-size: 16px;" title="The M Resort looking at the Vegas Strip" alt="The M Resort" src="http://inchoo.net/wp-content/uploads/2013/04/imagine2013-the-m-resort-600x450.jpg" width="293" height="221" /></p>
<p><strong>The Art of Commerce</strong> was this year’s tagline and it showed throughout the venue &#8211; The M Resort, conveniently located well away from the distracting neons of Las Vegas, was turned into a true Magento base for this event, much like last year (or so I&#8217;ve heard).</p>
<p>The organizers and producers took their time to plan out a stunning visual experience on the main stage but also took special care of those little details that often make or break an event &#8211; and on this Imagine eCommerce conference, things were really clicking.</p>
<h3>The marketplace, the people and the Inchoo syndrome</h3>
<p>As this was my first time at the Imagine conference (our CEO Tomislav was here last year), I was very happy to meet some of the people I’ve gotten to know only via email, Skype or Twitter over the years.</p>
<p>So, where better to start then in the official marketplace on Day 1 of the event &#8211; and my head was spinning fast &#8211; meeting all the folks from <strong>Blue Acorn, Classy Llama, Atwix, Cofa Media, Guidance, aheadWorks, WebShopApps, Sweet Tooth, Demac Media</strong>, you name it &#8211; it felt so great shaking hands with some of these people and seeing the Magento community actually is more than just some vague concept.</p>
<p>I also experienced for the first time that feeling some of our developers who attended Developers Paradise and other events told us about &#8211; when you have people thanking you for contributing to the community and saying how you’ve helped them out &#8211; because they saw “Inchoo” on your conference badge.</p>
<p>You’re welcome, guys, but you should really be thanking our&#8230;</p>
<h3>Developers, developers, developers!</h3>
<p>No, fortunately neither John Donahoe (eBay’s CEO) nor <a title="Roy Rubin - you know who that is :)" href="http://twitter.com/royrubin05" target="_blank">Roy Rubin</a> (Magento co-founder and COO, but come on &#8211; you already knew that, right?) pulled a Steve Ballmer on stage, but they were very adamant about recognizing the contribution of developers to the growth of Magento as a platform.</p>
<p><em><strong>“We are nothing without our community.”</strong></em> and <em><strong>“Magento developers are our rock stars.”</strong></em> &#8211; these were two sentences mentioned on several occasions and it felt good to be there, representing a company who contributes 14 certified developers (12 backend, 2 frontend) to the ecosystem.</p>
<h3>The state of Magento &#8211; Fabric is no more, high hopes for Magento 2</h3>
<p>Most of the participants make their living with and off of Magento, regardless of whether we were Magento employees, industry or solution partners, merchants or even freelance developers. So, everyone was interested to hear about the state of Magento nation, get a feeling of what lies ahead with the whole eBay/PayPal story and take a look at the shape of things to come with our favorite ecommerce platform.</p>
<p>And the last year’s story of X.commerce and Fabric was finally brought to an end in a simple remark by Magento’s CTO <a title="Matthew Mengerink" href="http://twitter.com/mengerin" target="_blank">Matthew Mengerink</a> &#8211; well, nothing unexpected there really, but it was good to finally hear it officially.</p>
<p>After seeing some nice figures on Magento’s (and eBay’s for that matter) growth, it was clear that much investment is being made into <strong>Magento 2</strong> which is supposed to have its Beta in Q4 this year &#8211; some of you who have been actively involved in Magento 2 talks and events already know that it is truly a revamp of Magento as we know it, but it really is too early to make any flashy announcements so we can only keep our fingers crossed &#8211; or <a title="Magento2 github" href="https://github.com/magento/magento2" target="_blank">actively participate here</a>.</p>
<p>While Magento 2 is slowly cooking, there is much to be done with the current clients and current versions of both Community and Enterprise editions, so new releases were announced to keep us and our clients happy as we await the Number 2 to show up.</p>
<h3>EE 1.13 released, CE 1.8 to follow suit</h3>
<p>With all the buzz around new releases, it wasn’t much of a surprise to see Enterprise Edition 1.13 officially presented and released during the conference. Community Edition 1.8 Alpha will come out in a couple of weeks, and we’ll see what’s in store then, but for now let’s focus on the latest EE version &#8211; and good news is that it’s all about performance optimization.</p>
<h4>Reindexing revamp, checkout page load times, tax calculations and more</h4>
<p>One of the main features of the newest release is a revamped indexing system in Magento which will now run reindexing as a background process and allow for partial (incremental) reindexing&#8230;</p>
<p>In addition to this, full page caching has apparently been improved and the checkout has some extra tweaks that help customers go through the entire process more easily.</p>
<p>This time around, Magento already prepared quite a lot of details on the new features and its usage which is all available here:</p>
<ul>
<li><a title="Magento EE 1.13 and CE 1.8 documentation" href="http://www.magentocommerce.com/knowledge-base/entry/ce-18-and-ee-113-documentation-home" target="_blank">Documentation for EE 1.13 and CE 1.8</a></li>
<li><a title="Magento EE 1.13 indexing explained" href="http://www.magentocommerce.com/knowledge-base/entry/ee113-indexing" target="_blank">Reindexing in details</a></li>
<li><a title="Magento performance and scalability - EE 1.13 white paper" href="http://www.magentocommerce.com/knowledge-base/entry/ee113-performance-and-scalability-white-paper" target="_blank">EE 1.13 performance and scalability white paper</a></li>
</ul>
<p>So, make sure to check these out and good luck upgrading your clients’ stores <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Keynotes and awards</h3>
<p>There were several very interesting keynote speakers on this Imagine, including Steve Levitt, the co-author of <a title="Freakonomics" href="http://www.freakonomics.com/" target="_blank">Freakonomics</a> and <a title="Jamie Clarke" href="http://www.jamieclarke.com/" target="_blank">Jamie Clarke</a>, adventurer and Magento merchant with stand-up comedy skills who really lit up the stage with his incredibly engaging storytelling.</p>
<p><a title="Jane McGonigal" href="http://janemcgonigal.com/" target="_blank">Jane McGonigal</a>, game designer and researcher, brought some of her TED experience to the crowd and had us all engaged in a massive multiplayer thumb wrestling game with 1500 people joining hands for some 30 seconds &#8211; apparently, that means we’re more likely to help each other now&#8230; <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>And then, some awards were given out &#8211; in addition to partner awards that didn’t quite make the center stage, there was one awards that really stood out &#8211; <a title="Delicious Karma" href="http://deliciouskarma.com/" target="_blank">Delicious Karma</a>, a social shopping site for artisanal and gourmet goods, received the Most innovative Magento site of 2012 award &#8211; their site was implemented by <a title="Rocket Web" href="http://www.rocketweb.com/" target="_blank">RocketWeb</a> &#8211; a US SilverSolution Partner with a Polish signature &#8211; congratulations!</p>
<h3>Key takeaways</h3>
<p><img class="wp-image-18014 alignright" style="line-height: 24px; font-size: 16px;" title="Roy Rubin explaining the State of Magento" alt="Roy Rubin at Imagine2013" src="http://inchoo.net/wp-content/uploads/2013/04/imagine2013-roy-rubin-600x394.jpg" width="384" height="252" /></p>
<p>Good news for everyone around Magento is that it apparently is here to stay, eBay doesn&#8217;t have plans to mess with it much, and with the latest versions of its two main products (EE and CE) and an eye out on Magento 2, the near future for the platform looks quite solid. With that said, there&#8217;s never any time for complacency and the guys at Magento seem to be very clear about this which is a good sign.</p>
<p>Other than this, here are some nice takeaways from this conference:</p>
<ul>
<li><a title="Brent W. Peterson" href="http://twitter.com/brentwpeterson" target="_blank">Brent W. Peterson</a> tweets really fast, and so does <a title="Sherrie Rohde" href="http://twitter.com/sherrierohde" target="_blank">Sherrie Rohde</a> (it&#8217;s a tie)</li>
<li><a title="The Buzz Lab" href="http://thebuzzlab.com/" target="_blank">The Buzz Lab</a> is a truly fun and creative bunch</li>
<li><a title="Classy Llama team" href="http://www.classyllama.com/team" target="_blank">Classy Llamas</a> are quite tall</li>
<li><em>Magento vs Magneto vs Magenta</em> fight is still not quite over</li>
<li><a title="Mike Rossi" href="http://twitter.com/m3rossi" target="_blank">Mike Rossi</a> (Sweet Tooth) is a man of his words &#8211; he&#8217;ll take <a title="Ignacio Riesco" href="http://twitter.com/ignacioriesco" target="_blank">Ignacio Riesco</a> (Interactiv4) to Hawaii <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li><a title="Yoav Kutner" href="http://twitter.com/YoavMagento" target="_blank">Yoav Kutner</a> is a cool guy, and we can&#8217;t wait to start playing with the OroCRM</li>
<li>when in US, always order &#8220;small&#8221; drink or meal, even if you&#8217;re very hungry</li>
</ul>
<h3>The Art of Commerce</h3>
<p>The event artists Taylor McFerrin and Marshall Davis Jones closed out the event with a new performance &#8211; so, what better to wrap up this year’s Magento Imagine then some of their lyrics:</p>
<p><em><strong>“Imagine, what can we imagine</strong></em><br />
<em><strong> How can we be better than before?</strong></em><br />
<em><strong> What can we deliver, beautiful, bigger?</strong></em><br />
<em><strong> Give it all we’ve got just to give a little more.”</strong></em></p>
<p>See you all next year!</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/recap-of-magento-imagine-2013-the-art-of-commerce/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Top 10 reasons to choose Magento</title>
		<link>http://inchoo.net/ecommerce/magento/top-10-reasons-to-choose-magento/</link>
		<comments>http://inchoo.net/ecommerce/magento/top-10-reasons-to-choose-magento/#comments</comments>
		<pubDate>Tue, 09 Apr 2013 09:02:10 +0000</pubDate>
		<dc:creator>Branko Ajzele</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[Starting up]]></category>
		<category><![CDATA[starting up]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=17959</guid>
		<description><![CDATA[Ever since it got released Magento got a lot of attention from developer and merchant community when it comes to web shops, or to put it more robustly, when it &#8230;]]></description>
				<content:encoded><![CDATA[<p>Ever since it got released Magento got a lot of attention from developer and merchant community when it comes to web shops, or to put it more robustly, when it comes to eCommerce platforms. Developers love it because of its modularity, as then can (almost) do anything client asks them. Merchants love it because of the wast number of features it provides out of the box.<span id="more-17959"></span></p>
<p>Here is a list I put together, to kind of emphasise the top 10 reasons to choose Magento.</p>
<ol>
<li><strong>SEO friendly right out of the box</strong> &#8211; Search engine friendly URL’s, Google Site Map, Meta-information for products, categories and content pages, etc.</li>
<li><strong>Internationalization support</strong> &#8211; Support for localization, multiple currencies and tax rates. Support for accented characters and right to left text. Configurable list of allowed countries for certain features. European Union VAT-ID validation, EU cookie notification, etc.</li>
<li><strong>Enormous number of built-in eCommerce web shop related features</strong> (most than any of its PHP/open source based competitors) &#8211; Features like support for both Multi-Site and Multi-Domain setup. You can download a feature list from here http://www.magentocommerce.com/images/uploads/magento-feature-list.pdf.</li>
<li><strong>Extremely modular architecture</strong> &#8211; enables you to do deep customizations of both frontend (layouts and templates) and backend (event, observer, rewrites, grids, etc.)</li>
<li><strong>Magento&#8217;s Expert Consulting Group</strong> (not a free service, but still highly important one to have if needed)<br />
Official Training &amp; Professional Certification Program &#8211; Training for backend developers, frontend developers, merchants, etc. Instructor-led Training, On-Demand Training. Magento Certified Developer, Magento Certified Developer Plus, Magento Certification Directory (find a certified developer anywhere in the world).</li>
<li><strong>Security</strong> &#8211; Magento takes security very seriously and as a highly rated priority. Magento EE even comes with Secure Payment Bridge which provides PCI Data Security Standard (PCI PA-DSS).</li>
<li><strong>Magento Connect</strong> &#8211; the world&#8217;s largest eCommerce application marketplace.</li>
<li><strong>Code-level Access</strong> &#8211; open source, PHP code available for you to play with.</li>
<li><strong>Web Services API</strong> &#8211; Built in support for SOAP v1, SOAP v2, XMLRPC, REST with 3-legged OAuth 1.0a.</li>
<li><strong>Because it is awesome</strong> <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ol>
<p>That sort of sums it up. Although Magento has so much more to offer.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/top-10-reasons-to-choose-magento/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>One of the first Magento Certified Front End Developers in the World</title>
		<link>http://inchoo.net/ecommerce/magento/magento-certified-front-end-developers/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-certified-front-end-developers/#comments</comments>
		<pubDate>Mon, 08 Apr 2013 21:34:47 +0000</pubDate>
		<dc:creator>Tomislav Bilic</dc:creator>
				<category><![CDATA[Frontend]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[certification]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=17966</guid>
		<description><![CDATA[We received a news few days ago that Vanja Devcic and Hrvoje Jurisic achieved the passing score and therefore have achieved the status of Magento Certified Front End Developers. It was a great news for us since they are one of the first in the world. ]]></description>
				<content:encoded><![CDATA[<p>We received a news few days ago that <a href="http://inchoo.net/author/vanja-devcic/" title="Vanja Devcic - Magento Certified Front End Developer">Vanja Devcic</a> and <a href="http://inchoo.net/author/hrvoje/" title="Hrvoje Jurisic - Magento Certified Front End Developer">Hrvoje Jurisic</a> achieved the passing score and therefore have achieved the status of <strong>Magento Certified Front End Developers</strong>. It was a great news for us since they are one of the first in the world. </p>
<p>We were invited late January to participate in a certification beta testing session for Magento Front End Developers. We couldn&#8217;t just take the voucher to some testing centre as we normally do. Instead, we needed to go to a place called Fast Lane Institute for Knowledge Transfer GmbH &#8211; Munich.<br />
<span id="more-17966"></span><br />
<a href="http://www.flickr.com/photos/tomislav-bilic/8435569513/in/set-72157632663683645"><img src="http://inchoo.net/wp-content/uploads/2013/04/InchooersOnBled.jpg" alt="Vanja, Tomislav, Hrvoje and Filip" width="300" height="271" class="alignright size-full wp-image-17968" /></a>We formed a crew of three frontend developers: Vanja Devcic, Hrvoje Jurisic and Filip Svetlicic plus me as a car driver and <a href="http://goo.gl/maps/hr0Qz" title="From Osijek to Hallbergmoos" target="_blank">hit the road</a> to a small place called Hallbergmoos. </p>
<p>In Slovenia, we stopped at the most popular tourist destination &#8211; Bled. Known primarily for its beautiful lake, incredible castle, and position in the Julian Alps, the town of Bled itself is slightly underwhelming. We fed a few swans there on the lake, but we didn&#8217;t have much time to climb all the way to castle. </p>
<p>We arrived to Hallbergmoos late that night and saw the <a href="http://www.flickr.com/photos/tomislav-bilic/8436674612/in/set-72157632663683645" title="Weird item - A moose" target="_blank">most interesting item ever</a> at reception desk. That night, we had a few beers hoping it will not be too much for the exam tomorrow. </p>
<p>The exam was exhausting. In this beta testing session, candidates needed to answer <strong>almost 200 questions in 4 hours</strong>. To make a comparison, <a href="http://www.magentocommerce.com/certification/#mfd" title="Magento Front End Developer Certification Test Details" target="_blank">final test</a> now has 65 questions and lasts for 90 minutes.</p>
<p>Since I was only a driver there, I wandered <a href="http://www.flickr.com/photos/tomislav-bilic/8435575531/in/set-72157632663683645" title="Institute for Knowledge Transfer, Hallbergmoos, Germany" target="_blank">around The Institute</a>. I was very happy to meet Kuba Zwolinski from <a href="http://snowdog.pl/" title="Snowdog - Poland" target="_blank">Snowdog</a>. Thank you Kuba for sharing insights of Meet Magento Poland organisation. <img src='http://inchoo.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><a href="http://www.flickr.com/photos/tomislav-bilic/8436693558/in/set-72157632663683645"><img src="http://inchoo.net/wp-content/uploads/2013/04/InchooersInMunich.jpg" alt="Drinking Beers in Munich" width="640" height="294" class="alignnone size-full wp-image-17971" /></a></p>
<p>After the exam, we used that afternoon to visit Munich and drink some more beers there. Wind was blowing like crazy, so there was not a great sightseeing day. You get it, we had to drink some more. We also had a chance to see one of the <a href="http://www.flickr.com/photos/tomislav-bilic/8435601475/in/set-72157632663683645" title="Weird Church" target="_blank">weirdest looking church interiors</a>.</p>
<p>Unfortunately, Filip from the three didn&#8217;t get a passing score, but he was very close since he had very similar number of positive answers as Vanja. With the next voucher, we are sure he will get to the list. With writing this article, I asked Vanja and Hrvoje couple of questions.</p>
<p class="question">Vanja, was the majority of questions from practice or theory? Do you feel a senior Magento frontend developer can pass the test without going through the study guide?</p>
<blockquote class="answer"><p>Majority was definitely from practice. Magento, in depth, can only be learned by practice and  experience. I feel that senior Magento frontend developer could pass the test without going through the study guide, which covers theoretical questions the most, like Magentos fallback system, but it is practical very hard or even impossible to pass the test only with learning from study guide and not to have or to have little real experience with Magento code.
</p></blockquote>
<p class="question">Hrvoje, did the test cover important Magento areas for frontend developer? Did something there surprise you? Do you need to know PHP or ZEND to pass it? </p>
<blockquote class="answer"><p>The exam covered the most important areas of Magento frontend development, concentrating mainly on xml layouts, which are, in fact, the main weapon in the Magento front-end developer&#8217;s drawer. There were no surprises. The test was all about our everyday routine of a Magento Frontend developer: themes, fallbacks, layouts, blocks, templates, html, css and javascript&#8230;</p>
<p>If there was one thing I could point out as a weak spot of the exam, it would be lack (or a very small number)  of specific, non-magento related HTML, CSS and Javascript questions where examinees would prove their Front End expertise. I have a feeling that every Magento Backend developer could pass the test even though their frontend skills may not be high level. But I might be wrong about that <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-certified-front-end-developers/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Magento Shopping Cart Promotion Rule for Product with Custom Options</title>
		<link>http://inchoo.net/ecommerce/magento/magento-shopping-cart-promotion-rule-for-product-with-custom-options/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-shopping-cart-promotion-rule-for-product-with-custom-options/#comments</comments>
		<pubDate>Sun, 07 Apr 2013 09:48:32 +0000</pubDate>
		<dc:creator>Branko Ajzele</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[Products]]></category>
		<category><![CDATA[magento custom configurable product]]></category>
		<category><![CDATA[product]]></category>
		<category><![CDATA[promotion]]></category>
		<category><![CDATA[promotion rule]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=17941</guid>
		<description><![CDATA[Magento is a great eCommerce platform, it comes with so many built in features some of which you will probably never use. However one feature that we hear a lot &#8230;]]></description>
				<content:encoded><![CDATA[<p>Magento is a great eCommerce platform, it comes with so many built in features some of which you will probably never use. However one feature that we hear a lot of complain about is the lack of possibility to have a Shopping Cart Promotion Rule that targets the products custom options.<span id="more-17941"></span> If you login to Magento admin, and go to <strong>Promotions > Shopping Cart Price Rules > Add New Rule</strong>, then click on the <strong>Conditions</strong> tab of the Shopping Cart Price Rule edit screen you will see a screen like the one shown below.</p>
<div id="attachment_17942" class="wp-caption alignnone" style="width: 610px"><a href="http://inchoo.net/wp-content/uploads/2013/04/Google-Chrome.png"><img src="http://inchoo.net/wp-content/uploads/2013/04/Google-Chrome-600x316.png" alt="Magento Shopping Cart Price Rule" width="600" height="316" class="size-medium wp-image-17942" /></a><p class="wp-caption-text">Shopping Cart Price Rule</p></div>
<p>As you can see on that screen, there is no mention of products custom options, only its attributes.</p>
<p>In this article I&#8217;m gonna show you a nice little, cheap trick on how you can achieve the effect of having Shopping Cart Promotion Rule for Product with Custom Options. It will require a few lines of code to add and a little tiny bit of &#8220;manual calculation&#8221;. We will extract the code into our special little Inchoo_QuoteItemRule extension. Before we start writing the code, lets first explain what &#8220;Quote&#8221; has to do with &#8220;Custom Options&#8221;. Imagine we have a product product with SKU assigned &#8220;test_no2&#8243;. That product has two custom options (Color &#038; size) and every option value has its SKU assigned as well like those shown on the image below. </p>
<div id="attachment_17945" class="wp-caption alignnone" style="width: 610px"><a href="http://inchoo.net/wp-content/uploads/2013/04/pcc.png"><img src="http://inchoo.net/wp-content/uploads/2013/04/pcc-600x314.png" alt="Product Custom Options" width="600" height="314" class="size-medium wp-image-17945" /></a><p class="wp-caption-text">Product Custom Options</p></div>
<p>Now if we add that product to cart a product with selected Green color and Medium size option then this will get recorded under sales_flat_quote_item database table as entry with SKU value of &#8220;<strong>test_no2-color_green-size_m</strong>&#8220;, which is actualy and entry with the following <strong>formula</strong>: </p>
<blockquote><p>product main SKU + &#8220;-&#8221; + first custom option SKU + &#8220;-&#8221; + second custom option SKU + &#8220;-&#8221; + &#8230; nth custom option SKU.</p></blockquote>
<p>So the idea is that we actually create a rule condition that would allow us to have a Cart Item Attribute condition, like shown on image below, since Cart Item Attribute is actually a sales_flat_quote_item table entry field to put it like that. And we said that adding a product with custom option to cart results in sales_flat_quote_item table entry with SKU value of &#8220;<strong>test_no2-color_green-size_m</strong>&#8220;.</p>
<div id="attachment_17947" class="wp-caption alignnone" style="width: 610px"><a href="http://inchoo.net/wp-content/uploads/2013/04/mrc.png"><img src="http://inchoo.net/wp-content/uploads/2013/04/mrc-600x367.png" alt="Shopping Cart Price Rule Condition" width="600" height="367" class="size-medium wp-image-17947" /></a><p class="wp-caption-text">Shopping Cart Price Rule Condition</p></div>
<p>Now lets jump into the code, we will need 3 files to achieve the desired functionality.</p>
<p>app/etc/modules/Inchoo_QuoteItemRule.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_QuoteItemRule&gt;
            &lt;active&gt;true&lt;/active&gt;
            &lt;codePool&gt;community&lt;/codePool&gt;
        &lt;/Inchoo_QuoteItemRule&gt;
    &lt;/modules&gt;
&lt;/config&gt;
</pre>
<p>app/code/community/Inchoo/QuoteItemRule/etc/config.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_QuoteItemRule&gt;
            &lt;version&gt;1.0.0.0&lt;/version&gt;
        &lt;/Inchoo_QuoteItemRule&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;models&gt;
            &lt;salesrule&gt;
                &lt;rewrite&gt;
                    &lt;rule_condition_product&gt;Inchoo_QuoteItemRule_Model_SalesRule_Rule_Condition_Product&lt;/rule_condition_product&gt;
                &lt;/rewrite&gt;
            &lt;/salesrule&gt;
        &lt;/models&gt;
    &lt;/global&gt;
&lt;/config&gt;
</pre>
<p>app/code/community/Inchoo/QuoteItemRule/Model/SalesRule/Rule/Condition/Product.php:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
class Inchoo_QuoteItemRule_Model_SalesRule_Rule_Condition_Product extends Mage_Rule_Model_Condition_Product_Abstract
{
    protected function _addSpecialAttributes(array &amp;$attributes)
    {
        parent::_addSpecialAttributes($attributes);
        $attributes['quote_item_qty'] = Mage::helper('salesrule')-&gt;__('Quantity in cart');
        $attributes['quote_item_price'] = Mage::helper('salesrule')-&gt;__('Price in cart');
        $attributes['quote_item_row_total'] = Mage::helper('salesrule')-&gt;__('Row total in cart');
        /* @inchoo */
        $attributes['quote_item_sku'] = Mage::helper('salesrule')-&gt;__('SKU');
        /* @inchoo */
    }
    public function validate(Varien_Object $object)
    {
        $product = false;
        if ($object-&gt;getProduct() instanceof Mage_Catalog_Model_Product) {
            $product = $object-&gt;getProduct();
        } else {
            $product = Mage::getModel('catalog/product')
                -&gt;load($object-&gt;getProductId());
        }
        $product
            -&gt;setQuoteItemQty($object-&gt;getQty())
            -&gt;setQuoteItemPrice($object-&gt;getPrice())
            -&gt;setQuoteItemRowTotal($object-&gt;getBaseRowTotal())
            /* @inchoo */
            -&gt;setQuoteItemSku($object-&gt;getSku())
            /* @inchoo */;
        return parent::validate($product);
    }
}
</pre>
<p>We basically just needed to add two lines of code for the whole thing to work (you can see those two lines surrounded by &#8220;/* @inchoo */&#8221; comment). Now if you revisit the Promotions > Shopping Cart Price Rules > Add New Rule, then click on the Conditions tab, select the Product Attribute Combination as first condition then under the next condition dropdown you will see SKU under Cart Item Attribute like shown on the screenshot above. So finally, we can create a Shopping Cart Promotion Rule for Product with Custom Options like shown on the images below.</p>
<p><a href="http://inchoo.net/wp-content/uploads/2013/04/scr2.png"><img src="http://inchoo.net/wp-content/uploads/2013/04/scr2-600x338.png" alt="scr2" width="600" height="338" class="alignnone size-medium wp-image-17952" /></a></p>
<p><a href="http://inchoo.net/wp-content/uploads/2013/04/scr1.png"><img src="http://inchoo.net/wp-content/uploads/2013/04/scr1-600x418.png" alt="scr1" width="600" height="418" class="alignnone size-medium wp-image-17951" /></a></p>
<p>Hope it helps.</p>
<p>P.S. This example was provided in its simplest form, mostly just to demonstrate a quick &#8220;fix&#8221; for product custom options rule. More robust solution would be more proper for serious projects.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-shopping-cart-promotion-rule-for-product-with-custom-options/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>5 tips for increasing E-commerce homepage conversions</title>
		<link>http://inchoo.net/ecommerce/5-tips-for-increasing-e-commerce-homepage-conversions/</link>
		<comments>http://inchoo.net/ecommerce/5-tips-for-increasing-e-commerce-homepage-conversions/#comments</comments>
		<pubDate>Sat, 06 Apr 2013 14:37:39 +0000</pubDate>
		<dc:creator>Vice Bozic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[conversion rate optimization]]></category>
		<category><![CDATA[e-commerce]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=17897</guid>
		<description><![CDATA[This is the question I get asked often: “How can we increase our conversion rate and convert more visitors into buyers?”. In this blog post I will focus on your &#8230;]]></description>
				<content:encoded><![CDATA[<p>This is the question I get asked often: “How can we increase our conversion rate and convert more visitors into buyers?”. In this blog post I will focus on your online store homepage, for many of your visitors the first page that they will see. Here is the 5 key steps checklist you can follow to make sure you are doing it right.<br />
<span id="more-17897"></span></p>
<h3>1. Create your buyer personas</h3>
<p>To optimise your homepage to better match expectations of site visitors, it is useful to develop buyer personas. A buyer persona is an overall description of everything you know about your typical buyer. This description can include your buyer name, photo, age, buying habbits, etc., you can go into details as much as you want. My advice is to focus on creating 2 or 3 buyer personas, no more than that. Once you have your buyer personas in place, you can get a better insight and understanding of what do they expect from your site, and what you must do to meet those expectations.</p>
<h3>2. Declutter and simplify</h3>
<p>Whether you already have an online store, or planning one, keep in mind that <strong>simplicity</strong> is the key of a great customer experience. Too often, visitors are bombarded with lots of irrelevant content that just gets in the way, and if a visitor is having trouble finding their way through the website, chances that he will buy something are decreasing quickly. The only way for the great content to stand out is to remove other things away. Ask yourself: &#8220;Do I really need to have this feature?&#8221;, &#8220;Does this headline include clear call-to-action?&#8221;,&#8221;Can I reduce the amount of text?&#8221;, etc. Answering these questions will help your customers to perform their task much easier, and ultimately will increase a chance for successful sale.</p>
<h3>3. Place your most important content above the fold</h3>
<p>&#8220;Above the fold&#8221; is the area on your website that visitors will see without having to scroll. For a E-commerce site, this area is mostly used to display featured product, products on sale, main navigation, logo, contact email and/or phone, and a search form. Consider carefully what content will you be placing &#8220;above the fold&#8221;, because small mistakes can make a big impact on your conversion rate.</p>
<h3>4. Test your Call-To-Action (CTA) buttons</h3>
<p>Call-to-action buttons combined with great offer are one of the most important conversion drivers. Variables that will determine the effectiveness of your CTA button are size, color, text and placement. For example, if we compare “Add to Cart” vs. &#8220;Buy now&#8221; text, research has shown that “Add to Cart” will function much better just because users think that they will be charged immediately after they click the &#8220;Buy now&#8221; button. These are some of the general guidelines you can follow, but the best idea is to do some A/B testing on your own to find out which combination works best for your store.</p>
<h3>5. Conduct A/B Testing</h3>
<p>Before you start, decide what elements do you want to test &#8211; website layout, headline, CTA buttons, etc. To conduct the testing, you can use <a href="http://www.youtube.com/watch?v=TGrujIh2H0I" target="_blank">Content Experiments in Google Analytics</a> and compare how different web pages perform using a random sample of your visitors. Here is the nice <a href="http://www.youtube.com/watch?v=TGrujIh2H0I" target="_blank">video</a> that explains the whole process.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/5-tips-for-increasing-e-commerce-homepage-conversions/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Magento Imagine coming to Europe &#8211; Croatia to host the 2014 event</title>
		<link>http://inchoo.net/fun-zone/magento-imagine-coming-to-europe-croatia-to-host-the-2014-event/</link>
		<comments>http://inchoo.net/fun-zone/magento-imagine-coming-to-europe-croatia-to-host-the-2014-event/#comments</comments>
		<pubDate>Mon, 01 Apr 2013 08:31:41 +0000</pubDate>
		<dc:creator>Aron Stanic</dc:creator>
				<category><![CDATA[Fun & Events]]></category>
		<category><![CDATA[conference]]></category>
		<category><![CDATA[croatia]]></category>
		<category><![CDATA[dubrovnik]]></category>
		<category><![CDATA[magento imagine]]></category>
		<category><![CDATA[split]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=17851</guid>
		<description><![CDATA[The decision has been made &#8211; Magento is finally moving its biggest ecommerce event to Europe &#8211; and Croatia will be the proud host of the 2014 Imagine eCommerce conference! &#8230;]]></description>
				<content:encoded><![CDATA[<p>The decision has been made &#8211; Magento is finally moving its biggest ecommerce event to Europe &#8211; and Croatia will be the proud host of the 2014 Imagine eCommerce conference! And that’s not all &#8211; we’re giving away free conference packages for attending the next year’s event, so make sure to read on!<span id="more-17851"></span></p>
<p>&#8212;&#8212;</p>
<p><strong>DISCLAIMER:</strong></p>
<p><strong>This was (and still is), as many of you guessed already, an April Fools&#8217; Day joke &#8211; but we certainly wouldn&#8217;t mind if Magento did decide to bring you all to Croatia. Stay tuned for more news and make sure to drop by on next April 1st as well <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </strong></p>
<p>&#8212;&#8212;</p>
<p>As many of us are preparing for Vegas and this year’s biggest Magento event &#8211; <a title="Magento Imagine 2013" href="http://imagineecommerce.com" target="_blank">Imagine eCommerce conference</a> &#8211; one decison that’s been long in the making has finally been made public &#8211; Magento will finally bring the entire Imagine experience to Europe in 2014.</p>
<h3>Why Croatia?</h3>
<p><em><strong>“I’m really excited to confirm that we have a venue for the first European Imagine event &#8211; it’s Croatia, a beautiful young Mediterranean country where we’ll all meet this time next year. We’re still deciding between <a title="Split, Croatia" href="http://bit.ly/Z37xdz" target="_blank">Split</a> and <a title="Dubrovnik, Croatia" href="http://bit.ly/10s1e5z" target="_blank">Dubrovnik</a> as the main resort but both of these cities are breathtaking and this will bring the entire Imagine experience to a whole new level.”</strong></em> said a reliable source<strong> </strong>from Magento when asked about the decision.</p>
<p>You’ll hear more details about this in Vegas next week, but this is the official announcement which we at Inchoo, as Magento’s local organizing partner, had the pleasure to make, and we’re also here to offer some great incentives to anyone planning to attend.</p>
<p>This decision also follows nicely Croatia&#8217;s accession to the EU which is about to take place in July 2013, and we shouldn’t hide the fact that one of the biggest unofficial Magento blogs (hint &#8211; it’s this one) comes from this country.</p>
<p>On top of that, Inchoo as a <a title="Magento Solution Partner Profile - Inchoo" href="http://www.magentocommerce.com/partners/details/partner/id/2465/" target="_blank">Silver Solution Partner</a> has established quite a rapport with the powers that be at Magento over the last several years, so when you take all of this into account, the pieces fall into place nicely.</p>
<h3>The popular vote</h3>
<p>Let’s see what some of the famous Magento ecosystem faces had to say when they heard of this decision:</p>
<p><em><strong>“I’ve been to Croatia many times and I just love the weather, the people and the cuisine &#8211; so it’s great that many of my dear friends will have the opportunity to experience it firsthand &#8211; love this decision &#8211; we’ll start the preparations in Vegas &#8211; Croatia, here we come!”</strong></em><br />
- a famous freelance Magento coder</p>
<p><em><strong>“Well, truth be told, I’m already a bit tired of the desert and all the pools &#8211; I’d love to take a dip in the real sea, so I’m all for it! I heard you guys have some top notch beaches, hope we’ll have a couple of breakout sessions right there on the beach &#8211; now, that would be something!”</strong></em><br />
- a well-known Community Manager in the Magento world</p>
<p><em><strong>“Croatia? Where in the world is that? Come on, guys &#8211; I was kind of ok with the whole concept of Europe, but this? There’s only 4,5 million of them? Let’s get serious, people&#8230;”</strong></em><br />
- anonymous (we know this guy, just don’t want him to become a target of angry Croatian football fans)</p>
<p>Croatia likes to boast with its natural beauty to a large extent still untouched by the negative impacts of the mass tourism seen in many other Mediterranean countries, so one of the taglines of its Tourist Board is “<strong>Mediterranean as it once was</strong>” &#8211; and you’ll see it really is &#8211; even if you don’t have any idea or care for that matter what this “Mediterranean” is or what it looked like before <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Here&#8217;s also a quick welcome message from our CEO:</p>
<p><em><strong>“This is truly great news. We have been thinking of organizing Meet Magento initially, but when this opportunity presented itself, we were more than thrilled to reach out to Magento and make sure they had the needed confidence and trust that there’s a strong local partner here who can support the entire process and make things happen. We look forward to working with everyone on organizing this event and are excited to welcome you all in Croatia!”</strong></em><br />
- Tomislav Bilic (Inchoo)</p>
<h3></h3>
<h3>Free conference packages giveaway</h3>
<p>And to make things more interesting, Magento has decided to offer us, as their conference organizing partner, the opportunity to not only present this as breaking news, but also to give out <strong>10 (yes, ten) free packages</strong> to attend Imagine eCommerce 2014.</p>
<p>The full Croatian experience package includes:</p>
<p>• the conference registration fee<br />
• accommodation at the venue, and &#8211; wait for it&#8230;<br />
• covered travel costs from anywhere within Europe!!!</p>
<p>So, if you’re traveling from the Americas, Australia, Africa or Asia &#8211; you only need to get to London, Paris, Berlin or any other major European city and we’ll take care of the costs from there.</p>
<p>All you have to do to qualify is to leave a comment below with <strong>one fun fact about Croatia or your favorite Croatian person</strong> (athlete, scientist, musician, writer, businessman, or even politician &#8211; ok, don’t go quite there) and we’ll make sure to contact you with details on the next steps to receive the package.</p>
<p>First three people who reach out to us will also get a <strong>complimentary surprise welcome package</strong> courtesy of Inchoo.</p>
<p>Let the hunt for Croatia begin &#8211; leave your comments below and see you here this time next year, the conference starts on April 1st 2014 so mark your calendars!</p>
<p><iframe src="http://www.youtube.com/embed/5M2Bn_DbrA8" height="343" width="609" frameborder="0"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/fun-zone/magento-imagine-coming-to-europe-croatia-to-host-the-2014-event/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
	</channel>
</rss>
