<?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>Magebase</title>
	<atom:link href="http://magebase.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://magebase.com</link>
	<description>Magento Tutorials, Tips and Extensions - For Developers by Developers</description>
	<lastBuildDate>Mon, 30 Apr 2012 04:04:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Free Magento Extension &#8211; Customer Comments In The Checkout</title>
		<link>http://magebase.com/magento-extensions/free-magento-extension-customer-comments-in-the-checkout/</link>
		<comments>http://magebase.com/magento-extensions/free-magento-extension-customer-comments-in-the-checkout/#comments</comments>
		<pubDate>Mon, 30 Apr 2012 04:00:47 +0000</pubDate>
		<dc:creator>Robert Popovic</dc:creator>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[checkout]]></category>
		<category><![CDATA[customer comments]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1568</guid>
		<description><![CDATA[There are a number of "Customer Comments in the Checkout" extensions available already but, today, we offer one that is not only free but also teaches us a lesson in Magento minimalism. Enjoy!<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2012 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-thumbnail wp-image-1615" title="free extension: customer comments in checkout" src="http://magebase.com/wp-content/uploads/2012/03/free-ext-customer-comments-150x150.png" alt="free extension: customer comments in checkout" width="150" height="150" />Most e-commerce sites provide a way for customers to add comments to the order when they are checking out. Surprisingly, Magento does not provide built in functionality to deal with this simple requirement. This means that we will need to add this functionality as a custom extension and there are several extensions on the Magento extensions directory that provide this functionality.</p>
<p>So why are we adding yet another customer comment extension to the mix? We feel that our solution achieves the task with minimal and unobtrusive code and is in line with the Magento order management workflow.</p>
<p>Let&#8217;s see in a few screenshots how this extension shows up once it is installed.</p>
<h2>1. Extension Configuration</h2>
<p>The extension has a configuration section under: System &gt; Configuration &gt; Sales &gt; Checkout &gt; Magebase Checkout Comment Options:</p>
<div id="attachment_1601" class="wp-caption alignnone" style="width: 674px"><img class="size-full wp-image-1601" title="cutomer comment configuration" src="http://magebase.com/wp-content/uploads/2012/03/mb-cutomer-comment-config.png" alt="cutomer comment configuration" width="664" height="284" /><p class="wp-caption-text">The only configuration parameter is Enabled/Disabled</p></div>
<p>All it controls is whether the extension functionality is enabled or disabled. No rocket science there.</p>
<h2>2. Checkout &#8211; Shipping Step</h2>
<p>The extension comes with a layout file under <code>app/design/frontend/base/default/layout/magebase/checkoutcomment.xml</code> and a couple of phtml files under <code>app/design/frontend/base/default/template/magebase/checkoutcomment/</code>. Out of the box, the extension will automatically display the Customer Comment field on the shipping methods step in the one page checkout. No action should be necessary to make this field show unless you have a heavily customized checkout or you are using a custom checkout extension.</p>
<div id="attachment_1600" class="wp-caption alignnone" style="width: 690px"><a class="zoom" href="http://magebase.com/wp-content/uploads/2012/03/mb-cutomer-comment-shipping.png"><img class="size-large wp-image-1600 " title="customer comment field on shipping step" src="http://magebase.com/wp-content/uploads/2012/03/mb-cutomer-comment-shipping-680x404.png" alt="customer comment field on shipping step" width="680" height="404" /></a><p class="wp-caption-text">The customer comment field on the shipping step</p></div>
<p>Note that the extension doesn&#8217;t supply its own CSS so you will need to style appropriately.</p>
<h2>3. Order Administration</h2>
<div id="attachment_1602" class="wp-caption alignright" style="width: 418px"><img class="size-full wp-image-1602 " title="cutomer comment order admin" src="http://magebase.com/wp-content/uploads/2012/03/mb-cutomer-comment-order-admin.png" alt="cutomer comment order admin" width="408" height="365" /><p class="wp-caption-text">The customer comment appears in the Comment History</p></div>
<p>Once the customer has completed the checkout and placed the order, we need to know where the customer comment information will be shown on the order management page. This is where the extension is &#8216;clever&#8217; and keeps in line with the Magento order workflow. The extension will simply add the customer comment to the Comments History as shown in the screenshot to the right. This means that the extension doesn&#8217;t alter the default database to add custom columns to any Magento entities but uses the built in functionality to its advantage.</p>
<p>From an order workflow perspective, this makes sense as any notes and comments around the order are kept in the same area.</p>
<h2 class="clear">4. Order Confirmation Email</h2>
<p>Another serendipitous consequence of using the built in Comments History functionality is that the customer comment is automatically sent out in the order confirmation email without any extra effort or additional template changes.</p>
<div id="attachment_1603" class="wp-caption alignnone" style="width: 668px"><img class="size-full wp-image-1603 " title="customer comment in confirmation email" src="http://magebase.com/wp-content/uploads/2012/03/mb-cutomer-comment-email.png" alt="customer comment in confirmation email" width="658" height="57" /><p class="wp-caption-text">The customer comment in the confirmation email</p></div>
<h2>How it works</h2>
<p>If you lift the &#8216;hood&#8217; off this extension, you will see that the code is very simple. It leverages off built in Magento features to provide this simple functionality in an unobtrusive way by using an event observer, the comments history method and the <code>output="toHtml"</code> layout attribute to force itself to render on the checkout template. The phtml is structured based on the Magento customer widget field implementation.</p>
<p>Suffice to say, the single line of code (in <code>Observer.php</code>) that makes it all happen is:</p>
<pre class="brush: php; title: ; notranslate">
$observer-&gt;getEvent()-&gt;getQuote()-&gt;getShippingAddress()-&gt;setCustomerNotes($orderComment)-&gt;save();
</pre>
<h2>Download</h2>
<p class="download"><a href="http://magebase.com/wp-content/uploads/2012/03/Magebase_CheckoutComment-0.1.0.tar.gz">Magebase_CheckoutComment</a></p>
<h2>Summary</h2>
<p>Hopefully, we have supplied the community with a simple, free and useful extension and shown how to utilize built in Magento features to minimize our own programming effort and create efficient, performance conscious code.</p>
<p class="note">Note: This extension was developed and tested on Magento 1.6.2.0 but should work fine for Magento CE 1.4.x and up, PE, EE 1.8.0 and up. There is no warranty or guarantee for the functionality and I don’t provide support for this extension. Use at your own risk and ALWAYS backup your database before installing.</p>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2012 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-extensions/free-magento-extension-customer-comments-in-the-checkout/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Understanding the Grid Serializer Block</title>
		<link>http://magebase.com/magento-tutorials/understanding-the-grid-serializer-block/</link>
		<comments>http://magebase.com/magento-tutorials/understanding-the-grid-serializer-block/#comments</comments>
		<pubDate>Mon, 16 Apr 2012 05:00:56 +0000</pubDate>
		<dc:creator>Paryank Kansara</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[adminhtml]]></category>
		<category><![CDATA[grid serializer]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1581</guid>
		<description><![CDATA[In this new series of Magento tutorials, I will explain the function and use of the Adminhtml Grid Serializer object. We will see how it functions as well as how we can create our own custom serializers to handle our data.<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2012 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<h2><img class="alignright size-thumbnail wp-image-1595" title="magento grid serializer" src="http://magebase.com/wp-content/uploads/2012/04/magento-grid-serializer-150x150.jpg" alt="magento grid serializer" width="150" height="150" />Limitations of multi-select boxes</h2>
<p>There are many cases in an ecommerce platform where some entities are related to each other with one-to-many relationship. Familiar examples are Upsell, Cross-sell and Related Products. One product may have many upsell, cross-sell or related products. Let’s take Upsell Products for example. Each product can have more than one Upsell product. To accept data for managing and storing this kind of relationship through a form or admin interface, multi-select boxes are normally sufficient, but this approach has a few limitations:</p>
<ol>
<li>It can be used to display only one property of the entity. In our example, we can display product names in a multi-select box, but we can’t easily display other attributes like SKU, price etc.</li>
<li>The user can only select multiple entities but cannot supply additional data for each selection. In our example, the form can accept a selection of products but cannot accept data for the position of each product.</li>
<li>When there is huge number of options, multi-select boxes can become bulky and difficult to manage.</li>
<li>It cannot provide sorting or filtering so that user can easily pick choices from a subset of results.</li>
</ol>
<h2>The Grid Component as a Form Field</h2>
<p>To overcome the limitations of a simple multi-select box, we should have an advanced element that has features like:</p>
<ol>
<li>Ability to select/unselect multiple entities</li>
<li>Ability to display more information about entities</li>
<li>Ability to accept additional user input data</li>
<li>Should support pagination when there is a large number of entities</li>
<li>Should support sorting and filtering by multiple parameters</li>
<li>Should be unified so that it can be used for different entities and different data</li>
</ol>
<p>Fortunately, Magento provides some very interesting components, which are very useful in the development of extensions involving the admin interface. These components are so powerful that developers have to write very little to almost ‘no’ template code to create an intuitive user interface.</p>
<p>One of these components is the ‘Grid’. It provides built-in pagination, sorting, and filtering. The Grid is widely used in the admin interface for listing entities like products, orders, invoices, customers etc. But my most favorite use of the Grid is as a form element. Magento provides an excellent solution to overcome the above described limitations of multi-select boxes by using the grid as a form element for accepting data for creating one-to-many relationships.</p>
<pre class="brush: php; title: ; notranslate">$this-&gt;addColumn('in_products', array(
    'header_css_class' =&gt; 'a-center',
    'type'            =&gt; 'checkbox',
    'name'            =&gt; 'in_products',
    'values'          =&gt; $this-&gt;_getSelectedProducts(),
    'align'           =&gt; 'center',
    'index'           =&gt; 'entity_id'
 ));</pre>
<p>When a Grid is used as a form element as a replacement for multi-select boxes, normally, the first column type is defined as ‘checkbox’. So each row in the grid displays a checkbox. Users can tick the checkboxes to select particular rows. This is more intuitive than selecting multiple options in a multi-select box.</p>
<h2>Data preservation problem between AJAX reloads</h2>
<p>At first glance, this mechanism seems perfect. But, the grid also has pagination, sorting and filtering. Each time these operations are performed, the grid is reloaded through an AJAX call, and each time the grid is reloaded, the selection made previously is lost. If, for example, we are selecting upsell products, we could select 3 products from the grid by ticking the corresponding checkboxes. Now, we click on the ‘Next’ link to load the next page of products and perhaps, select 3 products here too. Then, we click on the ‘Previous’ link to load the previous page again. We may find that our 3 previously chosen products are no longer selected. The same would happen for sorting and filtering. So while Grid component overcomes the limitation of multi-select boxes, the features of pagination, filtering and sorting add another issue in the sense that our selected data is not preserved across these actions.</p>
<h2>How the Serializer Block solves data preservation problem</h2>
<p>Magento provides another block called the ‘Serializer Block’ for preserving selection data. The serializer block is normally appended to the grid block. This block adds a hidden field and creates a Serializer JavaScript object. The Serializer JS Object uses the Grid JS Object to retrieve any selected rows. Then it serializes the data i.e. <code>key1=value1&amp;key2=value2&amp;…</code> and stores this serialized string in the hidden field. As this block is always outside of the grid block, even after the grid block is reloaded via AJAX, the value of it is preserved. This serialized string is passed as part of the form submission data which can easily be decoded using the PHP function <code>parse_str()</code>.</p>
<p>However, a form element doesn’t only store user input data but also displays what has been stored in it. For example, when we enter some text in a textbox, it displays whatever we have typed. When we select any option from a select box, it displays which options have been selected. Similarly, this new user input element should also display which rows a user has selected. In other words, it should mark checkboxes checked for each selected row.</p>
<p>For this, Serializer JS object keeps its interaction with the Grid JS object by observing events from the grid. So when a grid block is reloaded, the Serializer JS object automatically selects checkboxes of rows, which we may have already selected.</p>
<p>So, with this theory out of the way, we can focus on how to apply this knowledge to create our own custom admin grid interfaces.</p>
<h2>Using the Grid Serializer Block</h2>
<p>Magento provides a built-in library for creating custom grid and serializer blocks. Here, we can take Upsell Products grid as an example to understand how this works.</p>
<p>On the product edit page, there is a tab – Upsell Products. The tab content is loaded via AJAX. The action called for this AJAX tab is: <code>Mage_Adminhtml_Catalog_ProductController::upsellAction()</code>.</p>
<p>So the layout update loaded for this action is defined as below in the layout XML file <code>app/design/adminhtml/default/default/catalog.xml</code></p>
<pre class="brush: xml; title: ; notranslate">&lt;adminhtml_catalog_product_upsell&gt;
    &lt;block type=&quot;core/text_list&quot; name=&quot;root&quot;&gt;
        &lt;block type=&quot;adminhtml/catalog_product_edit_tab_upsell&quot; name=&quot;catalog.product.edit.tab.upsell&quot;/&gt;
        &lt;block type=&quot;adminhtml/widget_grid_serializer&quot; name=&quot;upsell_grid_serializer&quot;&gt;
            &lt;reference name=&quot;upsell_grid_serializer&quot;&gt;
                &lt;action method=&quot;initSerializerBlock&quot;&gt;
                    &lt;grid_block_name&gt;catalog.product.edit.tab.upsell&lt;/grid_block_name&gt;
                    &lt;data_callback&gt;getSelectedUpsellProducts&lt;/data_callback&gt;
                    &lt;hidden_input_name&gt;links[upsell]&lt;/hidden_input_name&gt;
                    &lt;reload_param_name&gt;products_upsell&lt;/reload_param_name&gt;
                &lt;/action&gt;
                &lt;action method=&quot;addColumnInputName&quot;&gt;
                    &lt;input_name&gt;position&lt;/input_name&gt;
                &lt;/action&gt;
            &lt;/reference&gt;
        &lt;/block&gt;
    &lt;/block&gt;
 &lt;/adminhtml_catalog_product_upsell&gt;</pre>
<p>Here, the root block is core/text_list type. So all children blocks are automatically rendered in sequence. See <a href="http://magebase.com/magento-tutorials/demystifying-magentos-layout-xml-part-1/">Demystifying Magento&#8217;s Layout XML Part 1</a>.</p>
<p>First child block <code>catalog.product.edit.tab.upsell</code> is type of <code>adminhtml/catalog_product_edit_tab_upsell</code>, which is inherited class of <code>Mage_Adminhtml_Block_Widget_Grid</code>. So it creates a grid. The second child block <code>adminhtml/widget_grid_serializer</code> is of type <code>adminhtml/widget_grid_serializer</code>, which is the serializer block. So as we discussed above, the serializer block is appended to the grid block.</p>
<p>In layout XML, for the serializer block, an action <code>initSerializerBlock is called with the following parameters:</code></p>
<ol>
<li>grid_block_name: It defines the grid’s block name in the layout. In our case it is <code>catalog.product.edit.tab.upsell</code>.</li>
<li>data_callback: This defines a method to be called on the grid block instance to retrieve already selected values. In our case it is <code>getSelectedUpsellProducts()</code>.</li>
<li>hidden_input_name: This is a hidden input element name by which the data can be retrieved from the POST object. In our case it is <code>links[upsell]</code>.</li>
<li>reload_param_name: This is the parameter name by which the selection data is posted back to the AJAX call while reloading the grid for pagination, filtering, sorting etc. In our case it is <code>products_upsell</code>.</li>
</ol>
<p>When the serializer block is initialized, it calls a method defined by data_callback on our grid block instance to retrieve initial data. In our case it is <code>getSelectedUpsellProducts()</code>. Here is the code for this method in Upsell Grid Block:</p>
<pre class="brush: php; title: ; notranslate">public function getSelectedUpsellProducts()
{
    $products = array();
    foreach (Mage::registry('current_product')-&gt;getUpSellProducts() as $product) {
        $products[$product-&gt;getId()] = array('position' =&gt; $product-&gt;getPosition());
    }
    return $products;
}</pre>
<p>Here, it returns already saved upsell products. The serializer JS object stores it in the serializer field. So initially, when our grid is loaded for the first time, the serializer sets saved upsell products as selected.</p>
<p>In the grid block, a protected method <code>_prepareColumns()</code> is used to define the grid columns. The first column of upsell grid block is defined as checkbox:</p>
<pre class="brush: php; title: ; notranslate">$this-&gt;addColumn('in_products', array(
    'header_css_class' =&gt; 'a-center',
    'type'            =&gt; 'checkbox',
    'name'            =&gt; 'in_products',
    'values'          =&gt; $this-&gt;_getSelectedProducts(),
    'align'           =&gt; 'center',
    'index'           =&gt; 'entity_id'
 ));</pre>
<p>Here, type is defined as <code>'checkbox'</code> so the column will display checkboxes for each row. values defines the checkbox values i.e. product ids for which checkboxes should be selected. Here, <code>$this-&gt;_getSelectedProducts()</code> is called to get the selection data.</p>
<p>There is also a method <code>getGridUrl()</code> defined in the upsell grid block:</p>
<pre class="brush: php; title: ; notranslate">public function getGridUrl()
{
    return $this-&gt;_getData('grid_url') ? $this-&gt;_getData('grid_url') : $this-&gt;getUrl('*/*/upsellGrid', array('_current'=&gt;true));
}</pre>
<p>This method defines the URL to be called for AJAX reloading while paginating, sorting or filtering. This URL should return only a Grid block without including any other blocks such as the Serializer block.</p>
<p>The action method for this URL is defined as:</p>
<pre class="brush: php; title: ; notranslate">public function upsellGridAction()
{
    $this-&gt;_initProduct();
    $this-&gt;loadLayout();
    $this-&gt;getLayout()-&gt;getBlock('catalog.product.edit.tab.upsell')
-&gt;setProductsUpsell($this-&gt;getRequest()-&gt;getPost('products_upsell', null));
    $this-&gt;renderLayout();
}</pre>
<p>The layout XML for it is defined as:</p>
<pre class="brush: xml; title: ; notranslate">&lt;adminhtml_catalog_product_upsellgrid&gt;
    &lt;block type=&quot;core/text_list&quot; name=&quot;root&quot;&gt;
        &lt;block type=&quot;adminhtml/catalog_product_edit_tab_upsell&quot; name=&quot;catalog.product.edit.tab.upsell&quot;/&gt;
    &lt;/block&gt;
&lt;/adminhtml_catalog_product_upsellgrid&gt;</pre>
<p>So the Serializer block adds a hidden field with a name as defined by <code>hidden_input_name</code>. When a user selects any row, the serialized data is stored in that hidden field. When a user browses next/previous pages, sorts the grid or filters by a value, the grid is reloaded via AJAX. The selection data is added as a parameter to this AJAX call with parameter name defined by <code>reload_param_name</code>, which is <code>products_upsell</code> in our case. As mentioned above in the code snippet of <code>upsellGridAction()</code>, the value of the POST parameter <code>products_upsell</code> is retrieved and passed in <code>setProductsUpsell()</code> on our upsell grid block instance. So calling <code>getProductsUpsell()</code> on upsell grid block instance will return previously selected data.</p>
<p>I mentioned above that the call <code>$this-&gt;_getSelectedProducts()</code> is used for getting selection data. Here is the code for this method:</p>
<pre class="brush: php; title: ; notranslate">protected function _getSelectedProducts()
{
    $products = $this-&gt;getProductsUpsell();
    if (!is_array($products)) {
        $products = array_keys($this-&gt;getSelectedUpsellProducts());
    }
    return $products;
}</pre>
<p>As mentioned earlier, the selection data can be retrieved by calling <code>getProductsUpsell()</code> on the upsell block instance. Here, it is attempted to retrieve selection data by calling this method. But in case, we are editing an existing product and if, after loading the Upsell Products tab, we haven’t made any changes, the grid should display already saved upsell products as selected. However, if there is no previous selection data found, the grid attempts to retrieve any edited upsell products by calling <code>$this-&gt;getSelectedUpsellProducts()</code>.</p>
<p>Finally, when the product form is submitted, the selection data can be retrieved from the POST object by the <code>hidden_input_name</code> key. In our case it is <code>links[upsell]</code>. This data is still in serialized format. Magento provides a Helper Method for decoding serialized data: <code>Mage::helper('adminhtml/js')-&gt;decodeGridSerializedInput()</code>.</p>
<p>The product controller calls <code>_initSave()</code> before doing actual save operation. This method contains code, which is responsible for decoding serialized input:</p>
<pre class="brush: php; title: ; notranslate">$links = $this-&gt;getRequest()-&gt;getPost('links');
...
if (isset($links['upsell']) &amp;&amp; !$product-&gt;getUpsellReadonly()) {
    $product-&gt;setUpSellLinkData(Mage::helper('adminhtml/js')-&gt;decodeGridSerializedInput($links['upsell']));
}
</pre>
<p>So, to summarize, the complete execution sequence of the Grid Serializer block:</p>
<ol>
<li>Initially, Grid and Serializer blocks are loaded</li>
<li>When Serializer block is initialized, it loads saved selection data, stores it in a hidden field in serialized format and marks the corresponding entities as selected in the grid block.</li>
<li>When a user makes any changes on the grid, it is automatically reflected in the  hidden serializer field.</li>
<li>While paging, filtering or sorting, only the grid is reloaded not the serializer. So our serializer data is not lost.</li>
<li>While reloading, the current selection data is passed in the POST parameters to an AJAX call.</li>
<li>The Grid block attempts to retrieve data from the POST. If no data is found, it retrieves the saved data.</li>
<li>When the form is submitted, selection data is retrieved in serialized format.</li>
<li>Finally the selection data is decoded and stored in the database.</li>
</ol>
<h2>Summary</h2>
<p>Here, we have taken the example of Upsell Product management to understand how to use the Grid and Serializer blocks in combination as a replacement for multi-select boxes. In my next tutorial in this series, I will discuss more advanced usage of the Grid Serializer to create custom widgets that provide a more fully featured and user friendly interface.</p>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2012 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-tutorials/understanding-the-grid-serializer-block/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>When Should You Override Magento Core Files In app/code/local/Mage?</title>
		<link>http://magebase.com/magento-articles/when-should-you-override-magento-core-files-in-app_code_local_mage/</link>
		<comments>http://magebase.com/magento-articles/when-should-you-override-magento-core-files-in-app_code_local_mage/#comments</comments>
		<pubDate>Mon, 12 Mar 2012 04:00:10 +0000</pubDate>
		<dc:creator>Robert Popovic</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[core modification]]></category>
		<category><![CDATA[overrides]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1559</guid>
		<description><![CDATA[Some forums and tutorials advise overriding Magento core functionality by copying the core file into the <code>app/code/local/Mage/</code> space to maintain your customization after an upgrade but is this really a good approach?<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2012 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-thumbnail wp-image-1572" title="local-mage-override" src="http://magebase.com/wp-content/uploads/2012/03/local-mage-override-150x150.png" alt="local-mage-override" width="150" height="150" /></p>
<p>The short answer is:<br />
<strong>NEVER!</strong></p>
<p>The longer answer is somewhat less absolute and requires some explanation.</p>
<p>Often you will see Magento tutorials or forum posts that implement a feature or functionality change that is different from what the core does which requires changing something in the core of Magento. Someone may then advise that, instead of hacking core files it is better to copy them into the <code>app/code/local/Mage</code> location and perform the modifications there, so that, upon upgrade, the modifications are not lost. This process is called overriding Magento core functionality and is based on the fact that Magento sets its PHP include paths to first look in <code>app/code/local/</code> then <code>app/code/community/</code> and finally in <code>app/code/core/</code>. This has the effect that any files of the same name placed under the local or community name space will take precedence in loading, hence, we can override almost any core file in this way. To learn about how exactly Magento sets up its system, <a href="http://alanstorm.com/category/magento#magento_config">read the excellent series on the Magento Configuration by Alan Storm</a>.</p>
<p>This is one, sometimes recommended, way of overriding core functionality without hacking the core but why is it, as you may conclude from my initial statement, so bad?</p>
<p>First, let&#8217;s see what scenarios would be compelling us to override core files:</p>
<ol>
<li>We want to change a piece of functionality in a core method so we copy the php file containing the code and modify one or more methods.</li>
<li>We want to add a new method to a core block class, so it&#8217;s available for use in the phtml template so we copy the relevant core Block php file and add our method to it.</li>
<li>We may have several modifications consisting of core functionality changes and additions over several files.</li>
</ol>
<p>So, what are we actually doing here, when we override core files?</p>
<p>For one thing, we must override the complete core file because we can&#8217;t trim out the stuff that we don&#8217;t want changed since we would lose all that functionality and most likely break Magento. Once the overridden file is in place, this will be the file and code Magento will be using from now onwards. Given that most core classes contain several and many times a large number of methods it means that we are effectively overriding all those methods in our file.</p>
<p>Now, remember when we were advised to use this override approach so we can make sure that our customizations are going to be preserved after a Magento version upgrade? Well that, indeed, will be true, but, what if the new Magento version has changes in the very files we have previously overridden? What if they have newly implemented methods or bug fixes in existing methods? Since our override will always take precedence, these new features and fixes will never be operational as our override runs all the old code. If you&#8217;re lucky, you may get an error report because a new change falls over due to missing methods but what if you don&#8217;t get error reports and instead, somehow, some inexplicable and erratic behavior starts expressing itself on your site?</p>
<p>You can see the problem now, right? After each upgrade, you will have to go and check all your <code>app/code/local/Mage/</code> overrides and compare them to the new core files and port any core changes to your local override in order to maintain your site&#8217;s integrity. If you have lots of such overrides, this will be tedious. Also, if you are a developer who gets passed on an existing site with these kinds of overrides, you will not be happy. Often you won&#8217;t even know what the purpose of the override was and you&#8217;d need to laboriously go from diff to diff and decipher the meaning of any changes. It gets worse if the previous developer already performed some Magento upgrades.</p>
<p>By now, I guess, you have a good idea about the dangers of applying this kind of override, so, let&#8217;s get back to our original question, when, if at all, should you use this approach?</p>
<p>There are a few cases when this approach may be justified, in my opinion, these are the cases:</p>
<ul>
<li>If you want to quickly try a core modification to see if it will solve your task as a proof of concept, but don&#8217;t want to create an extension just yet. When you are satisfied, you remove your override and implement a proper Magento extension with rewrites.</li>
<li>If you are implementing a temporary override of some core functionality that you will remove after your task is complete. A prime example of this is overriding the Magento dataflow classes for importing, when you want to change the way the importer handles certain things in an initial customer or product import.</li>
</ul>
<p>The key concept here is: <strong>temporary</strong> changes/experiments. You are not planning on leaving your overrides.</p>
<p class="note">Note: There are some other scenarios where local Mage overrides are the only way to customize parts of Magento&#8217;s core functionality. I&#8217;d like to encourage a discussion in the comments to see what others think about this.</p>
<h2>Conclusion</h2>
<p>The take-away from this article is, never use the <code>app/code/local/Mage/</code> approach to permanently override core functionality! If you must, then only use if for temporary changes that you will <span style="text-decoration: underline;">remove</span> afterwards.</p>
<p>As for the question that now presents itself: how, then, should you implement core overrides? The answer is by creating a custom Magento module and using the available class rewrite mechanisms, or better yet, using event observers if possible.</p>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2012 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-articles/when-should-you-override-magento-core-files-in-app_code_local_mage/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Quick Tip: Disable all Local Modules at Once</title>
		<link>http://magebase.com/magento-tutorials/quick-tip-disable-all-local-modules-at-once/</link>
		<comments>http://magebase.com/magento-tutorials/quick-tip-disable-all-local-modules-at-once/#comments</comments>
		<pubDate>Mon, 13 Feb 2012 05:00:14 +0000</pubDate>
		<dc:creator>Robert Popovic</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[config]]></category>
		<category><![CDATA[modules]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1551</guid>
		<description><![CDATA[Sometimes it's useful to disable all your local module code in one fell swoop. Magento has provided a neat configuration option to do just that.<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2012 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<p>While going through the study guide for the Magento Developer Exam, I&#8217;ve been learning a few interesting details that are squirreled away in the Magento code, but can be useful in day to day Magento development.</p>
<p>For example, while going through the section on Module loading, it is revealed that we can easily disable all modules living in the local (<code>app/code/local</code>) namespace by editing <code>app/etc/local.xml</code> and setting the <code>disable_local_modules</code> node to true:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;config&gt;
    &lt;global&gt;
        ...
        &lt;disable_local_modules&gt;true&lt;/disable_local_modules&gt;
        ...
    &lt;/global&gt;
    ...
&lt;/config&gt;
</pre>
<p>Of course, if you have cache enable, clear or disable it to see the effects.</p>
<p>This will immediately prevent Magento from loading any code from your local code pool. You could use this to troubleshoot issues with custom modules or local Mage overrides. Of course, to find the exact culprit would require disabling individual modules one by one but at least you can narrow down your area of search quickly this way.</p>
<p>Note that this will not affect the community modules.</p>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2012 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-tutorials/quick-tip-disable-all-local-modules-at-once/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Quick Tip: Easy pop-ups with window.js in the front end with Magento</title>
		<link>http://magebase.com/magento-tutorials/quick-tip-easy-pop-ups-with-window-js-in-the-front-end-with-magento/</link>
		<comments>http://magebase.com/magento-tutorials/quick-tip-easy-pop-ups-with-window-js-in-the-front-end-with-magento/#comments</comments>
		<pubDate>Sat, 05 Nov 2011 05:33:51 +0000</pubDate>
		<dc:creator>Robert Popovic</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[window.js]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1530</guid>
		<description><![CDATA[Did you know that your Magento install comes with a Prototype based library called window.js? If you want to make use of popup windows, this is the library to include. Let's see what we can do with it.<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-thumbnail wp-image-1538" title="window.js" src="http://magebase.com/wp-content/uploads/2011/11/windowjs-150x150.png" alt="window.js" width="150" height="150" />Magento comes with a lot of files, utilities and libraries, one of which is <a title="window.js" href="http://prototype-window.xilinus.com/">window.js</a>. It is a Prototype based library implementing some classes that allow you to add windows to a web page. This can be simple pop-ups and modal windows and dialogs. They can be dragged, minimized, resized and closed. You can open multiple windows if you wanted to. You can load content from a link, an HTML container on the page or via Ajax. This library is seriously versatile. The Magento admin already uses <code>window.js</code> for various pop-up functions such as the widget options and image management. Well if the back end can do it, then the front end can too.</p>
<h2 class="clear">How to use it</h2>
<p>The library is located under <code>[magento_root]/js/prototype/window.js</code>. Additionally, <code>window.js</code> comes with a bunch of CSS themes found under: <code>/js/prototype/windows/themes/*</code>. To load the library in the front end we will make or add an entry to our design theme&#8217;s <code>local.xml</code>:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;default&gt;
    &lt;reference name=&quot;head&quot;&gt;
        &lt;action method=&quot;addJs&quot;&gt;&lt;script&gt;prototype/window.js&lt;/script&gt;&lt;/action&gt;
        &lt;action method=&quot;addItem&quot;&gt;&lt;type&gt;js_css&lt;/type&gt;&lt;name&gt;prototype/windows/themes/default.css&lt;/name&gt;&lt;/action&gt;
        &lt;action method=&quot;addItem&quot;&gt;&lt;type&gt;js_css&lt;/type&gt;&lt;name&gt;prototype/windows/themes/magento.css&lt;/name&gt;&lt;/action&gt;
    &lt;/reference&gt;
&lt;/default&gt;
</pre>
<p>The bare minimum necessary to make the windows look right is <code>default.css</code>. In our example above, we are also loading a supplied <code>window.js</code> theme: <code>magento.css</code>. This is the theme that the back-end loads. Now, that we have the library and styles loaded, what can we do with this? For example, we can load the compare items page in a nice pop-up instead of opening a new window. Make an override of the <code>template/catalog/product/compare/sidebar.phtml</code> in your local design theme and add the following to the end:</p>
<pre class="brush: php; title: ; notranslate">&lt;script type=&quot;text/javascript&quot;&gt;// &lt;![CDATA[
function showCompare(url) {
    winCompare = new Window({className:'magento',title:'Compare Products',url:url,width:820,height:600,minimizable:false,maximizable:false,showEffectOptions:{duration:0.4},hideEffectOptions:{duration:0.4}});
    winCompare.setZIndex(100);
    winCompare.showCenter(true);
}
// ]]&gt;&lt;/script&gt;
</pre>
<p>Also modify the line that says:</p>
<pre class="brush: php; title: ; notranslate">
&lt;button class=&quot;button&quot; title=&quot;&lt;?php echo $this-&gt;__('Compare') ?&gt;&quot; onclick=&quot;popWin('&lt;?php echo $_helper-&gt;getListUrl() ?&gt;','compare','top:0,left:0,width=820,height=600,resizable=yes,scrollbars=yes')&quot; type=&quot;button&quot;&gt;&lt;/button&gt;
</pre>
<p>to:</p>
<pre class="brush: php; title: ; notranslate">
&lt;button class=&quot;button&quot; title=&quot;&lt;?php echo $this-&gt;__('Compare') ?&gt;&quot; onclick=&quot;showCompare('&lt;?php echo $this-&gt;helper('catalog/product_compare')-&gt;getListUrl() ?&gt;')&quot; type=&quot;button&quot;&gt;&lt;/button&gt;
</pre>
<p>Add some items to compare and click on the &#8220;Compare&#8221; button and, voila, your compare page loads in a nice pop-up. I know, the Magento window theme isn&#8217;t exactly the most exciting one, but you can copy a theme CSS file to your local skin CSS folder and customize to your heart&#8217;s content.</p>
<p>Now, we might notice that the button actions in the compare window don&#8217;t quite work as expected. This is due to some of the links like Add to Cart and Add to Wishlist use <code>setPLocation</code> to set the target page URL. This won&#8217;t work in our pop-up since <code>window.js</code> loads the page into an iframe. So the remedy is to override the <code>product/compare/list.phtml</code> and add:</p>
<pre class="brush: php; title: ; notranslate">
&lt;script type=&quot;text/javascript&quot;&gt;
// &lt;![CDATA[
function setILocation(url){
    window.parent.location.href = url;
}
// ]]&gt;
&lt;/script&gt;
</pre>
<p>Then replace all <code>setPLocation</code> calls with <code>setILocation</code>.</p>
<p>The close button won&#8217;t work either but you don&#8217;t really need that as the window provides its own close button so you can simply remove it from the template.</p>
<h2>Conclusion</h2>
<p>In our example we saw how to open the compare page in a window.js pop-up. You can use this approach to create size guide pop-ups for example. However this is a powerful library and can do much more that just pop-up windows. To get a good overview of its power, visit the window.js homepage at <a title="window.js" href="http://prototype-window.xilinus.com/">prototype-window.xilinus.com</a>. You will find the documentation and a few examples there.</p>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-tutorials/quick-tip-easy-pop-ups-with-window-js-in-the-front-end-with-magento/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>Magento Sort By Newest Products Made Easy</title>
		<link>http://magebase.com/magento-tutorials/magento-sort-by-newest-products-made-easy/</link>
		<comments>http://magebase.com/magento-tutorials/magento-sort-by-newest-products-made-easy/#comments</comments>
		<pubDate>Thu, 27 Oct 2011 09:13:04 +0000</pubDate>
		<dc:creator>Robert Popovic</dc:creator>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[catalog]]></category>
		<category><![CDATA[sort]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1520</guid>
		<description><![CDATA[To add the ability to sort your catalog by Newest Products, you don't need to purchase extensions or hack core files. We will show you how you can do it in 5 minutes.<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<h2><img class="alignleft size-thumbnail wp-image-1525" title="sort by newest" src="http://magebase.com/wp-content/uploads/2011/10/sort-by-newest-150x150.png" alt="sort by newest" width="150" height="150" />The Situation</h2>
<p>Recently, I had the pleasure of working on an existing site we took over. The site had been upgraded from Magento CE to EE before it came to me. One of the tasks was to make a new enterprise theme and clean up any unused or incompatible extensions.</p>
<p>I will just focus on one extension here that was added to allow the catalog to be sorted by newest products. This is the EWTechnologies_SortByNewest. It came to my attention after debugging the toolbar for not showing the pagination links where there is more than one page of products. So I looked into it and to my horror realized that it was overriding the default <code>Mage_Catalog_Block_Product_List_Toolbar</code> class but extending from <code>Mage_Page_Block_Html_Pager</code>. If that wasn&#8217;t bad enough, it was also completely overriding the <code>Mage_Eav_Model_Config</code> class. This one has been substantially changed in later versions of Magento so the override implements very old code. I decided that this is too risky to keep even though there were no other visible adverse effects. It certainly isn&#8217;t best practice to run outdated code in any case.</p>
<p>I thought this feature shouldn&#8217;t require overriding so much core code so I investigated and, to my delight, found that the solution was very simple and quite elegant and didn&#8217;t involve overriding any core code as such.</p>
<h2>The Approach</h2>
<p>The Product Entity in Magento has a &#8216;created_at&#8217; attribute which stores the date when the product was created. Logically, it lends itself to be used for the sort by newest feature as it is set only once by the system, when the product was created.</p>
<p>A look into the <code>eav_attribute</code> table gives us the attribute_id and an inspection of the <code>catalog_eav_attribute</code> table shows that the attribute is set to not be used in the sort by drop-down. So, the obvious course of action was to set the attribute&#8217;s <code>used_in_sort_by</code> field to 1 and then the only other thing left was to update the <code>frontend_label</code> in <code>eav_attribute</code> to read &#8220;Newest&#8221;. That&#8217;s all, folks!</p>
<h2>The Extension</h2>
<p>I&#8217;ve whipped up a quick extensions that will perform those updates and makes it easy to install on any site that needs this feature.</p>
<p class="note">Note: This should work fine for Magento CE 1.4.x and up, PE, EE 1.8.0 and up. There is no guarantee and I don&#8217;t provide support for this extension. Use at your own risk and ALWAYS backup your database before installing.</p>
<p class="download"><a href="http://magebase.com/wp-content/uploads/2011/10/Magebase_SortByNewest.zip">Download it here.</a></p>
<h2>Conclusion</h2>
<p>This approach should be upgrade safe and works on any Magento CE version over 1.4 as well as PE and EE versions. The only issue would be if a future Magento upgrade was updating the created_at attribute but then it&#8217;s easy enough to reapply the database edits to restore functionality &#8211; easier than troubleshoot issues with core code overrides.</p>
<p class="note green"><strong>Update:</strong> If you want to set the default sort direction for the toolbar, you can do this via the layout XML. Best in your <a title="5 Useful Tricks For Your Magento local.xml" href="http://magebase.com/magento-tutorials/5-useful-tricks-for-your-magento-local-xml/">local.xml</a> but you can edit catalog.xml if your theme has overridden that:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;catalog_category_default&gt;
    /* other layout nodes */
    &lt;reference name=&quot;product_list_toolbar&quot;&gt;
        &lt;action method=&quot;setDefaultDirection&quot;&gt;&lt;dir&gt;desc&lt;/dir&gt;&lt;/action&gt;
    &lt;/reference&gt;
&lt;/catalog_category_default&gt;

&lt;catalog_category_layered&gt;
    /* other layout nodes */
    &lt;reference name=&quot;product_list_toolbar&quot;&gt;
        &lt;action method=&quot;setDefaultDirection&quot;&gt;&lt;dir&gt;desc&lt;/dir&gt;&lt;/action&gt;
    &lt;/reference&gt;
&lt;/catalog_category_layered&gt;
</pre>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-tutorials/magento-sort-by-newest-products-made-easy/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Quick Tip: Using a Frontend Model For Your Module Configuration Parameter</title>
		<link>http://magebase.com/magento-tutorials/quick-tip-using-a-frontend-model-for-your-module-configuration-parameter/</link>
		<comments>http://magebase.com/magento-tutorials/quick-tip-using-a-frontend-model-for-your-module-configuration-parameter/#comments</comments>
		<pubDate>Mon, 05 Sep 2011 05:00:44 +0000</pubDate>
		<dc:creator>Robert Popovic</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[config]]></category>
		<category><![CDATA[UX]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1503</guid>
		<description><![CDATA[You can greatly enhance your module's configuration options by using a front end model class. This example quick tip will show how to create a Yes/No toggle option that reveals or hides the dependent text option. <p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re a fastidious Magento module developer, you will try to make sure that your module options only reveal the necessary and configured fields to the admin user and hide all the irrelevant stuff. Specifically, I&#8217;m referring to Yes/No options that allow the administrator to enable and configure a subsequent option. For example, you have an extension that can show additional field content if an option is enabled and allows for entering the field contents:</p>
<div id="attachment_1505" class="wp-caption aligncenter" style="width: 590px"><img class="size-full wp-image-1505" title="Standard options configuration" src="http://magebase.com/wp-content/uploads/2011/09/toggle-options-1.png" alt="Standard options configuration" width="580" height="350" /><p class="wp-caption-text">Standard options configuration</p></div>
<p>As we can see, the initial state is &#8216;No&#8217; for the &#8216;Enable Additional Text&#8217; option, and the textarea is blank. It would be really nice if the whole &#8216;Additional Text&#8217; row was hidden in this scenario.</p>
<p>We can achieve that by utilizing a front end model for our Yes/No option. Magento provides this mechanism for creating options that depend on certain settings or other dependencies. Some of the built in options are the &#8216;Allowed Countries&#8217;, Enable Flat Catalog Products/Categories and the Tax Destination Calculation &#8216;State&#8217; option.</p>
<p>We are going to use the front end model to add some logic to enable/disable the textarea and some JavaScript to enable the toggle functionality when the Yes/No drop-down is changed. Note that this is just one, albeit trivial, example of using this technique. Especially since Magento provides the <code>&lt;depends&gt;</code> node for this specific purpose (see the <a href="#update">update</a> below).</p>
<p>Using the same tutorial module from our <a href="http://magebase.com/magento-tutorials/quick-tip-explain-your-module-configuration-options-with-tooltips/">Explain Your Module Configuration Options With Tooltips</a> quick tip, we&#8217;ll change our <code>system.xml</code> to read:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;config&gt;
    &lt;tabs&gt;
        &lt;magebase translate=&quot;label&quot; module=&quot;custom&quot;&gt;
            &lt;label&gt;Magebase&lt;/label&gt;
            &lt;sort_order&gt;700&lt;/sort_order&gt;
        &lt;/magebase&gt;
    &lt;/tabs&gt;
    &lt;sections&gt;
        &lt;mbcustom translate=&quot;label&quot; module=&quot;custom&quot;&gt;
            &lt;tab&gt;magebase&lt;/tab&gt;
            &lt;label&gt;Magebase Tutorial Options&lt;/label&gt;
            &lt;frontend_type&gt;text&lt;/frontend_type&gt;
            &lt;sort_order&gt;10&lt;/sort_order&gt;
            &lt;show_in_default&gt;1&lt;/show_in_default&gt;
            &lt;show_in_website&gt;1&lt;/show_in_website&gt;
            &lt;show_in_store&gt;1&lt;/show_in_store&gt;
            &lt;groups&gt;
                &lt;default translate=&quot;label&quot;&gt;
                    &lt;label&gt;Conditional Toggle Options&lt;/label&gt;
                    &lt;frontend_type&gt;text&lt;/frontend_type&gt;
                    &lt;sort_order&gt;10&lt;/sort_order&gt;
                    &lt;show_in_default&gt;1&lt;/show_in_default&gt;
                    &lt;show_in_website&gt;1&lt;/show_in_website&gt;
                    &lt;show_in_store&gt;1&lt;/show_in_store&gt;
                    &lt;fields&gt;
                        &lt;mbcustomopt1 translate=&quot;label comment&quot;&gt;
                            &lt;label&gt;Enable Additional Text&lt;/label&gt;
                            &lt;frontend_type&gt;select&lt;/frontend_type&gt;
                            &lt;source_model&gt;adminhtml/system_config_source_yesno&lt;/source_model&gt;
                            &lt;frontend_model&gt;custom/adminhtml_system_config_form_field_customopt1toggle&lt;/frontend_model&gt;
                            &lt;sort_order&gt;10&lt;/sort_order&gt;
                            &lt;show_in_default&gt;1&lt;/show_in_default&gt;
                            &lt;show_in_website&gt;1&lt;/show_in_website&gt;
                            &lt;show_in_store&gt;0&lt;/show_in_store&gt;
                            &lt;comment&gt;Select whether to show a text block in the front end.&lt;/comment&gt;
                        &lt;/mbcustomopt1&gt;
                        &lt;mbcustomopt2 translate=&quot;label comment&quot;&gt;
                            &lt;label&gt;Additional Text&lt;/label&gt;
                            &lt;frontend_type&gt;textarea&lt;/frontend_type&gt;
                            &lt;sort_order&gt;20&lt;/sort_order&gt;
                            &lt;show_in_default&gt;1&lt;/show_in_default&gt;
                            &lt;show_in_website&gt;1&lt;/show_in_website&gt;
                            &lt;show_in_store&gt;0&lt;/show_in_store&gt;
                            &lt;comment&gt;Enter the content for the text block.&lt;/comment&gt;
                            &lt;tooltip&gt;Note that the content will be erased if you disable it above, and save.&lt;/tooltip&gt;
                        &lt;/mbcustomopt2&gt;
                    &lt;/fields&gt;
                &lt;/default&gt;
            &lt;/groups&gt;
        &lt;/mbcustom&gt;
    &lt;/sections&gt;
&lt;/config&gt;</pre>
<p>The key to our quick tip is in:</p>
<pre class="brush: xml; title: ; notranslate">&lt;frontend_model&gt;custom/adminhtml_system_config_form_field_customopt1toggle&lt;/frontend_model&gt;</pre>
<p>So, now, we&#8217;re going to create the front end model class. Incidentally, even though it&#8217;s named a &#8216;model&#8217; class we are going to create it as a Magento Block class since this is how the other built in front end model classes are implemented. Effectively, it is used for template output so it&#8217;s appropriate to create a block class for this.</p>
<p>Create <code>Customopt1toggle.php</code> under <code>.../Magebase/Custom/Block/Adminhtml/System/Config/Form/Field/</code> with the following content:</p>
<pre class="brush: php; title: ; notranslate">class Magebase_Custom_Block_Adminhtml_System_Config_Form_Field_Customopt1toggle extends Mage_Adminhtml_Block_System_Config_Form_Field
{

    /**
     * Get element ID of the dependent field to toggle
     *
     * @param object $element
     * @return String
     */
    protected function _getToggleElementId($element)
    {
        return substr($element-&gt;getId(), 0, strrpos($element-&gt;getId(), 'mbcustomopt1')) . 'mbcustomopt2';
    }
    /**
     * Get element ID of the dependent field's parent row
     *
     * @param object $element
     * @return String
     */
    protected function _getToggleRowElementId($element)
    {
        return 'row_'.$this-&gt;_getToggleElementId($element);
    }
    /**
     * Override method to output our custom HTML with JavaScript
     *
     * @param Varien_Data_Form_Element_Abstract $element
     * @return String
     */
    protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
    {
        // If our Yes/No toggle is 'No' then disable the text value field
        if(!$element-&gt;getValue() || $element-&gt;getValue()!=1) {
            $_frm = $element-&gt;getForm();
            $_elm = $_frm-&gt;getElement($this-&gt;_getToggleElementId($element));
            $_elm-&gt;setDisabled('disabled')-&gt;setValue('');
        }
        // Get the default HTML for this option
        $html = parent::_getElementHtml($element);
        // Set up additional JavaScript for our toggle action. Note we are using the two helper methods above
        // to get the correct field ID's. They are hard-coded and depend on your option names in system.xml
        $javaScript = &quot;
            &lt;script type=\&quot;text/javascript\&quot;&gt;
                Event.observe(window, 'load', function() {
                    enabled=$('{$element-&gt;getHtmlId()}').value;
                    if (!enabled || enabled!=1) {
                        $('{$this-&gt;_getToggleRowElementId($element)}').hide();
                    } else {
                        $('{$this-&gt;_getToggleRowElementId($element)}').show();
                    }
                });
                Event.observe('{$element-&gt;getHtmlId()}', 'change', function(){
                    enabled=$('{$element-&gt;getHtmlId()}').value;
                    $('{$this-&gt;_getToggleElementId($element)}').disabled = (!enabled || enabled!=1);
                    if (!enabled || enabled!=1) {
                        $('{$this-&gt;_getToggleRowElementId($element)}').hide();
                    } else {
                        $('{$this-&gt;_getToggleRowElementId($element)}').show();
                    }
                });
            &lt;/script&gt;&quot;;

        $html .= $javaScript;
        return $html;
    }
}</pre>
<p>The <code>Varien_Data_Form_Element_Abstract</code> class implements the <code>_getElementHtml()</code> method responsible for generating the HTML for each option element. This is where we can add out override and &#8216;inject&#8217; some custom code to control the other element as well as the JavaScript to implement the dynamic toggle functionality. The code is self-explanatory.</p>
<p>Basically, we have a couple of helper methods to return our HTML field and row ID&#8217;s depending on the names we gave our options in <code>config.xml</code>. The <code>_getElementHtml()</code> method just sets the disabled state of the textarea field if the option is &#8216;No&#8217; and adds the Prototype JavaScript to add our toggle functionality. The JavaScript code will execute on page load and completely hide the text field if the option is &#8216;No&#8217; and install an event observer on the Yes/No drop-down to show/hide the text option.</p>
<p>The result of our work would look like this initially:</p>
<div id="attachment_1506" class="wp-caption aligncenter" style="width: 590px"><img class="size-full wp-image-1506" title="Toggle options - text hidden" src="http://magebase.com/wp-content/uploads/2011/09/toggle-options-2.png" alt="Toggle options - text hidden" width="580" height="145" /><p class="wp-caption-text">Toggle options - Text Hidden</p></div>
<p>Selecting &#8216;Yes&#8217;, wil toggle the next field into its visible state:</p>
<div id="attachment_1504" class="wp-caption aligncenter" style="width: 690px"><a class="zoom" href="http://magebase.com/wp-content/uploads/2011/09/toggle-options-3.png"><img class="size-large wp-image-1504 " title="Toggle options - text revealed" src="http://magebase.com/wp-content/uploads/2011/09/toggle-options-3-680x310.png" alt="Toggle options - text revealed" width="680" height="310" /></a><p class="wp-caption-text">Toggle options - text revealed</p></div>
<h2>Conclusion</h2>
<p>We&#8217;ve seen how to create a nice little usability enhancement to busy module option pages. You can take this paradigm and enhance it for your own specific purposes. You can study the other examples of the built in Magento options using a frontend_model class for more inspiration and ideas.</p>
<p>One note, the above solution will erase a text option once its saved when the toggle is set to &#8216;No&#8217;. If you&#8217;d like to preserve the option, just remove the PHP code setting the text field as disabled as well as the <code>$('{$this-&gt;_getToggleElementId($element)}').disabled = (!enabled || enabled!=1);</code> JavaScript line. That should allow the hidden option to be saved.</p>
<h3 id="update"><span style="color: #0000ff;">Update:</span></h3>
<p>The same result as above can be achieved by utilizing the &lt;depends&gt; node in the system.xml as Damián pointed out:</p>
<pre class="brush: xml; title: ; notranslate">&lt;fields&gt;
    &lt;mbcustomopt1 translate=&quot;label comment&quot;&gt;
        &lt;label&gt;Enable Additional Text&lt;/label&gt;
        &lt;frontend_type&gt;select&lt;/frontend_type&gt;
        &lt;source_model&gt;adminhtml/system_config_source_yesno&lt;/source_model&gt;
        &lt;sort_order&gt;10&lt;/sort_order&gt;
        &lt;show_in_default&gt;1&lt;/show_in_default&gt;
        &lt;show_in_website&gt;1&lt;/show_in_website&gt;
        &lt;show_in_store&gt;0&lt;/show_in_store&gt;
        &lt;comment&gt;Select whether to show a text block in the front end.&lt;/comment&gt;
    &lt;/mbcustomopt1&gt;
    &lt;mbcustomopt2 translate=&quot;label comment&quot;&gt;
        &lt;label&gt;Additional Text&lt;/label&gt;
        &lt;frontend_type&gt;textarea&lt;/frontend_type&gt;
        &lt;sort_order&gt;20&lt;/sort_order&gt;
        &lt;show_in_default&gt;1&lt;/show_in_default&gt;
        &lt;show_in_website&gt;1&lt;/show_in_website&gt;
        &lt;show_in_store&gt;0&lt;/show_in_store&gt;
        &lt;depends&gt;&lt;mbcustomopt1&gt;1&lt;/mbcustomopt1&gt;&lt;/depends&gt;
        &lt;comment&gt;Enter the content for the text block.&lt;/comment&gt;
    &lt;/mbcustomopt2&gt;
&lt;/fields&gt;
</pre>
<p>However, this article illustrates how you can potentially add custom option processing using the front end model option. This is more relevant for example if you have an option where you need to check more complex conditions or link several options together.</p>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-tutorials/quick-tip-using-a-frontend-model-for-your-module-configuration-parameter/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Quick Tip: Conditional Loading of JavaScript and CSS Using Your Module Configuration</title>
		<link>http://magebase.com/magento-tutorials/quick-tip-conditional-loading-of-javascript-and-css-using-your-module-configuration/</link>
		<comments>http://magebase.com/magento-tutorials/quick-tip-conditional-loading-of-javascript-and-css-using-your-module-configuration/#comments</comments>
		<pubDate>Tue, 09 Aug 2011 21:26:26 +0000</pubDate>
		<dc:creator>Robert Popovic</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[config]]></category>
		<category><![CDATA[layout]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1483</guid>
		<description><![CDATA[It's really easy to create conditional JavaScript and CSS includes for your custom modules using module configuration parameters. Read on to see how.<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t know about you but I often find myself removing third party module&#8217;s CSS and sometimes even JS files from loading in my custom themes because I need to change most of the styling and don&#8217;t want to add bulk to my site.</p>
<p>Traditionally, I do it using my local.xml <a href="http://magebase.com/magento-tutorials/5-useful-tricks-for-your-magento-local-xml/">as outlined in my previous article</a>. However, it would be good practice if module developers would provide the option right from their module configuration.</p>
<p>This is actually really easy to do, watch this:</p>
<p>1. Create configuration options in system.xml:</p>
<pre class="brush: xml; title: ; notranslate">
...
&lt;groups&gt;
    &lt;advanced translate=&quot;label&quot;&gt;
    &lt;label&gt;Advanced&lt;/label&gt;
    &lt;frontend_type&gt;text&lt;/frontend_type&gt;
    &lt;sort_order&gt;100&lt;/sort_order&gt;
    &lt;show_in_default&gt;1&lt;/show_in_default&gt;
    &lt;show_in_website&gt;1&lt;/show_in_website&gt;
    &lt;show_in_store&gt;0&lt;/show_in_store&gt;
    &lt;fields&gt;
        &lt;load_css translate=&quot;label comment&quot;&gt;
            &lt;label&gt;Load Stylesheet&lt;/label&gt;
            &lt;frontend_type&gt;select&lt;/frontend_type&gt;
            &lt;source_model&gt;adminhtml/system_config_source_yesno&lt;/source_model&gt;
            &lt;sort_order&gt;10&lt;/sort_order&gt;
            &lt;show_in_default&gt;1&lt;/show_in_default&gt;
            &lt;show_in_website&gt;1&lt;/show_in_website&gt;
            &lt;show_in_store&gt;0&lt;/show_in_store&gt;
            &lt;comment&gt;Set to No if the supplied stylesheet file should not be loaded.&lt;/comment&gt;
        &lt;/load_css&gt;
        &lt;load_js translate=&quot;label comment&quot;&gt;
            &lt;label&gt;Load Javascript&lt;/label&gt;
            &lt;frontend_type&gt;select&lt;/frontend_type&gt;
            &lt;source_model&gt;adminhtml/system_config_source_yesno&lt;/source_model&gt;
            &lt;sort_order&gt;20&lt;/sort_order&gt;
            &lt;show_in_default&gt;1&lt;/show_in_default&gt;
            &lt;show_in_website&gt;1&lt;/show_in_website&gt;
            &lt;show_in_store&gt;0&lt;/show_in_store&gt;
            &lt;comment&gt;Set to No if the supplied javascript file should not be loaded.&lt;/comment&gt;
        &lt;/load_js&gt;
    &lt;/fields&gt;
    &lt;/advanced&gt;
&lt;/groups&gt;
...
</pre>
<p>Here, I&#8217;m only showing the relevant part for brevity. Essentially, I have an Advanced section with two Yes/No drop downs which allow the admin to configure the desired options.</p>
<p>2. Add your conditional includes to your module&#8217;s layout XML:</p>
<pre class="brush: xml; title: ; notranslate">
        &lt;reference name=&quot;head&quot;&gt;
            &lt;action method=&quot;addCss&quot; ifconfig=&quot;my_config_section/advanced/load_css&quot;&gt;&lt;stylesheet&gt;css/my_module/my_module.css&lt;/stylesheet&gt;&lt;/action&gt;
            &lt;action method=&quot;addItem&quot; ifconfig=&quot;my_config_section/advanced/load_js&quot;&gt;&lt;type&gt;skin_js&lt;/type&gt;&lt;name&gt;js/my_module/my_module.js&lt;/name&gt;&lt;/action&gt;
        &lt;/reference&gt;
</pre>
<p>And there you have it. Your css and js will only be included if the configuration allows it.</p>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-tutorials/quick-tip-conditional-loading-of-javascript-and-css-using-your-module-configuration/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Improving the File Cache Backend</title>
		<link>http://magebase.com/magento-tutorials/improving-the-file-cache-backend/</link>
		<comments>http://magebase.com/magento-tutorials/improving-the-file-cache-backend/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 21:00:44 +0000</pubDate>
		<dc:creator>Vinai Kopp</dc:creator>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1439</guid>
		<description><![CDATA[We know that we can enable the Magento cache to speed our sites up. We also know how to add APC or memcached into the mix. However, this does not always give us the expected results, so we need to understand the underlying caching mechanisms in order to improve on them.<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<p>The purpose of this post is to spread knowledge about the bolts and gears of the Magento cache system among developers, and to share one method of overcoming some limitations of the file cache storage class.</p>
<p>This article basically started with the site of a client who was having performance issues: when the cache reached about 38000 records, he was actually forced to clear the cache to keep the site responsive enough.</p>
<p>How strange is that? Shouldn’t a full cache give a better performance then an empty cache?</p>
<p>The number of records stored in the Magento cache depends on many factors, amongst others the number of store views, if a full page cache is used or not, and the size of the catalog. Many Sites don’t go above 1000 or 2000 cache records, but for large instances much higher values are common.</p>
<p><img class="alignnone size-large wp-image-1455" title="Filecount" src="http://magebase.com/wp-content/uploads/2011/08/Filecount-680x65.png" alt="" width="680" height="65" /></p>
<p>The performance issues of my client only occurred on specific pages, one of the most noticeable being the add-to cart action. Dropping a product to the cart took up to 4 seconds!<br />
Using some profiling, we could pin the issue down on part of the (full page) cache being cleared, more precisely, when the mini-cart in the page header had to be rebuilt.</p>
<p>Lets have a look at how the Magento caching (which uses the <code>Zend_Cache library</code>) works.<br />
Each cache entry consists of the following information</p>
<ul>
<li>the cached data</li>
<li>a cache key (or ID), that uniquely identifies this entry and is used to retrieve the data from the cache</li>
<li>a cache lifetime, after which the cache entry expires</li>
<li>zero or more cache tags</li>
</ul>
<p>Most of these are obvious, but what is the purpose of cache tags? Cache tags are used to segment the cache for partial deletion. For example, you could clear all entries of the configuration cache, without touching the any entries of the HTML block cache.</p>
<p>On the cache management page most of the cache tags used by Magento are listed. Depending on the modules and extensions installed there could be more or less tags, e.g. <code>CONFIG, LAYOUT_GENERAL_CACHE_TAG, BLOCK_HTML, TRANSLATIONS, FULL_PAGE_CACHE,</code> …</p>
<div id="attachment_1458" class="wp-caption alignleft" style="width: 310px"><a class="zoom" href="http://magebase.com/wp-content/uploads/2011/08/Cache-Management1.png"><img class="size-medium wp-image-1458  " title="Listed Cache Tags - more are used internaly" src="http://magebase.com/wp-content/uploads/2011/08/Cache-Management1-300x163.png" alt="Listed Cache Tags - more are used internaly" width="300" height="163" /></a><p class="wp-caption-text">Listed Cache Tags</p></div>
<p>All the information associated with the cache record is saved in the cache storage every time the method <code>Mage::app()-&gt;saveCache()</code> is called. And to read cache records the Method <code>Mage::app()-&gt;loadCache()</code> is used.<br />
Magento offers several different options what to use as a cache storage, and each of these storage systems is used by means of a PHP class called “cache backend”.</p>
<p>By default, cache data is stored in files (located in the directory <code>var/cache/</code>). Another option is the database, which is slower then the files option mostly because the database is a heavily used resource for Magento instances anyway. Then there are storage schemes that use RAM (which are much faster), e.g. <a title="APC" href="http://php.net/manual/en/apc.setup.php" target="_blank">APC</a> (shared memory) or <a title="memcached" href="http://memcached.org/" target="_blank">memcached</a> (a networked caching server).</p>
<p>So, lets use RAM as our cache storage, right?</p>
<p>Sounds good, except for one problem: APC and memcached only support storing simple key-value pairs, so the cache tags are lost! This renders the whole caching rather useless, because every time we need to clear only one part of the cache, EVERY cache entry is cleared.</p>
<p>But, do not despair! The Zend Framework contains a solution to this problem. There is a special cache backend called Twolevels. The Twolevels backend uses a fast cache backend (i.e. APC or memcached) for the cache data, and a slow backend (i.e. files or database) for the lifetime and the cache tag information. This way we can have the best of both worlds!</p>
<p>According to the excellent <a title="Magento Performance Whitepaper" href="http://www.magentocommerce.com/whitepaper" rel="external">performance whitepaper</a> (login required) Magento has released, it is recommended to use APC for the fast backend and files for the slow backend for single webserver setups. If you use a cluster of webservers, you should use memcached for the fast backend and the database for the slow backend. The latter has more overhead then the APC/files combo, but having all servers share one cache pool makes up for that.</p>
<p>Magento makes it easy to configure all this by the way &#8211; have a look at the file <code>app/etc/local.xml.additional</code> for further information. I will not go deeper into the setup here because <a href="http://magebase.com/magento-tutorials/speeding-up-magento-with-apc-or-memcached/">we have already written about this</a>.</p>
<p>Now, back to the problem at hand &#8211; why is a nice, full, cache slower then an empty one?<br />
The site in question was using APC as the fast backend and files as the slow backend.</p>
<p>So, lets have a look at what is happening.<br />
Every time a product is added to the cart, the following method is called:</p>
<pre class="brush: php; title: ; notranslate">Mage::app()-&gt;getCache()-&gt;clean(
    Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG,
    array($cacheTag)
);</pre>
<p><code>$cacheTag</code> is an MD5 hash built from several parameters identifying the active customers mini-cart block cache.<br />
So, how do the twolevel and the file cache backends handle this?</p>
<p>In the method <code>Zend_Cache_Backend_TwoLevels::clean()</code> each request with the cleaning mode <code>CLEANING_MODE_MATCHING_ANY_TAG</code> fetches all cache IDs matching the given tags from the slow backend using the method <code>getIdsMatchingAnyTags()</code>, and then removes one cache entry after the other in a loop.</p>
<pre class="brush: php; title: ; notranslate">case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
    $ids = $this-&gt;_slowBackend-&gt;getIdsMatchingAnyTags($tags);
    $res = true;
    foreach ($ids as $id) {
        $bool = $this-&gt;remove($id);
        $res = $res &amp;&amp; $bool;
    }
    return $res;
    break;</pre>
<p>Lets dive in a little bit deeper and find out how the <code>Zend_Cache_Backend_File</code> backend finds those cache IDs.<br />
The interesting part happens in the method <code>_get()</code>. Here we can see a list of all cache entries is built, and then it loops over each one, reads in the corresponding meta data file (using <code>file_get_contents()</code> and <code>unserialize()</code>) and then checks if the cache entry is associated with a matching cache tag.</p>
<p>This following code is slightly simplified for educational purposes:</p>
<pre class="brush: php; title: ; notranslate">$result = array();
$glob = @glob($cacheDir . $prefix . '--*');
if ($glob !== false) {
    foreach ($glob as $file) {
        $fileName = basename($file);
        $id = $this-&gt;_fileNameToId($fileName);
        $metadatas = $this-&gt;_getMetadatas($id);
        …
       switch ($mode) {
           …
           case 'matchingAny':
               $matching = false;
               foreach ($tags as $tag) {
                   if (in_array($tag, $metadatas['tags'])) {
                       $result[] = $id;
                       break;
                   }
               }
               break;
           …
       }
    }
}</pre>
<p>This code is probably fine for a couple of hundred cache entries, but after not even a day my clients Magento instance reached 40k records. Opening and unserializing thousands of files takes some time, even on a strong machine.</p>
<p><strong>It turns out the file backend doesn’t scale well.</strong></p>
<p>The remedy to this is obviously some kind of index, mapping the tags to the matching cache IDs.<br />
Instead of writing that information into a file that would have to be parsed and updated, I decided to use the filesystem itself as the index utilizing directories and symlinks.</p>
<p>In the modified file cache backend developed for the client, every time a cache entry is written, a directory with the name of each tag is created and a symlink to the metadata file is placed into it. This gives a little more overhead during the write operation. There is no difference reading cache entries. But every operation matching some tags is a lot faster. And since Magento makes heavy use of cache tags, the effect is quite noticeable, depending on the number of records in the cache.  For example, adding a product to the cart now takes less then a second on the original instance. And I’m happy to say the reports of the friends who have been nice enough to test the extension have been positive for smaller sites also.</p>
<p><a name="benchmark"></a><strong>Benchmarks!</strong></p>
<p>Inspired by Marc Jakubowski&#8217;s comment below, I added a little benchmark script. Here are some results to give a more detailed idea.<br />
<strong>UPDATE:</strong> Thanks to Collin Mollenhour&#8217;s comment below, I also added benchmarks for Redis using his <a title="Zend_Cache_Backend_Redis on github" href="https://github.com/colinmollenhour/Zend_Cache_Backend_Redis" target="_blank">Zend Cache Backend</a> Class &#8211; it&#8217;s incredibly fast, so if you have the possibility to use <a title="Redis" href="http://redis.io/" target="_blank">Redis 2.4</a> or newer, go for it! For this test I used the default Redis configuration, with the server running on the same machine I was running the tests. Before using it in production I would like to write some unit tests for this new backend, but it seems to work okay.</p>
<table>
<tbody>
<tr>
<th>Records</th>
<th>Tags</th>
<th>Avg. Records / Tag</th>
<th>Cache Backend</th>
<th>Avg. Time for getIdsMatchingTags()</th>
</tr>
<tr>
<td>50000</td>
<td>250</td>
<td>~700</td>
<td>File</td>
<td>20.71s</td>
</tr>
<tr>
<td>50000</td>
<td>250</td>
<td>~700</td>
<td>Symlink</td>
<td>2.28s</td>
</tr>
<tr>
<td>50000</td>
<td>250</td>
<td>~1500</td>
<td>Redis</td>
<td>0.01s</td>
</tr>
<tr>
<td>6000</td>
<td>120</td>
<td>~175</td>
<td>File</td>
<td>2.41s</td>
</tr>
<tr>
<td>6000</td>
<td>120</td>
<td>~175</td>
<td>Symlink</td>
<td>0.23s</td>
</tr>
<tr>
<td>6000</td>
<td>120</td>
<td>~370</td>
<td>Redis</td>
<td>0.002s</td>
</tr>
<tr>
<td>2000</td>
<td>80</td>
<td>~88</td>
<td>File</td>
<td>0.78s</td>
</tr>
<tr>
<td>2000</td>
<td>80</td>
<td>~88</td>
<td>Symlink</td>
<td>0.08s</td>
</tr>
<tr>
<td>2000</td>
<td>80</td>
<td>~180</td>
<td>Redis</td>
<td>0.001s</td>
</tr>
</tbody>
</table>
<p>The numbers for the records and tags where chosen because they roughly correspond the average cache pool size and tags on several live Magento instances of different sizes. These benchmarks where run on my laptop, and obviously the results may be different depending on the drive, file system, system memory etc. Please go ahead and test on your system.<br />
One interesting thing about the Redis backend is that the average number of ID&#8217;s per tag is much higher then with the other backends. I&#8217;m not sure why, my guess is that it has something to do with the way Redis manages the tag hash tables. I don&#8217;t have time to check it out at the moment, but maybe Collin already knows why.</p>
<p>By the way, according to the PHP reference, the <a title="PHP symlink function" href="http://php.net/manual/en/function.symlink.php" target="_blank">symlink function</a> is no longer limited to Unix systems, but since PHP 5.3 it is also available under Windows (Vista, Server 2008 or greater).  I haven’t tested this, though.</p>
<p>This module is provided with no warranty, you use it at your own risk. I know it is being used successfully on several sites, both as a primary cache backend and as a slow backend in combination with APC or memcached.<br />
I invite you to have a look at it and try it out, but please start with a test instance and not your live store. You can download the module from <a title="Netzarbeiter Cache on Magento Connect" href="http://www.magentocommerce.com/magento-connect/vinai/extension/7416/netzarbeiter_cache" rel="external">Magento Connect</a> or from <a title="Netzarbeiter Cache on github" href="https://github.com/Vinai/Symlink-Cache" rel="external">github</a>.<br />
If you find bugs or have improvements, please send them in.</p>
<p>After installing the extension clear the config and block_html cache and visit System &gt; Tools &gt; Symlink Cache.</p>
<p><a class="zoom" href="http://magebase.com/wp-content/uploads/2011/08/Symlink-Cache-Page.png"><img class="alignright size-medium wp-image-1467" title="Symlink-Cache Utility Page" src="http://magebase.com/wp-content/uploads/2011/08/Symlink-Cache-Page-300x282.png" alt="Symlink-Cache Utility Page" width="300" height="282" /></a><br />
There you can see sample XML that you will have to add to your <code>app/code/local.xml</code> file for both variants, to use it on its own or to use it as a slow backend.<br />
Then, after you have updated the <code>local.xml</code> file, clear the config cache, go to the Symlink Cache page and hit the “Initialize Tag Symlinks” button.<br />
And that is all, your system is set up and uses the tag symlinks. Enjoy!<br />
I would be happy to hear about other methods, ideas and experiences about improving cache performance.</p>
<h2>Downloads</h2>
<p class="download"><a title="Netzarbeiter Cache on Magento Connect" href="http://www.magentocommerce.com/magento-connect/vinai/extension/7416/netzarbeiter_cache" rel="external">Magento Connect</a></p>
<p>or</p>
<p class="download"><a title="Netzarbeiter Cache on github" href="https://github.com/Vinai/Symlink-Cache" rel="external">Github</a></p>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-tutorials/improving-the-file-cache-backend/feed/</wfw:commentRss>
		<slash:comments>132</slash:comments>
		</item>
		<item>
		<title>Google Optimizer on Magento: Where to start for maximum gain</title>
		<link>http://magebase.com/magento-tutorials/google-optimizer-on-magento-where-to-start-for-maximum-gain/</link>
		<comments>http://magebase.com/magento-tutorials/google-optimizer-on-magento-where-to-start-for-maximum-gain/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 02:23:05 +0000</pubDate>
		<dc:creator>Mark Hammersley</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[analytics]]></category>
		<category><![CDATA[google optimizer]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[optimization]]></category>

		<guid isPermaLink="false">http://magebase.com/?p=1423</guid>
		<description><![CDATA[Magento has Google Optimizer tools built in and so it makes sense to use them.  Google Optimizer allows you to present different content options to your prospective customers and then tracks which version converts more.  On top of this Google Optimizer has built in probability formulae that understand when a result is a ‘confident result’ [...]<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></description>
			<content:encoded><![CDATA[<p>Magento has Google Optimizer tools built in and so it makes sense to use them.  Google Optimizer allows you to present different content options to your prospective customers and then tracks which version converts more.  On top of this Google Optimizer has built in probability formulae that understand when a result is a ‘confident result’ rather than a random occurrence.</p>
<p>To get a confident result you need to either have a test that is really obviously better or a decent number of transactions.  But as a rule of thumb if you are getting more than 10 transactions a day then you can benefit from using Google Optimizer.</p>
<h2>Where to start?</h2>
<p>If you have a lower number of transactions it makes sense to start optimizing on the pages that most people see.  This tends to be the home and checkout pages of the site. However we need not guess the best place to start when we have good data available to tell us exactly.</p>
<p>We can find the best place to start by looking at Google Analytics.  Google Analytics should be setup using Ecommerce mode and to be tracking conversions, which is a standard part of Magento as long as you have entered the Google ID in the Google API area of Magento’s configuration settings.</p>
<p>In Google Analytics go to ‘content’</p>
<p><img class="alignleft size-full wp-image-224" title="go1" src="http://www.browsertobuyer.com/wp-content/uploads/2011/08/go1.png" alt="" width="229" height="108" /></p>
<p class="clear">Then top content</p>
<p><img class="alignleft size-full wp-image-225" title="go2" src="http://www.browsertobuyer.com/wp-content/uploads/2011/08/go2.png" alt="" width="217" height="182" /></p>
<p>Then set the time line for Google Analytics to show a decent length of time.  I am using 6 months in my example – just use as much data as you have since the site has been stable and not changed.</p>
<p>On the top content screen find the right most column called $ index – the $ index is the average value for a page that a user visited before completing an Ecommerce transaction.  Ordering by the $ index will give you the most valuable pages on your site.  However you also need to click on ‘weighted sort’ to give you not only the most valuable pages but the most relevant valuable pages.  Without weighted sort you are only going to see the pages that randomly got high values because an odd buyer used them to make a big purchase.  By using weighted sort we can filter out these anomalies.</p>
<p><img class="size-full wp-image-226 alignnone" title="go3" src="http://www.browsertobuyer.com/wp-content/uploads/2011/08/go3.png" alt="" width="582" height="88" /></p>
<p>On the site I am looking at for this example this gives me the following pages</p>
<p><img class="alignleft size-full wp-image-227" title="go4" src="http://www.browsertobuyer.com/wp-content/uploads/2011/08/go4.png" alt="" width="375" height="216" /></p>
<p>As you can see these are all checkout pages which are NOT part of the inbuilt Google Optimizer set of tools that Magento supplies.  Whilst I have personally run split tests here, its tricky and not something I can easily show you.  However you can optimise these pages by creating a ‘goal’ funnel and looking at the profile, but I want to cover that in another blog post.</p>
<p>So what I am going to do is to scroll through the list until I find one of the following pages that is built into Magento to Google Optimizer test</p>
<ul class="clear">
<li>Product page</li>
<li>CMS page – (this could be a Google Adwords landing page and in many of my sites these are the best pages to test as they drive a significant proportion of my revenue)</li>
<li>Category page</li>
<li>Home page</li>
</ul>
<p>In my example site the first page I find is not the home page as I would have expected but instead a product page.  It just goes to show how important it is to look at the stats before deciding where to test.</p>
<p>The product I can use to test is worth $102 and thus a decent sale for the site and must have a fair number of transactions to rank this highly.  So this is where I would start.</p>
<p>I am not going to go through how to actually setup the experiment as there are plenty of good blog tutorials available – just Google “Google Optimizer for Magento” – but I wanted to show you where to test first as this will actually allow you to make the most important changes to your site first.</p>
<p>Originally published on <a href="http://magebase.com">magebase.com</a>. Copyright &copy; 2011 Magebase - All Rights Reserved.</p>]]></content:encoded>
			<wfw:commentRss>http://magebase.com/magento-tutorials/google-optimizer-on-magento-where-to-start-for-maximum-gain/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Database Caching using disk: basic
Object Caching 631/724 objects using disk: basic

Served from: magebase.com @ 2012-05-19 00:03:48 -->
