<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns: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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
<channel>
	<title>Inchoo</title>
	
	<link>http://inchoo.net</link>
	<description>Magento Design and Magento Development Professionals - Inchoo</description>
	<lastBuildDate>Thu, 23 May 2013 12:19:23 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Inchoo" /><feedburner:info uri="inchoo" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>Inchoo</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>To blog or not to blog, that is the question</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/44BZCVBQUvI/</link>
		<comments>http://inchoo.net/ecommerce/to-blog-or-not-to-blog-that-is-the-question/#comments</comments>
		<pubDate>Thu, 23 May 2013 12:17:27 +0000</pubDate>
		<dc:creator>Vice Bozic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Online Marketing]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[Content Marketing]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18924</guid>
		<description><![CDATA[If you are a online store owner and you don&#8217;t have a blog, you are missing a great opportunity. In this article I will outline 3 main reasons why you &#8230;]]></description>
				<content:encoded><![CDATA[<p>If you are a online store owner and you don&#8217;t have a blog, you are missing a great opportunity. In this article I will outline 3 main reasons why you should integrate blog into your E-commerce strategy.<br />
<span id="more-18924"></span></p>
<h3>1. Online retailers are becoming publishers</h3>
<p><img class="size-full wp-image-18939 alignleft" alt="content_marketing" src="http://inchoo.net/wp-content/uploads/2013/05/dm.jpg" width="609" height="384" /></p>
<p>More and more online retailers are becoming publishers. A recent study by Econsultancy has shown that 39% digital marketers consider content marketing as their top priority in 2013. Also, what&#8217;s interesting is that on the 2nd place with 38% is conversion rate optimisation. Fusion between those two will result in more meaningful content that will provide more value, both to the customer and the store owners. This trend will continue as more retailers decide to invest time and money into producing quality content.</p>
<h3>2. More blog posts means more visitors, inbound links and better search engine rankings</h3>
<p>To illustrate value of blogging, here are some useful graphs generated from data from 1,531 HubSpot customers. Companies that blog are getting in average 55% more visitors, 97% more inbound links and 434% more indexed pages.</p>
<p><img class="alignleft size-full wp-image-18945" alt="blog_visitors" src="http://inchoo.net/wp-content/uploads/2013/05/blog1.jpg" width="609" height="384" /></p>
<p><img class="alignleft size-full wp-image-18946" alt="blog_inboundlinks" src="http://inchoo.net/wp-content/uploads/2013/05/blog2.jpg" width="609" height="384" /></p>
<p><img class="alignleft size-full wp-image-18947" alt="blog_seo" src="http://inchoo.net/wp-content/uploads/2013/05/blog3.jpg" width="609" height="384" /></p>
<h3>3. Blogging gives your company a human face</h3>
<p>In today&#8217;s technology world, we often forget that at the end of the day we are all humans. Blogging can help you to present your company in an honest, transparent and more informal way, which can build trust and loyalty with your potential customers. Also, you can interact with your customers in real-time by responding to their comments on the blog content.</p>
<p><strong>Have you included blog into your E-commerce strategy? I would love to hear your thoughts and experiences in the comments below.</strong></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=44BZCVBQUvI:RgrgjBLa4uQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=44BZCVBQUvI:RgrgjBLa4uQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=44BZCVBQUvI:RgrgjBLa4uQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=44BZCVBQUvI:RgrgjBLa4uQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=44BZCVBQUvI:RgrgjBLa4uQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=44BZCVBQUvI:RgrgjBLa4uQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=44BZCVBQUvI:RgrgjBLa4uQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=44BZCVBQUvI:RgrgjBLa4uQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/44BZCVBQUvI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/to-blog-or-not-to-blog-that-is-the-question/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/to-blog-or-not-to-blog-that-is-the-question/</feedburner:origLink></item>
		<item>
		<title>Mobile e-commerce strategy</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/gkuHnkwc7bY/</link>
		<comments>http://inchoo.net/ecommerce/mobile-e-commerce-strategy/#comments</comments>
		<pubDate>Thu, 23 May 2013 11:24:25 +0000</pubDate>
		<dc:creator>Hrvoje Jurisic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Mobile web]]></category>
		<category><![CDATA[Mobile development]]></category>
		<category><![CDATA[mobile friendly]]></category>
		<category><![CDATA[mobile web]]></category>
		<category><![CDATA[responsive web design]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18937</guid>
		<description><![CDATA[Smartphones are becoming the dominant way how users access the internet today. You don&#8217;t want to be left out of it. Are you ready for the future? If you haven’t &#8230;]]></description>
				<content:encoded><![CDATA[<p>Smartphones are becoming the dominant way how users access the internet today. You don&#8217;t want to be left out of it. Are you ready for the future?<span id="more-18937"></span></p>
<p>If you haven’t been living under the rock in the last couple of years, you probably noticed that <strong>mobile</strong> is kind of a big thing now. Ever since Apple launched iPhone in 2007, number of people surfing the web on their mobile device is climbing sky high.</p>
<p><img class="alignnone size-full wp-image-18949" alt="traffic" src="http://inchoo.net/wp-content/uploads/2013/05/traffic.png" width="609" height="447" /></p>
<p>Globally it rose from around 1% back in 2009 to 13% in December 2012. We also checked some of our stats, and the numbers are even higher. From 11% mobile visitors for site in India, to whooping 42% for UK site.</p>
<h2>M-Commerce growing rapidly</h2>
<p>Last year, 11% of all sales in USA came from mobile device. Americans spent $24.66 billion, and this numbers are 81% higher than they were in 2011. That’s some growth!</p>
<p><img class="alignnone size-full wp-image-18948" alt="growth" src="http://inchoo.net/wp-content/uploads/2013/05/growth.png" width="609" height="447" /></p>
<p>This year alone, mobile sales rose 31% in the first quarter, mostly on the tablets, so called “couch commerce”  is rapidly becoming the most popular form of online shopping .<br />
Predictions are that mobile will have 15% of e-commerce sales this year. And by the end of 2016 that number should rise to 27%, or $87 billion.</p>
<h2>If you build it, they will come</h2>
<p>So, what is the main reason for this “web surfing on smartphones” boom? Smartphones themselves, sure&#8230;  The total of smartphones entering the World per day in 2012. was about 3.6M devices. <a href="http://www.lukew.com/ff/entry.asp?1728">Luke Wroblewski</a> compared that number to 371k of newborn children worldwide every day. Striking numbers, right?</p>
<p>But there are some other reasons too. Mobile devices before iPhone could also browse the web, but it was a painful experience. Smartphones changed that. But web browsing remained unpleasant experience on websites that are not optimized for small screens and low bandwidth.</p>
<p>With the rise of mobile friendly websites, share of traffic and revenue on mobile devices rose too. It is symptomatic that most of the websites saw 100-400% mobile growth after launching mobile friendly version. Even “non-mobile” numbers were higher.</p>
<p>For example, these are <a href="http://www.oneillclothing.com/">O’Neill clothing</a> numbers after launching their responsive website (<a href="http://electricpulp.com/notes/you-like-apples/">source</a>):</p>
<ul>
<li>65.7% conversion rate increase on iPhone/iPod</li>
<li>101.2% revenue growth on iPhone/iPod</li>
<li>407.3% conversion rate increase on Android devices</li>
<li>591.4% revenue growth on Android devices</li>
<li>20.3% conversion rate increase on non-mobile devices</li>
<li>41.1% revenue growth on non-mobile devices</li>
</ul>
<h2>So, what’s the best mobile strategy?</h2>
<p>Depends. There’s no silver bullet. Depends on your target audience, your goals, type of website or web app. Lot of stuff. You have to keep in mind that today, we have a plethora of devices and resolutions. Generally, there are three ways to go:</p>
<ul>
<li>Native app</li>
<li>Mobile website</li>
<li>Responsive website</li>
</ul>
<h3><strong>Native Apps</strong></h3>
<p>&#8230;run physically on the specific mobile device and they are coded just for that device. These applications usually can be downloaded from “app stores” like Google play or iOS App Store. This is the best choice when you need to access device’s hardware and settings.</p>
<p>Downside is that you would have to develop app for every platform. iOS, Android, Blackberry, Windows Phone, tablets&#8230; And user would <a href="http://www.reddit.com/r/technology/comments/17vb1u/no_im_not_going_to_download_your_bullshit_app/">have to</a> <a href="http://sethholloway.com/blog/2012/06/12/i-dont-want-to-install-your-app/">want to</a> <a href="http://idontwantyourfuckingapp.tumblr.com/">download it</a>.</p>
<p>Basically, if you own regular online store, or website, this is not the road you want to take.</p>
<h3><strong>Mobile website</strong></h3>
<p>&#8230;has different code base and content for desktop and mobile. With that in mind, it could offer completely different user experience for these two groups. But mobile website usually targets only one resolution, so you end up covering only small portion of visitor’s possible resolution.</p>
<h3><strong>Responsive web design</strong></h3>
<p>&#8230;is device and resolution agnostic.  It serves the same code and the same content to all users, regardless of their platform. It uses fluid layouts, media queries and flexible images to adapt to every resolution. Smartphone, tablet, laptop, desktop, TV&#8230; you name it. RWD is future ready, for all those devices and resolutions yet to come.</p>
<p>As said before, RWD is not a silver bullet, but it is probably the best solution for most of the projects. The bottom line is that customer doesn’t care if your website is responsive, mobile or any other kind. He only cares to finish the goal that got him to your website in the first place. Reading an article, buying a product, searching for a location&#8230; whatever he&#8217;s after. And you should give him the best possible user experience, regardless of his platform and resolution.</p>
<p>With mobile traffic expanding this quick, and with new devices coming out almost on a daily basis, “mobile” is not to be ignored. In days ahead, everything on the web will be “responsive” by default, and we will not be talking about your “mobile strategy”, we’ll talk about your “web strategy”.</p>
<p>So, would you care tell us about <strong>your web strategy</strong>?</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=gkuHnkwc7bY:aQBChg5bbnw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=gkuHnkwc7bY:aQBChg5bbnw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=gkuHnkwc7bY:aQBChg5bbnw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=gkuHnkwc7bY:aQBChg5bbnw:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=gkuHnkwc7bY:aQBChg5bbnw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=gkuHnkwc7bY:aQBChg5bbnw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=gkuHnkwc7bY:aQBChg5bbnw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=gkuHnkwc7bY:aQBChg5bbnw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/gkuHnkwc7bY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/mobile-e-commerce-strategy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/mobile-e-commerce-strategy/</feedburner:origLink></item>
		<item>
		<title>Enable Gift Wrapping module for certain countries – EE</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/sGGvLcTE9GU/</link>
		<comments>http://inchoo.net/ecommerce/magento/enable-gift-wrapping-module-for-certain-countries-ee/#comments</comments>
		<pubDate>Wed, 22 May 2013 11:29:13 +0000</pubDate>
		<dc:creator>Ivan Galambos</dc:creator>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[countries]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[gift message]]></category>
		<category><![CDATA[gift wrapping]]></category>
		<category><![CDATA[magento enterprise]]></category>
		<category><![CDATA[programming]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18875</guid>
		<description><![CDATA[I promised in one of my previous posts that I&#8217;ll share with you this nice feature about how to enable Gift Wrapping module in Magento Enterprise Edition, but for certain &#8230;]]></description>
				<content:encoded><![CDATA[<p>I promised in one of my <a title="Free Gift Wrappin post" href="http://inchoo.net/ecommerce/magento/free-gift-wrapping-service-magento-ee/" target="_blank">previous posts</a> that I&#8217;ll share with you this nice feature about <strong>how to enable Gift Wrapping module in Magento Enterprise Edition</strong>, but for certain countries. So let&#8217;s extend it so merchants can easily enable this enhancement as they wish.</p>
<p><span id="more-18875"></span></p>
<p>There&#8217;s one caveat about front-end look &amp; feel. This enhancement is build on top of onestepcheckout Magento EE extension. It&#8217;s easy to set up everything for your needs (in case if you don&#8217;t use onestepcheckout extension) if you just follow logic in example mentioned bellow. Additionally, our request was that client wanted to <strong>remove checkbox</strong> for &#8220;Add gift options&#8221; and <strong>place radio</strong> buttons instead, where customers will have option to choose between &#8220;<strong>Basic</strong>&#8221; and &#8220;<strong>Luxury</strong>&#8221; gift wrapping service. In our example we&#8217;ll do the same. Feel free to modify everything for your own needs.</p>
<p>Let&#8217;s begin!</p>
<ol>
<li>Tell Magento about our module</li>
<li>Create configuration file</li>
<li>Create system xml file</li>
<li>Create Helper class</li>
<li>Tweaking front-end look and feel</li>
</ol>
<h4>1. Tell Magento about our module</h4>
<p>Create file <strong>app/etc/modules/Inchoo_GiftWrapping.xml</strong> with the following content:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_GiftWrapping&gt;
            &lt;active&gt;true&lt;/active&gt;
            &lt;codePool&gt;local&lt;/codePool&gt;
            &lt;depends&gt;
                &lt;Enterprise_GiftWrapping/&gt;
            &lt;/depends&gt;
        &lt;/Inchoo_GiftWrapping&gt;
    &lt;/modules&gt;
&lt;/config&gt;
</pre>
<h4>2. Create configuration file</h4>
<p>Create file <strong>app/code/local/Inchoo/GiftWrapping/etc/config.xml</strong> with the following content:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_GiftWrapping&gt;
            &lt;version&gt;1.0.0.1&lt;/version&gt;
        &lt;/Inchoo_GiftWrapping&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;helpers&gt;
            &lt;inchoo_giftwrapping&gt;
                &lt;class&gt;Inchoo_GiftWrapping_Helper&lt;/class&gt;
            &lt;/inchoo_giftwrapping&gt;
        &lt;/helpers&gt;
    &lt;/global&gt;
 &lt;/config&gt;
</pre>
<h4>3. Create system.xml file</h4>
<p>Create file <strong>app/code/local/Inchoo/GiftWrapping/etc/system.xml</strong> with the following content:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;sections&gt;
        &lt;sales&gt;
            &lt;groups&gt;
                &lt;gift_options&gt;
                    &lt;fields&gt;
                        &lt;allowed_countries translate=&quot;label&quot; module=&quot;inchoo_giftwrapping&quot;&gt;
                            &lt;label&gt;Gift Wrap Service is available in the following countries:&lt;/label&gt;
                            &lt;frontend_type&gt;multiselect&lt;/frontend_type&gt;
                            &lt;sort_order&gt;14&lt;/sort_order&gt;
                            &lt;source_model&gt;adminhtml/system_config_source_country&lt;/source_model&gt;
                            &lt;show_in_default&gt;1&lt;/show_in_default&gt;
                            &lt;show_in_website&gt;0&lt;/show_in_website&gt;
                            &lt;show_in_store&gt;0&lt;/show_in_store&gt;
                            &lt;can_be_empty&gt;1&lt;/can_be_empty&gt;
                        &lt;/allowed_countries&gt;
                    &lt;/fields&gt;
                &lt;/gift_options&gt;
            &lt;/groups&gt;
        &lt;/sales&gt;
    &lt;/sections&gt;
&lt;/config&gt;
</pre>
<p>Note that now you can see in Magento administration under <strong>System/Configuration/Sales/Sales/Gift Options</strong> tab new input field where you can specify desired amount for: “<strong>Gift Wrap Service is available in the following countries</strong>:“.</p>
<h4>4. Create Helper class</h4>
<p>Create file <strong>app/code/local/Inchoo/GiftWrapping/Helper/Data.php</strong> with the following content:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
/**
 * GiftWrapping helper data
 *
 * @category    Inchoo
 * @package     Inchoo_GiftWrapping
 * @author      Ivan Galamboš &lt;ivan.galambos@inchoo.net&gt;
 */
class Inchoo_GiftWrapping_Helper_Data extends Mage_Core_Helper_Abstract
{
    /**
     * Allowed countries array
     *
     * @var array
     */
    public $_allowedCountriesArray = array();
    /**
     * Allowed countries array
     *
     * @var array
     */
    public $_allowedCountries = array();
    /**
     * Return response as JSON.
     *
     * @return string
     */
    public function getAllowedCountries()
    {
        $this-&gt;_allowedCountries = Mage::getStoreConfig('sales/gift_options/allowed_countries');
        if (strlen($this-&gt;_allowedCountries)) {
            $this-&gt;_allowedCountriesArray = explode(',', $this-&gt;_allowedCountries);
        } else {
            $this-&gt;_allowedCountriesArray = array();
        }
        return Mage::helper('core')-&gt;jsonEncode($this-&gt;_allowedCountriesArray);
    }
}
</pre>
<h4>5. Front-end modifications</h4>
<p>As I previously wrote, I did this enhancement on top of the onestepcheckout Magento EE extension. I&#8217;ll give you a JS code for it as well as modifications that I did.</p>
<p>Open file: <strong>app/design/frontend/enterprise/[YOUR_THEME]/template/onestepcheckout/checkout.phtml</strong> and find</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php if($this-&gt;settings['enable_gift_messages']): ?&gt;...&lt;?php endif; ?&gt;
</pre>
<p>(around line 600), replace everything with:</p>
<pre class="brush: php; title: ; notranslate">
&lt;script type=&quot;text/javascript&quot;&gt;
//&lt;![CDATA[
    var allowedCountries = &lt;?php echo $this-&gt;helper('inchoo_giftwrapping')-&gt;getAllowedCountries();?&gt;;
    var displayOnestepcheckoutGiftmessages = true;
    allowedCountries = $A(allowedCountries);
Event.observe(window, 'load', function() {
    if ($('billing:use_for_shipping_yes').getValue()) {
            displayOnestepcheckoutGiftmessages = false;
            allowedCountries.each(function(elem) {
                    if ($('billing:country_id').getValue() === elem) {
                        displayOnestepcheckoutGiftmessages = true;
                    }
                }
            );
            if (!displayOnestepcheckoutGiftmessages) {
                $('onestepcheckout-giftmessages').setStyle({display:'none'});
            } else {
                $('onestepcheckout-giftmessages').setStyle({display:'block'});
            }
    } else {
            displayOnestepcheckoutGiftmessages = false;
            allowedCountries.each(function(elem) {
                    if ($('shipping:country_id').getValue() === elem) {
                        displayOnestepcheckoutGiftmessages = true;
                    }
                }
            );
            if (!displayOnestepcheckoutGiftmessages) {
                $('onestepcheckout-giftmessages').setStyle({display:'none'});
            } else {
                $('onestepcheckout-giftmessages').setStyle({display:'block'});
            }
    }
    $('billing:country_id').observe('change', function(e) {
        if ($('billing:use_for_shipping_yes').getValue()) {
                displayOnestepcheckoutGiftmessages = false;
                allowedCountries.each(function(elem) {
                        if ($('billing:country_id').getValue() === elem) {
                            displayOnestepcheckoutGiftmessages = true;
                        }
                    }
                );
                if ( !displayOnestepcheckoutGiftmessages ) {
                    $('allow_gift_options_custom').checked = true;
                    toogleVisibilityOnObjectsCustom($('allow_gift_options_custom'), ['allow-gift-options-container']);
                    giftWrapRefresh('&lt;?php echo $this-&gt;getUrl('onestepcheckout/ajax/set_methods_separate', array('_secure'=&gt;true)); ?&gt;');
                    $('onestepcheckout-giftmessages').setStyle({display:'none'});
                } else {
                    $('onestepcheckout-giftmessages').setStyle({display:'block'});
                }
        }
    });
    $('shipping:country_id').observe('change', function(e) {
        if ( !$('billing:use_for_shipping_yes').getValue() ) {
                displayOnestepcheckoutGiftmessages = false;
                allowedCountries.each(function(elem) {
                        if ($('shipping:country_id').getValue() === elem) {
                            displayOnestepcheckoutGiftmessages = true;
                        }
                    }
                );
                if ( !displayOnestepcheckoutGiftmessages ) {
                    $('allow_gift_options_custom').checked = true;
                    toogleVisibilityOnObjectsCustom($('allow_gift_options_custom'), ['allow-gift-options-container']);
                    giftWrapRefresh('&lt;?php echo $this-&gt;getUrl('onestepcheckout/ajax/set_methods_separate', array('_secure'=&gt;true)); ?&gt;');
                    $('onestepcheckout-giftmessages').setStyle({display:'none'});
                } else {
                    $('onestepcheckout-giftmessages').setStyle({display:'block'});
                }
        }
    });
});
//]]&gt;
&lt;/script&gt;
        &lt;?php if($this-&gt;settings['enable_gift_messages']): ?&gt;
            &lt;div id=&quot;onestepcheckout-giftmessages&quot;&gt;
                &lt;div class=&quot;onestepcheckout-giftmessagecontainer&quot;&gt;
                    &lt;?php echo $this-&gt;helper('onestepcheckout/message')-&gt;getInline('onepage_checkout', $this-&gt;getQuote(), $this-&gt;getDontDisplayContainer()) ?&gt;
                    &lt;?php if(is_object(Mage::getConfig()-&gt;getNode('global/models/enterprise_giftwrapping'))):?&gt;
                        &lt;script type=&quot;text/javascript&quot;&gt;
                            Event.observe(window, 'load', function() {
                                var items = $$('.onestepcheckout-giftmessagecontainer input, .onestepcheckout-giftmessagecontainer select, .onestepcheckout-giftmessagecontainer textarea');
                                if(items.length &gt; 0){
                                    items.each(function(elem){
                                        elem.observe('change', function(e){
                                            giftWrapRefresh('&lt;?php echo $this-&gt;getUrl('onestepcheckout/ajax/set_methods_separate', array('_secure'=&gt;true)); ?&gt;');
                                        });
                                    });
                                }
                            });
                        &lt;/script&gt;
                    &lt;?php endif;?&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;?php endif; ?&gt;
</pre>
<p>Now we&#8217;ve prepared most of our JS code required for onestepcheckout extension to work on desired way. Now we need to <strong>change checkbox to radio button</strong> and we need to add method <strong>toogleVisibilityOnObjectsCustom</strong>().</p>
<p>Open file: <strong>app/design/frontend/enterprise/[YOUR_THEME]/template/giftmessage/inline.phtml</strong> and replace:</p>
<pre class="brush: php; title: ; notranslate">
if(!window.toogleVisibilityOnObjects) {
    var toogleVisibilityOnObjects = function(source, objects) {
        if($(source) &amp;&amp; $(source).checked) {
            objects.each(function(item){
                $(item).show();
                $$('#' + item + ' .input-text').each(function(item) {
                    item.removeClassName('validation-passed');
                });
            });
        } else {
            objects.each(function(item){
                if ($(item)) {
                    $(item).hide();
                    $$('#' + item + ' .input-text').each(function(sitem) {
                        sitem.addClassName('validation-passed');
                    });
                    $$('#' + item + ' .giftmessage-area').each(function(sitem) {
                        sitem.value = '';
                    });
                    $$('#' + item + ' .checkbox').each(function(sitem) {
                        sitem.checked = false;
                    });
                    $$('#' + item + ' .select').each(function(sitem) {
                        sitem.value = '';
                    });
                    $$('#' + item + ' .price-box').each(function(sitem) {
                        sitem.addClassName('no-display');
                    });
                }
            });
        }
    }
}
</pre>
<p>with:</p>
<pre class="brush: php; title: ; notranslate">
if(!window.toogleVisibilityOnObjects) {
    var toogleVisibilityOnObjects = function(source, objects) {
        if($(source) &amp;&amp; $(source).checked) {
            objects.each(function(item){
                $(item).show();
                $$('#' + item + ' .input-text').each(function(item) {
                    item.removeClassName('validation-passed');
                });
            });
        } else {
            objects.each(function(item){
                if ($(item)) {
                    $(item).hide();
                    $$('#' + item + ' .input-text').each(function(sitem) {
                        sitem.addClassName('validation-passed');
                    });
                    $$('#' + item + ' .giftmessage-area').each(function(sitem) {
                        sitem.value = '';
                    });
                    $$('#' + item + ' .checkbox').each(function(sitem) {
                        sitem.checked = false;
                    });
                    $$('#' + item + ' .select').each(function(sitem) {
                        sitem.value = '';
                    });
                    $$('#' + item + ' .price-box').each(function(sitem) {
                        sitem.addClassName('no-display');
                    });
                }
            });
        }
    }
    var toogleVisibilityOnObjectsCustom = function(source, objects) {
        if($(source) &amp;&amp; $(source).checked) {
            objects.each(function(item){
                if ($(item)) {
                    $(item).hide();
                    $$('#' + item + ' .input-text').each(function(sitem) {
                        sitem.addClassName('validation-passed');
                    });
                    $$('#' + item + ' .giftmessage-area').each(function(sitem) {
                        sitem.value = '';
                    });
                    $$('#' + item + ' .checkbox').each(function(sitem) {
                        sitem.checked = false;
                    });
                    $$('#' + item + ' .select').each(function(sitem) {
                        sitem.value = '';
                    });
                    $$('#' + item + ' .price-box').each(function(sitem) {
                        sitem.addClassName('no-display');
                    });
                }
            });
        } else {
        }
    }
}
</pre>
<p>In same file, <strong>app/design/frontend/enterprise/[YOUR_THEME]/template/giftmessage/inline.phtml</strong>, replace:</p>
<pre class="brush: php; title: ; notranslate">
&lt;div class=&quot;add-gift-message no-display&quot; id=&quot;add-gift-options-&lt;?php echo $this-&gt;getEntity()-&gt;getId() ?&gt;&quot;&gt;
        &lt;h3&gt;&lt;?php echo $this-&gt;__('Do you have any gift items in your order?'); ?&gt;&lt;/h3&gt;
        &lt;p&gt;
            &lt;input type=&quot;checkbox&quot; name=&quot;allow_gift_options&quot; id=&quot;allow_gift_options&quot; value=&quot;1&quot; onclick=&quot;toogleVisibilityOnObjects(this, ['allow-gift-options-container']);&quot;&lt;?php if($this-&gt;getItemsHasMesssages() || $this-&gt;getEntityHasMessage()): ?&gt; checked=&quot;checked&quot;&lt;?php endif; ?&gt; class=&quot;checkbox&quot; /&gt;
            &lt;label for=&quot;allow_gift_options&quot;&gt;&lt;?php echo $this-&gt;__('Add gift options') ?&gt;&lt;/label&gt;
        &lt;/p&gt;
    &lt;/div&gt;
</pre>
<p> with:</p>
<pre class="brush: php; title: ; notranslate">
&lt;div class=&quot;add-gift-message no-display&quot; id=&quot;add-gift-options-&lt;?php echo $this-&gt;getEntity()-&gt;getId() ?&gt;&quot;&gt;
            &lt;p&gt;
                &lt;input type=&quot;radio&quot; name=&quot;allow_gift_options&quot; id=&quot;allow_gift_options_custom&quot; value=&quot;0&quot; onclick=&quot;toogleVisibilityOnObjectsCustom(this, ['allow-gift-options-container']);&quot; class=&quot;checkbox&quot; /&gt;
                &lt;label for=&quot;allow_gift_options_custom&quot;&gt;&lt;?php echo $this-&gt;__('Basic Wrap (Free)') ?&gt;&lt;/label&gt;
            &lt;/p&gt;
            &lt;p&gt;
                &lt;input type=&quot;radio&quot; name=&quot;allow_gift_options&quot; id=&quot;allow_gift_options&quot; value=&quot;1&quot; onclick=&quot;toogleVisibilityOnObjects(this, ['allow-gift-options-container']);&quot;&lt;?php if($this-&gt;getItemsHasMesssages() || $this-&gt;getEntityHasMessage()): ?&gt; checked=&quot;checked&quot;&lt;?php endif; ?&gt; class=&quot;checkbox&quot; /&gt;
                &lt;label for=&quot;allow_gift_options&quot;&gt;&lt;?php echo $this-&gt;__('Luxury Wrap') ?&gt;&lt;/label&gt;
            &lt;/p&gt;
        &lt;/div&gt;
</pre>
<p>And that&#8217;s it. If you refresh your checkout page, you&#8217;ll notice that you can&#8217;t see anymore Gift Wrap functionality. That&#8217;s expected because now you need to go to administration and enable some/all desired countries that can get Gift Wrapping service. Go to Magento administration and under System/Configuration/Sales/Sales/Gift Options tab you&#8217;ll see new input field &#8220;Gift Wrap Service is available in the following countries:&#8221; where you can select desired countries.</p>
<p>You can see on default Magento EE installation with sample data and onestepcheckout extension how this looks like:</p>
<p><a href="http://inchoo.net/wp-content/uploads/2013/05/radiogift.jpg"><img class="alignnone size-medium wp-image-18877" alt="radiogift" src="http://inchoo.net/wp-content/uploads/2013/05/radiogift-600x318.jpg" width="600" height="318" /></a></p>
<p>If you have any question, feel free to ask!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=sGGvLcTE9GU:tcPoDucpWec:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=sGGvLcTE9GU:tcPoDucpWec:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=sGGvLcTE9GU:tcPoDucpWec:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=sGGvLcTE9GU:tcPoDucpWec:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=sGGvLcTE9GU:tcPoDucpWec:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=sGGvLcTE9GU:tcPoDucpWec:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=sGGvLcTE9GU:tcPoDucpWec:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=sGGvLcTE9GU:tcPoDucpWec:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/sGGvLcTE9GU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/enable-gift-wrapping-module-for-certain-countries-ee/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/enable-gift-wrapping-module-for-certain-countries-ee/</feedburner:origLink></item>
		<item>
		<title>Inbound selling is how Inchoo sells</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/Z9wGgvNrdSw/</link>
		<comments>http://inchoo.net/ecommerce/inbound-selling-is-how-inchoo-sells/#comments</comments>
		<pubDate>Wed, 22 May 2013 11:04:45 +0000</pubDate>
		<dc:creator>Sanja Martinovic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[business development]]></category>
		<category><![CDATA[business strategy]]></category>
		<category><![CDATA[inbound sales]]></category>
		<category><![CDATA[sales]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18900</guid>
		<description><![CDATA[Inbound selling is a rather new approach in the world of sales. It’s a way of selling where you don’t call or interrupt your potential clients and leads. You acquire &#8230;]]></description>
				<content:encoded><![CDATA[<p>Inbound selling is a rather new approach in the world of sales. It’s a way of selling where you don’t call or interrupt your potential clients and leads. You acquire them with your inbound and other marketing techniques and respond to their interest and inquiries. And this is how we at Inchoo mostly sell our services.<span id="more-18900"></span></p>
<p>Inbound selling method enables the salesperson to act like an advisor, consultant, solution-provider and a problem-solver, and all that is well received by the customers. The leads you generate could be acquired through any of the marketing channels you use and of course via your inbound marketing techniques. The key is &#8211; you attract them with your quality of work, brand and knowledge, and then you respond when they ask you to. <strong>You don’t interrupt and you don’t do classic sales pitching.</strong></p>
<p>The leads come to you and then you communicate and have a chance to close the deals (sell) to the leads actually interested in what you have to say and the products/services you offer. You spend your time and energy more efficiently and the chances your sales teams’ efforts will bear fruit are much higher. Inbound sales team is connected to every part of the company. Actually, your entire business acts like a great sales pitch, especially every communication with potential leads and your customers through social media channels and every other public appearance.</p>
<p>Your selling effort is in the part of generating leads (e.g. inbound marketing channels), welcoming their arrivals, communicating and of course, <a title="Lead to deal and back again - Inchoo" href="http://inchoo.net/ecommerce/lead-to-deal-and-back-again/" target="_blank">closing the deals</a>. It is a more lenient selling approach, but it takes a greater common effort throughout the whole business process and the entire company.</p>
<h3>Inbound sales can operate if you pay attention to&#8230;</h3>
<ul>
<li>Identity and visibility &#8211; you will get inquiries and calls if you are recognized for what you do and if you are known for sustained quality</li>
<li>Proper business strategy &#8211; sales is not a separate department of the company that offers a finished product &#8211; it is connected to other processes and it’s not the last line of operations</li>
<li>Networking and communication &#8211; this is not only social media kind of networking, but connecting all the dots of your business into recognizable perception. Every effort you and your employees make could acquire you new leads</li>
</ul>
<h3><strong>What makes Inchoo inbound sales work</strong></h3>
<ul>
<li>Identity and visibility through our blog and social media channels &#8211; we offer our knowledge and experience for free and our potential customers react positively on our <a title="Marketing by sharing - Inchoo" href="http://inchoo.net/ecommerce/marketing-by-sharing/" target="_blank">knowledge sharing</a>. They want to work with someone who shows good quality and expertise.</li>
<li>Proper business strategy &#8211; our sales team is not on the last line of operations only closing the deals. We communicate with our development teams and discuss what could be the best for a particular business situation we come across. We <a title="Don't do all the work - Inchoo" href="http://inchoo.net/ecommerce/dont-do-all-the-work/" target="_blank">don’t take on every project</a> and we try to take on work which will help us to maintain our desired level of quality.</li>
<li>We don’t do sales pitching and don’t offer our services directly to potential customers. Communication is something we do a lot, and it is not only with a number of leads, but it is with our partner companies and also with our development teams.</li>
</ul>
<p><strong>Does inbound selling mean you need less selling effort?</strong> Actually no. It means your effort is different &#8211; it is a transformed way of selling, closely associated with your marketing and other areas of business.</p>
<p>Inbound selling seems like a logical transformation of selling as we know it. People don’t want to get disturbed and they don’t respond to what they have seen before. They have more information and knowledge available than ever, so we should focus our strengths on doing meaningful things and delivering valuable solutions. We should let them discover us as their best choice and then sell to them because of that.</p>
<p><strong>And what is your business and sales strategy? How do you attract new leads and could you implement inbound selling in your company?</strong> Share your experiences in the comments below&#8230;</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=Z9wGgvNrdSw:GXTtYHJXVqY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=Z9wGgvNrdSw:GXTtYHJXVqY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=Z9wGgvNrdSw:GXTtYHJXVqY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=Z9wGgvNrdSw:GXTtYHJXVqY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=Z9wGgvNrdSw:GXTtYHJXVqY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=Z9wGgvNrdSw:GXTtYHJXVqY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=Z9wGgvNrdSw:GXTtYHJXVqY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=Z9wGgvNrdSw:GXTtYHJXVqY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/Z9wGgvNrdSw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/inbound-selling-is-how-inchoo-sells/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/inbound-selling-is-how-inchoo-sells/</feedburner:origLink></item>
		<item>
		<title>(Free) Gift Wrapping Service – Magento EE</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/1qoJMOMKvn0/</link>
		<comments>http://inchoo.net/ecommerce/magento/free-gift-wrapping-service-magento-ee/#comments</comments>
		<pubDate>Tue, 21 May 2013 15:40:06 +0000</pubDate>
		<dc:creator>Ivan Galambos</dc:creator>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[gift message]]></category>
		<category><![CDATA[gift wrapping]]></category>
		<category><![CDATA[magento enterprise]]></category>
		<category><![CDATA[programming]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18852</guid>
		<description><![CDATA[Maybe you&#8217;ve wondered how not to charge for the Gift Wrapping Services for customers that have more items in their cart. We&#8217;ve gotten a request where client wanted to provide &#8230;]]></description>
				<content:encoded><![CDATA[<p>Maybe you&#8217;ve wondered how not to charge for the Gift Wrapping Services for customers that have more items in their cart. We&#8217;ve gotten a request where client wanted to provide free Gift Wrapping Services (Gift Card, Gift Wrap, Gift Message) for their customers with total basket value above a certain limit. If you are wondering how we did it, keep reading.</p>
<p><span id="more-18852"></span></p>
<p>Shortly about <strong>Gift Wrapping module</strong>, from Magento Enterprise Edition User Guide:<br />
&#8220;In Magento Enterprise Edition, store customers can select a gift message and/or gift wrapping for the entire order, as well as for separate order items, and a printed card, such as a picture post card, to the order. You can process the gift wrapping and printed card, and charge customers for them, as well as add gift messages, gift wrapping, and a gift card in orders that are created from the Admin Panel.<br />
This feature was introduced in Version 1.10 of Magento Enterprise Edition.&#8221;</p>
<p>Basically we&#8217;ll need to rewrite one model and we&#8217;ll need to create our helper class which will check for us can we show Free Gift Wrapping Service &#8211; only if value of items in basket is above certain limit.</p>
<ol>
<li>Tell Magento about our module</li>
<li>Create configuration file</li>
<li>Create system.xml file</li>
<li>Rewrite Required Model</li>
<li>Create Our Helper class</li>
<li>Tweak frontend look and feel</li>
</ol>
<p>So let&#8217;s start.</p>
<h4>1. Tell Magento about our module</h4>
<p>Create file app/etc/modules/Inchoo_GiftWrapping.xml with the following content:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_GiftWrapping&gt;
            &lt;active&gt;true&lt;/active&gt;
            &lt;codePool&gt;local&lt;/codePool&gt;
            &lt;depends&gt;
                &lt;Enterprise_GiftWrapping/&gt;
            &lt;/depends&gt;
        &lt;/Inchoo_GiftWrapping&gt;
    &lt;/modules&gt;
&lt;/config&gt;
</pre>
<h4>2. Create configuration file</h4>
<p>Create file app/code/local/Inchoo/GiftWrapping/etc/config.xml with the following content:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_GiftWrapping&gt;
            &lt;version&gt;1.0.0.0&lt;/version&gt;
        &lt;/Inchoo_GiftWrapping&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;models&gt;
            &lt;enterprise_giftwrapping&gt;
                &lt;rewrite&gt;
                    &lt;total_quote_giftwrapping&gt;Inchoo_GiftWrapping_Model_Total_Quote_Giftwrapping&lt;/total_quote_giftwrapping&gt;
                &lt;/rewrite&gt;
            &lt;/enterprise_giftwrapping&gt;
        &lt;/models&gt;
        &lt;helpers&gt;
            &lt;inchoo_giftwrapping&gt;
                &lt;class&gt;Inchoo_GiftWrapping_Helper&lt;/class&gt;
            &lt;/inchoo_giftwrapping&gt;
        &lt;/helpers&gt;
    &lt;/global&gt;
 &lt;/config&gt;
</pre>
<h4>3. Create system.xml file</h4>
<p>Create file app/code/local/Inchoo/GiftWrapping/etc/system.xml with the following content:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;sections&gt;
        &lt;sales&gt;
            &lt;groups&gt;
                &lt;gift_options&gt;
                    &lt;fields&gt;
                        &lt;free_gift_wrapping_price translate=&quot;label&quot; module=&quot;inchoo_giftwrapping&quot;&gt;
                            &lt;label&gt;Charge for Gift Wrap Service if the basket value is under&lt;/label&gt;
                            &lt;frontend_type&gt;text&lt;/frontend_type&gt;
                            &lt;sort_order&gt;15&lt;/sort_order&gt;
                            &lt;show_in_default&gt;1&lt;/show_in_default&gt;
                            &lt;show_in_website&gt;0&lt;/show_in_website&gt;
                            &lt;show_in_store&gt;0&lt;/show_in_store&gt;
                            &lt;can_be_empty&gt;1&lt;/can_be_empty&gt;
                        &lt;/free_gift_wrapping_price&gt;
                    &lt;/fields&gt;
                &lt;/gift_options&gt;
            &lt;/groups&gt;
        &lt;/sales&gt;
    &lt;/sections&gt;
&lt;/config&gt;
</pre>
<p>Note that now you can see in Magento administration under System/Configuration/Sales/Sales/Gift Options tab new input field where you can specify desired amount for: &#8220;<strong>Charge for Gift Wrap Service if the basket value is under</strong>&#8220;.</p>
<h4>4. Rewrite Model</h4>
<p>Create file app/code/local/Inchoo/GiftWrapping/Model/Total/Quote/Giftwrapping.php with the following content:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
/**
 * GiftWrapping total calculator for quote
 * @category    Inchoo
 * @package     Inchoo_GiftWrapping
 * @author      Ivan Galambos &lt;ivan.galambos@inchoo.net&gt;
 */
class Inchoo_GiftWrapping_Model_Total_Quote_Giftwrapping extends Enterprise_GiftWrapping_Model_Total_Quote_Giftwrapping
{
    /**
     * Collect wrapping total for quote
     *
     * @param   Mage_Sales_Model_Quote_Address $address
     * @return  Enterprise_GiftWrapping_Model_Total_Quote_Giftwrapping
     */
    protected function _collectWrappingForQuote($address)
    {
        $wrappingBasePrice = false;
        $wrappingPrice = false;
        //include price if !canuseFreeGiftWrapping
        if ( !(Mage::helper('inchoo_giftwrapping')-&gt;canUseFreeGiftWrapping()) ) {
            if ($this-&gt;_quoteEntity-&gt;getGwId()) {
                $wrapping = $this-&gt;_getWrapping($this-&gt;_quoteEntity-&gt;getGwId(), $this-&gt;_store);
                $wrappingBasePrice = $wrapping-&gt;getBasePrice();
                $wrappingPrice = $this-&gt;_store-&gt;convertPrice($wrappingBasePrice);
            }
        }
        $address-&gt;setGwBasePrice($wrappingBasePrice);
        $address-&gt;setGwPrice($wrappingPrice);
        return $this;
    }
    /**
     * Collect printed card total for quote
     *
     * @param   Mage_Sales_Model_Quote_Address $address
     * @return  Inchoo_GiftWrapping_Model_Total_Quote_Giftwrapping
     */
    protected function _collectPrintedCard($address)
    {
        $printedCardBasePrice = false;
        $printedCardPrice = false;
        //include price if !canuseFreeGiftWrapping
        if ( !(Mage::helper('inchoo_giftwrapping')-&gt;canUseFreeGiftWrapping()) ) {
            if ($this-&gt;_quoteEntity-&gt;getGwAddCard()) {
                $printedCardBasePrice = Mage::helper('enterprise_giftwrapping')-&gt;getPrintedCardPrice($this-&gt;_store);
                $printedCardPrice = $this-&gt;_store-&gt;convertPrice($printedCardBasePrice);
            }
        }
        $address-&gt;setGwCardBasePrice($printedCardBasePrice);
        $address-&gt;setGwCardPrice($printedCardPrice);
        return $this;
    }
}
</pre>
<h4>5. Create Helper class</h4>
<p>Create file app/code/local/Inchoo/GiftWrapping/Helper/Data.php with the following content:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
/**
 * GiftWrapping helper data
 *
 * @category    Inchoo
 * @package     Inchoo_GiftWrapping
 * @author      Ivan Galamboš &lt;ivan.galambos@inchoo.net&gt;
 */
class Inchoo_GiftWrapping_Helper_Data extends Mage_Core_Helper_Abstract
{
    /**
     * Min. base price to get free GiftWrapping Service
     *
     * @var mixed
     */
    public $_baseFreePrice = null;
    /**
     * can use free Gift Wrapping service
     *
     * @var mixed
     */
    public $freeGiftWrapping = null;
    /**
     * Return limit as base price for free Gift Wrapping Service
     *
     * @return flaot
     */
    public function getBasePriceForFreeGiftWrappingService()
    {
        if (empty($this-&gt;_baseFreePrice)) {
            $this-&gt;_baseFreePrice = (float)Mage::getStoreConfig('sales/gift_options/free_gift_wrapping_price');
        }
        return $this-&gt;_baseFreePrice;
    }
    /**
     * Can show free Gift Wrapping Service on frontend
     * Basket value must be grater or equal to set price for Free Gift Wrapping Service
     *
     * @return bool
     */
    public function canUseFreeGiftWrapping()
    {
        if (!is_bool($this-&gt;freeGiftWrapping)) {
            $baseFreeGift = $this-&gt;getBasePriceForFreeGiftWrappingService();
            $baseTotal = Mage::getModel('checkout/session')-&gt;getQuote()-&gt;getBaseGrandTotal();
            if ( $baseTotal &gt;= $baseFreeGift ) {
                $this-&gt;freeGiftWrapping = true;
            } else {
                $this-&gt;freeGiftWrapping = false;
            }
        }
        return $this-&gt;freeGiftWrapping;
    }
}
</pre>
<p>And for the end we can tweak desired frontend look and feel <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h4>6. Front-end modifications</h4>
<p>For example you can open file: app/design/frontend/enterprise/[YOUR_THEME]/template/giftwrapping/checkout/options.phtml and add 2 modifications (you don&#8217;t want to change core file &#8211; if you don&#8217;t have one please copy one):<br />
1) in <strong>gift-wrapping-container</strong> area you can replace with:</p>
<pre class="brush: php; title: ; notranslate">
&lt;span class=&quot;regular-price&quot;&gt;
                        &lt;span class=&quot;label&quot;&gt;&lt;?php echo $this-&gt;__('Price') ?&gt;:&lt;/span&gt;
                        &lt;?php if (Mage::helper('inchoo_giftwrapping')-&gt;canUseFreeGiftWrapping()):?&gt;
                            &lt;span class=&quot;price&quot;&gt;&lt;?php echo $this-&gt;__('Free') ?&gt;&lt;/span&gt;
                        &lt;?php else: ?&gt;
                            &lt;span class=&quot;price&quot; id=&quot;regular-price-{{id}}&quot;&gt;&lt;/span&gt;
                        &lt;?php endif; ?&gt;
&lt;/span&gt;
</pre>
<p>and 2) <span class="regular-price"> in gift-options-container area you can replace with:<br />
</span></p>
<pre class="brush: php; title: ; notranslate">
&lt;span class=&quot;regular-price&quot;&gt;
                    &lt;span class=&quot;label&quot;&gt;&lt;?php echo $this-&gt;__('Price') ?&gt;:&lt;/span&gt;
                    &lt;span class=&quot;price&quot; id=&quot;regular-card-price-{{id}}&quot;&gt;
                    &lt;?php echo (Mage::helper('inchoo_giftwrapping')-&gt;canUseFreeGiftWrapping()) ? $this-&gt;__('Free') : '{{price}}'; ?&gt;&lt;/span&gt;
&lt;/span&gt;
</pre>
<p>Now your customers will see &#8220;Free&#8221; price instead of regular one on checkout page for Gift Wrapping service &amp; Printed Card feature.</p>
<p>And as the end result you might come up with something similar to the next screenshoot:</p>
<p><img alt="Gift Wrapping Example" src="http://inchoo.net/wp-content/uploads/2013/05/freegiftwrap.jpg" width="609" height="300" /></p>
<p>Note that for production ready code you&#8217;ll need first to check and decide which amount should be default for your base currency, otherwise system might show free of charge Gift Wrapping Service.</p>
<p>Did you have any similar request? How have you handled it?</p>
<p>In <a href="http://inchoo.net/ecommerce/magento/enable-gift-wrapping-module-for-certain-countries-ee/" title="Enable Gift Wrapping for selected countries" target="_blank">one of my next posts</a> I&#8217;ll show you how you can enable Gift Wrapping module only for customers from certain countries, so stay tuned!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=1qoJMOMKvn0:jcRlQ8CCVUo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=1qoJMOMKvn0:jcRlQ8CCVUo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=1qoJMOMKvn0:jcRlQ8CCVUo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=1qoJMOMKvn0:jcRlQ8CCVUo:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=1qoJMOMKvn0:jcRlQ8CCVUo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=1qoJMOMKvn0:jcRlQ8CCVUo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=1qoJMOMKvn0:jcRlQ8CCVUo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=1qoJMOMKvn0:jcRlQ8CCVUo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/1qoJMOMKvn0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/free-gift-wrapping-service-magento-ee/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/free-gift-wrapping-service-magento-ee/</feedburner:origLink></item>
		<item>
		<title>Object-specific Layout Update Handles</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/qBI2-07CrjU/</link>
		<comments>http://inchoo.net/ecommerce/magento/custom-layout-update-handles/#comments</comments>
		<pubDate>Tue, 21 May 2013 13:48:16 +0000</pubDate>
		<dc:creator>Zvonimir Buric</dc:creator>
				<category><![CDATA[Events & Observers]]></category>
		<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Frontend]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[handle]]></category>
		<category><![CDATA[layout]]></category>
		<guid isPermaLink="false">http://inchoo.net/?p=18837</guid>
		<description><![CDATA[Every HTTP request in Magento results with a few layout handles which can be used to customize layout of desired pages. If you ever tried to dump layout handles in Magento, &#8230;]]></description>
				<content:encoded><![CDATA[<p>Every HTTP request in Magento results with a few layout handles which can be used to customize layout of desired pages. If you ever tried to dump layout handles in Magento, you would see many of them. These handles are calculated differently, based on different variables.<span id="more-18837"></span></p>
<p>Depending on <strong>whether the user is logged in or not</strong>, Magento uses customer_logged_in and customer_logged_out handles. Different stores have also different layout updates (e.g. STORE_default, STORE_cars, STORE_fashion&#8230;).<br />
<strong>Themes have their own layout handles</strong>, e.g. THEME_frontend_default_default, THEME_frontend_enterprise_default.</p>
<p>While we were working on a website that uses <strong>&#8220;Shop by Brand&#8221; extension</strong>, client asked us if we could change layout for one brand page. In order to provide that functionality we had to extend this extension in a way that every brand page has it&#8217;s own layout update handle.</p>
<p>You might noticed that Magento uses this functionality to create unique layout handles for different categories (e.g. CATEGORY_96, CATEGORY_35) and products (e.g. PRODUCT_22735, PRODUCT_225).</p>
<p>Here <b>I&#8217;ll show you how you can create object-specific layout handle functionality for your custom modules</b>. Handle will be composed of string concatenated to object&#8217;s id (like OUR_COOL_OBJECT_535, OUR_COOL_OBJECT_863).</p>
<h3>1. Create Observer</h3>
<p>In order to add handle to Magento&#8217;s layout update object before it&#8217;s too late, we have to observe controller_action_layout_load_before event.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;frontend&gt;
        &lt;events&gt;
            &lt;controller_action_layout_load_before&gt;
                &lt;observers&gt;
                    &lt;inchoo_controller_action_layout_load_before&gt;
                        &lt;class&gt;inchoo_layouthandle/observer&lt;/class&gt;
                        &lt;method&gt;controllerActionLayoutLoadBefore&lt;/method&gt;
                    &lt;/inchoo_controller_action_layout_load_before&gt;
                &lt;/observers&gt;
            &lt;/controller_action_layout_load_before&gt;
        &lt;/events&gt;
    &lt;/frontend&gt;
&lt;/config&gt;
</pre>
<h3>2. Add Handle</h3>
<p>Now we have to calculate layout update handle and add it to the layout update object.</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
    class Inchoo_LayoutHandle_Model_Observer
    {
        public function controllerActionLayoutLoadBefore(Varien_Event_Observer $observer)
        {
            /** @var $layout Mage_Core_Model_Layout */
            $layout = $observer-&gt;getEvent()-&gt;getLayout();
            $id = Mage::app()-&gt;getRequest()-&gt;getParam('id');
            /* or */
            if($ourCoolObject = Mage::registry('our_cool_object'))
            {
                $id = $ourCoolObject-&gt;getId();
            }
            $layout-&gt;getUpdate()-&gt;addHandle('OUR_COOL_OBJECT_'.$id);
        }
    }
</pre>
<p>That&#8217;s it!<br />
Hope this helps! <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=qBI2-07CrjU:omzxEYggX8A:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=qBI2-07CrjU:omzxEYggX8A:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=qBI2-07CrjU:omzxEYggX8A:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=qBI2-07CrjU:omzxEYggX8A:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=qBI2-07CrjU:omzxEYggX8A:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=qBI2-07CrjU:omzxEYggX8A:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=qBI2-07CrjU:omzxEYggX8A:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=qBI2-07CrjU:omzxEYggX8A:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/qBI2-07CrjU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/custom-layout-update-handles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/custom-layout-update-handles/</feedburner:origLink></item>
		<item>
		<title>Newsletter auto-subscribe on create account and place order in Magento</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/pU-XrH3txS4/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=pU-XrH3txS4:6_e8S3rHE0o:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=pU-XrH3txS4:6_e8S3rHE0o:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=pU-XrH3txS4:6_e8S3rHE0o:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=pU-XrH3txS4:6_e8S3rHE0o:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=pU-XrH3txS4:6_e8S3rHE0o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=pU-XrH3txS4:6_e8S3rHE0o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=pU-XrH3txS4:6_e8S3rHE0o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=pU-XrH3txS4:6_e8S3rHE0o:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/pU-XrH3txS4" height="1" width="1"/>]]></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>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/newsletter-auto-subscribe-create-account-place-order-magento/</feedburner:origLink></item>
		<item>
		<title>Go Responsive (or go home) – workshop about Responsive Web Design</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/22Xg52-GTSQ/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=22Xg52-GTSQ:ZOWzmGH2tE0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=22Xg52-GTSQ:ZOWzmGH2tE0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=22Xg52-GTSQ:ZOWzmGH2tE0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=22Xg52-GTSQ:ZOWzmGH2tE0:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=22Xg52-GTSQ:ZOWzmGH2tE0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=22Xg52-GTSQ:ZOWzmGH2tE0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=22Xg52-GTSQ:ZOWzmGH2tE0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=22Xg52-GTSQ:ZOWzmGH2tE0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/22Xg52-GTSQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/fun-zone/go-responsive-or-go-home/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://inchoo.net/fun-zone/go-responsive-or-go-home/</feedburner:origLink></item>
		<item>
		<title>Automatic Cross Related Products – CSV Import</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/BeytiEIr6vo/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=BeytiEIr6vo:uHU_L2EkcIE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=BeytiEIr6vo:uHU_L2EkcIE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=BeytiEIr6vo:uHU_L2EkcIE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=BeytiEIr6vo:uHU_L2EkcIE:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=BeytiEIr6vo:uHU_L2EkcIE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=BeytiEIr6vo:uHU_L2EkcIE:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=BeytiEIr6vo:uHU_L2EkcIE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=BeytiEIr6vo:uHU_L2EkcIE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/BeytiEIr6vo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/automatic-cross-related-products-csv-import/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/automatic-cross-related-products-csv-import/</feedburner:origLink></item>
		<item>
		<title>Customer journey and multichannel shopping</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/0nINY8j3qds/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=0nINY8j3qds:q7fJzFhdtik:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=0nINY8j3qds:q7fJzFhdtik:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=0nINY8j3qds:q7fJzFhdtik:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=0nINY8j3qds:q7fJzFhdtik:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=0nINY8j3qds:q7fJzFhdtik:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=0nINY8j3qds:q7fJzFhdtik:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=0nINY8j3qds:q7fJzFhdtik:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=0nINY8j3qds:q7fJzFhdtik:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/0nINY8j3qds" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/customer-journey-and-multichannel-shopping/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/customer-journey-and-multichannel-shopping/</feedburner:origLink></item>
		<item>
		<title>Per product meta robots tag control in Magento</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/5dPKQtP_sNI/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=5dPKQtP_sNI:wwEdyxbGJME:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=5dPKQtP_sNI:wwEdyxbGJME:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=5dPKQtP_sNI:wwEdyxbGJME:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=5dPKQtP_sNI:wwEdyxbGJME:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=5dPKQtP_sNI:wwEdyxbGJME:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=5dPKQtP_sNI:wwEdyxbGJME:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=5dPKQtP_sNI:wwEdyxbGJME:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=5dPKQtP_sNI:wwEdyxbGJME:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/5dPKQtP_sNI" height="1" width="1"/>]]></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>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/per-product-meta-robots-tag-control-in-magento/</feedburner:origLink></item>
		<item>
		<title>Easily manage LAMP name based virtual hosts</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/UGRJozeQrx4/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=UGRJozeQrx4:R-vUZ-Oo3pk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=UGRJozeQrx4:R-vUZ-Oo3pk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=UGRJozeQrx4:R-vUZ-Oo3pk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=UGRJozeQrx4:R-vUZ-Oo3pk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=UGRJozeQrx4:R-vUZ-Oo3pk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=UGRJozeQrx4:R-vUZ-Oo3pk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=UGRJozeQrx4:R-vUZ-Oo3pk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=UGRJozeQrx4:R-vUZ-Oo3pk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/UGRJozeQrx4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/tools-frameworks/easily-manage-lamp-name-based-virtual-hosts/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://inchoo.net/tools-frameworks/easily-manage-lamp-name-based-virtual-hosts/</feedburner:origLink></item>
		<item>
		<title>Ultimate Google Analytics Dashboard for Ecommerce</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/Ci2IygGFxaI/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=Ci2IygGFxaI:8ns19vUl1Ec:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=Ci2IygGFxaI:8ns19vUl1Ec:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=Ci2IygGFxaI:8ns19vUl1Ec:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=Ci2IygGFxaI:8ns19vUl1Ec:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=Ci2IygGFxaI:8ns19vUl1Ec:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=Ci2IygGFxaI:8ns19vUl1Ec:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=Ci2IygGFxaI:8ns19vUl1Ec:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=Ci2IygGFxaI:8ns19vUl1Ec:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/Ci2IygGFxaI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/ultimate-google-analytics-dashboard-for-ecommerce/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/ultimate-google-analytics-dashboard-for-ecommerce/</feedburner:origLink></item>
		<item>
		<title>301 redirects vs canonical links in Magento</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/A4COF5j882E/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=A4COF5j882E:AmvsgFYfI54:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=A4COF5j882E:AmvsgFYfI54:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=A4COF5j882E:AmvsgFYfI54:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=A4COF5j882E:AmvsgFYfI54:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=A4COF5j882E:AmvsgFYfI54:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=A4COF5j882E:AmvsgFYfI54:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=A4COF5j882E:AmvsgFYfI54:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=A4COF5j882E:AmvsgFYfI54:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/A4COF5j882E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/301vscanonicals/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/301vscanonicals/</feedburner:origLink></item>
		<item>
		<title>Product Stock Alerts (not) working</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/tS04N-TaHZc/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=tS04N-TaHZc:zjr8qqo56-E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=tS04N-TaHZc:zjr8qqo56-E:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=tS04N-TaHZc:zjr8qqo56-E:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=tS04N-TaHZc:zjr8qqo56-E:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=tS04N-TaHZc:zjr8qqo56-E:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=tS04N-TaHZc:zjr8qqo56-E:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=tS04N-TaHZc:zjr8qqo56-E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=tS04N-TaHZc:zjr8qqo56-E:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/tS04N-TaHZc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/product-stock-alerts-not-working/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/product-stock-alerts-not-working/</feedburner:origLink></item>
		<item>
		<title>Magento 2 and Twig</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/SKfrM6rvXJ0/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=SKfrM6rvXJ0:fDU7vTn0jOk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=SKfrM6rvXJ0:fDU7vTn0jOk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=SKfrM6rvXJ0:fDU7vTn0jOk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=SKfrM6rvXJ0:fDU7vTn0jOk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=SKfrM6rvXJ0:fDU7vTn0jOk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=SKfrM6rvXJ0:fDU7vTn0jOk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=SKfrM6rvXJ0:fDU7vTn0jOk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=SKfrM6rvXJ0:fDU7vTn0jOk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/SKfrM6rvXJ0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-2-and-twig/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/magento-2-and-twig/</feedburner:origLink></item>
		<item>
		<title>How to pass Hubspot Inbound Marketing Certification Exam</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/-i-nPhUW3Ro/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=-i-nPhUW3Ro:BmUcASBPogE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=-i-nPhUW3Ro:BmUcASBPogE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=-i-nPhUW3Ro:BmUcASBPogE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=-i-nPhUW3Ro:BmUcASBPogE:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=-i-nPhUW3Ro:BmUcASBPogE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=-i-nPhUW3Ro:BmUcASBPogE:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=-i-nPhUW3Ro:BmUcASBPogE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=-i-nPhUW3Ro:BmUcASBPogE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/-i-nPhUW3Ro" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/how-to-pass-hubspot-inbound-marketing-certification-exam/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/how-to-pass-hubspot-inbound-marketing-certification-exam/</feedburner:origLink></item>
		<item>
		<title>Magento Maximum Allowed Order Amount</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/OsOWsn7U13o/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=OsOWsn7U13o:ng2uao3NqXc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=OsOWsn7U13o:ng2uao3NqXc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=OsOWsn7U13o:ng2uao3NqXc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=OsOWsn7U13o:ng2uao3NqXc:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=OsOWsn7U13o:ng2uao3NqXc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=OsOWsn7U13o:ng2uao3NqXc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=OsOWsn7U13o:ng2uao3NqXc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=OsOWsn7U13o:ng2uao3NqXc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/OsOWsn7U13o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-maximum-allowed-order-amount/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/magento-maximum-allowed-order-amount/</feedburner:origLink></item>
		<item>
		<title>Magento Event Driven Programming Tips &amp; Tricks</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/wcJ5-0pmKD0/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=wcJ5-0pmKD0:zEeKjoO4vpk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=wcJ5-0pmKD0:zEeKjoO4vpk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=wcJ5-0pmKD0:zEeKjoO4vpk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=wcJ5-0pmKD0:zEeKjoO4vpk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=wcJ5-0pmKD0:zEeKjoO4vpk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=wcJ5-0pmKD0:zEeKjoO4vpk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=wcJ5-0pmKD0:zEeKjoO4vpk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=wcJ5-0pmKD0:zEeKjoO4vpk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/wcJ5-0pmKD0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-event-driven-programming-tips-tricks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://inchoo.net/ecommerce/magento/magento-event-driven-programming-tips-tricks/</feedburner:origLink></item>
		<item>
		<title>3 ways you can use videos on your E-commerce site</title>
		<link>http://feedproxy.google.com/~r/Inchoo/~3/X3Wme74lugQ/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Inchoo?a=X3Wme74lugQ:1byNiAlnIt0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=X3Wme74lugQ:1byNiAlnIt0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=X3Wme74lugQ:1byNiAlnIt0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=X3Wme74lugQ:1byNiAlnIt0:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=X3Wme74lugQ:1byNiAlnIt0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Inchoo?i=X3Wme74lugQ:1byNiAlnIt0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=X3Wme74lugQ:1byNiAlnIt0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Inchoo?a=X3Wme74lugQ:1byNiAlnIt0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Inchoo?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Inchoo/~4/X3Wme74lugQ" height="1" width="1"/>]]></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>
		<feedburner:origLink>http://inchoo.net/ecommerce/3-ways-you-can-use-videos-on-your-e-commerce-site/</feedburner:origLink></item>
	</channel>
</rss>
