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

<channel>
	<title>Magento Design and Development &#187; E-Commerce</title>
	<atom:link href="http://inchoo.net/category/ecommerce/feed/" rel="self" type="application/rss+xml" />
	<link>http://inchoo.net</link>
	<description>Magento Design and Magento Development Professionals - Inchoo</description>
	<lastBuildDate>Wed, 16 May 2012 12:17:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>How to add static blocks to main navigation dropdown?</title>
		<link>http://inchoo.net/ecommerce/magento/how-to-add-static-blocks-to-main-navigation-dropdown/</link>
		<comments>http://inchoo.net/ecommerce/magento/how-to-add-static-blocks-to-main-navigation-dropdown/#comments</comments>
		<pubDate>Wed, 09 May 2012 10:59:52 +0000</pubDate>
		<dc:creator>Srdjan Stojiljkovic</dc:creator>
				<category><![CDATA[Frontend]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[dropdown]]></category>
		<category><![CDATA[nav]]></category>
		<category><![CDATA[navigation]]></category>
		<category><![CDATA[Static blocks]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=14614</guid>
		<description><![CDATA[Many stores require some additional information in the main navigation drop-down section. Displaying only subcategories might not always be enough and I noticed this is becoming a trend on shopping &#8230;]]></description>
			<content:encoded><![CDATA[<p>Many stores require some additional information in the main navigation drop-down section. Displaying only subcategories might not always be enough and I noticed this is becoming a trend on shopping sites now days. Although there are many ways to accomplish this (including building you own custom module) I would like to show you a more clever way that will allow you to use static blocks and easily connect them with product categories. <span id="more-14614"></span>To better understand what I am talking about see the sample image of the end result below.</p>
<p style="text-align: center;"><a href="http://inchoo.net/ecommerce/magento/how-to-add-static-blocks-to-main-navigation-dropdown/attachment/sample-01/" rel="attachment wp-att-14615"><img class="size-full wp-image-14615 aligncenter" title="Static block in main navigation" src="http://inchoo.net/wp-content/uploads/2012/05/sample-01.jpg" alt="Static block in main navigation" width="384" height="415" /></a></p>
<h2>The idea</h2>
<p><strong>Magento 1.6 and earlier</strong><br />
The general idea is to use static blocks because they are easily editable and can hold many different types of content. The problem with static blocks is that you cannot assign them directly to product categories in Magento, or can you? Here&#8217;s an idea, set the &#8220;Identifier&#8221; value of the static block to be the same as the &#8220;URL Key&#8221; of the desired category. Now you have a logical connection between your static block and a product category. We just have to display the appropriate static blocks in the main navigation drop-down.</p>
<p><strong>Magento 1.7<br />
</strong>Now, in version 1.7 Magento introduced a completely new way of rendering menu items (thanks Johnboy for reminding me) that require some changes for this to work. The general idea is the same as above (for Magento 1.6) but this time we need to use something else instead of &#8220;URL Key&#8221; to connect our static block to a category. This time we will use the category ID value with a simple string prefix.</p>
<h2>The implementation</h2>
<p><strong>Magento 1.6 and earlier</strong><br />
To implement this simple idea we need to override a core Magento block class and add a few lines of code to a single function. How simple is that <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<ol>
<li>First we need to override the core Magento block class by copying the block file from core to local folder. We are going to use <strong>&#8220;Mage_Catalog_Block_Navigation&#8221;</strong>class so we need to copy:
<pre class="brush: php; title: ; notranslate">/app/code/core/Mage/Catalog/Block/Navigation.php</pre>
<p>to</p>
<pre class="brush: php; title: ; notranslate">/app/code/local/Mage/Catalog/Block/Navigation.php</pre>
<p>If you don’t have a folder structure in your local folder you will need to create it.</li>
<li>Find the <strong>protected function _renderCategoryMenuItemHtml </strong>(should begin at around line 218).<strong> </strong>This is the function that will render all the menu items which is exactly what we need.</li>
<li>Now find this piece of code (lines 309-312):
<pre class="brush: php; title: ; notranslate">

$html[] = '&lt;ul class=&quot;level' . $level . '&quot;&gt;';
$html[] = $htmlChildren;
$html[] = '&lt;/ul&gt;';
</pre>
</li>
<li>Add the following code just above the line with the closed ul tag:
<pre class="brush: php; title: ; notranslate">

$staticBlock = trim($this-&gt;getLayout()-&gt;createBlock('cms/block')-&gt;setBlockId(strtolower($category-&gt;getUrlKey()))-&gt;toHtml());
if(!empty($staticBlock)){
	$html[] = '&lt;span class=&quot;nav-static-block&quot; style=&quot;background:#fff; border-top:1px solid #ccc; padding:10px;&quot;&gt;';
	$html[] = $staticBlock;
	$html[] = '&lt;/span&gt;';
}
</pre>
<p><span>The end result should look like this:</span></p>
<pre class="brush: php; title: ; notranslate">

$html[] = '&lt;ul class=&quot;level' . $level . '&quot;&gt;';
$html[] = $htmlChildren;
$staticBlock = trim($this-&gt;getLayout()-&gt;createBlock('cms/block')-&gt;setBlockId(strtolower($category-&gt;getUrlKey()))-&gt;toHtml());
if(!empty($staticBlock)){
	$html[] = '&lt;span class=&quot;nav-static-block&quot; style=&quot;background:#fff; border-top:1px solid #ccc; padding:10px;&quot;&gt;';
	$html[] = $staticBlock;
	$html[] = '&lt;/span&gt;';
}
$html[] = '&lt;/ul&gt;';
</pre>
<p><span>The implementation is simple, check if there is a static block with the identifier value that is the same as the current category URL Key. If so, add the static block to the menu.</span></p>
<p><span>I used some inline CSS for the sake of simplicity but you should use your own.</span></li>
<li>Now you need to create a static block with the identifier value set to whatever category URL Key you want and you are all done! I used the default Magento sample data and created a static block with the identifier set to &#8220;furniture&#8221; because that is the URL Key of the Furniture category.</li>
</ol>
<p><strong>Magento 1.7<br />
</strong>This time we need to override a different Magento core class because in 1.7 Magento uses  <strong>Mage_Page_Block_Html_Topmenu</strong> to render the main menu.</p>
<ol>
<li>First we need to override the core Magento block class by copying the block file from core to local folder. We need to copy:
<pre class="brush: php; title: ; notranslate">/app/code/core/Mage/Page/Block/Html/Topmenu.php</pre>
<p>to</p>
<pre class="brush: php; title: ; notranslate">/app/code/local/Mage/Page/Block/Html/Topmenu.php</pre>
<p>If you don’t have a folder structure in your local folder you will need to create it.</li>
<li>Find the <strong>protected function _getHtml </strong>(should begin at around line 84).<strong></strong></li>
<li>Now find this piece of code (lines 121-123):
<pre class="brush: php; title: ; notranslate">

$html .= '&lt;ul&gt;';
$html .= $this-&gt;_getHtml($child, $childrenWrapClass);
$html .= '&lt;/ul&gt;';
</pre>
</li>
<li>Add the following code just above the line with the closed ul tag:
<pre class="brush: php; title: ; notranslate">

$staticBlock = trim($this-&gt;getLayout()-&gt;createBlock('cms/block')-&gt;setBlockId($child-&gt;getId())-&gt;toHtml());
if(!empty($staticBlock)){
	$html .= '&lt;span style=&quot;background:#fff; border-top:1px solid #ccc; padding:10px;&quot;&gt;';
	$html .= $staticBlock;
	$html .= '&lt;/span&gt;';
}
</pre>
<p>The end result should look like this:</p>
<pre class="brush: php; title: ; notranslate">

$html .= '&lt;ul class=&quot;level' . $childLevel . '&quot;&gt;';
$html .= $this-&gt;_getHtml($child, $childrenWrapClass);
$staticBlock = trim($this-&gt;getLayout()-&gt;createBlock('cms/block')-&gt;setBlockId($child-&gt;getId())-&gt;toHtml());
if(!empty($staticBlock)){
	$html .= '&lt;span class=&quot;nav-static-block&quot; style=&quot;background:#fff; border-top:1px solid #ccc; padding:10px;&quot;&gt;';
	$html .= $staticBlock;
	$html .= '&lt;/span&gt;';
}
$html .= '&lt;/ul&gt;';
</pre>
<p>The implementation is simple, check if there is a static block with the identifier value set to current category ID with a prefix <strong>&#8220;category-node-&#8221;</strong>. If so, add the static block to the menu. The prefix is used because if you inspect the value of <strong>$chlid-&gt;getId()</strong> you will see that it returns a category ID with that prefix so, for example, if the category ID is <strong>&#8220;10&#8243;</strong> you will get <strong>&#8220;category-node-10&#8243;</strong>. I used this value because it is unique for each individual category.</p>
<p>I used some inline CSS for the sake of simplicity but you should use your own.</li>
<li>Now you need to create a static block with the identifier value set to whatever category <strong>Prefix+Category ID</strong> you want and you are all done! I used the default Magento sample data and created a static block with the identifier set to <strong>&#8220;category-node-10&#8243;</strong> because Furniture category has the id of 10. That&#8217;s it.</li>
</ol>
<p>Hope you&#8217;ll find this post helpful.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/how-to-add-static-blocks-to-main-navigation-dropdown/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Inchoo Demostore extension</title>
		<link>http://inchoo.net/ecommerce/magento/inchoo-demostore-extension/</link>
		<comments>http://inchoo.net/ecommerce/magento/inchoo-demostore-extension/#comments</comments>
		<pubDate>Tue, 08 May 2012 07:22:44 +0000</pubDate>
		<dc:creator>Darko Goles</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[demo]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[Tools & Frameworks]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=13715</guid>
		<description><![CDATA[In my last project, during development of API extension for Mageboard application, when started to develope Apple Push Notifications Services integration, one problem came out that took me too much &#8230;]]></description>
			<content:encoded><![CDATA[<p>In my last project, during development of API extension for <a title="Mageboard - your mobile dashboard" href="http://mageboard.inchoo.net/" target="_blank">Mageboard application</a>, when started to develope Apple Push Notifications Services integration, one problem came out that took me too much time each day to solve: Push notifications are supposed to be active only if some new order and/or customer is made on site.</p>
<p>So if there are no constant new orders and/or new customers, I can not test my APNS integration.<span id="more-13715"></span></p>
<p>At first I started to enter orders and customers manually on dev server, but it took much time, so I decided to do something to solve it.<br />
After some searching, i didn&#8217;t find the suitable extension to solve automatic creation of customers and orders as I need, so that&#8217;s the reason a new extension was made.</p>
<p>So let me list the features that I needed in new extension:</p>
<ul>
<li>Automatic creation of random customers with fully random names and addresses, e-mail adresses and other random personal data.</li>
<li>Automatic creation of orders with random order items in basket.</li>
<li>Automatic shipment</li>
<li>Automatic invoice</li>
<li>Make all of this features random</li>
<li>Work with cron job, so generation is happening periodically (every minute, or depends how my Magento cron is set).</li>
</ul>
<p>One interesting thing that I found when searching inside Magento core source code is a class Mage_Adminhtml_Model_Sales_Order_Random.</p>
<p>When I looked in code, it was obvious for me that this class was made for some purpose, but when trying to find where this class is used, I didn&#8217;t find nothing. Anyway, I decided to try this class to see if it works well, but this class has some serious issues in code that have to be rewritten in order to make it work.</p>
<p>So, here is my new order creation source code:</p>
<pre class="brush: php; title: ; notranslate">

&lt;!--?php &lt;br ?--&gt;
/*
 * @category Inchoo
 * @package Inchoo_Demostore
 * @author Darko Goleš
 * @copyright Inchoo
 * @license http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */

class Inchoo_Demostore_Model_Sales_Order_Random {

    protected $_quote;
    protected $_order;
    protected $_store;
    protected $_customer;
    protected $_productCollection;
    protected static $_storeCollection;
    protected static $_customerCollection;

    public function __construct() {
        $this-&gt;_quote = Mage::getModel('sales/quote')-&gt;save();
        $this-&gt;_order = Mage::getModel('sales/order');
    }

    protected function _getStores() {
        if (!self::$_storeCollection) {
            self::$_storeCollection = Mage::getResourceModel('core/store_collection')
                    -&gt;load();
        }
        return self::$_storeCollection-&gt;getItems();
    }

    protected function _getCustomers() {
        if (!self::$_customerCollection) {
            self::$_customerCollection = Mage::getResourceModel('customer/customer_collection')
                    -&gt;addAttributeToSelect('*')
                    -&gt;joinAttribute('billing_country_id', 'customer_address/country_id', 'default_billing', null, 'inner')
                    -&gt;joinAttribute('shipping_country_id', 'customer_address/country_id', 'default_shipping', null, 'inner')
                    -&gt;load();
        }

        return self::$_customerCollection-&gt;getItems();
    }

    protected function _getProducts() {
        if (!$this-&gt;_productCollection) {
            $this-&gt;_productCollection = Mage::getResourceModel('catalog/product_collection');
            Mage::getSingleton('catalog/product_status')-&gt;addVisibleFilterToCollection($this-&gt;_productCollection);
            $this-&gt;_productCollection-&gt;addAttributeToSelect('name')
                    -&gt;addAttributeToSelect('sku')
                    -&gt;addAttributeToFilter('type_id', Mage_Catalog_Model_Product_Type::TYPE_SIMPLE)
                    -&gt;load();
        }

        return $this-&gt;_productCollection-&gt;getItems();
    }

    protected function _getCustomer() {
        if (!$this-&gt;_customer) {
            $items = $this-&gt;_getCustomers();
            $randKey = array_rand($items);
            $this-&gt;_customer = $items[$randKey];
        }
        return $this-&gt;_customer;
    }

    protected function _getRandomProduct() {
        $items = $this-&gt;_getProducts();
        $randKey = array_rand($items);
        return isset($items[$randKey]) ? $items[$randKey] : false;
    }

    protected function _getStore() {
        if (!$this-&gt;_store) {
            $items = $this-&gt;_getStores();
            $randKey = array_rand($items);
            $this-&gt;_store = $items[$randKey];
        }
        return $this-&gt;_store;
    }

    public function createOrder() {
        $customer = $this-&gt;_getCustomer();

        $this-&gt;_quote-&gt;setStore($this-&gt;_getStore())
                -&gt;setCustomer($customer)-&gt;setCustomerIsGuest(0);
        $this-&gt;_quote-&gt;getBillingAddress()-&gt;importCustomerAddress($customer-&gt;getDefaultBillingAddress());
        $this-&gt;_quote-&gt;getShippingAddress()-&gt;importCustomerAddress($customer-&gt;getDefaultShippingAddress());

        $productCount = rand(3, 10);
        for ($i = 0; $i &lt; $productCount; $i++) {             $product = $this-&gt;_getRandomProduct();
            if ($product) {
                $product-&gt;setQuoteQty(1);

                $stockData = $product-&gt;getStockData();
                if (!$stockData) {
                    $product = $product-&gt;load($product-&gt;getId());
                    $stockData = array(
                        'manage_stock' =&gt; 1,
                        'is_in_stock' =&gt; 1,
                        'qty' =&gt; 1
                    );

                    $product-&gt;setStockData($stockData);
                    $product-&gt;save();
                }
                $this-&gt;_quote-&gt;addProduct($product);
            }
        }

        $this-&gt;_quote-&gt;getPayment()-&gt;setMethod('checkmo');
        $this-&gt;_quote-&gt;getShippingAddress()-&gt;setShippingMethod('flatrate_flatrate'); //-&gt;collectTotals()-&gt;save();
        $this-&gt;_quote-&gt;getShippingAddress()-&gt;setCollectShippingRates(true);
        $this-&gt;_quote-&gt;collectTotals()
                -&gt;save();
        $this-&gt;_quote-&gt;save();

        $service = Mage::getModel('sales/service_quote', $this-&gt;_quote);
        $service-&gt;submitAll();

        $order = $service-&gt;getOrder();
        $rand = rand(1, 4);

        switch ($rand) {
            case 1:
                $this-&gt;invoiceOrder($order);
                break;
            case 2:
                $this-&gt;shipOrder($order);
                break;
            case 3:
                $this-&gt;invoiceOrder($order);
                $this-&gt;shipOrder($order);
                break;
            default:
                break;
        }

        return $this;
    }

    protected function invoiceOrder($order) {

        try {

            if (!$order-&gt;canInvoice()) {
                $order-&gt;addStatusHistoryComment('Inchoo_Invoicer: Order cannot be invoiced.', false);
                $order-&gt;save();
            }

            $invoice = Mage::getModel('sales/service_order', $order)-&gt;prepareInvoice();

            $invoice-&gt;setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_OFFLINE);
            $invoice-&gt;register();

            $invoice-&gt;getOrder()-&gt;setCustomerNoteNotify(false);
            $invoice-&gt;getOrder()-&gt;setIsInProcess(true);
            $order-&gt;addStatusHistoryComment('Automatically INVOICED by Inchoo_Invoicer.', false);

            $transactionSave = Mage::getModel('core/resource_transaction')
                    -&gt;addObject($invoice)
                    -&gt;addObject($invoice-&gt;getOrder());

            $transactionSave-&gt;save();
        } catch (Exception $e) {
            Mage::logException($e);
        }
    }

    protected function shipOrder($order) {

        try {
            $shipment = $order-&gt;prepareShipment();
            $shipment-&gt;register();

            $order-&gt;setIsInProcess(true);
            $order-&gt;addStatusHistoryComment('Automatically SHIPPED by Inchoo_Invoicer.', false);

            $transactionSave = Mage::getModel('core/resource_transaction')
                    -&gt;addObject($shipment)
                    -&gt;addObject($shipment-&gt;getOrder())
                    -&gt;save();
        } catch (Exception $e) {
            Mage::logException($e);
        }
    }

}
</pre>
<p>As you can see from source code, invoice and shipment will not be generated every time, but random sometimes shipment, sometimes order, sometimes both and sometimes nothing.</p>
<pre class="brush: php; title: ; notranslate">

       $order = $service-&gt;getOrder();
        $rand = rand(1, 4);

        switch ($rand) {
            case 1:
                $this-&gt;invoiceOrder($order);
                break;
            case 2:
                $this-&gt;shipOrder($order);
                break;
            case 3:
                $this-&gt;invoiceOrder($order);
                $this-&gt;shipOrder($order);
                break;
            default:
                break;
        }
</pre>
<p>There are bunch of articles here on inchoo.net about programatically creating orders and/or customers, so this article is not about how to do it, but rather to inform the community that the extension that I am talking about is available on Magento Connect under name: Inchoo Demostore, so, Dear developers, if you need to save some time, feel free to install it to dynamically &#8211; periodically create new customers and orders on your development or some demo server.</p>
<p>I am aware that this extension can be improved with possible configuration options added, maybe on admin side, adding additional features for creating orders, random quantities for order items, but, hey &#8211; this extension is made for developers to save their time, and I don&#8217;t see a problem if someone wants to improve it. For me, it it enough to give fresh data to demo store for <a title="Mageboard" href="http://mageboard.inchoo.net/" target="_blank">Mageboard Application</a>.</p>
<p>Cheers.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/inchoo-demostore-extension/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Magento mobile theme &#8211; imobile</title>
		<link>http://inchoo.net/ecommerce/magento/magento-mobile-theme-imobile/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-mobile-theme-imobile/#comments</comments>
		<pubDate>Mon, 07 May 2012 11:22:43 +0000</pubDate>
		<dc:creator>Stanislav Mihic</dc:creator>
				<category><![CDATA[Frontend]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Mobile web]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[magento theme]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[responsive design]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=14461</guid>
		<description><![CDATA[Magento meets jQuery mobile (ver 1.1.0), before we start please note this is only experiment, use this theme on your own, this is not (yet) production ready. In a nutshell &#8230;]]></description>
			<content:encoded><![CDATA[<p>Magento meets jQuery mobile (ver 1.1.0), before we start please note <strong>this is only experiment, use this theme on your own, this is not (yet) production ready</strong>. In a nutshell we have &#8220;package&#8221; under which we place all edited files. For start we use magento iphone theme and then add some &#8220;extra stuff&#8221;.<span id="more-14461"></span></p>
<p>Some of key features:</p>
<ul>
<li>Autodetects the mobile device</li>
<li>jQuery mobile (v. 1.1.0)</li>
<li>Homepage slider (<a href="http://swipejs.com/">http://swipejs.com/</a>)</li>
<li>Almost all pages styled <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
</ul>
<p>Installation is simple, just copy downloaded files, (app, skin) after that go to administration and do some Magento magic. Magento already have browser detection, you only need to create rule. In our case we dropped table support because most of them will display normal desktop view store. Here is rule:</p>
<pre class="brush: php; title: ; notranslate">
iPhone|iPod|BlackBerry|Palm|Googlebot-Mobile|mobile|mobi|Windows Mobile|Safari Mobile|Android|Opera Mini|Fennec
</pre>
<p>You can add any other browser to this Expression, just point your device to <a href="http://whatsmyuseragent.com/">http://whatsmyuseragent.com/</a> and find out user agent name of device browser. And this is how it looks in administration</p>
<div id="attachment_14465" class="wp-caption aligncenter" style="width: 619px"><a href="http://inchoo.net/wp-content/uploads/2012/05/packagesettings.jpg"><img class=" wp-image-14465 " title="packagesettings" src="http://inchoo.net/wp-content/uploads/2012/05/packagesettings.jpg" alt="" width="609" height="238" /></a><p class="wp-caption-text">Using expressions</p></div>
<p>We need to mention that theme is independent from main store theme, all files which are edited don&#8217;t &#8220;break&#8221; default Magento markup we are only using power of HTML5 and one of the new cool feature &#8220;<a href="http://www.w3.org/html/wg/html5/#custom">custom data attributes</a>&#8220;.</p>
<blockquote><p>Simply, the specification for custom data attributes states that any attribute that starts with &#8220;data-&#8221; will be treated as a storage area for private data (private in the sense that the end user can&#8217;t see it &#8211; it doesn&#8217;t affect layout or presentation).</p></blockquote>
<p>Short explanation by <a href="http://ejohn.org/blog/html-5-data-attributes/">John Resig</a></p>
<p>And here is our example for store header:</p>
<pre class="brush: php; title: ; notranslate">&lt;/pre&gt;
&lt;div data-role=&quot;header&quot; data-position=&quot;inline&quot; data-theme=&quot;c&quot;&gt;
&lt;h1&gt;&lt;a href=&quot;&lt;?php echo $this-&gt;getUrl('') ?&gt;&quot; data-icon=&quot;home&quot;&gt;
&lt;img src=&quot;&lt;?php echo $this-&gt;getLogoSrc() ?&gt;&quot; alt=&quot;&lt;?php echo $this-&gt;getLogoAlt() ?&gt;&quot; /&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;!--?php echo $this-----&gt;getChildhtml('top-user');?&gt;&lt;/div&gt;
&lt;pre&gt;</pre>
<p>We don&#8217;t have any local hosted files regarding to jQuery because it is much easier to edit and place the newest version of js.</p>
<pre class="brush: php; title: ; notranslate">
					&lt;![CDATA[&lt;script type=&quot;text/javascript&quot; src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js&quot;&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot;&gt;jQuery.noConflict();&lt;/script&gt;]]&gt;
					&lt;![CDATA[&lt;script type=&quot;text/javascript&quot; src=&quot;http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js&quot;&gt;&lt;/script&gt;]]&gt;
				&lt;![CDATA[		&lt;link rel=&quot;stylesheet&quot; href=&quot;http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css&quot; /&gt;]]&gt;
            skin_jsjs/swipe.js
</pre>
<p>Ah, if you need more info about jQuery mobile framework go to: <a href="http://jquerymobile.com/">http://jquerymobile.com/</a>.</p>
<p>Swipe JS, <a href="http://swipejs.com/">http://swipejs.com/</a>,</p>
<blockquote><p>Swipe is a lightweight mobile slider with 1:1 touch movement, resistant bounds, scroll prevention, and completely library agnostic. <img src='http://inchoo.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .</p></blockquote>
<p>Ok, we made simple approach, create static block, named Slider with ID slider and place this code</p>
<pre class="brush: php; title: ; notranslate">&lt;/pre&gt;
&lt;div style=&quot;display: block;&quot;&gt;&lt;img src=&quot;{{media url=&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;
&lt;div style=&quot;display: none;&quot;&gt;&lt;img src=&quot;{{media url=&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;
&lt;div style=&quot;display: none;&quot;&gt;&lt;img src=&quot;{{media url=&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;
&lt;div style=&quot;display: none;&quot;&gt;&lt;img src=&quot;{{media url=&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;
&lt;pre&gt;
</pre>
<p>If is there no needs for homepage slider just removed it from local.xml (from line 44).</p>
<p>For styling pages, we cover most of them but there is always more space to improve some part of Magento interface.</p>
<p>For demo and download go to our demo store <a href="http://imobile.inchoo4u.net">http://imobile.inchoo4u.net</a> with your smartphone, emulate in browser (change user agent), <a href="https://github.com/doxikus/imobile">visit @ github</a>, or just scan this QR code.</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/05/qr.png"><img class="aligncenter size-full wp-image-14484" title="qr" src="http://inchoo.net/wp-content/uploads/2012/05/qr.png" alt="" width="400" height="400" /></a></p>
<p>So if you have any suggestion, issues, trouble just comment below, enjoy</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-mobile-theme-imobile/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Magento API v2 SOAP demystified</title>
		<link>http://inchoo.net/ecommerce/magento/magento-v2-soap-demystified/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-v2-soap-demystified/#comments</comments>
		<pubDate>Thu, 26 Apr 2012 12:35:21 +0000</pubDate>
		<dc:creator>Darko Goles</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[Mobile web]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[SOAP]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[Web sercvices]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=13588</guid>
		<description><![CDATA[Last few weeks, i often see confused people asking questions about difference between Magento&#8217;s API v1 and v2, and also bunch of questions about how to use WSDL and WS-I &#8230;]]></description>
			<content:encoded><![CDATA[<p>Last few weeks, i often see confused people asking questions about difference between Magento&#8217;s API v1 and v2, and also bunch of questions about how to use WSDL and WS-I files when developing own or extending existing Magento soap API v2.<br />
It is obvious that short articles about specific Magento API parts will not help them to get the bigger picture about Magento core API v2. Because of that, I decided to demystify practical usage of Magento API v2 and also to explain difference when using v1 and/or v2 API.</p>
<p>Let&#8217;s start from beginning, to everything clear later:</p>
<p><span id="more-13588"></span></p>
<h2>SOAP basics</h2>
<p><strong>SOAP</strong> = Simple Object Access Protocol. It is based on XML mostly via HTTP (POST).<br />
Soap basic structure is basically Envelope with Header and Body inside:</p>
<div id="attachment_13605" class="wp-caption aligncenter" style="width: 291px"><a href="http://inchoo.net/wp-content/uploads/2012/04/Soap-structure.jpg"><img class="size-thumbnail wp-image-13605" title="Soap structure" src="http://inchoo.net/wp-content/uploads/2012/04/Soap-structure-281x300.jpg" alt="Soap structure" width="281" height="300" /></a><p class="wp-caption-text">Soap structure</p></div>
<p>Some example SOAP message looks like this:</p>
<pre class="brush: php; title: ; notranslate">

POST /InStock HTTP/1.1
Host: www.example.org
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 299
SOAPAction: &quot;http://www.w3.org/2003/05/soap-envelope&quot;

&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;soap:Envelope xmlns:soap=&quot;http://www.w3.org/2003/05/soap-envelope&quot;&gt;
  &lt;soap:Header&gt;
  &lt;/soap:Header&gt;
  &lt;soap:Body&gt;
     &lt;m:GetStockPrice xmlns:m=&quot;http://www.example.org/stock&quot;&gt;
     &lt;m:StockName&gt;IBM&lt;/m:StockName&gt;
     &lt;/m:GetStockPrice&gt;
  &lt;/soap:Body&gt;
&lt;/soap:Envelope&gt;
</pre>
<h4>WSDL</h4>
<p><strong>WSDL</strong> stands for: “Web Services Description Language”. It is basically XML &#8211; based language that is used for describing the functionality offered by a web service.</p>
<p>There are two possible versions of WSDL: WSDL 1.1 and WSDL 2.0. Since Magento uses WSDL 1.1, I will continue with this WSDL version in this article.</p>
<p><strong>Objects in WSDL</strong></p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/wsdl_objects.jpg"><img class="aligncenter size-full wp-image-13611" title="wsdl_objects" src="http://inchoo.net/wp-content/uploads/2012/04/wsdl_objects.jpg" alt="" width="609" height="388" /></a></p>
<h4>Magento Core API</h4>
<p>There are two API types present in Magento by default (I am talking about Magento versions 1.6.2CE and below):</p>
<ul>
<li>XML-RPC</li>
<li>SOAP (API v1 and v2)</li>
</ul>
<p>More on API types and differences you can find in post: <a title="Mobile development" href="http://inchoo.net/mobile-development/iphone-development/consuming-soap-web-services-in-ios/" target="_blank">Consuming SOAP web services in iOS</a> by Ivan Kalaica</p>
<h2>Accessing Magento API via SOAP &#8211; basic steps</h2>
<ol>
<li>Create appropriate role (Magento Admin)</li>
<li>Create web services user (Magento Admin)</li>
<li>Assign created role to the user (Magento Admin)</li>
<li>Log-in to web service and retrieve Session Id (Soap Client)</li>
<li>Call appropriate method (Soap Client)</li>
</ol>
<h4>Creating Web Service Role</h4>
<p style="text-align: left;">First we should define appropriate roles for web services user, so, log-in to admin panel, go to menu: System/Web services/Roles and click on Add New Role button.</p>
<p style="text-align: left;"><a href="http://inchoo.net/wp-content/uploads/2012/04/roles11.jpg"><img class="size-thumbnail wp-image-13631 aligncenter" title="roles1" src="http://inchoo.net/wp-content/uploads/2012/04/roles11-300x225.jpg" alt="" width="300" height="225" /></a><br />
On “Role info” tab, we need to enter some custom Role name, and then click on Role resources tab, choose wanted role resources and Save Role.</p>
<p style="text-align: left;"><a href="http://inchoo.net/wp-content/uploads/2012/04/Role_resources.jpg"><img class="aligncenter size-thumbnail wp-image-13626" title="Role_resources" src="http://inchoo.net/wp-content/uploads/2012/04/Role_resources-300x225.jpg" alt="" width="300" height="225" /></a></p>
<p>Role resources necessary for usage with API are basically defined in each Magento module&#8217;s api.xml file in etc folder, and can be checked there what role resources are needed for successful consuming specific API method.</p>
<h4>Creating Web Service User</h4>
<p>After creating role, let&#8217;s create web services user that will have defined role permissions.<br />
Go to menu: System/Web Services/Users and click on “Add New User” button. Under “User Info” tab fill the fields, and pay attention that “User Name” and “API key” values are values that we will use on client side to access API.</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/web_services_user.jpg"><img class="aligncenter size-thumbnail wp-image-13635" title="web_services_user" src="http://inchoo.net/wp-content/uploads/2012/04/web_services_user-300x225.jpg" alt="" width="300" height="225" /></a></p>
<h4>Assigning created Role to the User</h4>
<p>After that, we just have to click on User Role tab and click on radio-button to assign wanted role to current user.<br />
After that we just need to click Save User button.</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/user_role.jpg"><img class="aligncenter size-thumbnail wp-image-13636" title="user_role" src="http://inchoo.net/wp-content/uploads/2012/04/user_role-300x225.jpg" alt="" width="300" height="225" /></a></p>
<h4>Calling Magento API v1 methods</h4>
<pre class="brush: php; title: ; notranslate">

&lt;?php

$api_url_v1 = &quot;http://magento.local/api/soap/?wsdl=1&quot;;

$username = 'mobile';
$password = 'mobile123';

$cli = new SoapClient($api_url_v1);

//retreive session id from login
$session_id = $cli-&gt;login($username, $password);

//call customer.list method
$result = $cli-&gt;call($session_id, 'customer.list', array(array()));
</pre>
<h4>Calling Magento API v2 methods</h4>
<pre class="brush: php; title: ; notranslate">

&lt;?php

$api_url_v2 = &quot;http://magento.local/api/v2_soap/?wsdl=1&quot;;

$username = 'mobile';
$password = 'mobile123';

$cli = new SoapClient($api_url_v2);

//retreive session id from login
$session_id = $cli-&gt;login($username, $password);

//call customer.list method
$result = $cli-&gt;customerCustomerList($session_id);
</pre>
<p>If you compare those two versions of API calls, you will notice that v1 uses method “call” for ever requested method, and v2 has defined full method name to call.</p>
<pre class="brush: php; title: ; notranslate">
//API v1 way
$result = $cli-&gt;call($session_id, 'customer.list', array(array()));

//API v2 way
$result = $cli-&gt;customerCustomerList($session_id);&lt;/pre&gt;
</pre>
<p>Basically, API v2 calls method same way like v1, but there is some kind of wrapper around call method in v2. Somebody will ask: Why Magento did something like this? Why would somebody make different methods for accessing API when we have “call” method already?</p>
<p>Here comes the basic difference between v1 and v2 API in Magento.</p>
<p>To demystify that, we should first look at and compare WSDL for v1 and v2 API in Magento.</p>
<p>If we open url: <strong>http://yourserver.com/api/<em>soap</em>/?wsdl</strong> we can see that few basic method are inside: call, multiCall, login etc&#8230;<br />
But, if we look at <strong>http://yourserver.com/api/<em>v2_soap</em>/?wsdl</strong>, we will find that there is bunch of methods defined inside.</p>
<p>Imagine that you want to use some generator for SOAP methods to auto-generate your client-side classes end entities for consuming web services.<br />
When using WSDL generated for API v1, we could just generate those few methods which will not tell to our source code generator what methods are available, and what parameters for each methods can we use, what entities we should have on client side &#8230; but if we are consuming web services through v2 API, it&#8217;s already served for us inside WSDL&#8230;</p>
<p><strong>Conclusion:</strong></p>
<p>When using Magento v1 API, we access resources via call method and provide API method name and parameters as parameters of call method.</p>
<p>When using Magento v2 API, we access resources via real method name and we provide parameters as defined in WSDL for each specific method.</p>
<p>OK. When we got this difference, and showed how to consume SOAP, let&#8217;s focus on creating own web service methods compatible with API v2.</p>
<h2>Practical example: Creating own API v2 method</h2>
<h4>Basic steps:</h4>
<p>1. Create Magento Extension (we are not going explain here how to do it)<br />
2. Create Model for API method<br />
3. Create and configure api.xml file<br />
4. Create wsdl.xml file (with proper definitions)<br />
5. Create wsi.xml file (with proper definitions) (OPTIONAL)</p>
<h4>Creating Model for API v2</h4>
<p>After properly configuring our config.xml it looks like this:</p>
<pre class="brush: php; title: ; notranslate">

&lt;?xml version=&quot;1.0&quot;?&gt;

&lt;config&gt;
   &lt;modules&gt;
      &lt;Inchoo_Mapy&gt;
         &lt;version&gt;1.0.1&lt;/version&gt;
      &lt;/Inchoo_Mapy&gt;
   &lt;/modules&gt;
   &lt;global&gt;
      &lt;models&gt;
         &lt;inchoo_mapy&gt;
             &lt;class&gt;Inchoo_Mapy_Model&lt;/class&gt;
         &lt;/inchoo_mapy&gt;
      &lt;/models&gt;
   &lt;/global&gt;
&lt;/config&gt;
</pre>
<p>Let&#8217;s navigate through Magento core files to see where Magento API models are in file-system:</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/CoreApiModelsLocation.jpg"><img class="aligncenter size-full wp-image-13648" title="CoreApiModelsLocation" src="http://inchoo.net/wp-content/uploads/2012/04/CoreApiModelsLocation.jpg" alt="" width="609" height="398" /></a></p>
<p>Since we are going to use API v2 only, We will create our model like this:</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/ModelLocation.jpg"><img class="aligncenter size-full wp-image-13650" title="ModelLocation" src="http://inchoo.net/wp-content/uploads/2012/04/ModelLocation.jpg" alt="" width="274" height="235" /></a></p>
<pre><a href="http://inchoo.net/wp-content/uploads/2012/04/ModelSource.jpg"><img class="aligncenter size-full wp-image-13657" title="ModelSource" src="http://inchoo.net/wp-content/uploads/2012/04/ModelSource.jpg" alt="" width="609" height="411" /></a></pre>
<h4>Creating and configuring api.xml</h4>
<p>The easiest way is to copy/paste one of Magento&#8217;s api.xml files in our etc folder and make changes there to suit our needs. Our final api.xml should look like this:</p>
<pre class="brush: php; title: ; notranslate">

&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
   &lt;api&gt;
     &lt;resources&gt;
     &lt;!-- START GUSTOMER GROUP RESOURCES --&gt;
       &lt;mapy_customer_group&gt;
            &lt;model&gt;inchoo_mapy/customer_group_api&lt;/model&gt;
            &lt;title&gt;Inchoo Customer's Groups API&lt;/title&gt;
            &lt;acl&gt;mapy_data&lt;/acl&gt;
            &lt;methods&gt;
              &lt;list translate=&quot;title&quot; module=&quot;inchoo_mapy&quot;&gt;
                  &lt;title&gt;Retrieve customer groups&lt;/title&gt;
                  &lt;method&gt;mapyItems&lt;/method&gt;
              &lt;/list&gt;
            &lt;/methods&gt;
       &lt;/mapy_customer_group&gt;
     &lt;!-- END CUSTOMER GROUP RESOURCES --&gt;
    &lt;/resources&gt;
    &lt;v2&gt;
      &lt;resources_function_prefix&gt;
           &lt;mapy_customer_group&gt;mapy_customerGroup&lt;/mapy_customer_group&gt;
           &lt;/resources_function_prefix&gt;
    &lt;/v2&gt;
    &lt;acl&gt;
       &lt;resources&gt;
           &lt;mapy_data translate=&quot;title&quot; module=&quot;inchoo_mapy&quot;&gt;
              &lt;title&gt;Mapy data&lt;/title&gt;
              &lt;sort_order&gt;3&lt;/sort_order&gt;
           &lt;/mapy_data&gt;
       &lt;/resources&gt;
    &lt;/acl&gt;
  &lt;/api&gt;
&lt;/config&gt;
</pre>
<p>Here is logic that has to be implemented in api.xml file. Api.xml file basically connects API calls with php methods inside specific models. Also, the ACL resources are defined here for specific api call.</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/api_xml_explained.jpg"><img class="aligncenter size-medium wp-image-13659" title="api_xml_explained" src="http://inchoo.net/wp-content/uploads/2012/04/api_xml_explained-600x414.jpg" alt="" width="600" height="414" /></a></p>
<h4>Creating wsdl.xml file</h4>
<p>When working with wsdl.xml and wsi.xml later, if you are happy NetBeans user, I strongly suggest you to search on Google and download the XML Tools plug-in that can make life much easier &#8230;</p>
<p>There are few things that we have to fill-in when creating wsdl.xml.</p>
<ul>
<li>Bindings</li>
<li>Port types</li>
<li>Messages</li>
<li>Types / Complex types</li>
</ul>
<p>Also, it&#8217;s easier to copy one of Magento&#8217;s wsdl files, paste it in our etc folder and remove unnecessary things and add our own inside.</p>
<p>Here is NetBeans &#8211; XML Tools screen-shot how this look like:</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/wsdl_struct.jpg"><img class="aligncenter size-medium wp-image-13664" title="wsdl_struct" src="http://inchoo.net/wp-content/uploads/2012/04/wsdl_struct-600x430.jpg" alt="" width="600" height="430" /></a></p>
<p>This  image is showing logic and direction how should we fill-in wsdl.xml:</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/wsdl_filling.jpg"><img class="aligncenter size-medium wp-image-13669" title="wsdl_filling" src="http://inchoo.net/wp-content/uploads/2012/04/wsdl_filling-600x393.jpg" alt="" width="600" height="393" /></a></p>
<p>Let&#8217;s now look at real xml source:</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/Bindings.jpg"><img class="aligncenter size-medium wp-image-13677" title="Bindings" src="http://inchoo.net/wp-content/uploads/2012/04/Bindings-600x416.jpg" alt="" width="600" height="416" /></a></p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/Port-types.jpg"><img class="aligncenter size-medium wp-image-13678" title="Port types" src="http://inchoo.net/wp-content/uploads/2012/04/Port-types-600x391.jpg" alt="" width="600" height="391" /></a></p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/Messages.jpg"><img class="aligncenter size-medium wp-image-13679" title="Messages" src="http://inchoo.net/wp-content/uploads/2012/04/Messages-600x373.jpg" alt="" width="600" height="373" /></a></p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/complex-types.jpg"><img class="aligncenter size-medium wp-image-13680" title="complex types" src="http://inchoo.net/wp-content/uploads/2012/04/complex-types-600x449.jpg" alt="" width="600" height="449" /></a></p>
<p>After we finished with wsdl, let&#8217;s go to <strong>http://ourmagento/api/v2_soap/?wsdl=1</strong> to see changes in global wsdl we made. (<strong>Don&#8217;t forget to clear cache first!</strong>).</p>
<p>We can see that all wsdl.xml files including ours are rendered as single.</p>
<p>All available wsdl definitions for current Magento installations are shown and our definitions should be there.</p>
<p>Now we are ready to use our newly created SOAP method.</p>
<p>But, if we want use some generator for client classes with that, for example <a href="http://sudzc.com" target="_blank">SUDZC</a> (http://sudzc.com) we need to make one more thing in order to make it possible&#8230;</p>
<h4>WSI</h4>
<p>- WSI is in basic compatibility layer for different frameworks and provides a little bit more information that can be used for example with XSLT to transform definitions into our client source code.<br />
- It&#8217;s not essential in order web services to work.<br />
- It is rendered when: Magento admin: System/Configuration/Services/Magento core API/WSI-Compliance configuration value is set to “YES”.</p>
<p>We could say that following sections we have to fill-in inside, in order to add our definitions properly:</p>
<ul>
<li>Bindings</li>
<li>Port types</li>
<li>Messages</li>
<li>Types / elements</li>
<li>Types / complex types</li>
</ul>
<p>Let&#8217;s copy/paste one of Magento&#8217;s wsi.xml inside our etc folder first. After that, let&#8217;s delete all unnecessary definitions for our SOAP method.</p>
<p>Adding definitions inside WSI except for slightly different definitions are basically the same as for wsdl.xml. If you are using existing wsi.xml, it&#8217;s easy to delete unnecessary and rename few nodes to suit your needs. Just follow the rule to fill all of this in the above list (Bindings, Port types &#8230; ).</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/04/SOAP_xml.zip">Here you can download archive with basic wsdl.xml, wsi.xml, api.xml so you can easier start writing</a> your own web service methods. Just put these files in your etc folder, rename appropriate things with your own and that&#8217;s it.</p>
<p>That would be all for now. If interested in Magento API, stay tuned.</p>
<p>Cheers <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-v2-soap-demystified/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Injecting Variables into a Magento CMS static block</title>
		<link>http://inchoo.net/ecommerce/magento/injecting-variables-into-a-magento-cms-static-block/</link>
		<comments>http://inchoo.net/ecommerce/magento/injecting-variables-into-a-magento-cms-static-block/#comments</comments>
		<pubDate>Mon, 23 Apr 2012 09:30:44 +0000</pubDate>
		<dc:creator>Thomas Spigel</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[cms]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=13459</guid>
		<description><![CDATA[In this tutorial i&#8217;ll show you how to inject any custom variable you need into a cms static block in place of a {{var variable_name}} tag. You&#8217;ve seen this in &#8230;]]></description>
			<content:encoded><![CDATA[<p>In this tutorial i&#8217;ll show you how to inject any custom variable you need into a cms static block in place of a {{var variable_name}} tag. You&#8217;ve seen this in the email templates if you were working on them (in the matter of fact the model (filter) we&#8217;re calling is extending the same filter the email templates are using for injecting the variables).<span id="more-13459"></span></p>
<p>First, let&#8217;s assume a few things:<br />
1) the package is named &#8216;Company&#8217; and the module is named &#8216;Module&#8217;<br />
2) you know how to make a php module and a new block class. The block&#8217;s alias is in this example &#8216;module/dynamic&#8217;<br />
3) the phtml template for the dynamic block will be dynamic.phtml<br />
4) the block id of the static cms block will be &#8216;static_block&#8217; (and you already created it in the admin)<br />
5) you need to add the email of the current customer to the static block. The logic of when you want to show the block and everything deeper is out of the scope of this document.</p>
<p>First let&#8217;s look @ the phtml file, which only uses the method which we&#8217;ll create afterwards in the block class:</p>
<pre class="brush: php; title: ; notranslate">

&lt;?php if(Mage::getSingleton('customer/session')-&gt;getCustomer()-&gt;getId()) : ?&gt;
	&lt;?php echo $this-&gt;getStaticBlock();?&gt;
&lt;?php endif;?&gt;
</pre>
<p>As you see, we&#8217;re only checking if the customer is set and are getting the static block. So next let&#8217;s see the logic in the dynamic block class:</p>
<pre class="brush: php; title: ; notranslate">

&lt;?php
/**
 * Just another block class
 */
class Company_Module_Block_Dynamic extends Mage_Core_Block_Template
{
	/**
	 * This getter will return the html of your static block
	 * @return string
	 */
	public function getStaticBlock()
	{
		// loading the static block
		$block = Mage::getModel('cms/block')
		-&gt;setStoreId(Mage::app()-&gt;getStore()-&gt;getId())
		-&gt;load('static_block');
		/* @var $block Mage_Cms_Model_Block */

		// setting the assoc. array we send to the filter.
		$array = array();
		// the array keys are named after the tags in the static block. let's say $array['customer_email'] is {{var customer_email}} in the static block. you can set as many variables you need.
		$array['customer_email'] = Mage::getSingleton('customer/session')-&gt;getCustomer()-&gt;getEmail();

		// loading the filter which will get the array we created and parse the block content
		$filter = Mage::getModel('cms/template_filter');
		/* @var $filter Mage_Cms_Model_Template_Filter */
		$filter-&gt;setVariables($array);

		// return the filtered block content.
		return $filter-&gt;filter($block-&gt;getContent());

	}
}
?&gt;
</pre>
<p>Ok. Now enter somewhere in your static_block CMS block the tag {{var customer_email}} (or some other key you added) and it&#8217;ll be dynamically added into CMS block.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/injecting-variables-into-a-magento-cms-static-block/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>How to implement rel=prev and rel=next to Magento&#8217;s pagination?</title>
		<link>http://inchoo.net/ecommerce/magento/how-to-implement-relprev-and-relnext-to-magentos-pagination/</link>
		<comments>http://inchoo.net/ecommerce/magento/how-to-implement-relprev-and-relnext-to-magentos-pagination/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 09:40:58 +0000</pubDate>
		<dc:creator>Vanja Devcic</dc:creator>
				<category><![CDATA[Configuration]]></category>
		<category><![CDATA[Integration]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Search]]></category>
		<category><![CDATA[seo]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=13254</guid>
		<description><![CDATA[As most of you know that &#8220;When dealing with online stores with a lot of products, pagination on category pages can get really problematic for search engines&#8221; like Toni Anicic &#8230;]]></description>
			<content:encoded><![CDATA[<p>As most of you know that &#8220;When dealing with online stores with a lot of products, pagination on category pages can get really problematic for search engines&#8221; like Toni Anicic wrote in his <a href="http://inchoo.net/online-marketing/how-do-relnext-and-relprev-work/">article</a>. I don&#8217;t want to repeat his words, but to show you how you can add rel=&#8221;prev&#8221; and rel=&#8221;next&#8221; link tag attributes in the head tag for pages, which will boost your SEO. This peace of code is already provided by Magento community, but this is improved version.<span id="more-13254"></span></p>
<p><strong>Tested in Magento CE 1.6.1.0.</strong></p>
<h3>Implementation</h3>
<p>1. So, if you didn&#8217;t already modified head.phtml file, create identical directory hierarchy and copy/paste head.phtml in your theme or package.</p>
<p>Path example if using package:<br />
..\app\design\frontend\[your_package_name]\default\template\page\html\head.phtml</p>
<p>Path example if using theme:<br />
..\app\design\frontend\default\[your_theme_name]\template\page\html\head.phtml</p>
<p>2. Add code below to head.phtml. I&#8217;ve added code at the bottom of file.</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
$actionName = $this-&gt;getAction()-&gt;getFullActionName();
if ($actionName == 'catalog_category_view') // Category Page
{
    $category = Mage::registry('current_category');
    $prodCol = $category-&gt;getProductCollection()-&gt;addAttributeToFilter('status', 1)-&gt;addAttributeToFilter('visibility', array('in' =&gt; array(Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG, Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)));
    $tool = $this-&gt;getLayout()-&gt;createBlock('page/html_pager')-&gt;setLimit($this-&gt;getLayout()-&gt;createBlock('catalog/product_list_toolbar')-&gt;getLimit())-&gt;setCollection($prodCol);
    $linkPrev = false;
    $linkNext = false;
    if ($tool-&gt;getCollection()-&gt;getSelectCountSql()) {
        if ($tool-&gt;getLastPageNum() &gt; 1) {
            if (!$tool-&gt;isFirstPage()) {
                $linkPrev = true;
                if ($tool-&gt;getCurrentPage() == 2) {
                    $url = explode('?', $tool-&gt;getPreviousPageUrl());
                    $prevUrl = @$url[0];
                }
                else {
                    $prevUrl = $tool-&gt;getPreviousPageUrl();
                }
            }
            if (!$tool-&gt;isLastPage()) {
                $linkNext = true;
                $nextUrl = $tool-&gt;getNextPageUrl();
            }
        }
    }
    if ($linkPrev) echo '&lt;link rel=&quot;prev&quot; href=&quot;' . $prevUrl . '&quot; /&gt;';
    if ($linkNext) echo '&lt;link rel=&quot;next&quot; href=&quot;' . $nextUrl . '&quot; /&gt;';
}

?&gt;
</pre>
<h3>Result</h3>
<p>Below is a result if you are on page 3.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;head&gt;
...
&lt;link rel=&quot;prev&quot; href=&quot;http://www.example.com/store.html?p=2&quot;&gt;

&lt;link rel=&quot;next&quot; href=&quot;http://www.example.com/store.html?p=4&quot;&gt;
...
&lt;/head&gt;
</pre>
<h3>Search engine optimization in Magento&#8217;s Configuration</h3>
<p>After implementing rel=&#8221;prev&#8221; and rel=&#8221;next&#8221; you need to re-config Magento&#8217;s SEO options, which means that you don&#8217;t need anymore Canonical Link Meta Tag For Categories. Below is a example how we setup Magento&#8217;s SEO options for one of our clients.</p>
<p><a href="http://inchoo.net/ecommerce/magento/how-to-implement-relprev-and-relnext-to-magentos-pagination/attachment/seo_config/" rel="attachment wp-att-13267"><img class="alignnone size-full wp-image-13267" title="Magento's SEO Config" src="http://inchoo.net/wp-content/uploads/2012/04/seo_config.png" alt="" width="599" height="417" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/how-to-implement-relprev-and-relnext-to-magentos-pagination/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>The Difference</title>
		<link>http://inchoo.net/ecommerce/magento/the-difference-from-denmark-bilvask/</link>
		<comments>http://inchoo.net/ecommerce/magento/the-difference-from-denmark-bilvask/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 17:45:20 +0000</pubDate>
		<dc:creator>Zdravko Karanovic</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[customer care]]></category>
		<category><![CDATA[Portfolio]]></category>
		<category><![CDATA[support]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=13177</guid>
		<description><![CDATA[Hello Magento community! My name is Zdravko Karanovic and I work as a branch manager and a team leader here at Inchoo office in Serbia. As I am one of &#8230;]]></description>
			<content:encoded><![CDATA[<p>Hello Magento community! My name is Zdravko Karanovic and I work as a branch manager and a team leader here at Inchoo office in Serbia. As I am one of the few Inchooers who doesn&#8217;t code, I don&#8217;t get to write those exciting articles about extending controllers or making cool Magento modules for that latest social network.<br />
<span id="more-13177"></span><br />
As a team leader, my job is mostly of care and worry. I worry about my team, about their time, the work, the projects and their well-being. But most importantly we care about our clients. Here at Inchoo care about the clients and their business is a <strong>BIG</strong> thing. We shape our processes and work ethics around this idea, and that extraordinary care and effort we strive to make is what shaped us and made us into who we are today.</p>
<p>A story that perfectly reflects this attitude towards our clients started out 3 months ago when we were approached by Michael Vilnov from <a title="Bilvask.nu website" href="http://www.bilvask.nu" target="_blank">Bilvask.nu</a> to produce a new custom website for his car detailing company.</p>
<p>After our sales manager <a title="sells Magento, but only if we make it custom and from scratch" href="http://inchoo.net/author/aron/" target="_blank">Aron Stanic</a> won the deal we fired up the project with our marketing guru <a title="A SEO expert walks into a bar, bars, pub, tavern, public house, Irish pub, inchoo, bilvask, magento" href="http://inchoo.net/author/toni/" target="_blank">Toni Anicic</a> doing the wireframes. These were then passed on from Osijek to <a title="can design things not yet invented" href="http://inchoo.net/author/lyssandro-reis/" target="_blank">Lyssandro Reis</a> in Sydney, one of our best designers, with a task to work closely with Michael and produce the design templates. Time zone problems were surpassed and Lyssandro and Michael worked together using video chats and screencasts, almost as they were sitting in the same office.</p>
<p><img src="http://inchoo.net/wp-content/uploads/2012/04/bilvask-screenshot1.jpg" alt="Screenshot from Bilvask.nu website" title="Bilvask.nu Screenshot" width="620" height="451" class="alignright size-full wp-image-13193" />Once finished templates arrived at Novi Sad office, <a title="can spot if something is 0.5 pixels off" href="http://inchoo.net/author/srdjan.stojiljkovic/" target="_blank">Srdjan Stojiljkovic</a>, our frontend developer started to work on his HTML/CSS/JS magic, bringing life into those still Photoshop layers. At the same time <a title="will break Magento in ways never imagined" href="http://inchoo.net/author/nikola.stojiljkovic/" target="_blank">Nikola Stojiljkovic</a>, Srdjan&#8217;s brother and our backend developer was bending Magento to his own will, customizing it to serve our clients needs, as if the framework was tailored for them only.</p>
<p>Here is a short list of custom features we developed for Bilvask specific needs:</p>
<ul>
<li>backend controlled home page slider module</li>
<li>extensive contact form module, with backend control</li>
<li>customer uploaded images, backend control – with preview, and mass actions</li>
<li>AJAX top cart</li>
<li>custom main menu with dynamic content from static blocks</li>
<li>guide pages with integrated products</li>
<li>custom product reviews</li>
<li>split attributes for products</li>
<li>shipping quotes in customer cart page</li>
<li>custom sidebar for categories and sub categories</li>
<li>split descriptions for category pages</li>
</ul>
<p>Although we don&#8217;t like to use 3rd party extensions, client used quite a few of them, and we made sure they all played nicely with each other:</p>
<ul>
<li>Woopra Live Chat</li>
<li>J2T AJAX Add to Cart</li>
<li>One Step Checkout</li>
<li>Sweet Tooth Reward Points</li>
<li>Post Denmark</li>
<li>e-pay</li>
<li>schema org, Facebook Open Graph</li>
<li>Video Gallery</li>
</ul>
<p>So, did it end well? Did we surpass language barriers, conquered the timezones, and avoided extension pits with sharp spikes?</p>
<p>We approached Michael as he is the only one entitled to answer that question. When we asked him to write a short testimonial, he felt a need to go a step further and wrote up a review on his experience working with us from start to finish, explaining along the way our methodologies and work ethics.</p>
<p>Here is what he had to say:</p>
<h3>The difference between A: doing a job and B: doing a perfect job.</h3>
<div style="float:right; border:1px solid #84994A; background:#fff; margin:5px"><img alt="Michael Vilnov from Bilvask" src="http://www.bilvask.nu/media/MIchael-Vilnov.jpg" title="Michael Vilnov" class="alignright" width="200" height="277" style="margin:5px;" /></div>
<p>Our company <a title="Bilvask.nu website" href="http://www.bilvask.nu" target="_blank">Bilvask.nu</a>, is a Danish based Car detailing company with a webshop selling high-end car care equipment. Our daily work with luxury cars always requires a strong founded feeling of quality towards our work every single time. This being in all aspects of our relations, towards our clients, suppliers and partners.</p>
<p>However, on the IT development side of business, we’ve always had problems finding the same passion for reaching the ultimate result of perfection and customer service.</p>
<p>We stumbled upon Inchoo after searching for a solution partner for our new Magento store. We had been in the online business for a few years, and were now in the marked for a 100% custom made Magento store &#8211; to our exact specifications.</p>
<p>We chose Inchoo to make our new shop / website, because of several factors. The fact that they had <a title="Magento Silver Partners" href="http://www.magentocommerce.com/partners/details/partner/id/2465/" target="_blank">Magento Silver Partner Status</a>, and at the same time they had several employees Magento certified. This made Inchoo a trustworthy partner from the get go.</p>
<p>Starting at the first contact, working with Inchoo as a supplier of Magento web solutions have been a pure pleasure.</p>
<h4>First Contact, pre-work process</h4>
<p>First contact was replied fast, yet thoughtful. There was no sense of rush, yet a sense that the company didn&#8217;t just send you a standard email-answer, because of lack of time. The answer was prompt, and revealed a serious attitude towards taking care of other peoples business, other peoples livelihood.</p>
<p>The sketch up of the budget and site outline was made in due time, described in detail, nothing left out.<br />
Inchoo didn&#8217;t seem to be to interested in ”fitting” our budget, but more interested in giving a realistic price of the task as they saw it carried out in best practice.<br />
The initial offer Inchoo gave us was outlined as a best case, worst case and realistic case scenarios, with pricing for all the various turn of events.<br />
We’ve yet to see a better written partnership contract anywhere, and we’ve contacted a few before making our choice. The offer as well as fast contact made us confident in our choice, Inchoo was the company to go with.</p>
<h4>The actual work process</h4>
<p>Inchoo works within an agile project planning strategy &#8211; meaning, that all aspects of the shop build can be changed until a certain time of any process. This gives great opportunities to change elements as the build moves along, as there will always be aspects of a project this size, that will be able to be optimized as work goes deeper into details. Flaws are ironed as the work progresses, mistakes are caught, better and easier solutions are found along the way.</p>
<p>Inchoo’s way of leading us through the process of the build, with specialists on each phase:</p>
<ul>
<li>Wireframing phase</li>
<li>Design phase</li>
<li>Development phase</li>
<li>Launch phase</li>
<li>Aftercare phase</li>
</ul>
<p>This left us with a sense of constantly being in touch with the right people, who could give the feedback needed. We have at no point in the build been in doubt of who to contact, and the person who we wished to contact was never too busy to answer the phone, skype or email.</p>
<p>When making a project that lasts for several months, flaws will occur. Its humanly impossible to run a marathon without putting a foot wrong. Especially here, I think Inchoo showed the proper professionalism not trying to hide, cover or in any way make up excuses for time or progress being set back. Problems where explained and then dealt with, in fast and efficient manner.<br />
When all things are good, its easy to pad each other on the back and say great work, but when problems occur, this is when true work ethics show.</p>
<h4>Launch</h4>
<p>3 months after the first contact we had our launch. Minor bugs where taken care of in a fast and efficient manner. At no point have we experienced that our development team moved on to new projects. They are still as accessible as they where during our work process.</p>
<h4>Aftercare</h4>
<p>At the current time, it is difficult for us to value the aftercare that Inchoo offers, but rest a sure if it&#8217;s anything like what we’ve have experienced so far, and I cant wait to continue working with them in the future.</p>
<p>There is no doubt in my mind, that I will stick with the development team to continue creating a further success with our webshop.</p>
<p>To all of Inchoo – Thank you guys for a wonderful experience in work ethics.</p>
<p>It&#8217;s been a pure pleasure.</p>
<p>Michael Vilnov Hansen<br />
CEO<br />
<a title="Bilvask.nu website" href="http://www.bilvask.nu" target="_blank">Bilvask.nu</a></p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/the-difference-from-denmark-bilvask/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Magento certification cheat sheet revealed!</title>
		<link>http://inchoo.net/ecommerce/magento/magento-certification-cheat-sheet-revealed/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-certification-cheat-sheet-revealed/#comments</comments>
		<pubDate>Sun, 01 Apr 2012 06:55:23 +0000</pubDate>
		<dc:creator>Aron Stanic</dc:creator>
				<category><![CDATA[Fun & Events]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[april1]]></category>
		<category><![CDATA[certification]]></category>
		<category><![CDATA[cheat sheet]]></category>
		<category><![CDATA[magento certification]]></category>
		<category><![CDATA[magento certified developer]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=13049</guid>
		<description><![CDATA[After a joint effort of 42 developers worldwide who took the Magento Certified Developer exam over the last 12 weeks, we bring you the ultimate cheat sheet for getting certified &#8230;]]></description>
			<content:encoded><![CDATA[<p>After a joint effort of 42 developers worldwide who took the <strong>Magento Certified Developer</strong> exam over the last 12 weeks, we bring you the ultimate cheat sheet for getting certified &#8211; with a 100% pass rate guaranteed!<span id="more-13049"></span></p>
<p>&#8212;&#8212;</p>
<p><strong>EDIT:</strong> <em>This was, as most of you accurately guessed, an April Fools&#8217; Day joke. Thanks to everyone who joined in with their comments and for keeping the joke alive for some extra hours last Sunday &#8211; it was a rather obvious one (after all, who would simply share a cheat sheet, right? <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ), but we thought it would give you a couple of laughs. Happy certification, everyone!!!</em></p>
<p>&#8212;&#8212;</p>
<p>Here at Inchoo we have always taken pride in <a title="Marketing by sharing" href="http://inchoo.net/ecommerce/marketing-by-sharing/" target="_blank">sharing our knowledge</a> of Magento with the rest of the community, so this is only a continuation of a long-lasting tradition.</p>
<p>There&#8217;s been quite a few articles written on the whole certification process, one of the most recent ones being Ben Marks of Blue Acorn <a title="Ben Marks on Magento certification" href="http://www.blueacorn.com/magento-blog/certifiably-magento/" target="_blank">sharing his thoughts on how to become certified</a> - but this &#8211; this is something completely different!</p>
<p>We have <a title="Magento Certified Developers at Inchoo" href="http://inchoo.net/services/magento-development/" target="_blank">4 certified developers</a> today (haven’t used the cheat sheet ourselves yet), and with the results of our recent investigation (and with special thanks to all of you guys out there who were flunking the tests only to get us this invaluable info), there’s much more to come from us, and hopefully from all of you, our loyal readers and followers.</p>
<p>Have you just started poking around Magento but find it a bit overwhelming to pass the exam?</p>
<p>Or are you a Magento Solution Partner with little to none dedicated Magento developers, paying for your partner status simply because you can and outsourcing the development to other companies? You were probably worried when Magento announced you’ll need to have certified developers on board &#8211; well, worry no more &#8211; with our ultimate cheat sheet you can have your community managers pass the exam in their first try! Add a couple more people to the mix and you’re golden!</p>
<h3>Discovering the patterns</h3>
<p>This cheat sheet was prepared after we gathered the details about questions from 42 exams taken worldwide (it took quite an effort getting all these developers sneak in those mini cameras to capture the questions). Not in our wildest dreams did we expect to find clear answer patterns.</p>
<p>You can imagine our surprise when our consulting partner, a tenured professor at the University of Osijek’s <a title="Math Department" href="http://www.mathos.hr/en/" target="_blank">Department of Mathematics</a>, told us that to a math-trained eye the answer patterns were so obvious it would take a high-school graduate several hours to understand them and pass this exam.</p>
<p>The exam apparently uses one of the most common math concepts &#8211; prime numbers &#8211; as the pattern to answering the questions correctly.</p>
<p>How come this was missed by the <a href="http://www.magentocommerce.com/certification/board">Magento Certification Board</a>, you may ask? Well, call us conspiracy theorists if you will, but this can’t be a pure coincidence, so we somehow feel this was done on purpose, to allow the developers around their companies (who have the inside info) to pass the certification with flying colors.</p>
<p>Well, guys &#8211; <strong>the jig is up</strong>! Now everyone can become a Magento Certified Developer, and here’s how:</p>
<h3>What do you need to pass the exam?</h3>
<h4>1. Exam voucher number</h4>
<p>You have to <a href="http://www.magentocommerce.com/certification/">purchase a voucher</a> to be able to register for the exam, so once you make the purchase, you will get what appears to be a randomly generated voucher number, but what it actually represents is the first clue, or the key to solving the test, even if you have virtually no prior Magento experience.<img class="alignleft size-full wp-image-13055" title="voucher_magento" src="http://inchoo.net/wp-content/uploads/2012/03/voucher_magento.png" alt="" width="609" height="152" /></p>
<p>The last digit on the voucher number is the one that’s going to help you pass as it will correspond to the actual exam you’ll be solving. It contains the hidden answer to the first exam question and after that it’s all a smooth ride. It’s all explained in detail in the actual cheat sheet below.</p>
<h4>2. Prime numbers</h4>
<p>Well, you probably remember all about the prime numbers from your math class, right? I thought so &#8211; in a nutshell, a prime number is the one that only has two divisors &#8211; number 1 and itself &#8211; so, prime numbers are 2,3,5,7,11,13,&#8230; the list goes on indefinitely (but you’ll only need first seven primes to pass the exam).</p>
<p><img class="alignleft size-full wp-image-13058" title="prime_numbers_article" src="http://inchoo.net/wp-content/uploads/2012/03/prime_numbers_article.png" alt="" width="609" height="161" /></p>
<p>And that’s all the info you need &#8211; so, how does this actually help? Using your unique voucher number and primes with a little help from the cheat sheet, you can get all the answers right.</p>
<h3>The cheat sheet revealed</h3>
<p>So, without further ado, the cheat sheet together with instructions can be downloaded right here.</p>
<h4><a title="Magento Certified Developer exam cheat sheet" href="http://inchoo.net/wp-content/uploads/2012/03/MCD_Cheat_Sheet.pdf" target="_blank">Download the Magento Certified Developer exam cheat sheet!</a></h4>
<p>We actually gave this cheat sheet to one of the developers who initially flunked the test, and she was happy to share her thoughts for this article:</p>
<blockquote><p>“<em>Guys &#8211; this is incredible! Works like a charm! Ok, there was quite a bit of counting involved, but it also helps you not to look suspicious finishing the test too quickly. I deliberately answered several questions wrong and passed with a stunning <strong>64/70</strong> score! Thanks a lot for the cheat sheet, and I can only hope more people will benefit from this! Love Magento, love the community!</em>”</p></blockquote>
<p><strong><em>April Første, Magento Certified Developer (Denmark)</em></strong></p>
<p>So, there you go &#8211; what are you waiting for? Get Magento certified! And yes, you&#8217;re welcome! <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-certification-cheat-sheet-revealed/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Marketing by sharing</title>
		<link>http://inchoo.net/ecommerce/marketing-by-sharing/</link>
		<comments>http://inchoo.net/ecommerce/marketing-by-sharing/#comments</comments>
		<pubDate>Wed, 28 Mar 2012 09:43:43 +0000</pubDate>
		<dc:creator>Sanja Martinovic</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Marketing]]></category>
		<category><![CDATA[Online Marketing]]></category>
		<category><![CDATA[37signals]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[magento community]]></category>
		<category><![CDATA[marketing]]></category>
		<category><![CDATA[marketing by sharing]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=13023</guid>
		<description><![CDATA[Inchoo blog is very popular within Magento community. We get feedback from a lot of people who are interested in Magento or are Magento developers saying our blog is a &#8230;]]></description>
			<content:encoded><![CDATA[<p dir="ltr">Inchoo blog is very popular within Magento community. We get feedback from a lot of people who are interested in Magento or are Magento developers saying our blog is a very useful learning tool for them. Although it is very natural for us to share our knowledge, we noticed there are not a lot of companies that feel free enough to do so. For us, it is important to share with Magento community what we’ve learned as it can help others with their work and also be very helpful for us to get feedback so we deliver better solutions to our clients.<span id="more-13023"></span></p>
<p dir="ltr">The concept of open communication of sharing the way you work with your customers and clients is called Marketing by sharing. It’s first mentioned by Jason Fried who is the co-founder and President of <a href="http://37signals.com/">37signals</a>.</p>
<p dir="ltr">But you need to know how to do it well and to show great respect to your readers and potential customers. Also be careful not to show any disrespect to your clients. Of course, you can’t share everything and you should think of your strategy and channels of sharing.</p>
<p dir="ltr"><strong>Here are some tips from our experience on how to be a good marketer of sharing.    </strong></p>
<h3>1. Get to know your key competences so you know what and how to share</h3>
<p>You can’t mix and offer everything your business includes and deals with, since it might not be interesting and helpful to your readers as you may think. You are not forced to tell people everything your business works on, but you want to help them understand and want your products and services. Be aware of yourself and your business and learn what are your strengths that are worth talking about.</p>
<h3>2. Empower learning in organization</h3>
<p>Don&#8217;t do that just because its trendy to say you are a (lifelong) learning organization, but because you really aim for self-improvement and team growth. Let your employees see their job positions as platforms to develop themselves.</p>
<h3>3. Be unique, be worth coming back to</h3>
<p dir="ltr">Be consistent in delivering your promises by delivering only quality solutions (knowledge). You don’t want to share something that could be easily found by Google &#8211; but you want to be easily found by Google <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Build your type of knowledge sharing as something that could grow to be a positive habit of your customers, readers and community.</p>
<h3>4. Don’t forget all about it when your business is enjoying prosperity</h3>
<p dir="ltr">Knowledge sharing is about creating respectful relationships with your customers and people that want to listen to you. Don’t forget about them when you fulfil your initial goals. You might not get a second chance to be listened to.</p>
<h3>5. Remember that those who actually have a lot of knowledge are not afraid of using it</h3>
<p>Knowledge is the only resource that grows by sharing, so don’t be afraid of the opportunities to become better. If your company really has a lot of knowledge that can serve to others and eventually be sold through your products and services, you won’t even think of hiding it. If you really care (as you probably say you do), you will gladly involve customers and community in the life of your company, as your products and services are targeted at them. You will listen to them because they will be more than happy to tell you what you can do for them.</p>
<p dir="ltr"><strong>Don’t hesitate. Go market by sharing.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/marketing-by-sharing/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Validate your input, Magento style</title>
		<link>http://inchoo.net/ecommerce/magento/programming-magento/validate-your-input-magento-style/</link>
		<comments>http://inchoo.net/ecommerce/magento/programming-magento/validate-your-input-magento-style/#comments</comments>
		<pubDate>Sun, 25 Mar 2012 12:04:06 +0000</pubDate>
		<dc:creator>Branko Ajzele</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[sanitize]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12923</guid>
		<description><![CDATA[I&#8217;m sure most fo you will agree that Magento&#8217;s frontend validation for form input fields is a nice feature. All it takes is for you to add some CSS classes &#8230;]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m sure most fo you will agree that Magento&#8217;s frontend validation for form input fields is a nice feature. All it takes is for you to add some CSS classes to the input fields and then upon form submission validation is triggered that outputs, by default, red colored messages that point the possible validation failures etc. This validation is done on the client side via Java Script.<span id="more-12923"></span></p>
<p>For example, if you open the app/design/frontend/base/default/template/customer/form/register.phtml file and focus on the input fields and their &#8220;class&#8221; attributes you will see some of them named: &#8220;required-entry&#8221;, &#8220;validate-email&#8221;, &#8220;validate-zip-international&#8221;, etc. All of these are tied to the Java Script validation rules defined under js/prototype/validation.js file.</p>
<pre class="brush: jscript; title: ; notranslate">
Validation.add('IsEmpty', '', function(v) {
    return  (v == '' || (v == null) || (v.length == 0) || /^\s+$/.test(v)); // || /^\s+$/.test(v));
});

Validation.addAllThese([
    ['validate-select', 'Please select an option.', function(v) {
                return ((v != &quot;none&quot;) &amp;&amp; (v != null) &amp;&amp; (v.length != 0));
            }],
    ['required-entry', 'This is a required field.', function(v) {
                return !Validation.get('IsEmpty').test(v);
            }],
    ['validate-number', 'Please enter a valid number in this field.', function(v) {
                return Validation.get('IsEmpty').test(v) || (!isNaN(parseNumber(v)) &amp;&amp; !/^\s+$/.test(parseNumber(v)));
            }],
    ['validate-digits', 'Please use numbers only in this field. Please avoid spaces or other characters such as dots or commas.', function(v) {
                return Validation.get('IsEmpty').test(v) ||  !/[^\d]/.test(v);
            }],
    ['validate-digits-range', 'The value is not within the specified range.', function(v, elm) {
                var result = Validation.get('IsEmpty').test(v) ||  !/[^\d]/.test(v);
                var reRange = new RegExp(/^digits-range-[0-9]+-[0-9]+$/);
                $w(elm.className).each(function(name, index) {
                    if (name.match(reRange) &amp;&amp; result) {
                        var min = parseInt(name.split('-')[2], 10);
                        var max = parseInt(name.split('-')[3], 10);
                        var val = parseInt(v, 10);
                        result = (v &gt;= min) &amp;&amp; (v &lt;= max);
                    }
                });
                return result;
            }],
    ['validate-alpha', 'Please use letters only (a-z or A-Z) in this field.', function (v) {
                return Validation.get('IsEmpty').test(v) ||  /^[a-zA-Z]+$/.test(v)
            }],
    ['validate-code', 'Please use only letters (a-z), numbers (0-9) or underscore(_) in this field, first character should be a letter.', function (v) {
                return Validation.get('IsEmpty').test(v) ||  /^[a-z]+[a-z0-9_]+$/.test(v)
            }],
    ['validate-alphanum', 'Please use only letters (a-z or A-Z) or numbers (0-9) only in this field. No spaces or other characters are allowed.', function(v) {
                return Validation.get('IsEmpty').test(v) ||  /^[a-zA-Z0-9]+$/.test(v) /*!/\W/.test(v)*/
            }],
    ['validate-street', 'Please use only letters (a-z or A-Z) or numbers (0-9) or spaces and # only in this field.', function(v) {
                return Validation.get('IsEmpty').test(v) ||  /^[ \w]{3,}([A-Za-z]\.)?([ \w]*\#\d+)?(\r\n| )[ \w]{3,}/.test(v)
            }],
    ['validate-phoneStrict', 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.', function(v) {
                return Validation.get('IsEmpty').test(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v);
            }],
    ['validate-phoneLax', 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.', function(v) {
                return Validation.get('IsEmpty').test(v) || /^((\d[-. ]?)?((\(\d{3}\))|\d{3}))?[-. ]?\d{3}[-. ]?\d{4}$/.test(v);
            }],
    ['validate-fax', 'Please enter a valid fax number. For example (123) 456-7890 or 123-456-7890.', function(v) {
                return Validation.get('IsEmpty').test(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v);
            }],
    ['validate-date', 'Please enter a valid date.', function(v) {
                var test = new Date(v);
                return Validation.get('IsEmpty').test(v) || !isNaN(test);
            }],
    ['validate-email', 'Please enter a valid email address. For example johndoe@domain.com.', function (v) {
                //return Validation.get('IsEmpty').test(v) || /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(v)
                //return Validation.get('IsEmpty').test(v) || /^[\!\#$%\*/?|\^\{\}`~&amp;\'\+\-=_a-z0-9][\!\#$%\*/?|\^\{\}`~&amp;\'\+\-=_a-z0-9\.]{1,30}[\!\#$%\*/?|\^\{\}`~&amp;\'\+\-=_a-z0-9]@([a-z0-9_-]{1,30}\.){1,5}[a-z]{2,4}$/i.test(v)
                return Validation.get('IsEmpty').test(v) || /^([a-z0-9,!\#\$%&amp;'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9,!\#\$%&amp;'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*@([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*\.(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]){2,})$/i.test(v)
            }],
    ['validate-emailSender', 'Please use only visible characters and spaces.', function (v) {
                return Validation.get('IsEmpty').test(v) ||  /^[\S ]+$/.test(v)
                    }],
    ['validate-password', 'Please enter 6 or more characters. Leading or trailing spaces will be ignored.', function(v) {
                var pass=v.strip(); /*strip leading and trailing spaces*/
                return !(pass.length&gt;0 &amp;&amp; pass.length &lt; 6);
            }],
    ['validate-admin-password', 'Please enter 7 or more characters. Password should contain both numeric and alphabetic characters.', function(v) {
                var pass=v.strip();
                if (0 == pass.length) {
                    return true;
                }
                if (!(/[a-z]/i.test(v)) || !(/[0-9]/.test(v))) {
                    return false;
                }
                return !(pass.length &lt; 7);
            }],
    ['validate-cpassword', 'Please make sure your passwords match.', function(v) {
                var conf = $('confirmation') ? $('confirmation') : $$('.validate-cpassword')[0];
                var pass = false;
                if ($('password')) {
                    pass = $('password');
                }
                var passwordElements = $$('.validate-password');
                for (var i = 0; i &lt; passwordElements.size(); i++) {
                    var passwordElement = passwordElements[i];
                    if (passwordElement.up('form').id == conf.up('form').id) {
                        pass = passwordElement;
                    }
                }
                if ($$('.validate-admin-password').size()) {
                    pass = $$('.validate-admin-password')[0];
                }
                return (pass.value == conf.value);
            }],
    ['validate-url', 'Please enter a valid URL. Protocol is required (http://, https:// or ftp://)', function (v) {
                v = (v || '').replace(/^\s+/, '').replace(/\s+$/, '');
                return Validation.get('IsEmpty').test(v) || /^(http|https|ftp):\/\/(([A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))(\.[A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))*)(:(\d+))?(\/[A-Z0-9~](([A-Z0-9_~-]|\.)*[A-Z0-9~]|))*\/?$/i.test(v)
            }],
    ['validate-clean-url', 'Please enter a valid URL. For example http://www.example.com or www.example.com', function (v) {
                return Validation.get('IsEmpty').test(v) || /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i.test(v) || /^(www)((\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i.test(v)
            }],
    ['validate-identifier', 'Please enter a valid URL Key. For example &quot;example-page&quot;, &quot;example-page.html&quot; or &quot;anotherlevel/example-page&quot;.', function (v) {
                return Validation.get('IsEmpty').test(v) || /^[a-z0-9][a-z0-9_\/-]+(\.[a-z0-9_-]+)?$/.test(v)
            }],
    ['validate-xml-identifier', 'Please enter a valid XML-identifier. For example something_1, block5, id-4.', function (v) {
                return Validation.get('IsEmpty').test(v) || /^[A-Z][A-Z0-9_\/-]*$/i.test(v)
            }],
    ['validate-ssn', 'Please enter a valid social security number. For example 123-45-6789.', function(v) {
            return Validation.get('IsEmpty').test(v) || /^\d{3}-?\d{2}-?\d{4}$/.test(v);
            }],
    ['validate-zip', 'Please enter a valid zip code. For example 90602 or 90602-1234.', function(v) {
            return Validation.get('IsEmpty').test(v) || /(^\d{5}$)|(^\d{5}-\d{4}$)/.test(v);
            }],
    ['validate-zip-international', 'Please enter a valid zip code.', function(v) {
            //return Validation.get('IsEmpty').test(v) || /(^[A-z0-9]{2,10}([\s]{0,1}|[\-]{0,1})[A-z0-9]{2,10}$)/.test(v);
            return true;
            }],
    ['validate-date-au', 'Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.', function(v) {
                if(Validation.get('IsEmpty').test(v)) return true;
                var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
                if(!regex.test(v)) return false;
                var d = new Date(v.replace(regex, '$2/$1/$3'));
                return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) &amp;&amp;
                            (parseInt(RegExp.$1, 10) == d.getDate()) &amp;&amp;
                            (parseInt(RegExp.$3, 10) == d.getFullYear() );
            }],
    ['validate-currency-dollar', 'Please enter a valid $ amount. For example $100.00.', function(v) {
                // [$]1[##][,###]+[.##]
                // [$]1###+[.##]
                // [$]0.##
                // [$].##
                return Validation.get('IsEmpty').test(v) ||  /^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/.test(v)
            }],
    ['validate-one-required', 'Please select one of the above options.', function (v,elm) {
                var p = elm.parentNode;
                var options = p.getElementsByTagName('INPUT');
                return $A(options).any(function(elm) {
                    return $F(elm);
                });
            }],
    ['validate-one-required-by-name', 'Please select one of the options.', function (v,elm) {
                var inputs = $$('input[name=&quot;' + elm.name.replace(/([\\&quot;])/g, '\\$1') + '&quot;]');

                var error = 1;
                for(var i=0;i&lt;inputs.length;i++) {
                    if((inputs[i].type == 'checkbox' || inputs[i].type == 'radio') &amp;&amp; inputs[i].checked == true) {
                        error = 0;
                    }

                    if(Validation.isOnChange &amp;&amp; (inputs[i].type == 'checkbox' || inputs[i].type == 'radio')) {
                        Validation.reset(inputs[i]);
                    }
                }

                if( error == 0 ) {
                    return true;
                } else {
                    return false;
                }
            }],
    ['validate-not-negative-number', 'Please enter a valid number in this field.', function(v) {
                v = parseNumber(v);
                return (!isNaN(v) &amp;&amp; v&gt;=0);
            }],
    ['validate-state', 'Please select State/Province.', function(v) {
                return (v!=0 || v == '');
            }],

    ['validate-new-password', 'Please enter 6 or more characters. Leading or trailing spaces will be ignored.', function(v) {
                if (!Validation.get('validate-password').test(v)) return false;
                if (Validation.get('IsEmpty').test(v) &amp;&amp; v != '') return false;
                return true;
            }],
    ['validate-greater-than-zero', 'Please enter a number greater than 0 in this field.', function(v) {
                if(v.length)
                    return parseFloat(v) &gt; 0;
                else
                    return true;
            }],
    ['validate-zero-or-greater', 'Please enter a number 0 or greater in this field.', function(v) {
                if(v.length)
                    return parseFloat(v) &gt;= 0;
                else
                    return true;
            }],
    ['validate-cc-number', 'Please enter a valid credit card number.', function(v, elm) {
                // remove non-numerics
                var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_number')) + '_cc_type');
                if (ccTypeContainer &amp;&amp; typeof Validation.creditCartTypes.get(ccTypeContainer.value) != 'undefined'
                        &amp;&amp; Validation.creditCartTypes.get(ccTypeContainer.value)[2] == false) {
                    if (!Validation.get('IsEmpty').test(v) &amp;&amp; Validation.get('validate-digits').test(v)) {
                        return true;
                    } else {
                        return false;
                    }
                }
                return validateCreditCard(v);
            }],
    ['validate-cc-type', 'Credit card number does not match credit card type.', function(v, elm) {
                // remove credit card number delimiters such as &quot;-&quot; and space
                elm.value = removeDelimiters(elm.value);
                v         = removeDelimiters(v);

                var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_number')) + '_cc_type');
                if (!ccTypeContainer) {
                    return true;
                }
                var ccType = ccTypeContainer.value;

                if (typeof Validation.creditCartTypes.get(ccType) == 'undefined') {
                    return false;
                }

                // Other card type or switch or solo card
                if (Validation.creditCartTypes.get(ccType)[0]==false) {
                    return true;
                }

                // Matched credit card type
                var ccMatchedType = '';

                Validation.creditCartTypes.each(function (pair) {
                    if (pair.value[0] &amp;&amp; v.match(pair.value[0])) {
                        ccMatchedType = pair.key;
                        throw $break;
                    }
                });

                if(ccMatchedType != ccType) {
                    return false;
                }

                if (ccTypeContainer.hasClassName('validation-failed') &amp;&amp; Validation.isOnChange) {
                    Validation.validate(ccTypeContainer);
                }

                return true;
            }],
     ['validate-cc-type-select', 'Card type does not match credit card number.', function(v, elm) {
                var ccNumberContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_type')) + '_cc_number');
                if (Validation.isOnChange &amp;&amp; Validation.get('IsEmpty').test(ccNumberContainer.value)) {
                    return true;
                }
                if (Validation.get('validate-cc-type').test(ccNumberContainer.value, ccNumberContainer)) {
                    Validation.validate(ccNumberContainer);
                }
                return Validation.get('validate-cc-type').test(ccNumberContainer.value, ccNumberContainer);
            }],
     ['validate-cc-exp', 'Incorrect credit card expiration date.', function(v, elm) {
                var ccExpMonth   = v;
                var ccExpYear    = $(elm.id.substr(0,elm.id.indexOf('_expiration')) + '_expiration_yr').value;
                var currentTime  = new Date();
                var currentMonth = currentTime.getMonth() + 1;
                var currentYear  = currentTime.getFullYear();
                if (ccExpMonth &lt; currentMonth &amp;&amp; ccExpYear == currentYear) {
                    return false;
                }
                return true;
            }],
     ['validate-cc-cvn', 'Please enter a valid credit card verification number.', function(v, elm) {
                var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_cid')) + '_cc_type');
                if (!ccTypeContainer) {
                    return true;
                }
                var ccType = ccTypeContainer.value;

                if (typeof Validation.creditCartTypes.get(ccType) == 'undefined') {
                    return false;
                }

                var re = Validation.creditCartTypes.get(ccType)[1];

                if (v.match(re)) {
                    return true;
                }

                return false;
            }],
     ['validate-ajax', '', function(v, elm) { return true; }],
     ['validate-data', 'Please use only letters (a-z or A-Z), numbers (0-9) or underscore(_) in this field, first character should be a letter.', function (v) {
                if(v != '' &amp;&amp; v) {
                    return /^[A-Za-z]+[A-Za-z0-9_]+$/.test(v);
                }
                return true;
            }],
     ['validate-css-length', 'Please input a valid CSS-length. For example 100px or 77pt or 20em or .5ex or 50%.', function (v) {
                if (v != '' &amp;&amp; v) {
                    return /^[0-9\.]+(px|pt|em|ex|%)?$/.test(v) &amp;&amp; (!(/\..*\./.test(v))) &amp;&amp; !(/\.$/.test(v));
                }
                return true;
            }],
     ['validate-length', 'Text length does not satisfy specified text range.', function (v, elm) {
                var reMax = new RegExp(/^maximum-length-[0-9]+$/);
                var reMin = new RegExp(/^minimum-length-[0-9]+$/);
                var result = true;
                $w(elm.className).each(function(name, index) {
                    if (name.match(reMax) &amp;&amp; result) {
                       var length = name.split('-')[2];
                       result = (v.length &lt;= length);
                    }
                    if (name.match(reMin) &amp;&amp; result &amp;&amp; !Validation.get('IsEmpty').test(v)) {
                        var length = name.split('-')[2];
                        result = (v.length &gt;= length);
                    }
                });
                return result;
            }],
     ['validate-percents', 'Please enter a number lower than 100.', {max:100}],
     ['required-file', 'Please select a file', function(v, elm) {
         var result = !Validation.get('IsEmpty').test(v);
         if (result === false) {
             ovId = elm.id + '_value';
             if ($(ovId)) {
                 result = !Validation.get('IsEmpty').test($(ovId).value);
             }
         }
         return result;
     }],
     ['validate-cc-ukss', 'Please enter issue number or start date for switch/solo card type.', function(v,elm) {
         var endposition;

         if (elm.id.match(/(.)+_cc_issue$/)) {
             endposition = elm.id.indexOf('_cc_issue');
         } else if (elm.id.match(/(.)+_start_month$/)) {
             endposition = elm.id.indexOf('_start_month');
         } else {
             endposition = elm.id.indexOf('_start_year');
         }

         var prefix = elm.id.substr(0,endposition);

         var ccTypeContainer = $(prefix + '_cc_type');

         if (!ccTypeContainer) {
               return true;
         }
         var ccType = ccTypeContainer.value;

         if(['SS','SM','SO'].indexOf(ccType) == -1){
             return true;
         }

         $(prefix + '_cc_issue').advaiceContainer
           = $(prefix + '_start_month').advaiceContainer
           = $(prefix + '_start_year').advaiceContainer
           = $(prefix + '_cc_type_ss_div').down('ul li.adv-container');

         var ccIssue   =  $(prefix + '_cc_issue').value;
         var ccSMonth  =  $(prefix + '_start_month').value;
         var ccSYear   =  $(prefix + '_start_year').value;

         var ccStartDatePresent = (ccSMonth &amp;&amp; ccSYear) ? true : false;

         if (!ccStartDatePresent &amp;&amp; !ccIssue){
             return false;
         }
         return true;
     }]
]);
</pre>
<p>If we extract those from code, here is the list of validations available on client side trough Javascript:</p>
<ul>
<li>IsEmpty</li>
<li>validate-select</li>
<li>required-entry</li>
<li>validate-number</li>
<li>validate-digits</li>
<li>validate-digits-range</li>
<li>validate-alpha</li>
<li>validate-code</li>
<li>validate-alphanum</li>
<li>validate-street</li>
<li>validate-phoneStrict</li>
<li>validate-phoneLax</li>
<li>validate-fax</li>
<li>validate-date</li>
<li>validate-email</li>
<li>validate-emailSender</li>
<li>validate-password</li>
<li>validate-admin-password</li>
<li>validate-cpassword</li>
<li>validate-url</li>
<li>validate-clean-url</li>
<li>validate-identifier</li>
<li>validate-xml-identifier</li>
<li>validate-ssn</li>
<li>validate-zip</li>
<li>validate-zip-international</li>
<li>validate-date-au</li>
<li>validate-currency-dollar</li>
<li>validate-one-required</li>
<li>validate-one-required-by-name</li>
<li>validate-not-negative-number</li>
<li>validate-state</li>
<li>validate-new-password</li>
<li>validate-greater-than-zero</li>
<li>validate-zero-or-greater</li>
<li>validate-cc-number</li>
<li>validate-cc-type</li>
<li>validate-cc-type-select</li>
<li>validate-cc-exp</li>
<li>validate-cc-cvn</li>
<li>validate-ajax</li>
<li>validate-data</li>
<li>validate-css-length</li>
<li>validate-length</li>
<li>validate-percents</li>
<li>required-file</li>
<li>validate-cc-ukss</li>
</ul>
<p>The above mentioned handles the validation of data on the client side. However, client side data can be falsified/manipulated. What we need is the server side validation as well. Let&#8217;s check out few examples to see how Magento is handling the server side of the things. </p>
<p>First lets check out the &#8220;Customer Account Create&#8221; logic. Creating a new customer submits the POST of data to the Mage_Customer_AccountController->createPostAction(). Since customer and customer address are &#8220;EAV models&#8221;, they have a special way of handling the validation of data, they pass the POST data to the validateData() method of your custom class instance which extends the Mage_Eav_Model_Form class. Below is a code snippet that shows this:</p>
<pre class="brush: php; title: ; notranslate">
/* @var $customerForm Mage_Customer_Model_Form */
$customer = Mage::getModel('customer/customer');

$customerForm = Mage::getModel('customer/form');
$customerForm-&gt;setFormCode('customer_account_create')
    -&gt;setEntity($customer);

$customerData = $customerForm-&gt;extractData($this-&gt;getRequest());
// ...
$customerErrors = $customerForm-&gt;validateData($customerData);
</pre>
<p>Validating data on the &#8220;data models&#8221; is done somewhat different, here the model itself is suppose to implement the validate() method. For example, lets check out the Mage_Review_Model_Review model and the action of saving/creating the review itself, Mage_Review_ProductController->postAction():</p>
<pre class="brush: php; title: ; notranslate">
    public function postAction()
    {
        if ($data = Mage::getSingleton('review/session')-&gt;getFormData(true)) {
            $rating = array();
            if (isset($data['ratings']) &amp;&amp; is_array($data['ratings'])) {
                $rating = $data['ratings'];
            }
        } else {
            $data   = $this-&gt;getRequest()-&gt;getPost();
            $rating = $this-&gt;getRequest()-&gt;getParam('ratings', array());
        }

        if (($product = $this-&gt;_initProduct()) &amp;&amp; !empty($data)) {
            $session    = Mage::getSingleton('core/session');
            /* @var $session Mage_Core_Model_Session */
            $review     = Mage::getModel('review/review')-&gt;setData($data);
            /* @var $review Mage_Review_Model_Review */

            $validate = $review-&gt;validate();
            if ($validate === true) {
            // ...
</pre>
<p>The validate() points to the Mage_Review_Model_Review->validate(), which is implemented into the model itself:</p>
<pre class="brush: php; title: ; notranslate">
    public function validate()
    {
        $errors = array();

        $helper = Mage::helper('customer');

        if (!Zend_Validate::is($this-&gt;getTitle(), 'NotEmpty')) {
            $errors[] = $helper-&gt;__('Review summary can\'t be empty');
        }

        if (!Zend_Validate::is($this-&gt;getNickname(), 'NotEmpty')) {
            $errors[] = $helper-&gt;__('Nickname can\'t be empty');
        }

        if (!Zend_Validate::is($this-&gt;getDetail(), 'NotEmpty')) {
            $errors[] = $helper-&gt;__('Review can\'t be empty');
        }

        if (empty($errors)) {
            return true;
        }
        return $errors;
    }
</pre>
<p>As you can see, there is not anything Magento specific here actually, only Zend_Validate calls. However, its a good practice to define and implement validate() method if you are using data models.</p>
<p>Additionally, there is a Mage_Core_Model_Input_Filter_MaliciousCode class which implements the filter() method for filtering out malicious code as the name of the class suggests. You can open the class itself and look for $_expressions to see what expressions it covers by default.</p>
<p>Hope it helps. Cheers.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/programming-magento/validate-your-input-magento-style/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Magento with xDebug, web services API and testUnit</title>
		<link>http://inchoo.net/ecommerce/magento/magento-xdebug/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-xdebug/#comments</comments>
		<pubDate>Tue, 20 Mar 2012 07:56:43 +0000</pubDate>
		<dc:creator>Darko Goles</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[Tools & Frameworks]]></category>
		<category><![CDATA[xdebug]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12676</guid>
		<description><![CDATA[Using xDebug from NetBeans is pretty straightforward and after installing xDebug from their website does not require some special configuration in order to make it work. If you visit the &#8230;]]></description>
			<content:encoded><![CDATA[<p>Using xDebug from NetBeans is pretty straightforward and after installing <a title="xDebug" href="http://xdebug.org/find-binary.php" target="_blank">xDebug from their websit</a>e does not require some special configuration in order to make it work.<br />
If you visit the link above, you will notice that it&#8217;s enough to paste the source code of your phpinfo() and you will get directions what xDebug binary to download and how to set it.<span id="more-12676"></span></p>
<p>Assuming you did it already, let&#8217;s make it work in our NetBeans IDE.<br />
Open NetBeans and go to &#8216;Tools/Options&#8217; and click on &#8216;PHP&#8217; tab.<br />
On &#8216;General&#8217; tab inside, you will find options for xDebug configuration inside Netbeans. I just left all values predefined.</p>
<p>You have few options there to choose, and choose what you like, but make sure that port in which xDebug is set to run in php.ini is the same entered here.</p>
<p>Now, let&#8217;s test if xDebug is working. Assuming that you already have your Magento project opened in editor, just hit &#8216;Ctrl+F5&#8242; to start debugging session. What should happen is that your browser window should be opened wit URL like this:</p>
<p><strong>http://yourLocalMagentoUrl/index.php?XDEBUG_SESSION_START=netbeans-xdebug</strong></p>
<p>you can notice XDEBUG_SESSION START parameter inside URL.<br />
If you did all like I wrote and noting like this happens, then try to reconfigure your xDebug and/or NetBeans to make it work properly.</p>
<p>If you read my last article, you will find some example how to call Magento V2 Soap web services from test unit with SoapClient.</p>
<p><strong>So, what&#8217;s the current problem?</strong></p>
<p>If you set some breakpoints inside your code that will be executed, debugger will stop there and you can debug your or Magento/&#8217;s source code, look at variables window etc, but what will happen if we need to debug server- side of Magento&#8217;s web services or our extension to API V2 and all that from out test unit where SoapClient calls are implemented.</p>
<p><strong>How to tell to debugger to start the session and handle web service calls on server – side?</strong></p>
<p>To do so, the easier way I found is:</p>
<p>1. Start debugging with &#8216;Ctrl+F5&#8242; and browser window opens &#8230;<br />
2. Leave that browser window open and add XDEBUG_SESSION cookie to your soap client inside your unit test:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

require_once 'PHPUnit/Autoload.php';
require_once '../app/Mage.php';

class customerCustomerTest extends PHPUnit_Framework_TestCase {

    private $local_url_v2 = &quot;http://192.168.1.91/api/v2_soap/?wsdl=1&quot;;

    private $api_url_v1;
    private $api_url_v2;

    public function setUp() {
        Mage::app('default');

        $this-&gt;setApiUrlV2($this-&gt;local_url_v2);

    }

    public function getApiUrlV2() {
        return $this-&gt;api_url_v2;
    }

    public function setApiUrlV2($api_url_v2) {
        $this-&gt;api_url_v2 = $api_url_v2;
    }

    public function testLogin() {
        $cli = new SoapClient($this-&gt;api_url_v2);

        $username = 'mobile';
        $password = 'mobile123';
        $result = $cli-&gt;login($username, $password);
        $session_id = isset($result) ? $result : null;

        $this-&gt;assertNotNull($session_id);
        return $session_id;
    }

    public function testCoreCustomerList_V2() {

        $session_id = $this-&gt;testLogin();
        $cli = new SoapClient($this-&gt;api_url_v2);
        $cli-&gt;__setCookie('XDEBUG_SESSION', 'netbeans-xdebug');
        $result = $cli-&gt;customerCustomerList($session_id);

        $this-&gt;assertTrue(is_array($result));
        foreach ($result as $res) {
            $this-&gt;assertObjectHasAttribute('customer_id', $res);
        }
    }
</pre>
<p>Now set the breakpoints inside reachable code and run your tests with &#8216;Alt+F6&#8242;.</p>
<p>Your debugger will stop at your and debugging can start ….. <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-xdebug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Installation and configuration of local Mail server for Windows (hMail Server)</title>
		<link>http://inchoo.net/ecommerce/magento/installation-and-configuration-of-local-mail-server-for-windows-hmail-server/</link>
		<comments>http://inchoo.net/ecommerce/magento/installation-and-configuration-of-local-mail-server-for-windows-hmail-server/#comments</comments>
		<pubDate>Sat, 17 Mar 2012 04:39:37 +0000</pubDate>
		<dc:creator>Nikola Stojiljkovic</dc:creator>
				<category><![CDATA[Email]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[eMail]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[Tools & Frameworks]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12859</guid>
		<description><![CDATA[This is not exactly Magento related post, but it might be useful when you are setting up a dev environment on your local machine. There are many good and free &#8230;]]></description>
			<content:encoded><![CDATA[<p>This is not exactly Magento related post, but it might be useful when you are setting up a dev environment on your local machine. There are many good and free mail servers out there which are relatively easy to install on your Windows machine, but the problems may occur when you try to configure all the bits and pieces of your system so you can actually use your local mail server for something other than producing system errors <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  .</p>
<p>When I started working with PHP a long time ago, I was (naturally) looking for a mail server that could be used on my local machine. For some reason that is now long forgotten, I have decided to use <a title="hMail Server" href="http://www.hmailserver.com/" target="_blank">hMail Server</a> (freeware). Since it never failed me, it stayed in my standard set of must-have tools. In this post I&#8217;ll try to present a step-by-step manual on how to install and configure your system to use hMail Server.<span id="more-12859"></span></p>
<p>Although this post might be a bit lengthy, please, don&#8217;t be scared <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . These are all simple steps and if you have any experience as a Windows user, you should be able to skip reading the most of them.</p>
<p><strong>System properties (listed just as a reference)</strong></p>
<ul>
<li>Windows 7 Professional with the latest updates</li>
<li>MySQL 5.0.51b</li>
<li>Apache 2.2.17</li>
</ul>
<p><strong>Part 1 &#8211; Installation and Database configuration</strong></p>
<ul>
<li>Download hMail Server from their <a title="hMail Server Download Page" href="http://www.hmailserver.com/index.php?page=download" target="_blank">download page</a>. My suggestion is to get the latest production release as it is the most stable one;</li>
<li> Start the installer and pick &#8220;Full installation&#8221;. That should include Administrative tools which are very useful;</li>
<li>When asked, set MySQL as your mail database. You don&#8217;t need to create the database manually, installer will do that for you;</li>
<li>When you complete the installation wizard, database configuration wizard will appear where you should pick &#8220;Create new mail database&#8221; option;</li>
<li>Copy libmysql.dll to /hMailServer/bin directory;</li>
<li>Enter the MySQL server and user info.  You can use localhost as server name and whatever port you used for MySQL (default is 3306);</li>
<li>Pick the database service from the dropdown so that hMail server can hook to it. It&#8217;s usually listed as &#8220;MySQL&#8221; but  can be listed as &#8220;WAMP Mysql&#8221; (or whatever name you used) if you have WAMP installed;</li>
<li>Database configuration should be completed now and you can proceed to run the hMail Server Administration tool.</li>
</ul>
<p><strong>Part 2 &#8211; Configuring Windows DNS, port and firewall settings</strong></p>
<ul>
<li>The first thing you need to do is add a couple of entries to the Windows&#8217; <em>hosts </em>file. Click on the Windows Start button and search for Notepad. Right click Notepad.exe and choose &#8220;Run as Administrator&#8221;. This will ensure that you will be able to save the &#8220;hosts&#8221; file once you&#8217;ve finished adding the changes, since the file is protected by the operating system by default;</li>
<li>Open the hosts file in Notepad. It&#8217;s located in Windows\System32\drivers\etc\ folder;</li>
<li>add the following at the end of the file (you can put anything instead of &#8220;localserver&#8221;):</li>
</ul>
<pre class="brush: xml; title: ; notranslate">
127.0.0.1	mail.localserver.com
127.0.0.1	localserver.com
127.0.0.1	smtp.mail.localserver.com
127.0.0.1	pop3.mail.localserver.com
</pre>
<ul>
<li>Open &#8220;Windows Firewall&#8221; form Control Panel or by searching for it in the Start menu;</li>
<li>Go to &#8220;Inbound rules&#8221; in the left bar and create a new rule for a Port. Type the port numbers for SMTP, POP3 and optionally IMAP protocols in <em>TCP &gt; Selected local ports</em> field. You don&#8217;t need to create 3 rules for each port, because you can add all three of them with a comma separator (for example: 25, 110, 143);</li>
<li>Enter the name of the rule. Something like &#8220;hMail open ports&#8221; should do;</li>
<li>If you have any custom firewall installed, either stand-alone or as part of your AV software, you might want to look at your software&#8217;s documentation and see how to open ports. The ports you need to open are 25, 110 and optionally 143 if you plan to use IMAP.</li>
</ul>
<p><strong>Part 3 &#8211; Configuring hMail server</strong></p>
<ul>
<li>Create a new Domain in the hMail Administrator and put &#8220;mail.localserver.com&#8221; in the Domain field;</li>
<li>Create one administrator mail account by going to &#8220;Domains &gt; mail.localserver.com &gt; Accounts &gt; Add&#8221; and choosing &#8220;Server&#8221; in the &#8220;Administration level&#8221; field. We will use &#8220;master@mail.localserver.com&#8221; as an example;</li>
<li>Go to the &#8220;Delivery of e-mail&#8221; tab in the &#8220;Settings &gt; Protocols &gt; SMTP&#8221; and enter  &#8221;mail.localserver.com&#8221; in the &#8220;Local Host Name&#8221; field;</li>
<li>Go to &#8220;Settings &gt; Advanced &gt; TCP/IP Ports&#8221; and configure each of the sub-entries to use 127.0.0.1 as IP address.</li>
</ul>
<p><span style="font-size: small;"><span style="line-height: 24px;">That&#8217;s it! Your local mail server is now up and running. The only thing you need to do now is to connect your newly created local mail address to some e-mail application. I will post here a quick how-to tips for Thunderbird.</span></span></p>
<p><strong>Configuring Thunderbird mail account</strong></p>
<ul>
<li>Go to &#8220;Tools &gt; Account settings&#8221; in the Thunderbird main menu and create a new account (&#8220;Account actions&#8221; button, then &#8220;Add new account&#8221; option);</li>
<li>Use &#8220;master@mail.localserver.com&#8221; e-mail address (the one you have created in the hMail Administration) and set &#8220;Outgoing server&#8221; to &#8220;smtp.mail.localserver.com&#8221;;</li>
<li>Go to &#8220;Server settings&#8221; in your newly created mail account branch and use &#8220;pop3.mail.localserver.com&#8221; as &#8220;Server name&#8221;. &#8220;User name&#8221; field on this page should be the full name of your e-mail address, so, it would be &#8220;master@mail.localserver.com&#8221;</li>
</ul>
<p>You are now ready to use your local e-mail address for your local Magento installation. If you run into any trouble, you can always use the Diagnostics tool from the Utilities menu  or check for error messages in the Status window of the hMail Administrator. I will also suggest you to explore the Administrator application and set up one of the many useful logging and debugging parameters as well as playing with the options for mail accounts. Of course, you should not forget to take a look at the security options too.</p>
<p>Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/installation-and-configuration-of-local-mail-server-for-windows-hmail-server/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Magento Enterprise &#8211; Discount for specific Customer segments group</title>
		<link>http://inchoo.net/ecommerce/magento/administration-magento/magento-enterprise-discount-for-specific-customer-segments-group/</link>
		<comments>http://inchoo.net/ecommerce/magento/administration-magento/magento-enterprise-discount-for-specific-customer-segments-group/#comments</comments>
		<pubDate>Fri, 16 Mar 2012 07:36:02 +0000</pubDate>
		<dc:creator>Stanislav Mihic</dc:creator>
				<category><![CDATA[Administration]]></category>
		<category><![CDATA[Marketing]]></category>
		<category><![CDATA[administration]]></category>
		<category><![CDATA[customer]]></category>
		<category><![CDATA[customer segemnts]]></category>
		<category><![CDATA[enterprise]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[shopping cart rules]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12768</guid>
		<description><![CDATA[In previous post we create Customer group based on company emails. Now when we have few customers registered with company emails we will create campaign and give them 50% discount for &#8230;]]></description>
			<content:encoded><![CDATA[<p>In <a title="Customer Segments" href="http://inchoo.net/ecommerce/magento-customer-segments/">previous post</a> we create Customer group based on company emails. Now when we have few customers registered with company emails we will create campaign and give them 50% discount for purchasing Laptops.<span id="more-12768"></span></p>
<p>In Magento admin area open  Promotions -&gt; Shopping Cart Price Rules</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/03/shopping_cart_promotions.jpg"><img class="aligncenter size-full wp-image-12769" title="shopping_cart_promotions" src="http://inchoo.net/wp-content/uploads/2012/03/shopping_cart_promotions.jpg" alt="" width="600" height="193" /></a></p>
<p>Now we will create a new rule</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/03/Customer_segments_add_new_cart_rule.jpg"><img class="aligncenter size-full wp-image-12770" title="Customer_segments_add_new_cart_rule" src="http://inchoo.net/wp-content/uploads/2012/03/Customer_segments_add_new_cart_rule.jpg" alt="" width="600" height="186" /></a></p>
<p>Fill up information regarding new rule</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/03/shopping_cart_rule_settings.jpg"><img class="aligncenter size-full wp-image-12771" title="shopping_cart_rule_settings" src="http://inchoo.net/wp-content/uploads/2012/03/shopping_cart_rule_settings.jpg" alt="" width="600" height="474" /></a></p>
<p>Using conditions we will use our previously created Customer Segment &#8220;Company Discount&#8221;</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/03/use_customer_segments.jpg"><img class="aligncenter size-full wp-image-12772" title="use_customer_segments" src="http://inchoo.net/wp-content/uploads/2012/03/use_customer_segments.jpg" alt="" width="600" height="218" /></a></p>
<p>Under Action we will give 50% of discount on product price from Category &#8220;Laptops&#8221;</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/03/apply_discount.jpg"><img class="aligncenter size-full wp-image-12773" title="apply_discount" src="http://inchoo.net/wp-content/uploads/2012/03/apply_discount.jpg" alt="" width="600" height="298" /></a></p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/03/use_category1.jpg"><img class="aligncenter size-full wp-image-12775" title="use_category" src="http://inchoo.net/wp-content/uploads/2012/03/use_category1.jpg" alt="" width="600" height="332" /></a></p>
<p>Now we will go to store and login using Company email.</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/03/login_comapny_email.jpg"><img class="aligncenter size-full wp-image-12776" title="login_comapny_email" src="http://inchoo.net/wp-content/uploads/2012/03/login_comapny_email.jpg" alt="" width="600" height="375" /></a></p>
<p>Browse Category &#8220;Laptops&#8221; and choose one of the products, in my case it will be Apple MacBook Pro, normal price is displayed, continue to checkout.</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/03/buy_laptop.jpg"><img class="aligncenter size-full wp-image-12777" title="buy_laptop" src="http://inchoo.net/wp-content/uploads/2012/03/buy_laptop.jpg" alt="" width="600" height="234" /></a></p>
<p>And now we have finally applied our Company discount 50% off</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/03/final_discount.jpg"><img class="aligncenter size-full wp-image-12778" title="final_discount" src="http://inchoo.net/wp-content/uploads/2012/03/final_discount.jpg" alt="" width="600" height="254" /></a></p>
<p>This is only example you can create may other rules based on Customer Segments under Shopping Cart Price Rules, discount, free shipping, add reward points, etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/administration-magento/magento-enterprise-discount-for-specific-customer-segments-group/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Magento API V2 Soap unit testing</title>
		<link>http://inchoo.net/ecommerce/magento/magento-api-v2-soap-unit-testing/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-api-v2-soap-unit-testing/#comments</comments>
		<pubDate>Thu, 15 Mar 2012 12:22:00 +0000</pubDate>
		<dc:creator>Darko Goles</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[Tools & Frameworks]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[unit testing]]></category>
		<category><![CDATA[web services]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12621</guid>
		<description><![CDATA[In previous article, I wrote about setting up environment for Magento unit testing. Let&#8217;s expand our tests to test some Magento&#8217;s API calls with soap. Let&#8217;s add first tests in &#8230;]]></description>
			<content:encoded><![CDATA[<p>In previous article, I wrote about setting up environment for Magento unit testing. Let&#8217;s expand our tests to test some Magento&#8217;s API calls with soap.<span id="more-12621"></span></p>
<p>Let&#8217;s add first tests in our Tests/customerCustomerTest.php</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

require_once 'PHPUnit/Autoload.php';
require_once '../app/Mage.php';

class customerCustomerTest extends PHPUnit_Framework_TestCase {

private $local_url_v1 = &quot;http://192.168.1.91/api/soap/?wsdl=1&quot;;
private $local_url_v2 = &quot;http://192.168.1.91/api/v2_soap/?wsdl=1&quot;;
private $api_url_v1;
private $api_url_v2;

public function setUp() {
    Mage::app('default');
    $this-&gt;setApiUrlV2($this-&gt;local_url_v2);
}

public function getApiUrlV2() {
    return $this-&gt;api_url_v2;
}

public function setApiUrlV2($api_url_v2) {
    $this-&gt;api_url_v2 = $api_url_v2;
}

public function testLogin() {

   $cli = new SoapClient($this-&gt;api_url_v2);

   $username = 'mobile';
   $password = 'mobile123';

   $result = $cli-&gt;login($username, $password);
   $session_id = isset($result) ? $result : null;

   $this-&gt;assertNotNull($session_id);
   return $session_id;
}

public function testCoreCustomerList_V2() {

   $session_id = $this-&gt;testLogin();
   $cli = new SoapClient($this-&gt;api_url_v2);
   $result = $cli-&gt;customerCustomerList($session_id);

   $this-&gt;assertTrue(is_array($result));
   foreach ($result as $res) {
      $this-&gt;assertObjectHasAttribute('customer_id', $res);
   }
 }

}
</pre>
<p>Here we added two test methods: first one id login and it&#8217;s neccesary to return session Id for using in other API calls. Also it is neccesary to add mobile user with appropiate roles in administration of your Magento installation.</p>
<p>Hope that this article was useful to you.</p>
<p>Cheers.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-api-v2-soap-unit-testing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Does your company care about culture?</title>
		<link>http://inchoo.net/fun-zone/does-your-company-care-about-culture/</link>
		<comments>http://inchoo.net/fun-zone/does-your-company-care-about-culture/#comments</comments>
		<pubDate>Tue, 13 Mar 2012 11:58:15 +0000</pubDate>
		<dc:creator>Sanja Martinovic</dc:creator>
				<category><![CDATA[Fun & Events]]></category>
		<category><![CDATA[Marketing]]></category>
		<category><![CDATA[culture]]></category>
		<category><![CDATA[fun]]></category>
		<category><![CDATA[inchoo]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12798</guid>
		<description><![CDATA[Successful organizations care about maintaining and improving their organizational culture. Strong organizational culture means company has some customs, values, unwritten rules and basically a specific way of doing things, that &#8230;]]></description>
			<content:encoded><![CDATA[<p dir="ltr">Successful organizations care about maintaining and improving their organizational culture. Strong organizational culture means company has some customs, values, unwritten rules and basically a specific way of doing things, that all employees respect and believe in. All that helps them work better, increases their motivation, productivity, loyalty and pulls them to work better for achieving organization goals which they identify as their own.<span id="more-12798"></span></p>
<p dir="ltr">Opposite of strong is weak organizational culture, and it has a negative impact on employees motivation, productivity and overall organization success. When I started working at <a href="http://inchoo.hr/">Inchoo HQ</a>, it was obvious that a growing business as it is, has it’s own specific marks and customs that design its culture. Although you can determine and analyze a lot of levels that make some organization’s culture and measure its strength from many different aspects, here are a few characteristics that I saw as creators of organizational culture at Inchoo.</p>
<h3>1. Green</h3>
<p>Every business chooses its home color. But you need to ask yourself is it really representing your work and everyone involved in it? Well, Inchoo actually is green. Green means a desire to be safe but it also means growth. Green is calm but powerful, energetic but balanced. Everyone is very specific and different, but together in some particular way &#8211; they are developing and pursuing ideas to grow, while constantly finding a new common balance. Green is of course all around company interior.</p>
<h3>2. Coffee</h3>
<p>Developers drink a lot of coffee &#8211; that’s something everyone knows. <img src='http://inchoo.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  It’s once said that behind every successful man or woman is a substantial amount of coffee. It might be true, but at Inchoo when you go for (another) cup of coffee, you are reaching for a dose of energy, thinking through what you’re working on, or increasing an idea flow with your colleagues. It’s not just the coffee as a drink, it’s coffee as a common habit that brings working level up.</p>
<h3>3. Breaks and free time</h3>
<p>How do you spend that 15 minutes, or 30 when you have a break from your work? It’s a good culture when you do something relaxing, but what’s making you more close as colleagues and what will have a good impact on your work. Inchooers usually go to near by coffee place, each having its own sort of break-drink <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Most of the time, it is the time voluntarily invested in something related to work.</p>
<h3>4. Knowledge Sharing</h3>
<p>This is something most companies fear &#8211; sharing what you know with others, even customers. But if you really care about quality and delivering your promises to your customers, you have nothing to be afraid of, but to be happy if you serve your customers and public by sharing what you’ve learned. Knowledge sharing is as effective to your customers, as it brings back a great feedback to you and your organization reputation and perspective. The most important way of knowledge sharing in Inchoo is of course via our blog.</p>
<h3>5. Inchooers as comic characters</h3>
<p>Inchooers have their own <a title="Inchooers" href="http://inchoo.net/tag/inchooers/" target="_blank">comic characters</a>. Well, not all of them since there are some brand new faces on the team, but that is something very original, specific and unique that differs Inchooers and empowers their identity. You can see Inchooers’ characters all over the <a href="http://inchoo.net/blog/">blog</a>, <a href="http://www.facebook.com/inchoo">Facebook fan page</a> and on a lot of other material in the firm.</p>
<h3>6. Jokes and fun stuff</h3>
<p>Do you encourage laughing and making jokes on team meetings? Well you should, since it’s important for organizational culture to have their internal stuff going on and talking about. You don’t want your employees be that strict and making barriers to their creativity. What you want is a good atmosphere that brings lightning in dealing with projects, customers, problems and decision making. At Inchoo you can see just that.</p>
<h3>7. Team Building</h3>
<p>Do you do team building and why you do it? Because it’s trendy, you heard it’s a good practice or do you actually see the benefits of team activities within your organization? Can you, as employee or team leader make an atmosphere that almost every coffee break or pizza in the office brings team together? And do you plan team building as something with purpose that people want to be a part of? Inchoo has its <a href="http://www.flickr.com/photos/tomislav-bilic/sets/72157627757217034/">Inchoo Learning Days</a> to have fun and share knowledge. Along with that, if you are a good team leader you might be able to help creating a good atmosphere so every coffee break, pizza or burek in the office does a bit of team empowering.</p>
<h3>8. Values</h3>
<p>This is an important, if not a crucial part of organizational culture. What do you and your employees rely on when problems come, when people change and industries face crisis?  Value system comes from a leader but it needs to be spread throughout your company so you can survive, grow and make better everyday decisions. Projects come and go, but values keep all factors of your business together. Inchoo started to work on a project that brings other IT companies from Osijek area together, focused on delivering values to entire community (<a href="http://softwarecity.hr/">Osijek Software City</a>). You see, values are what your company relies on: it means getting back to its fundamental reasons of existence and it will make sure it actually does a good job through a longer period of time.</p>
<p dir="ltr"><strong>Do you think about improving your organizational culture so your work quality and productivity increases? How do you do that?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/fun-zone/does-your-company-care-about-culture/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Magento unit testing basic setup</title>
		<link>http://inchoo.net/ecommerce/magento/magento-unit-testing/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-unit-testing/#comments</comments>
		<pubDate>Wed, 07 Mar 2012 10:15:08 +0000</pubDate>
		<dc:creator>Darko Goles</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[phpUnit]]></category>
		<category><![CDATA[setup]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12608</guid>
		<description><![CDATA[In my first Magento post I mentioned importance of using unit testing during development. Somebody will say: &#8216;Hello, I don&#8217;t have a time to make some weird unit tests, and &#8230;]]></description>
			<content:encoded><![CDATA[<p>In my first Magento post I mentioned importance of using unit testing during development.<br />
Somebody will say: &#8216;Hello, I don&#8217;t have a time to make some weird unit tests, and why should I need them anyway?&#8217;<br />
I will not try to explain why this is necessary here, because any good experienced developer that wants to follow best practice rules will know what I am talking about&#8230;.<span id="more-12608"></span></p>
<p>Let&#8217;s use my current scenario:</p>
<p>I am currently extending core and developing custom Magento web service API calls to fit our project needs. Do I need to test the calls somehow or I will leave testing to the mobile side of the story?<br />
From my existing experience it&#8217;s more logical for me to test each call to API before I publish them to development server for testing on mobile side. Imagine that for each line of code you write, you have to re-publish source again and again an even you are not sure that it is working properly …<br />
What a waste of precious development time …</p>
<p>Let&#8217;s create our testing environment:</p>
<p>First of all, installing phpUnit is neccesary. Install <a title="PEAR" href="http://pear.php.net/" target="_blank">PEAR</a> (you will find how-to instructions on their website), and also install <a title="PHPUnit" href="http://pear.phpunit.de/" target="_blank">phpUnit</a> first.</p>
<p>With these packages installed, fire-up your favorite IDE (I am using NetBeans 7.0.1) and make some lightweight setup for unit testing:</p>
<p>Open:</p>
<p><strong>Tools/Options</strong> and select &#8216;<strong>Php</strong>&#8216; tab.<br />
Here you will find text field where you should insert location path for yours phpUnit script. In my case it is located in:<br />
&#8216;<em>C:\WampDeveloper\Components\Php\PEAR\phpunit.bat</em>&#8216;, but if yours localhost installation is somehow different, you should find it inside <strong>php/PEAR</strong> folder of yor local web server installation.</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/02/phpUnit_script_setting.jpg"><img class="aligncenter size-medium wp-image-12611" title="phpUnit_script_setting" src="http://inchoo.net/wp-content/uploads/2012/02/phpUnit_script_setting-600x377.jpg" alt="" width="600" height="377" /></a></p>
<p>You have plenty of ways to configure the way the tests will be executed, but for our purpose it will be enough to right click on your project inside &#8216;Projects&#8217; window and go to &#8216;Properties/phpUnit&#8217; where we will choose option: &#8216;<strong>Run all *Test files using PHPUnit</strong> &#8216; and press OK.</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/02/project_properties_phpUnit.jpg"><img class="aligncenter size-medium wp-image-12613" title="project_properties_phpUnit" src="http://inchoo.net/wp-content/uploads/2012/02/project_properties_phpUnit-600x457.jpg" alt="" width="600" height="457" /></a></p>
<p>Next step is to write/put some test files and configure them to run within Magento:</p>
<p>Create new folder inside your webroot in your project and call it for example: &#8216;Tests&#8217;.<br />
Inside that folder – create new Php class called for example: &#8216;customerCustomerTest.php&#8217;:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
// customerCustomerTest.php

require_once 'PHPUnit/Autoload.php';
require_once '../app/Mage.php';

class customerCustomerTest extends PHPUnit_Framework_TestCase {

    public function setUp() {
        Mage::app('default');
    }

}
</pre>
<p>Right click on our &#8216;Tests&#8217; folder and choose Tools/create phpUnit tests, and choose path to out &#8216;Tests&#8217; folder from file browser window. And we are done with basic set-up and we can start to write tests.</p>
<p>Of course – from above code it&#8217;s obvious that you will have to add phpUnit library under global include path if it isn&#8217;t the case already ….</p>
<p>Now you can write your first test with Magento.<br />
In next article I will make some web service API unit tests with SoapClient, so if you are interested, stay tuned … <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-unit-testing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extending Magento web services API v2</title>
		<link>http://inchoo.net/ecommerce/magento/magento-api-v2/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-api-v2/#comments</comments>
		<pubDate>Wed, 29 Feb 2012 09:31:55 +0000</pubDate>
		<dc:creator>Darko Goles</dc:creator>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[api v2]]></category>
		<category><![CDATA[web services]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12595</guid>
		<description><![CDATA[In some of previous posts on inchoo.net, colleague of mine – Branko Ajzele wrote about extending Magento API – v1. Let say that mine extension is called: Inchoo Mapy and &#8230;]]></description>
			<content:encoded><![CDATA[<p>In some of previous posts on inchoo.net, colleague of mine – Branko Ajzele wrote about extending Magento API – v1.</p>
<p>Let say that mine extension is called: Inchoo Mapy and I will extend the customer API V2 first.</p>
<p>Although Magento has pretty rich set of API calls, in my project I found that some of the API calls should be extended to fit our project needs. In later posts I will write about that specific needs and possibilities, but now let&#8217;s concentrate to extending core API V2 first.<span id="more-12595"></span></p>
<p>We should take in consideration that if we extend something with same API call name, we are not nice to other installed extensions that use core API too, so we will extend the core API, but let&#8217;s add new API calls to not interrupt core API maybe needed by other peoples extensions installed.</p>
<p>Folder structure of extension look like this:</p>
<p><a href="http://inchoo.net/wp-content/uploads/2012/02/inchoo_mapy_folder_structure.jpg"><img class="aligncenter size-full wp-image-12600" title="inchoo_mapy_folder_structure" src="http://inchoo.net/wp-content/uploads/2012/02/inchoo_mapy_folder_structure.jpg" alt="" width="407" height="324" /></a></p>
<p>You notice that in extension&#8217;s etc/folder I have several files:</p>
<p>config.xml, api.xml, wsdl.xml, wsi.xml</p>
<p>Main config.xml file should look like this:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;

&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_Mapy&gt;
            &lt;version&gt;0.1.0&lt;/version&gt;
        &lt;/Inchoo_Mapy&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;models&gt;
            &lt;customer&gt;
                &lt;rewrite&gt;
                    &lt;customer_api_v2&gt;Inchoo_Mapy_Model_Customer_Customer_Api_V2&lt;/customer_api_v2&gt;
                &lt;/rewrite&gt;
            &lt;/customer&gt;
        &lt;/models&gt;
    &lt;/global&gt;
&lt;/config&gt;
</pre>
<p>After we defined our rewrite(s), let&#8217;s create V2.php like you can see in folder structure – in fact, let&#8217;s copy V2 file from: core/Mage/Customer/Model/Customer/Api/ and paste it inside our folder structure and make some changes.</p>
<p>For example in this class we will only extend customerCustomerList API V2 call</p>
<pre class="brush: php; title: ; notranslate">
//Inchoo/Mapy_Model/Customer/Customer/Api/V2.php

&lt;?php

/**
 * Override for Magento's Customer/Customer API V2
 *
 * @author darko.goles@inchoo.net
 */
class Inchoo_Mapy_Model_Customer_Customer_Api_V2 extends Mage_Customer_Model_Customer_Api_V2 {

    public function mapyItems($filters)
    {
	//let's log a message from here
	Mage::log('Hello from extended API call', null, true, 'success.log')
    }
}
</pre>
<p>We have more steps to do: we need to add our api.xml file inside our etc folder, where our API calls will be defined, and we also have to define two more files: wsdl.xml for soap and wsi.xml to acoomplish possibility for client side to generate client source code from our definitions.</p>
<p>So, let&#8217;s copy content of file core/Mage/Customer/etc/api.xml file in our etc folder and edit and remove things that we not need yet for purpose of this article:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;!-- Inchoo/Mapy/etc/api.xml --&gt;
&lt;config&gt;
    &lt;api&gt;
        &lt;resources&gt;
&lt;!-- START RESOURCES --&gt;
            &lt;!-- START CUSTOMER RESOURCES --&gt;
            &lt;mapy_customer translate=&quot;title&quot; module=&quot;customer&quot;&gt;
                &lt;model&gt;customer/customer_api&lt;/model&gt;
                &lt;title&gt;Customer API&lt;/title&gt;
                &lt;acl&gt;customer&lt;/acl&gt;
                &lt;methods&gt;
                    &lt;list translate=&quot;title&quot; module=&quot;customer&quot;&gt;
                        &lt;title&gt;Retrieve customers paginated list&lt;/title&gt;
                        &lt;method&gt;mapyItems/method&gt;
                        &lt;acl&gt;customer/info&lt;/acl&gt;
                    &lt;/list&gt;
                &lt;/methods&gt;
                &lt;faults module=&quot;customer&quot;&gt;
                    &lt;data_invalid&gt;
                        &lt;code&gt;100&lt;/code&gt;
                        &lt;message&gt;Invalid customer data. Details in error message.&lt;/message&gt;
                    &lt;/data_invalid&gt;
                    &lt;filters_invalid&gt;
                        &lt;code&gt;101&lt;/code&gt;
                        &lt;message&gt;Invalid filters specified. Details in error message.&lt;/message&gt;
                    &lt;/filters_invalid&gt;
                    &lt;not_exists&gt;
                        &lt;code&gt;102&lt;/code&gt;
                        &lt;message&gt;Customer not exists.&lt;/message&gt;
                    &lt;/not_exists&gt;
                    &lt;not_deleted&gt;
                        &lt;code&gt;103&lt;/code&gt;
                        &lt;message&gt;Customer not deleted. Details in error message.&lt;/message&gt;
                    &lt;/not_deleted&gt;
                &lt;/faults&gt;
            &lt;/mapy_customer&gt;
            &lt;!-- END CUSTOMER RESOURCES --&gt;
&lt;!-- END RESOURCES --&gt;
        &lt;/resources&gt;
        &lt;v2&gt;
            &lt;resources_function_prefix&gt;
&lt;!-- START V2 FUNCTIONS PREFIX --&gt;
                    &lt;!-- START V2 CUSTOMER FUNCTION PREFIX --&gt;
                &lt;mapy_customer&gt;mapy_customerCustomer&lt;/mapy_customer&gt;
                    &lt;!-- END V2 CUSTOMER FUNCTION PREFIX --&gt;
&lt;!-- END V2 FUNCTIONS PREFIX --&gt;
            &lt;/resources_function_prefix&gt;
        &lt;/v2&gt;

        &lt;acl&gt;
            &lt;resources&gt;
&lt;!-- ACL RESOURCES --&gt;
                &lt;!-- START CUSTOMER ACL RESOURCES --&gt;
                &lt;mapy_customer translate=&quot;title&quot; module=&quot;customer&quot;&gt;
                    &lt;title&gt;Customers&lt;/title&gt;
                    &lt;sort_order&gt;3&lt;/sort_order&gt;
                    &lt;info translate=&quot;title&quot; module=&quot;customer&quot;&gt;
                        &lt;title&gt;Retrieve customer info&lt;/title&gt;
                    &lt;/info&gt;
                &lt;/mapy_customer&gt;
                &lt;!-- END CUSTOMER ACL RESOURCES --&gt;
&lt;!-- END ACL RESOURCES --&gt;
            &lt;/resources&gt;
        &lt;/acl&gt;
    &lt;/api&gt;
&lt;/config&gt;
</pre>
<p>You will notice that we have V2 node inside api.xml file – that is used as prefix for API V2 calls &#8230;<br />
Now just grab the wsdl.xml files and wsi.xml files from core/Mage/Customer/etc and edit them to suit your needs: add new API calls, extend existing complex types definitions etc, and Magento will load and merge all of these files with appropiate core files.</p>
<p>Of course, all API calls is availible at following url:<br />
<strong>http://yourmagentoinstallation/api/v2_soap/?wsdl=1</strong></p>
<p>When you are going to auto-generate web service&#8217;s client classes, don&#8217;t forget inside admin area to change WSI compliance to : yes and reurn to no when you are ready to consume web services.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-api-v2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Automatically invoice/ship/complete order in Magento</title>
		<link>http://inchoo.net/ecommerce/magento/magento-orders/automatically-invoice-ship-complete-order-in-magento/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-orders/automatically-invoice-ship-complete-order-in-magento/#comments</comments>
		<pubDate>Tue, 28 Feb 2012 14:55:57 +0000</pubDate>
		<dc:creator>Branko Ajzele</dc:creator>
				<category><![CDATA[Orders]]></category>
		<category><![CDATA[invoice]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[order]]></category>
		<category><![CDATA[payment]]></category>
		<category><![CDATA[shipment]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12683</guid>
		<description><![CDATA[Various merchants, various demands. Imagine you have a private on site sale or something like that, where your checkout requirements are pretty simply: create invoice / ship and complete the &#8230;]]></description>
			<content:encoded><![CDATA[<p>Various merchants, various demands. Imagine you have a private on site sale or something like that, where your checkout requirements are pretty simply: create invoice / ship and complete the order all at once. For example, you are doing the checkout for bunch of people standing in front of you, paying you money right on the spot. In such scenario overload of manually creating an invoice and shipment can be too much.<span id="more-12683"></span></p>
<p>Thus, having your Magento automatically invoice/ship/complete orders can be a logical request. So how do we do that?</p>
<p>Easy! All you need to do is to observe the <strong>sales_order_save_after</strong> event or observe the <strong>controller_action_predispatch</strong> event and target the <strong>Mage_Checkout_OnepageController::successAction()</strong> catching the <strong>Mage::getSingleton(&#8216;checkout/session&#8217;)->getLastOrderId()</strong>. In this example I decided to demonstrate the possible (not ideal, or not even the best) &#8220;<strong>sales_order_save_after</strong> event&#8221; approach.</p>
<p>If we where to code everything in form of a module/extension, then all we need are two files. Here is the content of config.xml of our module:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_Invoicer&gt;
            &lt;version&gt;1.0.0.0&lt;/version&gt;
        &lt;/Inchoo_Invoicer&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;models&gt;
            &lt;inchoo_invoicer&gt;
                &lt;class&gt;Inchoo_Invoicer_Model&lt;/class&gt;
            &lt;/inchoo_invoicer&gt;
        &lt;/models&gt;
        &lt;events&gt;
            &lt;sales_order_save_after&gt;
                &lt;observers&gt;
                    &lt;inchoo_invoicer_automatically_complete_order&gt;
                        &lt;class&gt;inchoo_invoicer/observer&lt;/class&gt;
                        &lt;method&gt;automaticallyInvoiceShipCompleteOrder&lt;/method&gt;
                    &lt;/inchoo_invoicer_automatically_complete_order&gt;
                &lt;/observers&gt;
            &lt;/sales_order_save_after&gt;
        &lt;/events&gt;
    &lt;/global&gt;
&lt;/config&gt;
</pre>
<p>And here is the code for our observer model.</p>
<pre class="brush: php; title: ; notranslate">
class Inchoo_Invoicer_Model_Observer
{
    /**
     * Mage::dispatchEvent($this-&gt;_eventPrefix.'_save_after', $this-&gt;_getEventData());
     * protected $_eventPrefix = 'sales_order';
     * protected $_eventObject = 'order';
     * event: sales_order_save_after
     */
    public function automaticallyInvoiceShipCompleteOrder($observer)
    {
        $order = $observer-&gt;getEvent()-&gt;getOrder();

        $orders = Mage::getModel('sales/order_invoice')-&gt;getCollection()
                        -&gt;addAttributeToFilter('order_id', array('eq'=&gt;$order-&gt;getId()));
        $orders-&gt;getSelect()-&gt;limit(1);  

        if ((int)$orders-&gt;count() !== 0) {
            return $this;
        }

        if ($order-&gt;getState() == Mage_Sales_Model_Order::STATE_NEW) {

            try {
                if(!$order-&gt;canInvoice()) {
                    $order-&gt;addStatusHistoryComment('Inchoo_Invoicer: Order cannot be invoiced.', false);
                    $order-&gt;save();
                }

                //START Handle Invoice
                $invoice = Mage::getModel('sales/service_order', $order)-&gt;prepareInvoice();

                $invoice-&gt;setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_OFFLINE);
                $invoice-&gt;register();

                $invoice-&gt;getOrder()-&gt;setCustomerNoteNotify(false);
                $invoice-&gt;getOrder()-&gt;setIsInProcess(true);
                $order-&gt;addStatusHistoryComment('Automatically INVOICED by Inchoo_Invoicer.', false);

                $transactionSave = Mage::getModel('core/resource_transaction')
                    -&gt;addObject($invoice)
                    -&gt;addObject($invoice-&gt;getOrder());

                $transactionSave-&gt;save();
                //END Handle Invoice

                //START Handle Shipment
                $shipment = $order-&gt;prepareShipment();
                $shipment-&gt;register();

                $order-&gt;setIsInProcess(true);
                $order-&gt;addStatusHistoryComment('Automatically SHIPPED by Inchoo_Invoicer.', false);

                $transactionSave = Mage::getModel('core/resource_transaction')
                    -&gt;addObject($shipment)
                    -&gt;addObject($shipment-&gt;getOrder())
                    -&gt;save();
                //END Handle Shipment
            } catch (Exception $e) {
                $order-&gt;addStatusHistoryComment('Inchoo_Invoicer: Exception occurred during automaticallyInvoiceShipCompleteOrder action. Exception message: '.$e-&gt;getMessage(), false);
                $order-&gt;save();
            }
        }

	return $this;
    }
}
</pre>
<p>Before I go any further, I must emphasize that there is a certain known buggy code within automaticallyInvoiceShipCompleteOrder method <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . This is to keep the example simple. Meaning this code should be written with more detailed checks if it where to go on live site. As you can see, the first thing I&#8217;m doing above is looking into the sales/order_invoice collection to check if there are any existing invoices created for the particular order. If there are none, then I proceed with creating both invoice and shipment.</p>
<p>Next in line is the simple check for order state, IF &#8220;new&#8221; (which means created right now) then do the entire process of invoicing and shipment. This IF condition is a good place if you wish ti limit this code to orders created by specific Payment gateway, for example Check/Money which has the &#8220;checkmo&#8221; code, in which case all you need to do is call <strong>if ($order->getPayment()->getMethod == &#8216;checkmo&#8217;)</strong>, etc. The above code was tested on Magento 1.6.2.0. If you plan using it on some live site, please test it thoroughly before and adjust it to your specific needs.</p>
<p>Cheers.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-orders/automatically-invoice-ship-complete-order-in-magento/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Building a &#8220;Facebook Like&#8221; button extension for Magento in 15 minutes</title>
		<link>http://inchoo.net/ecommerce/magento/magento-products/building-a-facebook-like-button-extension-for-magento-in-15-minutes/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-products/building-a-facebook-like-button-extension-for-magento-in-15-minutes/#comments</comments>
		<pubDate>Mon, 27 Feb 2012 14:00:04 +0000</pubDate>
		<dc:creator>Branko Ajzele</dc:creator>
				<category><![CDATA[Products]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[like]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[product]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12666</guid>
		<description><![CDATA[Facebook LIKE button is pretty easy and straight forward to implement. All you need to do is to copy paste 2-3 sections from Facebook developer site adjust them to your &#8230;]]></description>
			<content:encoded><![CDATA[<p>Facebook LIKE button is pretty easy and straight forward to implement. All you need to do is to copy paste 2-3 sections from Facebook developer site adjust them to your needs and you are done.<span id="more-12666"></span></p>
<p>Since we will be coding this for Magento, why not make it an extension, Inchoo_Flike. Imagine I&#8217;m working under the budget and my time is limited, I&#8217;ll do my best to code is as fast as I can, but still keeping the &#8220;Magento way of things&#8221; in mind. With that in mind, here is the content of my extensions config.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;modules&gt;
        &lt;Inchoo_Flike&gt;
            &lt;version&gt;1.0.0.0&lt;/version&gt;
        &lt;/Inchoo_Flike&gt;
    &lt;/modules&gt;
    &lt;frontend&gt;
        &lt;layout&gt;
            &lt;updates&gt;
                &lt;inchoo_flike&gt;
                    &lt;file&gt;inchoo/flike/flike.xml&lt;/file&gt;
                &lt;/inchoo_flike&gt;
            &lt;/updates&gt;
        &lt;/layout&gt;
    &lt;/frontend&gt;
&lt;/config&gt;
</pre>
<p>As implied within the above&#8217;s config I need to add the inchoo/flike/flike.xml under the default theme layout folder. Here is the content of flike.xml file:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;layout version=&quot;0.1.0&quot;&gt;
    &lt;catalog_product_view&gt;
        &lt;reference name=&quot;head&quot;&gt;
            &lt;block type=&quot;core/template&quot; name=&quot;inchoo_flike_tags&quot; template=&quot;inchoo/flike/tags.phtml&quot; before=&quot;-&quot; /&gt;
        &lt;/reference&gt;
        &lt;reference name=&quot;after_body_start&quot;&gt;
            &lt;block type=&quot;core/template&quot; name=&quot;inchoo_flike_js&quot; template=&quot;inchoo/flike/js.phtml&quot; before=&quot;-&quot; /&gt;
        &lt;/reference&gt;
        &lt;reference name=&quot;alert.urls&quot;&gt;
            &lt;block type=&quot;core/template&quot; name=&quot;inchoo_flike_button&quot; template=&quot;inchoo/flike/button.phtml&quot; before=&quot;-&quot; /&gt;
        &lt;/reference&gt;
    &lt;/catalog_product_view&gt;
&lt;/layout&gt;
</pre>
<p>For sake of simplicity and budget restriction, I decided to stay within the frames of &#8220;core/template&#8221; blocks. I can spare a minute or two on this one <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Now we move on to the files mentioned in the flike.xml file: tags.phtml, js.phtml, button.phtml.</p>
<p>File tags.phtml contains the &#8220;Open Graph Tags&#8221;, as we want to have the correct product image, description, etc. when we LIKE our product. Since this stuff needs to go under the &#8220;head&#8221; of HTML page, I injected it under the head block. Here is the content of tags.phtml:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php $_product = Mage::registry('current_product') ?&gt;
&lt;?php if ($_product &amp;&amp; $_product-&gt;getId()): ?&gt;
&lt;meta property=&quot;og:title&quot; content=&quot;&lt;?php echo $this-&gt;stripTags($_product-&gt;getName(), null, true) ?&gt;&quot; /&gt;
&lt;meta property=&quot;og:type&quot; content=&quot;product&quot; /&gt;
&lt;meta property=&quot;og:image&quot; content=&quot;&lt;?php echo $this-&gt;helper('catalog/image')-&gt;init($_product, 'small_image')-&gt;resize(130, 110); ?&gt;&quot; /&gt;
&lt;meta property=&quot;og:url&quot; content=&quot;&lt;?php echo $_product-&gt;getProductUrl() ?&gt;&quot; /&gt;
&lt;meta property=&quot;og:site_name&quot; content=&quot;&lt;?php echo Mage::app()-&gt;getStore()-&gt;getName() ?&gt;&quot; /&gt;
&lt;?php endif; ?&gt;
</pre>
<p>Notice the detail around the image size. This conforms to the official Facebook definition of <em>og:image</em> tag: <em>The og:image is the URL to the image that appears in the Feed story. The thumbnail&#8217;s width AND height must be at least 50 pixels, and cannot exceed 130&#215;110 pixels. The ratio of both height divided by width and width divided by height (w/h, h/w) cannot exceed 3.0. For example, an image of 126&#215;39 pixels will not be displayed, as the ratio of width divided by height is greater than 3.0 (126/39 = 3.23). Images will be resized proportionally.</em></p>
<p>File js.phtml containes the JavaScript code that goes along with LIKE button:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php $_product = Mage::registry('current_product') ?&gt;
&lt;?php if ($_product &amp;&amp; $_product-&gt;getId()): ?&gt;
&lt;div id=&quot;fb-root&quot;&gt;&lt;/div&gt;
&lt;script&gt;(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = &quot;//connect.facebook.net/en_US/all.js#xfbml=1&quot;;
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));&lt;/script&gt;
&lt;?php endif; ?&gt;
</pre>
<p>And finally, file button.phtml contains the actual button:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php $_product = Mage::registry('current_product') ?&gt;
&lt;?php if ($_product &amp;&amp; $_product-&gt;getId()): ?&gt;
&lt;div class=&quot;fb-like&quot; data-href=&quot;&lt;?php echo $_product-&gt;getProductUrl() ?&gt;&quot; data-send=&quot;true&quot; data-width=&quot;450&quot; data-show-faces=&quot;true&quot;&gt;&lt;/div&gt;
&lt;?php endif; ?&gt;
</pre>
<p>And that&#8217;s it. If you did not do any heavy modifications around your custom theme, more precisely the product view page by removing the &#8220;alert.urls&#8221; block, then you should be able to see Facebook LIKE button there, right near the product name.</p>
<p>Surely there is room for improvement to this little extension. Consider it only as a quick example.<br />
Cheers.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-products/building-a-facebook-like-button-extension-for-magento-in-15-minutes/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Magento EE, use reward points in X percent of total (subtotal) checkout value</title>
		<link>http://inchoo.net/ecommerce/magento/magento-checkout/magento-ee-use-reward-points-in-x-percent-of-total-subtotal-checkout-value/</link>
		<comments>http://inchoo.net/ecommerce/magento/magento-checkout/magento-ee-use-reward-points-in-x-percent-of-total-subtotal-checkout-value/#comments</comments>
		<pubDate>Mon, 27 Feb 2012 10:00:02 +0000</pubDate>
		<dc:creator>Branko Ajzele</dc:creator>
				<category><![CDATA[Checkout]]></category>
		<category><![CDATA[checkout]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[points]]></category>
		<category><![CDATA[reward]]></category>

		<guid isPermaLink="false">http://inchoo.net/?p=12655</guid>
		<description><![CDATA[Magento EE is a great platform, it offers so much features out of the box. However, merchants can be relentless sometimes and always ask for that little extra around a &#8230;]]></description>
			<content:encoded><![CDATA[<p>Magento EE is a great platform, it offers so much features out of the box. However, merchants can be relentless sometimes and always ask for that little extra around a given feature. So happens that I&#8217;ve been working on a project recently where we needed to squeeze a little extra from Magenot&#8217;s Reward Points functionality. We need the possibility to use reward points in X percent of total (subtotal) checkout value. This is not a built in option that you can configure, so it required a bit of custom coding.<span id="more-12655"></span></p>
<p>I&#8217;ll be honest with you, every time I need to poke around Magento checkout I get all nervous and jumpy, as you never know how much time it will take you. After some careful planning and analysis I came up with the quick solution. Why not simply override the method that returns the reward points balance and fake the reward points amount by implementing the &#8220;use reward points in X percent of total (subtotal) checkout value&#8221; logic. There is one major drawback to this, if we override the method to fake the amount of reward point&#8217;s then the amount would be faked trough entire site, which we do not want. We just want to fake it throughout the checkout process until we create a successful order.</p>
<p>So where do we begin (first off all, we are talking about Magento EE so I&#8217;m unable to give you a more detailed code overview, only what I coded)? We will begin by rewriting the Enterprise_Reward_Model_Reward class trough your modules config.xml file.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;global&gt;
	&lt;models&gt;
		&lt;enterprise_reward&gt;
			&lt;rewrite&gt;
				&lt;reward&gt;Inchoo_MyModule_Model_Reward&lt;/reward&gt;
			&lt;/rewrite&gt;
		&lt;/enterprise_reward&gt;
	&lt;/models&gt;
&lt;/global&gt;
</pre>
<p>Then the implementation of Inchoo_MyModule_Model_Reward itself.</p>
<pre class="brush: php; title: ; notranslate">
class Inchoo_MyModule_Model_Reward extends Enterprise_Reward_Model_Reward
{
    public function getPointsBalance()
    {
        $request = Mage::app()-&gt;getRequest();

        if ($request-&gt;getModuleName() == 'checkout') {
            if (($quote = Mage::getModel('checkout/session')-&gt;getQuote())) {
                $totals = $quote-&gt;getTotals();
                $cartTotal = floor($totals[&quot;subtotal&quot;]-&gt;getValue());
                if ($cartTotal &gt; 0) {
                    $rpPercent = 23; /* some integer value representing percent, could read this trough some config */

                    $rpAllowedMax = $cartTotal * ($rpPercent / 100);
                    $rpAllowedMax = floor($rpAllowedMax);

                    if ((int)$this-&gt;getData('points_balance') &gt;= $rpAllowedMax) {
                        return $rpAllowedMax;
                    }
                }
            }
        }

        return $this-&gt;getData('points_balance');
    }
}
</pre>
<p>The best part of all is the getPointsBalance() method itself. If you look at the parent class, you will see that the method does not exit there. It&#8217;s one of those Magento/PHP magic method implemented trough Varien_Object. So, by implementing the method our-self we get the control of the returned balance value, while still being able to fetch the true non-touched value of points_balance by calling the $reward->getData(&#8216;points_balance&#8217;) later in the code.</p>
<p>And for the grand finale, we simply limit the special &#8220;use reward points in X percent of total (subtotal) checkout value&#8221; function behavior to &#8220;checkout&#8221; module by usage of <strong>if($request->getModuleName() == &#8216;checkout&#8217;)</strong>. If you trace the controller actions more thoroughly, you can even limit it to a controller action level. Just be sure to test everything later so that you do not break calls to $reward->getPointsBalance() on a places that should not implement the above logic.</p>
<p>You might also change the default message for Reward Points shown on the Payment step of the checkout to something like:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php echo Mage::helper('enterprise_reward')-&gt;__('Use my reward points, %s available out of %d total', Mage::helper('enterprise_reward')-&gt;formatReward($this-&gt;getPointsBalance(), $this-&gt;getCurrencyAmount()), $this-&gt;getReward()-&gt;getData('points_balance')); ?&gt;
</pre>
<p>With this simple approach I was able to get the exact behavior I needed. I do realize that the approach I took might not be the best optimized, or in the best spirit of MVC since I was doing a module/controller action check within the module, but it strikes the right balance between &#8220;do it on time and do it stable&#8221; <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>I realize this article is somewhat specific and might not apply directly to wider public, but I hope it was useful, at least as an idea <img src='http://inchoo.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>Cheers.</p>
]]></content:encoded>
			<wfw:commentRss>http://inchoo.net/ecommerce/magento/magento-checkout/magento-ee-use-reward-points-in-x-percent-of-total-subtotal-checkout-value/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

