<?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>Atwix &#187; extensions</title>
	<atom:link href="http://www.atwix.com/tag/extensions/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.atwix.com</link>
	<description>Custom Magento development, Magento modules and design</description>
	<lastBuildDate>Tue, 21 May 2013 11:30:20 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Source, frontend and backend models in Magento system settings</title>
		<link>http://www.atwix.com/magento/frontend-backend-source/</link>
		<comments>http://www.atwix.com/magento/frontend-backend-source/#comments</comments>
		<pubDate>Mon, 25 Feb 2013 08:37:40 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[customize]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[field]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[magento]]></category>
		<category><![CDATA[settings]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=2592</guid>
		<description><![CDATA[You're welcome to check our new finding on source, frontend and backend models in Magento system settings.]]></description>
				<content:encoded><![CDATA[<p>In the previous <a title="article" href="http://www.atwix.com/magento/system-settings/">article</a> we have described how the different settings can be applied to a custom extension. There&#8217;s nothing difficult for the simple settings such as text field or text area. But, if you look at the drop down, multiselect or editable items list you&#8217;ll notice that these items have additional fields, e.g. source_model, backend_model, frontend_model. Let&#8217;s focus on these models and find out more info about creating settings that require data models. <span id="more-2592"></span></p>
<p>Source Model &#8211; a model class that serves to get existing values (stored in the db or somewhere else) for further displaying inside the setting&#8217;s field.</p>
<p>Frontend Model &#8211; as a rule, it&#8217;s a block&#8217;s class. Methods of this class return html of setting&#8217;s field. To be more specific, the block had to have method _getElementHtml() described inside the class which returns the raw html of setting&#8217;s field.</p>
<p>Backend Model &#8211; a class which allows to operate with configuration data on the different stages (save, load). It contains three major methods respectively for each event: _afterLoad(), _beforeSave() and _afterSave().</p>
<p>If you are interested in, you can always find the working examples of each of them in the Magento core itself. But firstly, let&#8217;s try to look on some custom examples of these models. The following part describes how to create a drop down menu with the custom values:</p>
<p>Init setting&#8217;s field in your system.xml:</p>
<pre class="brush: xml; gutter: true">&lt;color&gt;
    &lt;label&gt;Color&lt;/label&gt;
    &lt;frontend_type&gt;select&lt;/frontend_type&gt;
    &lt;source_model&gt;Atwix_Shoppingbar_Model_Adminhtml_System_Config_Source_Color&lt;/source_model&gt;
    &lt;sort_order&gt;2&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;/color&gt;</pre>
<p>Then, create the source model that was specified above:</p>
<pre class="brush: php; gutter: true">class Atwix_Shoppingbar_Model_Adminhtml_System_Config_Source_Color
{
   public function toOptionArray()
   {
       $themes = array(
           array(&#039;value&#039; =&gt; &#039;green&#039;, &#039;label&#039; =&gt; &#039;Green&#039;),
           array(&#039;value&#039; =&gt; &#039;blue&#039;, &#039;label&#039; =&gt; &#039;Blue&#039;),
           array(&#039;value&#039; =&gt; &#039;beige&#039;, &#039;label&#039; =&gt; &#039;Beige&#039;),
       );

       return $themes;
   }
}</pre>
<p>As you can see, there&#8217;s only one method toOptionArray(). It returns an array with the items (value -&gt; label) for the drop down menu. Nothing difficult is here <img src='http://www.atwix.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Let&#8217;s look onto another example to find out how to use frontend and source models. The best point is to review editable items list setting since it has both. The setting described below operates with the text items. It allows to add/remove email addresses:</p>
<pre class="brush: xml; gutter: true">&lt;addresses&gt;
    &lt;label&gt;Blocked Email Addresses&lt;/label&gt;
    &lt;frontend_model&gt;atwix_emailblocker/adminhtml_addresses&lt;/frontend_model&gt;
    &lt;backend_model&gt;adminhtml/system_config_backend_serialized&lt;/backend_model&gt;
    &lt;sort_order&gt;2&lt;/sort_order&gt;
    &lt;show_in_default&gt;1&lt;/show_in_default&gt;
    &lt;show_in_website&gt;0&lt;/show_in_website&gt;
    &lt;show_in_store&gt;0&lt;/show_in_store&gt;
    &lt;can_be_empty&gt;1&lt;/can_be_empty&gt;
&lt;/addresses&gt;</pre>
<p>Frontend model is a block:</p>
<pre class="brush: php; gutter: true">class Atwix_Emailblocker_Block_Adminhtml_Addresses extends Mage_Adminhtml_Block_System_Config_Form_Field
{
   protected $_addRowButtonHtml = array();
   protected $_removeRowButtonHtml = array();

   /**
    * Returns html part of the setting
    *
    * @param Varien_Data_Form_Element_Abstract $element
    * @return string
    */
   protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
   {
       $this-&gt;setElement($element);

       $html = &#039;&lt;div id=&quot;emailblocker_addresses_template&quot; style=&quot;display:none&quot;&gt;&#039;;
       $html .= $this-&gt;_getRowTemplateHtml();
       $html .= &#039;&lt;/div&gt;&#039;;

       $html .= &#039;&lt;ul id=&quot;emailblocker_addresses_container&quot;&gt;&#039;;
       if ($this-&gt;_getValue(&#039;addresses&#039;)) {
           foreach ($this-&gt;_getValue(&#039;addresses&#039;) as $i =&gt; $f) {
               if ($i) {
                   $html .= $this-&gt;_getRowTemplateHtml($i);
               }
           }
       }
       $html .= &#039;&lt;/ul&gt;&#039;;
       $html .= $this-&gt;_getAddRowButtonHtml(&#039;emailblocker_addresses_container&#039;,
           &#039;emailblocker_addresses_template&#039;, $this-&gt;__(&#039;Add New Email&#039;));

       return $html;
   }

   /**
    * Retrieve html template for setting
    *
    * @param int $rowIndex
    * @return string
    */
   protected function _getRowTemplateHtml($rowIndex = 0)
   {
       $html = &#039;&lt;li&gt;&#039;;

       $html .= &#039;&lt;div style=&quot;margin:5px 0 10px;&quot;&gt;&#039;;
       $html .= &#039;&lt;input style=&quot;width:100px;&quot; name=&quot;&#039;
           . $this-&gt;getElement()-&gt;getName() . &#039;[addresses][]&quot; value=&quot;&#039;
           . $this-&gt;_getValue(&#039;addresses/&#039; . $rowIndex) . &#039;&quot; &#039; . $this-&gt;_getDisabled() . &#039;/&gt; &#039;;

       $html .= $this-&gt;_getRemoveRowButtonHtml();
       $html .= &#039;&lt;/div&gt;&#039;;
       $html .= &#039;&lt;/li&gt;&#039;;

       return $html;
   }

   protected function _getDisabled()
   {
       return $this-&gt;getElement()-&gt;getDisabled() ? &#039; disabled&#039; : &#039;&#039;;
   }

   protected function _getValue($key)
   {
       return $this-&gt;getElement()-&gt;getData(&#039;value/&#039; . $key);
   }

   protected function _getSelected($key, $value)
   {
       return $this-&gt;getElement()-&gt;getData(&#039;value/&#039; . $key) == $value ? &#039;selected=&quot;selected&quot;&#039; : &#039;&#039;;
   }

   protected function _getAddRowButtonHtml($container, $template, $title=&#039;Add&#039;)
   {
       if (!isset($this-&gt;_addRowButtonHtml[$container])) {
           $this-&gt;_addRowButtonHtml[$container] = $this-&gt;getLayout()-&gt;createBlock(&#039;adminhtml/widget_button&#039;)
               -&gt;setType(&#039;button&#039;)
               -&gt;setClass(&#039;add &#039; . $this-&gt;_getDisabled())
               -&gt;setLabel($this-&gt;__($title))
               -&gt;setOnClick(&quot;Element.insert($(&#039;&quot; . $container . &quot;&#039;), {bottom: $(&#039;&quot; . $template . &quot;&#039;).innerHTML})&quot;)
               -&gt;setDisabled($this-&gt;_getDisabled())
               -&gt;toHtml();
       }
       return $this-&gt;_addRowButtonHtml[$container];
   }

   protected function _getRemoveRowButtonHtml($selector = &#039;li&#039;, $title = &#039;Delete&#039;)
   {
       if (!$this-&gt;_removeRowButtonHtml) {
           $this-&gt;_removeRowButtonHtml = $this-&gt;getLayout()-&gt;createBlock(&#039;adminhtml/widget_button&#039;)
               -&gt;setType(&#039;button&#039;)
               -&gt;setClass(&#039;delete v-middle &#039; . $this-&gt;_getDisabled())
               -&gt;setLabel($this-&gt;__($title))
               -&gt;setOnClick(&quot;Element.remove($(this).up(&#039;&quot; . $selector . &quot;&#039;))&quot;)
               -&gt;setDisabled($this-&gt;_getDisabled())
               -&gt;toHtml();
       }
       return $this-&gt;_removeRowButtonHtml;
   }
}</pre>
<p>It&#8217;s pretty huge. We have described the full version to show what&#8217;s going on there. You can simple extend your block from Mage_GoogleCheckout_Block_Adminhtml_Shipping_Merchant and override the necessary methods.</p>
<p>Backend model, in this case, it&#8217;s a standard Magento model:</p>
<pre class="brush: php; gutter: true">class Mage_Adminhtml_Model_System_Config_Backend_Serialized extends Mage_Core_Model_Config_Data
{
    protected function _afterLoad()
    {
        if (!is_array($this-&gt;getValue())) {
            $value = $this-&gt;getValue();
            $this-&gt;setValue(empty($value) ? false : unserialize($value));
        }
    }

    protected function _beforeSave()
    {
        if (is_array($this-&gt;getValue())) {
            $this-&gt;setValue(serialize($this-&gt;getValue()));
        }
    }
}</pre>
<p>As you can see, it simply unserializes/serializes field&#8217;s values before load/save respectively. That&#8217;s all. You are always able to improvise with the models described below to get the best result. If you want non-trivial form element &#8211; use your own fronted model. To get available values for settings you should use the source model. And if you need to save/load data in your format or make some other actions on these events &#8211; feel free to use the backend model.<br />
Good luck and graceful solutions <img src='http://www.atwix.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/frontend-backend-source/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Magento system settings overview</title>
		<link>http://www.atwix.com/magento/system-settings/</link>
		<comments>http://www.atwix.com/magento/system-settings/#comments</comments>
		<pubDate>Fri, 08 Feb 2013 08:26:59 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[customize]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[magento]]></category>
		<category><![CDATA[menus]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=2542</guid>
		<description><![CDATA[Our new article includes helpful snippets which contain xml code of the most recent settings used in Magento admin.]]></description>
				<content:encoded><![CDATA[<p>From time to time  Magento developers face with a need to add settings for their extensions. As it&#8217;s hard to remember all necessary details for each setting, so we would like to share our snippets which contain xml code of the most recent settings used in Magento admin.<span id="more-2542"></span></p>
<p>First of all, we would recommend you always place everything, that refers to Magento system settings, in the system.xml file, since it&#8217;s the main and the only role of this file.<br />
If you need to create your own tab in the admin system settings, you should simply add the following lines to the file:</p>
<pre class="brush: xml; gutter: true">&lt;config&gt;
    &lt;tabs&gt;
        &lt;atwix translate=&quot;label&quot;&gt;
            &lt;label&gt;Atwix Extensions&lt;/label&gt;
            &lt;sort_order&gt;150&lt;/sort_order&gt;
        &lt;/atwix&gt;
    &lt;/tabs&gt;    
&lt;/config&gt;</pre>
<p>As a result, you&#8217;ll get the new group (tab) in the admin settings. When you need to complete the procedure of adding settings you should add the following items: section, settings groups and the settings (fields) themselves:</p>
<pre class="brush: xml; gutter: true">&lt;config&gt;
    &lt;sections&gt;
        &lt;atwix_shoppingbar translate=&quot;label&quot; module=&quot;atwix_shoppingbar&quot;&gt;
            &lt;class&gt;separator-top&lt;/class&gt;
            &lt;label&gt;Shopping Bar&lt;/label&gt;
            &lt;tab&gt;atwix&lt;/tab&gt;
            &lt;sort_order&gt;130&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;quicksearch&gt;
                    &lt;label&gt;Quick search&lt;/label&gt;
                    &lt;frontend_type&gt;text&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;0&lt;/show_in_website&gt;
                    &lt;show_in_store&gt;1&lt;/show_in_store&gt;
                    &lt;fields&gt;
                        &lt;quicksearch_enabled translate=&quot;label comment&quot;&gt;
                            &lt;label&gt;Enable Quick Search&lt;/label&gt;
                            &lt;comment&gt;&lt;![CDATA[Enable quick search block]]&gt;&lt;/comment&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;1&lt;/sort_order&gt;
                            &lt;show_in_default&gt;1&lt;/show_in_default&gt;
                            &lt;show_in_website&gt;0&lt;/show_in_website&gt;
                            &lt;show_in_store&gt;1&lt;/show_in_store&gt;
                        &lt;/quicksearch_enabled&gt;
                        &lt;results_count translate=&quot;label comment&quot;&gt;
                            &lt;label&gt;Results count&lt;/label&gt;
                            &lt;comment&gt;&lt;![CDATA[Quick search results count (min 1, max 20)]]&gt;&lt;/comment&gt;
                            &lt;frontend_type&gt;text&lt;/frontend_type&gt;
                            &lt;sort_order&gt;5&lt;/sort_order&gt;
                            &lt;show_in_default&gt;1&lt;/show_in_default&gt;
                            &lt;show_in_website&gt;0&lt;/show_in_website&gt;
                            &lt;show_in_store&gt;1&lt;/show_in_store&gt;
                        &lt;/results_count&gt;
                    &lt;/fields&gt;
                &lt;/quicksearch&gt;
            &lt;/groups&gt;
        &lt;/atwix_shoppingbar&gt;
    &lt;/sections&gt;
&lt;/config&gt;</pre>
<p>Here is an illustration what means each of these terms:</p>
<p><img class="alignnone size-full wp-image-2557" alt="sections" src="http://www.atwix.com/wp-content/uploads/2013/01/sections.png" width="1250" height="556" /></p>
<p>Next question is how will the different settings in the xml config look like. As you already know, each setting is placed in the &lt;fields&gt; node, then follows the unique setting&#8217;s id and finally &#8211; setting&#8217;s attributes. Here is a small review of the most useful settings:</p>
<p><strong>Text field</strong></p>
<p>Simple input field for short text values:</p>
<p><img class="size-full wp-image-2556 alignnone" alt="text_field" src="http://www.atwix.com/wp-content/uploads/2013/01/text_field.png" width="609" height="31" /></p>
<pre class="brush: xml; gutter: true"> &lt;text_field translate=&quot;label&quot;&gt;
    &lt;label&gt;Text Field&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;/text_field&gt;</pre>
<p><strong>Textarea</strong></p>
<p>Wide input field for long text values:</p>
<p><img class="alignnone size-full wp-image-2555" alt="textarea" src="http://www.atwix.com/wp-content/uploads/2013/01/textarea.png" width="606" height="201" /></p>
<pre class="brush: xml; gutter: true">&lt;textarea translate=&quot;label&quot;&gt;
    &lt;label&gt;Textarea&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;1&lt;/show_in_store&gt;
&lt;/textarea&gt;</pre>
<p><strong>Drop down with Yes/No values</strong></p>
<p>Drop down menu with the values &#8220;Yes&#8221; and &#8220;No&#8221;. Commonly it is used as a flag for enabling/disabling something:</p>
<p><img class="alignnone size-full wp-image-2554" alt="dropdown_yesno" src="http://www.atwix.com/wp-content/uploads/2013/01/dropdown_yesno.png" width="582" height="31" /></p>
<pre class="brush: xml; gutter: true">&lt;enabled translate=&quot;label&quot;&gt;
    &lt;label&gt;Enabled&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;1&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;/enabled&gt;</pre>
<p><strong>Drop down with Enable/Disable values</strong></p>
<p>Almost the same as previous one, but instead of &#8220;Yes&#8221; and &#8220;No&#8221; you will get &#8220;Enable&#8221; and &#8220;Disable&#8221;:</p>
<p><img class="alignnone size-full wp-image-2551" alt="enableddisabled" src="http://www.atwix.com/wp-content/uploads/2013/01/enableddisabled.png" width="606" height="34" /></p>
<pre class="brush: xml; gutter: true">&lt;active translate=&quot;label&quot;&gt;
    &lt;label&gt;Enable/Disable&lt;/label&gt;
    &lt;frontend_type&gt;select&lt;/frontend_type&gt;
    &lt;sort_order&gt;40&lt;/sort_order&gt;
    &lt;source_model&gt;adminhtml/system_config_source_enabledisable&lt;/source_model&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;/active&gt;</pre>
<p><strong>Drop down with custom values</strong></p>
<p>Drop down with the custom set of values, generated by source model:</p>
<p><img class="alignnone size-full wp-image-2553" alt="custom_dropdown" src="http://www.atwix.com/wp-content/uploads/2013/01/custom_dropdown.png" width="607" height="35" /></p>
<pre class="brush: xml; gutter: true">&lt;default translate=&quot;label&quot;&gt;
    &lt;label&gt;Select&lt;/label&gt;
    &lt;frontend_type&gt;select&lt;/frontend_type&gt;
    &lt;!-- Source model for countries list. For custom list you need to use your own source model --&gt;
    &lt;source_model&gt;adminhtml/system_config_source_country&lt;/source_model&gt;
    &lt;sort_order&gt;50&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;/default&gt;</pre>
<p><strong>Multiselect with custom values</strong></p>
<p>Field with the ability to select few items at the same time:</p>
<p><img class="alignnone size-full wp-image-2550" alt="multiselect" src="http://www.atwix.com/wp-content/uploads/2013/01/multiselect.png" width="590" height="228" /></p>
<pre class="brush: xml; gutter: true">&lt;multiselect translate=&quot;label&quot;&gt;
    &lt;label&gt;Multiselect&lt;/label&gt;
    &lt;frontend_type&gt;multiselect&lt;/frontend_type&gt;
    &lt;!-- Source model for countries list. For custom list you need to use your own source model --&gt;
    &lt;source_model&gt;adminhtml/system_config_source_country&lt;/source_model&gt;
    &lt;sort_order&gt;60&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;can_be_empty&gt;1&lt;/can_be_empty&gt;
&lt;/multiselect&gt;</pre>
<p><strong>File</strong></p>
<p>Allows to choose a file for uploading. In this example the file will be saved in var/uploads directory:</p>
<p><img class="alignnone size-full wp-image-2548" alt="file" src="http://www.atwix.com/wp-content/uploads/2013/01/file.png" width="601" height="52" /></p>
<pre class="brush: xml; gutter: true">&lt;file translate=&quot;label comment&quot;&gt;
    &lt;label&gt;File&lt;/label&gt;
    &lt;frontend_type&gt;file&lt;/frontend_type&gt;
    &lt;backend_model&gt;adminhtml/system_config_backend_file&lt;/backend_model&gt;
    &lt;upload_dir&gt;var/uploads&lt;/upload_dir&gt;
    &lt;sort_order&gt;70&lt;/sort_order&gt;
    &lt;show_in_default&gt;1&lt;/show_in_default&gt;
    &lt;show_in_website&gt;0&lt;/show_in_website&gt;
    &lt;show_in_store&gt;0&lt;/show_in_store&gt;
&lt;/file&gt;</pre>
<p><strong>Time</strong></p>
<p>Is used to create three drop down menus for setting up the hours, minutes and seconds respectively:</p>
<p><img class="alignnone size-full wp-image-2552" alt="time" src="http://www.atwix.com/wp-content/uploads/2013/01/time.png" width="609" height="28" /></p>
<pre class="brush: xml; gutter: true">&lt;time translate=&quot;label comment&quot;&gt;
    &lt;label&gt;Time&lt;/label&gt;
    &lt;frontend_type&gt;time&lt;/frontend_type&gt;
    &lt;sort_order&gt;80&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;/time&gt;</pre>
<p><strong>Editable items list</strong></p>
<p>Allows to add/remove text values for the setting:</p>
<p><img class="alignnone size-full wp-image-2547" alt="editable_list" src="http://www.atwix.com/wp-content/uploads/2013/01/editable_list.png" width="577" height="113" /></p>
<pre class="brush: xml; gutter: true">&lt;addresses&gt;
    &lt;label&gt;Blocked Email Addresses&lt;/label&gt;
    &lt;frontend_model&gt;atwix_emailblocker/adminhtml_addresses&lt;/frontend_model&gt;
    &lt;backend_model&gt;adminhtml/system_config_backend_serialized&lt;/backend_model&gt;
    &lt;sort_order&gt;90&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;can_be_empty&gt;1&lt;/can_be_empty&gt;
&lt;/addresses&gt;</pre>
<p><strong>Heading</strong></p>
<p>Is used to entitle some settings inside the group:</p>
<p><img class="alignnone size-full wp-image-2549" alt="heading" src="http://www.atwix.com/wp-content/uploads/2013/01/heading.png" width="604" height="63" /></p>
<pre class="brush: xml; gutter: true">&lt;heading translate=&quot;label&quot;&gt;
    &lt;label&gt;Heading&lt;/label&gt;
    &lt;frontend_model&gt;adminhtml/system_config_form_field_heading&lt;/frontend_model&gt;
    &lt;sort_order&gt;90&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;/heading&gt;</pre>
<p><strong>Dependent field</strong></p>
<p>It can be any field. The main purpose of this one &#8211; it&#8217;s to hide/show the field depending on the state of  some other field. In the following example the field depends on the field&#8217;s <em>enablemethod</em> state. If <em>enablemethod</em> value is 1 &#8211; dependent_field will appear and vice versa:</p>
<pre class="brush: xml; gutter: true">&lt;dependent_field translate=&quot;label&quot;&gt;
    &lt;label&gt;Dependent Field&lt;/label&gt;
    &lt;frontend_type&gt;textarea&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;1&lt;/show_in_store&gt;
    &lt;depends&gt;
        &lt;enablemethod&gt;1&lt;/enablemethod&gt;
    &lt;/depends&gt;
&lt;/dependent_field&gt;</pre>
<p>There is also one interesting cheat. You are able to use javascript inside of the &lt;comment&gt;&lt;/comment&gt; node:</p>
<pre class="brush: xml; gutter: true">&lt;specificerrmsg translate=&quot;label&quot;&gt;
    &lt;label&gt;Displayed Error Message&lt;/label&gt;
    &lt;frontend_type&gt;textarea&lt;/frontend_type&gt;
    &lt;comment&gt;
    &lt;![CDATA[
        &lt;script type=&quot;text/javascript&quot;&gt;
            Event.observe(&#039;carriers_flatrate_active&#039;, &#039;change&#039;, function() {
                alert(&#039;Be careful with this one&#039;);
            })
        &lt;/script&gt;
    ]]&gt;
    &lt;/comment&gt;
    &lt;sort_order&gt;2013&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;/specificerrmsg&gt;</pre>
<p>It might be useful for changing field&#8217;s value depending on different credentials. We would not recommend you to use it very often there, especially for the big javascript code.</p>
<p>Moreover, as you might have noticed, there are some attributes like source_model for the custom drop downs or, all the more so, frontend model for editable list which may disappoint a bit. We are going to describe how to operate with these models in our next article, which will see the light in the nearest future. Thank you for reading us <img src='http://www.atwix.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/system-settings/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Creating CSV files in Magento</title>
		<link>http://www.atwix.com/magento/create-csv-files/</link>
		<comments>http://www.atwix.com/magento/create-csv-files/#comments</comments>
		<pubDate>Tue, 15 Jan 2013 09:00:26 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[csv]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[magento]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=2319</guid>
		<description><![CDATA[We would like to demonstrate the small example of the ability to generate and download CSV files in Magento.]]></description>
				<content:encoded><![CDATA[<p>There are many tools in Magento which allow you to view or generate and download different reports. So, we can conclude that Magento system has integrated tools for CSV and XML files generation. It might help in the situation when you need to generate a report for some feed or just export a list of structured data. We would like to demonstrate the small example that adds an ability to generate and download CSV files.<br />
Let&#8217;s assume that you have already created your custom extension and wish to add a CSV export functionality. If it&#8217;s not the case and you can&#8217;t guess how to create an extension, then you can always find the light in our previous articles, for example <a href="http://www.atwix.com/magento/add-category-attribute/">this one</a>. We called our extension Atwix_Tweaks so in the code examples below we will use this title.<br />
<span id="more-2319"></span><br />
As we said before, the file is being downloaded within some URL. Well, then we need to create the controller and corresponded method-action. In config.xml file add the section which will tell the system where our controller is located:</p>
<pre class="brush: xml; gutter: true">
   &lt;frontend&gt;
        &lt;routers&gt;
            &lt;atwix_tweaks&gt;
                &lt;use&gt;standard&lt;/use&gt;
                &lt;args&gt;
                    &lt;module&gt;Atwix_Tweaks&lt;/module&gt;
                    &lt;frontName&gt;mln&lt;/frontName&gt;
                &lt;/args&gt;
            &lt;/atwix_tweaks&gt;
        &lt;/routers&gt;
    &lt;/frontend&gt;
</pre>
<p>On the next step, we should create the controller itself (app/code/local/Atwix/Tweaks/controllers/IndexController.php):</p>
<pre class="brush: php; gutter: true">
class Atwix_Tweaks_IndexController extends Mage_Core_Controller_Front_Action
{
    /**
     * Returns generated CSV file
     */
    public function mlnProductsListAction()
    {
        $filename = &#039;mln.csv&#039;;
        $content = Mage::helper(&#039;atwix_tweaks/mln&#039;)-&gt;generateMlnList();

        $this-&gt;_prepareDownloadResponse($filename, $content);
    }
}
</pre>
<p>As you can see, the controller calls method generateMlnList() from helper &#8216;atwix_tweaks/mln&#8217;. What are we going to do next? Right, create the helper (app/code/local/Atwix/Tweaks/Helper/Mln.php):</p>
<pre class="brush: php; gutter: true">
class Atwix_Tweaks_Helper_Mln extends Mage_Core_Helper_Abstract
{
    /**
     * Contains current collection
     * @var string
     */
    protected $_list = null;

    public function __construct()
    {
        $collection = Mage::getModel(&#039;catalog/product&#039;)-&gt;getCollection()
            -&gt;addAttributeToSelect(&#039;*&#039;)
            -&gt;addAttributeToFilter(array(&#039;attribute&#039; =&gt; &#039;wight&#039;, &#039;gt&#039; =&gt; 2));

        $this-&gt;setList($collection);
    }

    /**
     * Sets current collection
     * @param $query
     */
    public function setList($collection)
    {
        $this-&gt;_list = $collection;
    }

    /**
     * Returns indexes of the fetched array as headers for CSV
     * @param array $products
     * @return array
     */
    protected function _getCsvHeaders($products)
    {
        $product = current($products);
        $headers = array_keys($product-&gt;getData());

        return $headers;
    }

    /**
     * Generates CSV file with product&#039;s list according to the collection in the $this-&gt;_list
     * @return array
     */
    public function generateMlnList()
    {
        if (!is_null($this-&gt;_list)) {
            $items = $this-&gt;_list-&gt;getItems();
            if (count($items) &gt; 0) {

                $io = new Varien_Io_File();
                $path = Mage::getBaseDir(&#039;var&#039;) . DS . &#039;export&#039; . DS;
                $name = md5(microtime());
                $file = $path . DS . $name . &#039;.csv&#039;;
                $io-&gt;setAllowCreateFolders(true);
                $io-&gt;open(array(&#039;path&#039; =&gt; $path));
                $io-&gt;streamOpen($file, &#039;w+&#039;);
                $io-&gt;streamLock(true);

                $io-&gt;streamWriteCsv($this-&gt;_getCsvHeaders($items));
                foreach ($items as $product) {
                    $io-&gt;streamWriteCsv($product-&gt;getData());
                }

                return array(
                    &#039;type&#039;  =&gt; &#039;filename&#039;,
                    &#039;value&#039; =&gt; $file,
                    &#039;rm&#039;    =&gt; true // can delete file after use
                );
            }
        }
    }
}
</pre>
<p>The helper uses Varien_Io_File class, integrated in Magento, to generate a custom CSV file. Generated file will be stored in the media folder and deleted before the controller sends header to the client side. If you don&#8217;t want to delete file, you can set parameter rm to false in the return statement. In the constructor (method __construct) you can use any collection you want (customers, orders, custom collections etc.). Also, you are able to pass the collection behind the constructor using method setList().<br />
I hope this small example will help you in your further development. If you have some suggestions or questions you can always place them here ⇩ <img src='http://www.atwix.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/create-csv-files/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Filter products by attribute on a Magento CMS page</title>
		<link>http://www.atwix.com/magento/products-list-cms/</link>
		<comments>http://www.atwix.com/magento/products-list-cms/#comments</comments>
		<pubDate>Fri, 21 Dec 2012 08:30:58 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[blocks]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[customize]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[magento]]></category>
		<category><![CDATA[module]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=2165</guid>
		<description><![CDATA[Our article describes how to add products list that is filtered by some attribute to Magento CMS page.]]></description>
				<content:encoded><![CDATA[<p>Ability to create pages with custom content is a great feature provided by Magento. You can easily create a new page for your store and add text, html, images, different widgets there. But sometimes people want to have something non-trivial on their pages. Usually it means that you need to operate some knowledge before you&#8217;ll get an appropriate result. In this article we would like to suggest you a simple solution on how to place a products list, prefiltered by some specific attribute, on your CMS page. The example below describes how to create a simple extension for this purpose.<br />
<span id="more-2165"></span><br />
Let&#8217;s call the extension <em>Atwix_Cmsattr</em>. First, you need to add the init file for you extension. The path is app/etc/modules/Atwix_Cmsattr.xml . The file&#8217;s content is:</p>
<pre class="brush: xml; gutter: true">&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_Cmsattr&gt;
            &lt;active&gt;true&lt;/active&gt;
            &lt;codePool&gt;local&lt;/codePool&gt;
        &lt;/Atwix_Cmsattr&gt;
    &lt;/modules&gt;
&lt;/config&gt;</pre>
<p>The extension contains one block class and one model, therefore the config file, which you should have by the following path: <em>app/code/local/Atwix/Cmsattr/etc/config.xml</em>, is pretty simple and consists of a few records:</p>
<pre class="brush: xml; gutter: true">&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_Cmsattr&gt;
            &lt;version&gt;0.1.0&lt;/version&gt;
        &lt;/Atwix_Cmsattr&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;blocks&gt;
            &lt;atwix_cmsattr&gt;
                &lt;class&gt;Atwix_Cmsattr_Block&lt;/class&gt;
            &lt;/atwix_cmsattr&gt;
        &lt;/blocks&gt;
        &lt;models&gt;
            &lt;atwix_cmsattr&gt;
                &lt;class&gt;Atwix_Cmsattr_Model&lt;/class&gt;
            &lt;/atwix_cmsattr&gt;
        &lt;/models&gt;
    &lt;/global&gt;
&lt;/config&gt;</pre>
<p>After that, create the block class <em>app/code/local/Atwix/Cmsattr/Block/List.php</em>:</p>
<pre class="brush: php; gutter: true">&lt;?php
class Atwix_Cmsattr_Block_List extends Mage_Catalog_Block_Product_Abstract
{
    protected $_itemCollection = null;

    public function getItems()
    {
        $color = $this-&gt;getColor();
        if (!$color)
            return false;
        if (is_null($this-&gt;_itemCollection)) {
            $this-&gt;_itemCollection = Mage::getModel(&#039;atwix_cmsattr/products&#039;)-&gt;getItemsCollection($color);
        }

        return $this-&gt;_itemCollection;
    }
}</pre>
<p>and the model class <em>app/code/local/Atwix/Cmsattr/Model/Products.php</em>:</p>
<pre class="brush: php; gutter: true">&lt;?php
class Atwix_Cmsattr_Model_Products extends Mage_Catalog_Model_Product
{
    public function getItemsCollection($valueId)
    {
        $collection = $this-&gt;getCollection()
            -&gt;addAttributeToSelect(&#039;*&#039;)
            -&gt;addAttributeToFilter(&#039;color&#039;, array(&#039;eq&#039; =&gt; $valueId));
        Mage::getSingleton(&#039;cataloginventory/stock&#039;)-&gt;addInStockFilterToCollection($collection);
        return $collection;
    }
}</pre>
<p>The next file is the most personal thing. You need the template file with your own mockup corresponding to your design. Here is an example for a simple list (<em>app/design/frontend/base/default/template/atwix/cmsattr/list.phtml</em>):</p>
<pre class="brush: php; gutter: true">&lt;?php $_items = $this-&gt;getItems() ?&gt;
&lt;div class=&quot;block&quot;&gt;
    &lt;div class=&quot;block-title&quot;&gt;
        &lt;strong&gt;&lt;span&gt;&lt;?php echo $this-&gt;__(&#039;Red Products&#039;) ?&gt;&lt;/span&gt;&lt;/strong&gt;
    &lt;/div&gt;
    &lt;div class=&quot;block-content&quot;&gt;
        &lt;ol class=&quot;mini-products-list&quot;&gt;
        &lt;?php foreach ($_items as $_item): ?&gt;
            &lt;li class=&quot;item&quot;&gt;
                &lt;div class=&quot;product&quot;&gt;
                    &lt;a href=&quot;&lt;?php echo $_item-&gt;getProductUrl() ?&gt;&quot; title=&quot;&lt;?php echo $this-&gt;htmlEscape($_item-&gt;getName()) ?&gt;&quot; class=&quot;product-image&quot;&gt;&lt;img src=&quot;&lt;?php echo $this-&gt;helper(&#039;catalog/image&#039;)-&gt;init($_item, &#039;thumbnail&#039;)-&gt;resize(50) ?&gt;&quot; width=&quot;50&quot; height=&quot;50&quot; alt=&quot;&lt;?php echo $this-&gt;htmlEscape($_item-&gt;getName()) ?&gt;&quot; /&gt;&lt;/a&gt;
                    &lt;div class=&quot;product-details&quot;&gt;
                        &lt;p class=&quot;product-name&quot;&gt;&lt;a href=&quot;&lt;?php echo $_item-&gt;getProductUrl() ?&gt;&quot;&gt;&lt;?php echo $this-&gt;htmlEscape($_item-&gt;getName()) ?&gt;&lt;/a&gt;&lt;/p&gt;
                        &lt;?php echo $this-&gt;getPriceHtml($_item, true) ?&gt;
                        &lt;?php if ($this-&gt;helper(&#039;wishlist&#039;)-&gt;isAllow()) : ?&gt;
                        &lt;a href=&quot;&lt;?php echo $this-&gt;getAddToWishlistUrl($_item) ?&gt;&quot; class=&quot;link-wishlist&quot;&gt;&lt;?php echo $this-&gt;__(&#039;Add to Wishlist&#039;) ?&gt;&lt;/a&gt;
                        &lt;?php endif; ?&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/li&gt;
        &lt;?php endforeach; ?&gt;
        &lt;/ol&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre>
<p>The last thing you need to do is to create a CMS page and insert the products list where you want to show it on the page. So, go to Admin-&gt;CMS-&gt;Pages-&gt;Add New Page. Fill the page with the necessary content and connect our products block anywhere in the content by putting the following string:</p>
<pre class="brush: php; gutter: true">{{block type=&quot;atwix_cmsattr/list&quot; name=&quot;cmsattr&quot; template=&quot;atwix/cmsattr/list.phtml&quot; color=&quot;26&quot;}}</pre>
<p>Note, that you need to pass the attribute value for color here. The product list on this page is filtered by this value. If you going to filter product by text attribute, such as &#8220;<em>name</em>&#8221; for example, you can pass the text value directly like <em>name=&#8221;Apple&#8221;</em>. But current example describes how to filter by attribute with type <em>select</em>. There are many ways to get value id from attribute&#8217;s value text. One of the simple (non programmatically) ways to do this is to inspect attributes values form using your browser. The example below describes how to do it within Google Chrome:</p>

<a href='http://www.atwix.com/magento/products-list-cms/attachment/screen-shot-2012-12-12-at-4-02-48-pm/' title='Screen Shot 2012-12-12 at 4.02.48 PM'><img width="150" height="150" src="http://www.atwix.com/wp-content/uploads/2012/12/Screen-Shot-2012-12-12-at-4.02.48-PM-150x150.png" class="attachment-thumbnail" alt="Screen Shot 2012-12-12 at 4.02.48 PM" /></a>
<a href='http://www.atwix.com/magento/products-list-cms/attachment/screen-shot-2012-12-12-at-4-03-01-pm/' title='Screen Shot 2012-12-12 at 4.03.01 PM'><img width="150" height="70" src="http://www.atwix.com/wp-content/uploads/2012/12/Screen-Shot-2012-12-12-at-4.03.01-PM-150x70.png" class="attachment-thumbnail" alt="Screen Shot 2012-12-12 at 4.03.01 PM" /></a>

<p>Also you can extend your model&#8217;s logic with the new method, which would transform attribute value text into it&#8217;s id, but this small article doesn&#8217;t describe how to do it <img src='http://www.atwix.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
In the next articles we are going to tell how to use layered navigation (filters) for products on CMS pages.<br />
Feel free to ask the questions and good luck in your coding experiments.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/products-list-cms/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Advices and Best Practices for Magento developers &#124; Part 2</title>
		<link>http://www.atwix.com/magento/best-practices-2/</link>
		<comments>http://www.atwix.com/magento/best-practices-2/#comments</comments>
		<pubDate>Mon, 26 Nov 2012 10:37:12 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[module]]></category>
		<category><![CDATA[modules]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=1966</guid>
		<description><![CDATA[Magento is one of the most powerful and flexible shopping cart engines and we continue to share our best practices with the Magento community.]]></description>
				<content:encoded><![CDATA[<p>We continue to share our experience with Magento developers by publishing the next set of Best Practices in Magento coding. If you missed our previous article, <a href="http://www.atwix.com/magento/best-practices/">here it is</a>.<br />
<span id="more-1966"></span></p>
<p><strong><em>Local or community code pool.</em></strong></p>
<p>Pretty often we face with the discussion about choosing a proper code pool. So, let&#8217;s talk about the difference. Local pool has the highest load priority and code in this pool can&#8217;t be overridden as easy as in community or core pools. But depending on the Magento ideology, local pool was primarily designed for local changes. If you own a website and make modifications for that website, then your modifications are classified as local and your changes should be made in the app/code/local folder. Also, when you do some custom work on the website &#8211; local code pool is for you. However, if the extension is used by many other customers, this extension is not local but shared with a (limited) community. Therefore, the extension belongs to the community pool.<br />
Provided that you are an extension developer, you shouldn&#8217;t prevent overriding your files by other developers for the purpose of making some small changes. That can always be done by using the local pool.</p>
<p><strong><em>Where to store the JS files in Magento?</em></strong></p>
<p>Usually developers choose one of the following paths to store JS files (we are talking about frontend):</p>
<pre class="brush: bash; gutter: true">
js
</pre>
<p>or</p>
<pre class="brush: bash; gutter: true">
skin/frontend/package/theme/js
</pre>
<p>Actually, you should think twice at this point. As we&#8217;ve told above, one of the major Magento ideas is modularity. Therefore, as a good developer you should allow third party developers to make small changes/customizations without a need to edit your code wherever it&#8217;s possible. If your JS files are located in the skins folder, other developers are always able to change something by copying JS files into their own theme&#8217;s folder. But if you use the root JS directory, they won&#8217;t be able to do that.</p>
<p><strong><em>Controllers and common logic.</em></strong></p>
<p>One of the common Magento problems is tons of logic in the controllers where it shouldn&#8217;t be. For exemple, let&#8217;s explore the core file <em>app/code/core/Mage/Customer/controllers/AccountController.php</em>. Look at the <em>createPostAction()</em> method and you will see a lot of operations there. Why not to use a helper to store this logic or some abstract class? It allows other developers to extend the logic for their own purposes easily. For example, if you need to add a new customer programmatically and you want to use a standard set of methods for this, you won&#8217;t be able to do it, because most of the logic is located in the controller. Hence, we think it would be a good practice to use more extendable structures for common logic instead of hardcoding it in the controllers.</p>
<p><strong><em>Dispatched events.</em></strong></p>
<p>There&#8217;s yet another way to improve the quality of your extensions using dispatched events. Dispatcher is a Magento integrated system, which allows you to set some &#8220;point&#8221; with the unique name and some necessary parameters where you can integrate our logic &#8220;on the fly&#8221;. In other words, you can create your own events in your logic. Then, you or other developers are able to catch these events and connect some handlers to the events. It&#8217;s always useful to have dispatched events in the extensions, because it provides you an ability to extend your code more effectively in the future and allows other developers to interact with your logic in intelligent way. Events are usually dispatched in models and controllers. It is good to know, that it is enough to use the following construction in your code to dispatch an event:</p>
<pre class="brush: php; gutter: true">
Mage::dispatchEvent(&#039;the_unique_name&#039;, array(&#039;var&#039; =&gt; $data));
</pre>
<p>As the second argument, you should pass the data, that you want to send to the observer&#8217;s method (some id or some object instance for example).</p>
<p><strong><em>DB queries profiler:</em></strong></p>
<p>Magento provides an ability for developers to track database queries. For this purpose you should use a built in DB resource profiler. It can help you to inspect database queries, detect the longest query, detect the slowest query, etc.. Here is a small example on how to use a DB profiler for your own needs :</p>
<pre class="brush: php; gutter: true">
$profiler = Mage::getSingleton(&#039;core/resource&#039;)-&gt;getConnection(&#039;core_write&#039;)-&gt;getProfiler();
foreach ($profiler-&gt;getQueryProfiles() as $query) {
    $queryTime[] = $query-&gt;getElapsedSecs(); // Get the query execution time
    $queryRaw[] = $query-&gt;getQuery(); // Get the query text
}
</pre>
<p>We would be glad to read your suggestions in the comments, so feel free to post them <img src='http://www.atwix.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/best-practices-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Adding a column to the customers grid in Magento admin. Alternative way</title>
		<link>http://www.atwix.com/magento/add-column-to-customers-grid-alternative-way/</link>
		<comments>http://www.atwix.com/magento/add-column-to-customers-grid-alternative-way/#comments</comments>
		<pubDate>Wed, 07 Nov 2012 09:27:24 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[blocks]]></category>
		<category><![CDATA[customize]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[grid]]></category>
		<category><![CDATA[magento]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=1856</guid>
		<description><![CDATA[This article presents the alternative way of adding a column to the customers grid in Magento admin.]]></description>
				<content:encoded><![CDATA[<p>Pretty often we face a task, where we need to add a custom column to the customers/orders grid in Magento admin. The solution is simple and if you google for it, you will get tons of solutions. However, pretty much all of them describe the same way, which isn&#8217;t always proper. <span id="more-1856"></span><br />
Nick described the simple and trivial way of adding columns in his article <a title="Adding a custom attribute/column to the orders grid in Magento admin" href="http://www.atwix.com/magento/customize-orders-grid/" target="_blank">Adding a custom attribute/column to the orders grid in Magento admin</a> and you are always able to follow it, except the cases, when some other extension already overrides the <em>_prepareColumns()</em> method. At that point, we need some universal solution that won&#8217;t conflict with other extensions that may potentially be overwriting the grid block. So, let&#8217;s use an observer for our task.<br />
First of all, you need to add your own extension for registering the observer. Create config files and other necessary stuff:</p>
<p>&nbsp;</p>
<p>Config to load the extension (<em>app/etc/modules/Atwix_CustomGrid.xml</em>):</p>
<pre class="brush: xml; gutter: true">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_CustomGrid&gt;
            &lt;active&gt;true&lt;/active&gt;
            &lt;codePool&gt;local&lt;/codePool&gt;
        &lt;/Atwix_CustomGrid&gt;
    &lt;/modules&gt;
&lt;/config&gt;</pre>
<p>&nbsp;</p>
<p>The extension config file (<em>app/code/local/Atwix/CustomGrid/etc/config.xml</em>):</p>
<pre class="brush: xml; gutter: true">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_CustomGrid&gt;
            &lt;version&gt;0.4.0&lt;/version&gt;
        &lt;/Atwix_CustomGrid&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;models&gt;
            &lt;atwix_customgrid&gt;
                &lt;class&gt;Atwix_CustomGrid_Model&lt;/class&gt;
            &lt;/atwix_customgrid&gt;
        &lt;/models&gt;
    &lt;/global&gt;
    &lt;adminhtml&gt;
        &lt;events&gt;
            &lt;core_block_abstract_prepare_layout_before&gt;
                &lt;observers&gt;
                    &lt;customgrid_column_append&gt;
                        &lt;type&gt;model&lt;/type&gt;
                        &lt;class&gt;Atwix_CustomGrid_Model_Observer&lt;/class&gt;
                        &lt;method&gt;appendCustomColumn&lt;/method&gt;
                    &lt;/customgrid_column_append&gt;
                &lt;/observers&gt;
            &lt;/core_block_abstract_prepare_layout_before&gt;
        &lt;/events&gt;
    &lt;/adminhtml&gt;
&lt;/config&gt;</pre>
<p>&nbsp;</p>
<p>The observer itself (<em>app/code/local/Atwix/CustomGrid/Model/Observer.php</em>):</p>
<pre class="brush: php; gutter: true">class Atwix_CustomGrid_Model_Observer extends Varien_Event_Observer
{
    /**
     * Adds column to admin customers grid
     *
     * @param Varien_Event_Observer $observer
     * @return Atwix_CustomGrid_Model_Observer
     */
    public function appendCustomColumn(Varien_Event_Observer $observer)
    {
        $block = $observer-&gt;getBlock();
        if (!isset($block)) {
            return $this;
        }

        if ($block-&gt;getType() == &#039;adminhtml/customer_grid&#039;) {
            /* @var $block Mage_Adminhtml_Block_Customer_Grid */
            $block-&gt;addColumnAfter(&#039;middlename&#039;, array(
                &#039;header&#039;    =&gt; &#039;Middle Name&#039;,
                &#039;type&#039;      =&gt; &#039;text&#039;,
                &#039;index&#039;     =&gt; &#039;middlename&#039;,
            ), &#039;email&#039;);
        }
    }
}</pre>
<p>&nbsp;</p>
<p>As you can see, the observer retrieves the customer grid block and executes its method addColumnAfter for adding a new column. The column type is &#8220;text&#8221; and the index is &#8220;middlename&#8221;. &#8220;Middlename&#8221; &#8211; it&#8217;s standard customer&#8217;s attribute in Magento, but you are able to add any custom attribute using this way.<br />
The advantage of this method: your code won&#8217;t conflict with other third party solutions that also add custom columns. You can use the observer for adding a column to almost any grid in Magento admin. All you need is to change the following condition:</p>
<pre class="brush: php; gutter: true">$block-&gt;getType() == &#039;adminhtml/customer_grid&#039;)</pre>
<p>depending on your grid block. For example, order&#8217;s grid block is <em>adminhtml/sales_order_grid</em>.<br />
Good luck and do not hesitate to ask your questions in comments below <img src='http://www.atwix.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/add-column-to-customers-grid-alternative-way/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Login as a customer from Magento admin</title>
		<link>http://www.atwix.com/magento/login-as-customer-from-admin/</link>
		<comments>http://www.atwix.com/magento/login-as-customer-from-admin/#comments</comments>
		<pubDate>Wed, 26 Sep 2012 06:10:16 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[grid]]></category>
		<category><![CDATA[magento]]></category>
		<category><![CDATA[universal password]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=1196</guid>
		<description><![CDATA[Often there are situations where customer has some issues while placing orders or making operations from the "My Account" section. At that point, an ability for admin to login as a customer and see what is wrong becomes very useful.]]></description>
				<content:encoded><![CDATA[<p>Often there are situations where customer has some issues while placing orders or making operations from the &#8220;My Account&#8221; section. At that point, an ability for admin to login as a customer and see what is wrong becomes very useful. <span id="more-1196"></span><br />
Sure, you can make a universal password logic, but that method has heavy security risks. Not so long ago, we&#8217;ve noticed that Magento has ability to load and use customer&#8217;s sessions different way. We will tell you how to create a simple extension for logging in as a customer from Magento admin.</p>
<p><strong><em>Step 1</em></strong></p>
<p>For example, let&#8217;s call our module <strong>Atwix_Ulogin</strong>. As always we must start by creating a module descriptor in <strong>app/etc/modules</strong> folder. So put the <strong>Atwix_Ulogin.xml</strong> file into this directory. The file will be with the following content:</p>
<pre class="brush: xml; gutter: true">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_Ulogin&gt;
            &lt;active&gt;true&lt;/active&gt;
            &lt;codePool&gt;community&lt;/codePool&gt;
        &lt;/Atwix_Ulogin&gt;
    &lt;/modules&gt;
&lt;/config&gt;
</pre>
<p><strong><em>Step 2</em></strong></p>
<p>On the next step, we need to create a configuration file for our extension: </p>
<pre class="brush: xml; gutter: true">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_Ulogin&gt;
            &lt;version&gt;0.4.0&lt;/version&gt;
        &lt;/Atwix_Ulogin&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;blocks&gt;
            &lt;adminhtml&gt;
                &lt;rewrite&gt;
                    &lt;customer_grid&gt;Atwix_Ulogin_Block_Adminhtml_Customer_Grid&lt;/customer_grid&gt;
                &lt;/rewrite&gt;
            &lt;/adminhtml&gt;
        &lt;/blocks&gt;
        &lt;helpers&gt;
            &lt;ulogin&gt;
                &lt;class&gt;Atwix_Ulogin_Helper&lt;/class&gt;
            &lt;/ulogin&gt;
        &lt;/helpers&gt;
    &lt;/global&gt;
    &lt;frontend&gt;
        &lt;routers&gt;
            &lt;ulogin&gt;
                &lt;use&gt;standard&lt;/use&gt;
                &lt;args&gt;
                    &lt;module&gt;Atwix_Ulogin&lt;/module&gt;
                    &lt;frontName&gt;ulogin&lt;/frontName&gt;
                &lt;/args&gt;
            &lt;/ulogin&gt;
        &lt;/routers&gt;
    &lt;/frontend&gt;
&lt;/config&gt;
</pre>
<p>Save this file as <strong>app/etc/community/Atwix/Ulogin/etc/config.xml</strong>.<br />
As you can see, we override customers grid block for admin panel to add new column. Then we tell system to use our custom router &#8216;ulogin&#8217; as an entry point for the user login.</p>
<p><strong><em>Step 3</em></strong></p>
<p>Now we need to create a controller. This controller will check allowed IP&#8217;s for autologin, register customer session and redirect to customer account. File should be placed into <strong>app/code/community/Atwix/Ulogin/controllers</strong>. The filename is <strong>LoginController.php</strong>.<br />
The content is:</p>
<pre class="brush: php; gutter: true">
&lt;?php
class Atwix_Ulogin_LoginController extends Mage_Core_Controller_Front_Action
{
    /**
     * Processes login action
     * @return bool
     * @throws Exception
     */
    public function autologinAction()
    {
        $session = $this-&gt;_getSession();
        if (!$this-&gt;_isAllowed()) {
            $message = $this-&gt;__(&#039;You have no pemission to use this option&#039;);
            $session-&gt;addError($message);
            $this-&gt;_redirect(&#039;customer/account/login&#039;);
        }
        else {
            $id = (int) trim($this-&gt;getRequest()-&gt;getParam(&#039;customerid&#039;));
            try{
                if($id){
                    $customer = Mage::getModel(&#039;customer/customer&#039;)-&gt;load($id);
                    $session-&gt;setCustomerAsLoggedIn($customer);
                    $message = $this-&gt;__(&#039;You are now logged in as %s&#039;, $customer-&gt;getName());
                    $session-&gt;addNotice($message);
                    Mage::log($message);
                }else{
                    throw new Exception ($this-&gt;__(&#039;The login attempt was unsuccessful. Some parameter is missing&#039;));
                }
            }catch (Exception $e){
                $session-&gt;addError($e-&gt;getMessage());
            }
            $this-&gt;_redirect(&#039;customer/account&#039;);
        }
    }

    /**
     * Gets customer session
     * @return Mage_Core_Model_Abstract
     */
    protected function _getSession()
    {
        return Mage::getSingleton(&#039;customer/session&#039;);
    }

    /**
     * Checks if ip is allowed for autologin
     * @return mixed
     */
    protected function _isAllowed()
    {
        $allowedIps = Mage::helper(&#039;ulogin&#039;)-&gt;getAllowedIps();
        return Mage::helper(&#039;ulogin&#039;)-&gt;checkAllowedIp($allowedIps);
    }
}
</pre>
<p>Also we need to create a helper file with useful methods </p>
<pre class="brush: php; gutter: true">
&lt;?php
class Atwix_Ulogin_Helper_Data extends Mage_Core_Helper_Abstract
{
    /**
     * Gets allowed ip-addresses from configuration
     * @return array
     */
    public function getAllowedIps()
    {
        $ipsList = array();
        $ipsText = &#039;127.0.0.1, 181.40.55.32&#039;; // Comma separated list of allowed IP  
        $ipsList = explode(&#039;,&#039;, $ipsText);
        array_walk($ipsList, &#039;trim&#039;);
        
        return $ipsList;
    }
    /**
     * Checks if remote ip is allowed
     * @param array $allowedList
     * @return bool
     */
    public function checkAllowedIp($allowedList)
    {
        if (count($allowedList) &gt; 0) {
            $remoteIp = Mage::helper(&#039;core/http&#039;)-&gt;getRemoteAddr();
            if (in_array($remoteIp, $allowedList))
                return true;
        }
        return false;
    }
}
</pre>
<p><strong>$ipsText</strong> variable contains comma separated list of IP addresses with allowed access to universal login ability.</p>
<p><strong><em>Step 4</em></strong></p>
<p>The last, but important step is to create an override for customers grid block in admin panel. Create file <strong>Grid.php</strong> at the location <strong>/app/code/community/Atwix/Ulogin/Block/Adminhtml/Customer</strong> with the following content:</p>
<pre class="brush: php; gutter: true">
class Atwix_Ulogin_Block_Adminhtml_Customer_Grid extends Mage_Adminhtml_Block_Customer_Grid
{
    protected function _prepareColumns()
    {
        parent::_prepareColumns();

        $column = $this-&gt;getColumn(&#039;action&#039;);
        $actions = $column-&gt;getActions();
        $actions[] = array(
            &#039;caption&#039; =&gt; &#039;Log in&#039;,
            &#039;popup&#039; =&gt; true,
            &#039;url&#039; =&gt; array(
             &#039;base&#039; =&gt; &#039;ulogin/login/autologin&#039;),
            &#039;field&#039; =&gt; &#039;customerid&#039;
        );
        $column-&gt;setActions( $actions );

        return $this;
    }
}
</pre>
<p>This method tells Magento to add one more item to Actions column &#8220;Login&#8221;.<br />
That&#8217;s all. You can try to go to <strong>Admin->Customers->Manage Customers</strong>. There will be a new action &#8216;Login&#8217; in Actions column. Choose this action brings a new popup window where you will be logged in as a customer.<br />
Do not forget to clean up Magento cache. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/login-as-customer-from-admin/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Advices and Best Practices for Magento developers</title>
		<link>http://www.atwix.com/magento/best-practices/</link>
		<comments>http://www.atwix.com/magento/best-practices/#comments</comments>
		<pubDate>Mon, 10 Sep 2012 12:48:25 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[blocks]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[grid]]></category>
		<category><![CDATA[layout]]></category>
		<category><![CDATA[log]]></category>
		<category><![CDATA[magento]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=1589</guid>
		<description><![CDATA[Advices and best practices for Magento Developers from the Atwix team.]]></description>
				<content:encoded><![CDATA[<p>I think everyone who is interested in ecommerce development get familiar with Magento earlier or later. It&#8217;s a very popular platform, where a lot of modern programming technologies are used. Since Magento is one of the most powerful and flexible shopping cart engines, it requires a deep level of expertise to develop extensions or even do some basic changes. So we&#8217;ve decided to share our tips for Magento Developers in this article. [Continue to <a href="http://www.atwix.com/magento/best-practices-2/">Part 2</a>]<span id="more-1589"></span><br />
You can get tons of solutions from the Internet on how to make one or another modifications for Magento functionality, but it&#8217;s worth noting that not all of them are smart, guarantee results and follow best practices.<br />
Every developer eventually gets to the experience level that allows him to follow good developing practice. I want to share my own findings with you. So lets start.</p>
<p><strong><em>Never use app/code/local/Mage to override core files.</em></strong></p>
<p>Instead of this always try to create your own extension to change/add/modify core logic. It saves you from errors upon further store upgrades or third party extension&#8217;s collisions. If you ever use<br />
<em>app/code/local/Mage</em>, then only use it for temporary changes that you will remove afterwards.</p>
<p><strong><em>Try to avoid overriding wherever it&#8217;s possible.</em></strong></p>
<p>Use event-listeners, helpers, or extend (not override) the core classes to form your own. It also saves your extension from conflicts with third party addons. For example, you always can use event <em>core_block_abstract_to_html_after</em> to inject button or some other element into html where there is no ability to inject it properly using xml layouts. There&#8217;s no reason to override <em>.phtml</em> files or block&#8217;s logic. For example, if you want to add/remove logic for <em>checkout.onepage.billing</em> block you need to create your own extension and specify your block class within xml layout. </p>
<pre class="brush: xml; gutter: true">
&lt;block type=&quot;your_extension/checkout_onepage_billing&quot; 
name=&quot;checkout.onepage.billing&quot; as=&quot;billing&quot; template=&quot;checkout/onepage/billing.phtml&quot;/&gt;
</pre>
<p>Where </p>
<pre class="brush: php; gutter: true">
class Your_Extension_Block_Checkout_Onepage_Billing extends Mage_Checkout_Block_Onepage_Billing
</pre>
<p><strong><em>Do not remove generic blocks from *.phtml files or xml layouts.</em> </strong></p>
<p>For example, you don&#8217;t need a generic block with name &#8216;<em>product_additional_data</em>&#8216; (product view page) and you think you are able to delete it from code. But you should not do this. Magento third party extensions usually use generic blocks to inject their own blocks there. If you have deleted it, you may spend a lot of time to find out why some extension doesn&#8217;t work.</p>
<p><strong><em>Use Magento generic CSS classes whenever possible.</em></strong></p>
<p>There are thousands of CSS classes, that are defined in Magento default installation and if you are going to make a new store template, you should use those classnames in your new template. It&#8217;s a good practice, because there is a lot of third party extensions that use those classnames for design integration.</p>
<p><strong><em>Always document your own code.</em></strong></p>
<p> As a good programmer, you should always use PHPDoc in your projects. If you were faced with problem and trying to find out the solution, it&#8217;s always easier to explore documented code. Also you should think about other programmers who may be forced to work with your code <img src='http://www.atwix.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong><em>Always explore core abstract classes during your work with Magento.</em></strong></p>
<p>It helps you to make your code more effectively. For example I met many developers who write their own methods for checking a status of their extensions (enabled/disabled) but only few of them use method <em>isModuleEnabled()</em> from <em>Mage_Core_Helper_Abstract</em></p>
<p><strong><em>Use cache for your own blocks.</em></strong></p>
<p>Magento allows to use cache system separately for custom blocks. Using cache for the blocks may greatly improve your extensions performance. To enable cache for the block you need to use the following part of code in your block constructor:</p>
<pre class="brush: php; gutter: true">
class Your_Extension_Block_Blah extends Mage_Core_Block_Template
{
protected function _construct()
    {
        parent::_construct();

        $this-&gt;addData(array(
            &#039;cache_lifetime&#039;    =&gt; 43200,
            &#039;cache_tags&#039;        =&gt; array(Mage_Catalog_Model_Product::CACHE_TAG),
        ));
    } 
}
</pre>
<p><strong><em>Use Magento built in log system for logging the behaviour of your extension. </em></strong></p>
<p>It always helps to find issues faster if any. You are able to create/use your own log using the code: </p>
<pre class="brush: php; gutter: true">
Mage::log(&#039;There was a bug&#039;, null, &#039;log_filename.log&#039;);
</pre>
<p>Don&#8217;t forget to check if logging is enabled in <em>Admin -> System -> Configuration -> Developer -> Debug</em> .</p>
<p><strong><em>Use Magento built in profiler to check the performance issues. </em></strong></p>
<p>Magento allows to display loading time for separate parts at the bottom of every page for development purposes. First, enable the profiler via <em>System -> Configuration -> Developer -> Debug -> Profiler (yes)</em>. Second, comment out the following line in index.php </p>
<pre class="brush: php; gutter: true">
#Varien_Profiler::enable();
</pre>
<p>Then you should see profiler on the store pages.</p>
<p><strong><em>Use XML layouts to integrate features or extend functionality wherever it&#8217;s possible.</em> </strong></p>
<p>Magento allows to make different actions within layout XML files. As you know, it is possible to integrate your block somewhere in the design, but you can call different methods more efficiently using XML. Usually programmers forget about this feature. For example, you need to extend admin order&#8217;s grid with additional column. You can always extend <em>Mage_Adminhtml_Block_Sales_Order_Grid</em> but it&#8217;s not the best solution because it may be overwritten within some other extension. Instead of this, you can call method <em>AddColumn</em>, <em>AddColumnAfter</em> or some other directly from xml layout. Take a look at the example below:</p>
<pre class="brush: xml; gutter: true">
&lt;adminhtml_sales_order_grid&gt;
        &lt;reference name=&quot;sales_order.grid&quot;&gt;
            &lt;action method=&quot;addColumnAfter&quot;&gt;
                &lt;columnId&gt;street&lt;/columnId&gt;
                &lt;arguments module=&quot;yourmodule&quot; translate=&quot;header&quot;&gt;
                    &lt;header&gt;Street&lt;/header&gt;
                    &lt;type&gt;text&lt;/type&gt;
                    &lt;index&gt;sales_flat_order_address.street&lt;/index&gt;
                &lt;/arguments&gt;
                &lt;after&gt;entity_id&lt;/after&gt;
            &lt;/action&gt;
        &lt;/reference&gt;
    &lt;/adminhtml_sales_order_grid&gt;
&lt;/layout&gt;
</pre>
<p><strong><em>Use IDE (Integrated Development Environment).</em></strong></p>
<p>There are many useful IDE to make Magento developing process faster, easier and more pleasant. You can try the most popular of them and choose which one is the best for you. There are many advantages of using IDE. You can inspect parent and abstract classes faster since most of IDE&#8217;s supports classes inheritance inspection. Popular IDE&#8217;s have the debugger in their toolset. It also may help you to save your time. Version control support, syntax checking, deployment management, smart snippets, refactoring, projects management and much more you can find in the modern IDE&#8217;s. As you can see, one application replaces many tools you have used before. All you need, is to find a convenient IDE for you and customise every detail. </p>
<p>To be continued&#8230; <a href="http://www.atwix.com/magento/best-practices-2/">Part 2</a>.</p>
<p>P.S. It would be great to see your own findings of Magento development in the comments. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/best-practices/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Adding thumbnail images to the Magento admin product grid</title>
		<link>http://www.atwix.com/magento/thumbnail-images-admin-product-grid/</link>
		<comments>http://www.atwix.com/magento/thumbnail-images-admin-product-grid/#comments</comments>
		<pubDate>Tue, 28 Feb 2012 10:07:07 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[grid]]></category>
		<category><![CDATA[magento]]></category>
		<category><![CDATA[thumbnails]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=917</guid>
		<description><![CDATA[This article describes how to insert images in the Magento admin product grid.
First of all, you will need to create your own extension. Let's call it: Atwix_Gridthumbs.]]></description>
				<content:encoded><![CDATA[<p>This article describes how to insert images in the Magento admin product grid.<br />
First of all, you will need to create your own extension. Let&#8217;s call it: Atwix_Gridthumbs.<br />
<span id="more-917"></span><br />
Create a file <em>/app/etc/modules/Atwix_Gridthumbs.xml</em> with this content:</p>
<pre class="brush: xml; gutter: true">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_Gridthumbs&gt;
            &lt;active&gt;true&lt;/active&gt;
            &lt;codePool&gt;community&lt;/codePool&gt;
        &lt;/Atwix_Gridthumbs&gt;
    &lt;/modules&gt;
&lt;/config&gt;</pre>
<p>Next step is the module&#8217;s config file. It should be located in <em>/app/code/community/Atwix/Gridthumbs/etc/config.xml</em>. The config file content will be like this:</p>
<pre class="brush: xml; gutter: true">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_Gridthumbs&gt;
            &lt;version&gt;1.0&lt;/version&gt;
        &lt;/Atwix_Gridthumbs&gt;
    &lt;/modules&gt;
    &lt;global&gt;
        &lt;blocks&gt;
            &lt;adminhtml&gt;
                &lt;rewrite&gt;
                    &lt;catalog_product_grid&gt;Atwix_Gridthumbs_Adminhtml_Block_Catalog_Product_Grid&lt;/catalog_product_grid&gt;
                &lt;/rewrite&gt;
            &lt;/adminhtml&gt;
        &lt;/blocks&gt;
    &lt;/global&gt;
&lt;/config&gt;</pre>
<p>Now we need to override standard grid file. Create file /app/code/community/Atwix/Gridthumbs/Adminhtml/Block/Catalog/Product/Grid.php with the following content:</p>
<pre class="brush: php; gutter: true">&lt;?php 
class Atwix_Gridthumbs_Adminhtml_Block_Catalog_Product_Grid extends Mage_Adminhtml_Block_Catalog_Product_Grid
{
    protected function _prepareColumns()
    {
        $this-&gt;addColumn(&#039;image&#039;, array(
            &#039;header&#039; =&gt; Mage::helper(&#039;catalog&#039;)-&gt;__(&#039;Image&#039;),
            &#039;align&#039; =&gt; &#039;left&#039;,
            &#039;index&#039; =&gt; &#039;image&#039;,
            &#039;width&#039;     =&gt; &#039;70&#039;,
            &#039;renderer&#039; =&gt; &#039;Atwix_Gridthumbs_Block_Adminhtml_Template_Grid_Renderer_Image&#039;
        )); 
        return parent::_prepareColumns();
    }
}</pre>
<p>Here you can see line <strong>&#8216;renderer&#8217; =&gt; &#8216;Atwix_Gridthumbs_Block_Adminhtml_Template_Grid_Renderer_Image&#8217;</strong> . It says to use the custom renderer for image column. There&#8217;s no standard renderer for images, so we need to create it. Create the renderer file <em>/app/code/community/Atwix/Gridthumbs/Block/Adminhtml/Template/Grid/Renderer/Image.php</em> with source:</p>
<pre class="brush: php; gutter: true">&lt;?php 
class Atwix_Gridthumbs_Block_Adminhtml_Template_Grid_Renderer_Image extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
{
    public function render(Varien_Object $row)
    {
        return $this-&gt;_getValue($row);
    } 
    protected function _getValue(Varien_Object $row)
    {       
        $val = $row-&gt;getData($this-&gt;getColumn()-&gt;getIndex());
        $val = str_replace(&quot;no_selection&quot;, &quot;&quot;, $val);
        $url = Mage::getBaseUrl(&#039;media&#039;) . &#039;catalog/product&#039; . $val; 
        $out = &quot;&lt;img src=&quot;. $url .&quot; width=&#039;60px&#039;/&gt;&quot;; 
        return $out;
    }
}</pre>
<p>Renderers return html or just plain text for the cell in the column. You can get the necessary values with the construction <strong>$row-&gt;getData($this-&gt;getColumn()-&gt;getIndex());</strong><br />
<strong>$this-&gt;getColumn()-&gt;getIndex();</strong> returns the column index which was entered in <strong>addColumn</strong> in the previous step. If there is not an image associated with a product, image url will say <em>&#8220;no_selection&#8221;,</em> so we should remove this string for empty cells with construction <strong>$val = str_replace(&#8220;no_selection&#8221;, &#8220;&#8221;, $val);</strong><br />
That&#8217;s it! To be safe, as will all changes, you should flush cache and log out/log in to be sure you are seeing the new content. Now you can see available images in product grid. Happy coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/thumbnail-images-admin-product-grid/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Magento auto invoice and set custom order status upon checkout</title>
		<link>http://www.atwix.com/magento/auto-invoice-and-custom-order-status-upon-checkout/</link>
		<comments>http://www.atwix.com/magento/auto-invoice-and-custom-order-status-upon-checkout/#comments</comments>
		<pubDate>Mon, 17 Oct 2011 09:03:21 +0000</pubDate>
		<dc:creator>Yaroslav Rogoza</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[magento]]></category>

		<guid isPermaLink="false">http://www.atwix.com/?p=417</guid>
		<description><![CDATA[Many developers are wondering how to customize Magento behavior once an order has been placed. In particular, sometimes a company would like to change the order status to &#8220;Pending&#8221; and send an invoice to the customer automatically after checkout. The following article offers a simple solution for this.Let&#8217;s assume that we need to have the [...]]]></description>
				<content:encoded><![CDATA[<p>Many developers are wondering how to customize Magento behavior once an order has been placed. In particular, sometimes a company would like to change the order status to &#8220;Pending&#8221; and send an invoice to the customer automatically after checkout. The following article offers a simple solution for this.<span id="more-417"></span>Let&#8217;s assume that we need to have the order status set to &#8220;Processing&#8221; instead of &#8220;Pending&#8221; for orders paid with the &#8220;Credit Card Save&#8221; payment method and have the standard invoice sent automatically at the same time.</p>
<p>A custom Magento module will be required for this task. Let&#8217;s name it <strong>Atwix_Orderhook</strong>.<br />
<i><b>Step 1</b></i></p>
<p>First, create a module initializer in /app/etc/modules/Atwix_Orderhook.xml with the following content:</p>
<pre class="brush: xml; gutter: true">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_Orderhook&gt;
            &lt;active&gt;true&lt;/active&gt;
            &lt;codePool&gt;community&lt;/codePool&gt;
        &lt;/Atwix_Orderhook&gt;
    &lt;/modules&gt;
&lt;/config&gt;</pre>
<p><i><b>Step 2</b></i></p>
<p>Create a module configuration file <strong>config.xml</strong> in /app/code/community/NAMESPACE/MODULENAME/etc/<br />
(replace <strong>NAMESPACE</strong> and <strong>MODULENAME</strong> with your own values). In our case the path will be /app/code/community/Atwix/Orderhook/etc/.</p>
<p><strong>config.xml</strong> content:</p>
<pre class="brush: xml; gutter: true">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;modules&gt;
        &lt;Atwix_Orderhook&gt;
            &lt;version&gt;1.0&lt;/version&gt;
        &lt;/Atwix_Orderhook&gt;
    &lt;/modules&gt;

    &lt;global&gt;

        &lt;models&gt;            
            &lt;orderhook&gt;
                &lt;class&gt;Atwix_Orderhook_Model&lt;/class&gt;
            &lt;/orderhook&gt;
        &lt;/models&gt;

        &lt;events&gt;
            &lt;sales_order_place_after&gt;
                &lt;observers&gt;
                    &lt;auto_invoice_order&gt;
                        &lt;type&gt;singleton&lt;/type&gt;
                        &lt;class&gt;orderhook/observer&lt;/class&gt;
                        &lt;method&gt;implementOrderStatus&lt;/method&gt;
                    &lt;/auto_invoice_order&gt;
                &lt;/observers&gt;
            &lt;/sales_order_place_after&gt;
        &lt;/events&gt;

    &lt;/global&gt;
&lt;/config&gt;</pre>
<p>As you can see, we have described observer in the events section. Observers allow you to execute some operations after a desired event took place. We need to observe the <strong>sales_order_place_after</strong> event in our extension. This event takes place after an order has been placed. Also, do not forget to init your Model path in the models section, like the example above.<br />
<strong>&lt;class&gt; &#8230; &lt;/class&gt;</strong> section contains a path to the file with observer class. In our case the file is app/code/community/Atwix/Orderhook/Observer.php, which we will create later.<br />
Section <strong>&lt;method&gt; &#8230; &lt;/method&gt;</strong> contains the method&#8217;s name, which will be called on in the <strong>sales_order_place_after</strong> event.</p>
<p><i><b>Step 3</b></i></p>
<p>Create observer file app/code/community/Atwix/Orderhook/Model/Observer.php with the following content:</p>
<pre class="brush: php; gutter: true">&lt;?php

class Atwix_Orderhook_Model_Observer 
{
    public function implementOrderStatus($event)
    {
        $order = $event-&gt;getOrder();

        if ($this-&gt;_getPaymentMethod($order) == &#039;ccsave&#039;) {
            if ($order-&gt;canInvoice())
                $this-&gt;_processOrderStatus($order);
        }
        return $this;
    }

    private function _getPaymentMethod($order)
    {
        return $order-&gt;getPayment()-&gt;getMethodInstance()-&gt;getCode();
    }

    private function _processOrderStatus($order)
    {
        $invoice = $order-&gt;prepareInvoice();

        $invoice-&gt;register();
        Mage::getModel(&#039;core/resource_transaction&#039;)
           -&gt;addObject($invoice)
           -&gt;addObject($invoice-&gt;getOrder())
           -&gt;save();

        $invoice-&gt;sendEmail(true, &#039;&#039;);
        $this-&gt;_changeOrderStatus($order);
        return true;
    }

    private function _changeOrderStatus($order)
    {
        $statusMessage = &#039;&#039;;
        $order-&gt;setState(Mage_Sales_Model_Order::STATE_PROCESSING, true);        
	$order-&gt;save();
    }
}</pre>
<p><strong>implementOrderStatus($event)</strong> {&#8230;} function will be called upon completion of the order&#8217;s placement. As you can see, there are some conditions inside that are responsible for the payment method name verification. As we have described above &#8211; order status will be changed only if &#8220;Credit Card Save&#8221; payment method has been used with the order. If you don&#8217;t need these conditions &#8211; just remove the verification.<br />
<strong>_processOrderStatus</strong> Method creates an invoice for the order and sends it to the customer.<br />
<strong>_changeOrderStatus</strong> Method changes the order status to <strong>STATE_PROCESSING</strong>.</p>
<p>That&#8217;s it. You can easily write your own handlers with any functionality from this observer. For example, you can send an additional email or shut down the server after an order has been placed <img src='http://www.atwix.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>P.S. Here is a list of the order statuses that you can apply to the order object:</p>
<pre class="brush: php; gutter: true">/**
 * change order status to &#039;Completed&#039;
 */
$order-&gt;setState(Mage_Sales_Model_Order::STATE_COMPLETE, true)-&gt;save();
Similarly, you can change the order status to pending, processing, canceled, closed, held, etc.

/**
 * change order status to &quot;Pending&quot;
 */
$order-&gt;setState(Mage_Sales_Model_Order::STATE_NEW, true)-&gt;save();

/**
 * change order status to &quot;Pending Paypal&quot;
 */
$order-&gt;setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT, true)-&gt;save();

/**
 * change order status to &quot;Processing&quot;
 */
$order-&gt;setState(Mage_Sales_Model_Order::STATE_PROCESSING, true)-&gt;save();

/**
 * change order status to &quot;Completed&quot;
 */
$order-&gt;setState(Mage_Sales_Model_Order::STATE_COMPLETE, true)-&gt;save();

/**
 * change order status to &quot;Closed&quot;
 */
$order-&gt;setState(Mage_Sales_Model_Order::STATE_CLOSED, true)-&gt;save();

/**
 * change order status to &quot;Canceled&quot;
 */
$order-&gt;setState(Mage_Sales_Model_Order::STATE_CANCELED, true)-&gt;save();

/**
 * change order status to &quot;Held&quot;
 */
$order-&gt;setState(Mage_Sales_Model_Order::STATE_HOLDED, true)-&gt;save();</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.atwix.com/magento/auto-invoice-and-custom-order-status-upon-checkout/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>
