<?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>SpinOneSolutions &#187; Magento</title>
	<atom:link href="http://www.spinonesolutions.com/tag/magento/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.spinonesolutions.com</link>
	<description>I waste my time so that you don't have to...</description>
	<lastBuildDate>Mon, 16 May 2011 17:01:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Magento Admin Form POST with form_key</title>
		<link>http://www.spinonesolutions.com/2011/01/admin-form-post-form_key/</link>
		<comments>http://www.spinonesolutions.com/2011/01/admin-form-post-form_key/#comments</comments>
		<pubDate>Mon, 31 Jan 2011 16:40:18 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Admin]]></category>
		<category><![CDATA[Form]]></category>
		<category><![CDATA[Post]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=685</guid>
		<description><![CDATA[The other day I was trying to help someone create a Form in the admin side of Magento that would simply POST to a Controller and capture some data. I thought it&#8217;d be fairly simple, I&#8217;ve done it before; I thought. Turns out I had done it before, but I&#8217;ve always used the built in [...]]]></description>
			<content:encoded><![CDATA[<p>The other day I was trying to help someone create a Form in the admin side of Magento that would simply POST to a Controller and capture some data.  I thought it&#8217;d be fairly simple, I&#8217;ve done it before; I thought.</p>
<p>Turns out I had done it before, but I&#8217;ve always used the built in Magento Form widgets, never specified a custom .phtml template and actually tried to write the Form code by hand.  It&#8217;s a little more tricky than I anticipated, but we struggled through it and finally found the catch.</p>
<p>The &#8220;catch&#8221;, as it were, is that you have to send a hidden &#8220;form_key&#8221;.  This lets Magento know that you are who you say you are and not some spoofer posting malicious code to your backend.  Let&#8217;s get started.</p>
<p>Let&#8217;s presume that I&#8217;ve got a Module <strong>Spinonesolutions_Helloworld</strong> in it I&#8217;m going to make a block:</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/Block/Adminhtml/Adminform.php</strong></p>
<pre class="php" name="code">class Spinonesolutions_Helloworld_Block_Adminhtml_Adminform extends Mage_Adminhtml_Block_Template {
public function __construct() {
    parent::__construct();
    $this-&gt;setTemplate('helloworld/form.phtml');
    $this-&gt;setFormAction(Mage::getUrl('*/*/new'));
  }
}</pre>
<p>It&#8217;s easily seen that I&#8217;m referencing a .phtml template within my Block for the presentation so let&#8217;s make that file as well:</p>
<p><strong>/app/design/adminhtml/default/default/template/hellworld/form.phtml</strong></p>
<pre class="html" name="code">&lt;form action="&lt;? echo $this-&gt;getFormAction(); ?&gt;" method="POST"&gt;
&lt;input type="text" id="var1" name="var1" /&gt;
&lt;input type="submit" id="submit" name="submit" /&gt;
&lt;/form&gt;</pre>
<p>Lastly we need a Controller to handle the POST and to render our Block:</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/controllers/Adminhtml/AdminformController.php</strong></p>
<pre class="php" name="code">class Spinonesolutions_Helloworld_Adminhtml_AdminformController extends Mage_Adminhtml_Controller_Action {

public function indexAction() {
  $this-&gt;loadLayout();
  $block = $this-&gt;getLayout()-&gt;createBlock('spinonesolutions_helloworld/adminhtml_adminform','admin_form');
  $this-&gt;getLayout()-&gt;getBlock('content')-&gt;append($block);
  $this-&gt;renderLayout();
}

public function newAction() {
  die('here I am!');
}
}</pre>
<p>OK, that&#8217;s it for the architecture.  Let&#8217;s wire it all up with some XML in <strong>config.xml</strong>.  Note this is partial, not a full module definition:</p>
<pre class="xml" name="code">&lt;blocks&gt;
&lt;spinonesolutions_helloworld&gt;
&lt;class&gt;Spinonesolutions_Helloworld_Block&lt;/class&gt;
&lt;/spinonesolutions_helloworld&gt;
&lt;/blocks&gt;
&lt;admin&gt;
&lt;routers&gt;

&lt;adminhtml&gt;
&lt;args&gt;
&lt;modules&gt;
&lt;Spinonesolutions_Helloworld before="Mage_Adminhtml"&gt;Spinonesolutions_Helloworld_Adminhtml&lt;/Spinonesolutions_Helloworld&gt;
&lt;/modules&gt;
&lt;/args&gt;
&lt;/adminhtml&gt;
&lt;/routers&gt;
&lt;/admin&gt;</pre>
<p>Now, if you visit */admin/adminform/index you should see your super simple Form.  If you hit submit your Form will certainly post, but instead of seeing the die output you&#8217;ll be redirected to the Dashboard.  This because we haven&#8217;t sent through the authentication required by Magento&#8217;s internal routing system that will validate our form.  Let&#8217;s change <strong>form.phtml</strong> so that we can POST successfully.</p>
<pre class="html" name="code">&lt;form action="&lt;? echo $this-&gt;getFormAction(); ?&gt;" method="POST"&gt;
&lt;input type="hidden" name="form_key" value="&lt;? echo $this-&gt;getFormKey(); ?&gt;" /&gt;
&lt;input type="text" id="var1" name="var1" /&gt;
&lt;input type="submit" id="submit" name="submit" /&gt;
&lt;/form&gt;</pre>
<p>That&#8217;s all there is to it!  Notice the &#8220;form_key&#8221; hidden variable.  That&#8217;s the key to submitting Forms in the Magento admin.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2011/01/admin-form-post-form_key/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Magento – Create a globally available static function</title>
		<link>http://www.spinonesolutions.com/2010/12/magento-create-a-globally-available-static-function/</link>
		<comments>http://www.spinonesolutions.com/2010/12/magento-create-a-globally-available-static-function/#comments</comments>
		<pubDate>Thu, 30 Dec 2010 15:00:43 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[global]]></category>
		<category><![CDATA[lib]]></category>
		<category><![CDATA[static]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=608</guid>
		<description><![CDATA[Sometimes, you&#8217;ve got a situation where you want to have a globally available static function.  Most often this occurs (for me) in a debugging context.  Recently I wanted to have FirePHP available from anywhere in my project so I made use of the lib folder. Unlike just about every other article on this site, for [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes, you&#8217;ve got a situation where you want to have a globally available static function.  Most often this occurs (for me) in a debugging context.  Recently I wanted to have FirePHP available from anywhere in my project so I made use of the <strong>lib</strong> folder.</p>
<p>Unlike just about every other article on this site, for this one we&#8217;re going to be considering the folder <strong>/lib</strong>.  Note that this folder is NOT within local, but resident in the root.  As such changes here should be put within their own sub-folders so that they too will survive an upgrade.</p>
<p>It&#8217;s really quite easy to create your class, just follow the usual Magento naming conventions. I&#8217;m going to create <strong>Spinonesolutions_Devel_FirePHP</strong> so all I do is create the file: <strong>/lib/Spinonesolutions/Devel/FirePHP.php</strong>.  Note the similarity to Model naming.</p>
<p>In here I create my class definition:</p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Devel_FirePHP {
  public static function send($var, $label = "DEBUG", $style = "LOG") {
    if (Mage::getIsDeveloperMode()) {
      $request = new Zend_Controller_Request_Http();
      $response = new Zend_Controller_Response_Http();
      $channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
      $channel-&gt;setRequest($request);
      $channel-&gt;setResponse($response);

      /*
      * Start output buffering
      */
      ob_start();

      Zend_Wildfire_Plugin_FirePhp::send($var, $label, $style);

      /*
      Style     Description
      LOG     Displays a plain log message
      INFO     Displays an info log message
      WARN     Displays a warning log message
      ERROR     Displays an error log message that increments Firebug?s error count
      TRACE     Displays a log message with an expandable stack trace
      EXCEPTION     Displays an error long message with an expandable stack trace
      TABLE     Displays a log message with an expandable table
      */

      /*
      * Flush log data to browser
      */
      $channel-&gt;flush();
      $response-&gt;sendHeaders();
    } else {
      return null;
    }
  }
}</pre>
<p>Now I can call <strong>Spinonesolutions_Devel_FirePHP:send()</strong> anywhere in my project.  Sweet!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/12/magento-create-a-globally-available-static-function/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Magento config.xml Cron Job</title>
		<link>http://www.spinonesolutions.com/2010/12/magento-config-xml-cron-job/</link>
		<comments>http://www.spinonesolutions.com/2010/12/magento-config-xml-cron-job/#comments</comments>
		<pubDate>Wed, 15 Dec 2010 15:00:27 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cron]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=606</guid>
		<description><![CDATA[It&#8217;s possible to setup process to run on a schedule provided that your server is setup to run cron. All internal cron jobs are run from a single page/script call. You&#8217;ll need to setup your server to either; make a request to /cron.php or execute /cron.sh. The time delta that you set here will be [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s possible to setup process to run on a schedule provided that your server is setup to run cron.  All internal cron jobs are run from a single page/script call.  You&#8217;ll need to setup your server to either; make a request to <strong>/cron.php</strong> or execute <strong>/cron.sh</strong>.</p>
<p>The time delta that you set here will be the minimum delta for your Magento jobs.  IE: If your server&#8217;s cron  requests <strong>/cron.php</strong> every ten minutes and you create a cron job within Magento to run every five minutes, you shouldn&#8217;t be surprised to see it running every ten minutes instead of every five.</p>
<p>This won&#8217;t be a huge deal for all of you who are administering your own box, but for those of you on a shared box; you&#8217;ll likely be limited to a certain minimum delta which you&#8217;ll want to be aware of.</p>
<p>Setting up a cron job is actually really simple so lets take a look.  The configuration lives in <strong>config.xml</strong>, which shouldn&#8217;t be a surprise for you module developers.  Using my default example module <strong>Spinonesolutions_Helloworld:</strong></p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/etc/config.xml (partial)</strong></p>
<pre class="xml" name="code">&lt;config&gt;
...
&lt;crontab&gt;
&lt;jobs&gt;
&lt;spinonesolutions_helloworld&gt;
&lt;schedule&gt;&lt;cron_expr&gt;*/10 * * * *&lt;/cron_expr&gt;&lt;/schedule&gt;
&lt;run&gt;&lt;model&gt;spinonesolutions_helloworld/observer::foobar&lt;/model&gt;&lt;/run&gt;
&lt;/spinonesolutions_helloworld&gt;
&lt;/jobs&gt;
&lt;/crontab&gt;
...
&lt;/config&gt;</pre>
<p>You can do a Google search on cron schedules in order to figure that part out, it&#8217;s outside the scope of this article.  The only other piece that deserves explanation is the static method call between the <strong>run</strong> tag.  As you&#8217;d expect my example call is referencing <strong>Spinonesolutions_Helloworld_Model_Observer</strong> <strong>(/app/code/local/Spinonesolutions/Helloworld/Model/Observer.php).</strong> This file doesn&#8217;t need to contain anything except for a class definition and a static method.</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/Observer.php</strong></p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Helloworld_Model_Observer {
  public static function foobar() {
  }
}</pre>
<p>That&#8217;s it.  Your static method will now be called on the schedule that you set!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/12/magento-config-xml-cron-job/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Magento SQL Setup</title>
		<link>http://www.spinonesolutions.com/2010/11/magento-sql-setup/</link>
		<comments>http://www.spinonesolutions.com/2010/11/magento-sql-setup/#comments</comments>
		<pubDate>Mon, 29 Nov 2010 15:00:31 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=604</guid>
		<description><![CDATA[One of the many aspects to good module development is packaging everything up in such a way that the module is as standalone as possible.  The goal is to provide a third-party with a single package that can take care of itself.  Many modules will make use of custom database tables and/or Magento storage mechanisms. [...]]]></description>
			<content:encoded><![CDATA[<p>One of the many aspects to good module development is packaging everything up in such a way that the module is as standalone as possible.  The goal is to provide a third-party with a single package that can take care of itself.  Many modules will make use of custom database tables and/or Magento storage mechanisms.</p>
<p>The Varien team has provided ways for your module to manage these stores automatically through the &#8220;setup&#8221; functionality.  Let&#8217;s check it out.</p>
<p>First, you have to let Magento know where your setup code is going to live and what version your module is currently at.  You do this in <strong>config.xml. </strong> As an example I&#8217;ll use a module called Helloworld.  You may recognize this Module from the <a title="Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">first article</a>.</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/etc/config.xml (partial)</strong></p>
<pre class="xml" name="code">&lt;global&gt;
...
&lt;spinonesolutions_helloworld_setup&gt;
&lt;setup&gt;
&lt;module&gt;Spinonesolutions_Helloworld&lt;/module&gt;
&lt;/setup&gt;
&lt;/spinonesolutions_helloworld_setup&gt;
...
&lt;/global&gt;</pre>
<p>The <strong>setup</strong> tag is going to cause Magento to look for a folder within the module called ..<strong>/sql/setup (/Spinonesolutions/Helloworld/sql/setup).</strong> We can change the name of the target folder by changing the tag.  Example: <strong>&lt;foobar_setup&gt;&lt;/foobar_setup&gt;</strong> would prompt Magento to look for ..<strong>/sql/foobar_setup</strong>.</p>
<p>The files that fall within this folder need to follow a strict naming scheme:</p>
<p><strong>mysql4-install-{version}.php</strong></p>
<p><strong>mysql4-upgrade-{versionFrom}-{versionTo}.php</strong></p>
<p>What happens is that Magento will run each file, in succession, until it reaches the version number specified in your <strong>config.xml</strong>.</p>
<p>If you ever need to check to see what version of a module Magento THINKS is installed, browse your database for the table <strong>core_resource</strong> and scan the <strong>codes</strong> till you find your module&#8217;s <strong>code</strong>.</p>
<p>If you ever need to have Magento re-run your setup scripts, just remove the entry from <strong>core_resource</strong> and refresh; the module will then be &#8220;reinstalled&#8221;.</p>
<p>Now lets take a look at some common things to do in a install/upgrade script.  One of the best resources for figuring this stuff out is Varien&#8217;s own codebase.  If you go through some modules in <strong>../core/Mage</strong> you&#8217;ll find all sorts of great material  to copy into your own module.</p>
<h2>Install/Update Wrapper</h2>
<p><strong>../sql/setup/mysql4-install-1.0.0.php</strong></p>
<pre class="php" name="code">&lt;?php
$installer = $this;
/* @var $installer Mage_Core_Model_Resource_Setup */
$connection = $installer-&gt;getConnection();
/* @var $connection Varien_Db_Adapter_Pdo_Mysql */

$installer-&gt;startSetup();
YOUR CODE GOES HERE

$installer-&gt;endSetup();</pre>
<h2>DataBase Table</h2>
<pre name="code" class="php">$installer-&gt;run("
DROP TABLE IF EXISTS {$installer-&gt;getTable('spinonesolutions_helloworld/foo')};
CREATE TABLE {$installer-&gt;getTable('spinonesolutions_helloworld/foo')} (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
created_at DATETIME NOT NULL,
modified_at DATETIME NOT NULL,
store_id int(5) UNSIGNED NOT NULL,
PRIMARY KEY (id)
)
ENGINE = InnoDB;
");</pre>
<p>Not much to explain other than the <strong>getTable</strong> function.  The parameter refers to <strong>config.xml -&gt; global -&gt; models -&gt; {resourceModel} -&gt; entities</strong>.</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/etc/config.xml (partial)</strong></p>
<pre class="xml" name="code">...
&lt;global&gt;
&lt;models&gt;
...
&lt;spinonesolutions_helloworld&gt;
&lt;class&gt;Spinonesolutions_Helloworld&lt;/class&gt;
&lt;resourceModel&gt;spinonesolutions_helloworld_mysql4&lt;/resourceModel&gt;
&lt;/spinonesolutions_helloworld&gt;
&lt;toms_bluehornet_mysql4&gt;
&lt;class&gt;Spinonesolutions_Helloworld_Model_Mysql4&lt;/class&gt;
&lt;entities&gt;
&lt;foo&gt;&lt;table&gt;spinonesolutions_helloworld_foo&lt;/table&gt;&lt;/foo&gt;
&lt;/entities&gt;
&lt;/toms_bluehornet_mysql4&gt;
...
&lt;/models&gt;
&lt;/global&gt;
...</pre>
<h2>New Attribute</h2>
<pre class="php" name="code">$installer-&gt;addAttribute('catalog_product', 'is_recurring', array(
'group'             =&gt; 'Recurring Profile',
'type'              =&gt; 'int',
'backend'           =&gt; '',
'frontend'          =&gt; '',
'label'             =&gt; 'Enable Recurring Profile',
'note'              =&gt; 'Products with recurring profile participate in catalog as nominal items.',
'input'             =&gt; 'select',
'class'             =&gt; '',
'source'            =&gt; 'eav/entity_attribute_source_boolean',
'global'            =&gt; Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'visible'           =&gt; true,
'required'          =&gt; false,
'user_defined'      =&gt; false,
'default'           =&gt; '',
'searchable'        =&gt; false,
'filterable'        =&gt; false,
'comparable'        =&gt; false,
'visible_on_front'  =&gt; false,
'unique'            =&gt; false,
'apply_to'          =&gt; 'simple,virtual',
'is_configurable'   =&gt; false
));</pre>
<h2>Mage_Eav_Model_Entity_Setup</h2>
<p><strong>Mage_Eav_Model_Entity_Setup</strong> has tons of useful methods to call from your setup script.  The installer itself is an object of type <strong>Mage_Catalog_Model_Resource_Eav_Mysql4_Setup</strong> which extends <strong>Mage_Eav_Model_Entity_Setup</strong> thus all the instance methods are available from <strong>$this</strong> or <strong>$installer </strong>if you use a wrapper like the one shown above.</p>
<p>Questions and comments welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/11/magento-sql-setup/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Magento Custom Widget</title>
		<link>http://www.spinonesolutions.com/2010/10/magento-custom-widget/</link>
		<comments>http://www.spinonesolutions.com/2010/10/magento-custom-widget/#comments</comments>
		<pubDate>Thu, 28 Oct 2010 17:00:24 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Module]]></category>
		<category><![CDATA[Widget]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=602</guid>
		<description><![CDATA[With the latest release of Magento admins now have the ability to create custom “widgets” that can be dropped anywhere on the site to provide additional functionality.  The most common type of widget that I come across is a simple frontend presentation widget.  Basically the developer is asked to display some sort of data in [...]]]></description>
			<content:encoded><![CDATA[<p>With the latest release of Magento admins now have the ability to create custom “widgets” that can be dropped anywhere on the site to provide additional functionality.  The most common type of widget that I come across is a simple frontend presentation widget.  Basically the developer is asked to display some sort of data in a new way.</p>
<p>Widgets can basically be thought of as easily customizable blocks.  The main difference between standard blocks and widgets is that widgets can be added to CMS pages through the WYSIWYG editor and they can easily accept parameters, also defined through the WYSIWYG.  Thus a non-programmer can add quasi-dynamic content to their CMS pages, hurrah!</p>
<p>You should reference previous articles if you want more details about creating custom Modules and Blocks.</p>
<p>As an example I’m going to build a super simple slideshow widget called “Glider”.  It’s going to be a widget that takes four static block_id(s) as parameters and then displays each static block, in succession, as a slideshow.  If you let your imagination work a little you should be able to see some cool possibilities for such a thing, given that you extend it a little.</p>
<p>I’m using static blocks as the source material for each slide because this would allow a content manager to change out the content of a slide by either editing the static block that contains the content or by editing the block id being passed to the widget.  Either way it’s manageable through the interface.</p>
<p>Also note that the template (presentation layer) is going to be statically defined in this example, but you could easily make that a parameter and create multiple templates for the content manager to choose from!</p>
<p>Finally, I’ve used jQuery to build the actual slideshow.  I’m not going to go into very much detail about the presentation of the slideshow as that’s not really the focus of this article.  Feel free to write in if you want to see the details on how to implement jQuery (or any other script).</p>
<p>First let’s setup the Module:</p>
<p><strong>/app/etc/modules/Spinonesolutions_WidgetGlider.xml</strong></p>
<pre class="xml" name="code">&lt;?xml version="1.0"?&gt;
 &lt;config&gt;
 &lt;modules&gt;
 &lt;Spinonesolutions_WidgetGlider&gt;
   &lt;active&gt;true&lt;/active&gt;
   &lt;codePool&gt;local&lt;/codePool&gt;
   &lt;depends&gt;
     &lt;Mage_Cms /&gt;
   &lt;/depends&gt;
 &lt;/Spinonesolutions_WidgetGlider&gt;
 &lt;/modules&gt;
 &lt;/config&gt;</pre>
<p><strong>/app/code/local/Spinonesolutions/WidgetGlider/etc/config.xml</strong></p>
<pre class="xml" name="code">&lt;?xml version="1.0"?&gt;
 &lt;config&gt;
 &lt;modules&gt;
 &lt;Spinonesolutions_WidgetGlider&gt;
   &lt;version&gt;1.0.0&lt;/version&gt;
 &lt;/Spinonesolutions_WidgetGlider&gt;
 &lt;/modules&gt;
 &lt;global&gt;
 &lt;blocks&gt;
   &lt;spinonesolutions_widgetglider&gt;
     &lt;class&gt;Spinonesolutions_WidgetGlider_Block&lt;/class&gt;
   &lt;/spinonesolutions_widgetglider&gt;
 &lt;/blocks&gt;
 &lt;/global&gt;
 &lt;/config&gt;</pre>
<p>OK!  The next thing we need to do is define our widget’s interface.  To do that we create a <strong>widget.xml</strong> file inside our module’s “etc” folder.</p>
<p><strong>/app/code/local/Spinonesolutions/WidgetGlider/etc/widget.xml</strong></p>
<pre class="xml" name="code">&lt;?xml version="1.0"?&gt;
&lt;widgets&gt;
&lt;glider type="spinonesolutions_widgetglider/glider"&gt;
   &lt;name&gt;SpinoneSolutions: Glider&lt;/name&gt;
   &lt;description&gt;Displays the given HTML Sections in a Glider Slideshow&lt;/description&gt;
   &lt;parameters&gt;
     &lt;section1&gt;
       &lt;required&gt;0&lt;/required&gt;
       &lt;visible&gt;1&lt;/visible&gt;
       &lt;label&gt;Section1&lt;/label&gt;
       &lt;type&gt;text&lt;/type&gt;
     &lt;/section1&gt;
     &lt;section2&gt;
       &lt;required&gt;0&lt;/required&gt;
       &lt;visible&gt;1&lt;/visible&gt;
       &lt;label&gt;Section2&lt;/label&gt;
       &lt;type&gt;text&lt;/type&gt;
     &lt;/section2&gt;
     &lt;section3&gt;
       &lt;required&gt;0&lt;/required&gt;
       &lt;visible&gt;1&lt;/visible&gt;
       &lt;label&gt;Section3&lt;/label&gt;
       &lt;type&gt;text&lt;/type&gt;
     &lt;/section3&gt;
     &lt;section4&gt;
       &lt;required&gt;0&lt;/required&gt;
       &lt;visible&gt;1&lt;/visible&gt;
       &lt;label&gt;Section4&lt;/label&gt;
       &lt;type&gt;text&lt;/type&gt;
     &lt;/section4&gt;
     &lt;template&gt;
       &lt;visible&gt;0&lt;/visible&gt;
       &lt;value&gt;widgetglider/banner.phtml&lt;/value&gt;
     &lt;/template&gt;
   &lt;/parameters&gt;
&lt;/glider&gt;
&lt;/widgets&gt;</pre>
<p>You can define any number of widgets in here.  We’re only creating one so I’ve only got a single entry, <strong>glider</strong>.</p>
<p>The <strong>type</strong> attribute tells Magento what class to use when instantiating objects.  I’ve set it as <strong>spinonesolutions_widgetglider/glider</strong>.  If you go back and inspect the config.xml and remember your Magento naming conventions you can surmise that this is going to cause Magento to try and instantiate an object of type <strong>Spinonesolutions_WidgetGlider_Block_Glider</strong>.  That class doesn’t exist yet so we should create it.</p>
<p><strong>/app/code/local/Spinonesolutions/WidgetGlider/Block/Glider.php</strong></p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_WidgetGlider_Block_Glider extends Mage_Core_Block_Template
implements Mage_Widget_Block_Interface {
  const MAXSECTIONS = 4;
  public $sectionArr = array();

  protected function _construct() {
    parent::_construct();
  }

  protected function _toHtml() {
    for ($i=1;$i &lt;= self::MAXSECTIONS;$i++) {
      if ($this-&gt;getData("section$i")) {
        $blockHTML = $this-&gt;getLayout()-&gt;createBlock('cms/block')-&gt;setBlockId($this-&gt;getData("section$i"))-&gt;toHtml();
        $this-&gt;sectionArr[$i] = $blockHTML;
      }
    }
    return parent::_toHtml();
  }
}</pre>
<p>Let’s inspect the class from top to bottom.  The first thing to notice is that in the declaration it implements <strong>Mage_Widget_Block_Interface</strong>.  This is a requirement for Widgets.</p>
<p>Notice my constant <strong>MAXSECTIONS</strong> is set to 4, the same number of section parameters that I defined in widget.xml.  There’s probably some room for improvement here: one could probably figure out the number of parameters dynamically and then remove the constant.  That would make the widget more flexible for future uses.</p>
<p>I call the <strong>_construct</strong> function so that everything gets setup the way it’s supposed to.</p>
<p>Finally the real work gets done in <strong>_toHtml</strong>.  This function will be called automagically by Magento when it goes to render this object to the screen.</p>
<p>What I do is load up each block that gets passed into the widget and I stuff it’s HTML into an array element.  This way the widget can render any block, independently, by referencing a key in the array.</p>
<p>It’s not the classes job to do the rendering, that’s left to the presentation layer.  This class is just gathering everything that the presentation layer needs.</p>
<p>To move on with the tutorial we need to look back at our widget declaration in <strong>widget.xml</strong>.  I’m sure you noticed the last parameter <strong>template</strong> that I haven’t discussed yet.  Notice that the attribute <strong>visible</strong> is set to false.  What this parameter does is define the template that our widget is going to use for presentation.  My value is <strong>widgetglider/banner.phtml</strong> this template doesn’t exist by default so let’s create it.</p>
<p><strong>/app/design/frontend/default/spinonesolutions/template/widgetglider/banner.phtml</strong></p>
<pre class="php" name="code">&lt;style&gt;
.slideshow {
  position:relative;
}

.slideshow .items div {
  float:left;
  opacity:0.0;
  position:absolute;
  z-index:8;
}

.slideshow .items div.active {
  opacity:1.0;
  z-index:10;
}
&lt;/style&gt;

&lt;script&gt;
function slideSwitch() {
  var active = jQuery('.slideshow .items .active');
  // use this to pull the images in the order they appear in the markup
  var next =  jQuery(active).next().length ? jQuery(active).next() : jQuery('.slideshow .items div:first');
  jQuery(next).css({opacity: 0.0})
  .addClass('active')
  .animate({opacity: 1.0}, 1000, function() {
    jQuery(active).removeClass('active');
  });

  jQuery(active).animate({opacity:0.0}, 1000, function(){
  });
}

// execute your scripts when the DOM is ready. this is mostly a good habit
jQuery('document').ready(function() {
  var active = jQuery('.slideshow .items .active');
  if ( active.length == 0 ) {
    active = jQuery('.slideshow .items div:first');
    active.addClass('active').animate({opacity: 1.0}, 1000);
  }

  jQuery(function() {
    setInterval( "slideSwitch()", 5000 );
  });
});
&lt;/script&gt;
&lt;div class="slideshow"&gt;
  &lt;div class="items"&gt;
    &lt;?php foreach($this-&gt;sectionArr as $key =&gt; $section) { ?&gt;
    &lt;div class=""&gt;
      &lt;?php echo $section; ?&gt;
    &lt;/div&gt;
    &lt;?php } ?&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>
<p>The first part of that path is determined by the theme that you’ve set in Configuration.</p>
<p>Inspecting this file the real takeaway is simply the foreach loop.  All it does it loop over the array that was defined in the Business Layer and output the HTML stored in each element.  The template file does all the presentation.</p>
<p>The reason for doing things this way is that one can easily envision some department manager coming to you and asking for another, different, presentation of the same data for some other location of your website.  Since you’ve done a good job of separating your layers all you have to do is make a new .phtml file, and then change the <strong>template</strong> parameter of your <strong>widget.xml</strong> file and viola, you’ve got a new presentation of your data.</p>
<p>That does it for the code, all we need to do now is build a little demo using the interface.</p>
<p>Load up the admin and navigate to CMS -&gt; Static Blocks.  Create four static blocks and put an image file into each one.  If you hover your mouse over the row you’ll see the block_id.  Make note of these as you’ll need them for when you create the widget.  Mine are: 6,8,9,10.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/static-blocks.png"><img class="aligncenter size-medium wp-image-624" title="static-blocks" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/static-blocks-700x69.png" alt="static-blocks" width="700" height="69" /></a></p>
<p>Go to CMS -&gt; Pages and create a new CMS page to hold the widget.  Alternatively you could add the widget to a preexisting page.  Switch to the Content Tab.  Click the add Widget icon to add your widget.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/add-widget-button.png"><img class="aligncenter size-full wp-image-625" title="add-widget-button" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/add-widget-button.png" alt="add-widget-button" width="97" height="104" /></a></p>
<p>Choose your new widget from the dropdown menu.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/insert-widget-choose.png"><img class="aligncenter size-medium wp-image-626" title="insert-widget-choose" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/insert-widget-choose-700x356.png" alt="insert-widget-choose" width="700" height="356" /></a></p>
<p>Fill in the block_id(s) of your static blocks.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/insert-widget-filledin.png"><img class="aligncenter size-medium wp-image-627" title="insert-widget-filledin" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/insert-widget-filledin-700x360.png" alt="insert-widget-filledin" width="700" height="360" /></a></p>
<p>Hit Insert.</p>
<p>As a learning exercise click the “Show/HideEditor” button.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/widget-markup.png"><img class="aligncenter size-medium wp-image-628" title="widget-markup" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/widget-markup-700x114.png" alt="widget-markup" width="700" height="114" /></a></p>
<p>Notice what was generated!  It should be pretty similar to what’s in your <strong>widget.xml</strong> file.  As the smart and curious type the you are also realize that you can change these parameters right here.  Thus the widget.xml file serves a template for your widget, which can be customized later to suit your specific needs.</p>
<p>Ok, save your CMS page.  That’s it!</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/glider-demo.png"><img class="aligncenter size-medium wp-image-629" title="glider-demo" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/glider-demo-700x535.png" alt="glider-demo" width="700" height="535" /></a></p>
<p>You can see my <a title="Glider Demo" href="http://magento.spinonesolutions.com/glider-demo" target="_blank">demo here</a>.</p>
<p>As always, questions and comments welcomed!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/10/magento-custom-widget/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Magento CMS Tags (Directives)</title>
		<link>http://www.spinonesolutions.com/2010/04/magento-cms-tags-directives/</link>
		<comments>http://www.spinonesolutions.com/2010/04/magento-cms-tags-directives/#comments</comments>
		<pubDate>Fri, 16 Apr 2010 15:00:57 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[CMS]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=575</guid>
		<description><![CDATA[Here is, I think, a comprehensive list of tags (directives) available for use within the Magento CMS.  You can use these either in static blocks or CMS pages. Magento: Enterprise ver 1.6.0.0 block Description Outputs a virgin block or loads a defined block. Parameters type : Type of block to be created. id : Id [...]]]></description>
			<content:encoded><![CDATA[<p>Here is, I think, a comprehensive list of tags (directives) available for use within the Magento CMS.  You can use these either in static blocks or CMS pages.</p>
<p>Magento: Enterprise ver 1.6.0.0</p>
<h2>block</h2>
<p><span style="text-decoration: underline;">Description</span><br />
Outputs a virgin block or loads a defined block.</p>
<p><span style="text-decoration: underline;">Parameters</span><br />
<strong>type : </strong>Type of block to be created.<br />
<strong>id : </strong>Id of block to be created.<br />
<strong>output : </strong>The block instance method to call after creation.  If blank &#8220;toHtml()&#8221; will be called by default.<br />
<strong>&lt;parameter&gt; : </strong>Any additional parameters will get key value pairs set in the block&#8217;s Data array.</p>
<p><span style="text-decoration: underline;">Usage</span><br />
{{block type=&#8221;cms/block&#8221;}}<br />
Results in a virgin static block with no data.</p>
<p>{{block id=&#8221;myBlock&#8221;}}<br />
Results in an instance of <strong>myBlock</strong>.</p>
<p>{{block id=&#8221;myBlock&#8221; param1=&#8221;foo&#8221; param2=&#8221;bar&#8221;}}<br />
Results in an instance of <strong>myBlock</strong> with a data array containing key value pairs param1=&gt;&#8221;foo&#8221; param2=&gt;&#8221;bar&#8221;.</p>
<p>{{block id=&#8221;myBlock&#8221; output=&#8221;myMethod&#8221;}}<br />
Results in an instance of <strong>myBlock</strong> after it has called member method <strong>myMethod</strong>.</p>
<p>Note that if you already HAVE a block with this particular ID than it will be loaded.  This is great if you want to include a static block into a CMS page or into another static block!  Just create the block in the CMS section of admin and use the ID that you set.</p>
<p>Any parameter that your block class is sensitive too will work as well.  For example:</p>
<p>{{block id=&#8221;myBlock&#8221; template=&#8221;customfolder/customTemplate.phtml&#8221;}}<br />
Results in an instance of <strong>myBlock</strong> using a custom template.</p>
<h2>layout</h2>
<p><span style="text-decoration: underline;">Description</span><br />
Outputs the contents of the defined layout.</p>
<p><span style="text-decoration: underline;">Parameters<br />
</span><strong>area : </strong>The<strong> </strong>area to load.  If blank the layout&#8217;s default area will be used.<br />
<strong>handle : </strong>The layout handle to load.<br />
<strong>&lt;parameter&gt; : </strong>Any additional parameters will get key value pairs set in the layout&#8217;s Data array.</p>
<p><span style="text-decoration: underline;">Usage<br />
</span>{{layout handle=&#8221;default&#8221;}}<br />
Outputs the <strong>default</strong> layout handle.</p>
<h2>skin</h2>
<p><span style="text-decoration: underline;">Description</span><br />
Outputs the url for a resource in the current skin.</p>
<p><span style="text-decoration: underline;">Parameters<br />
</span><strong>url : </strong>The url to reference within the current skin directory.<br />
<strong>&lt;parameter&gt; : </strong>Any additional parameters will be passed to the getSkinUrl() method.</p>
<p><span style="text-decoration: underline;">Usage</span><br />
{{skin url=&#8221;images/myimage.gif&#8221;}}<br />
Outputs: http://www.mydomain.com/skin/frontend/default/default/images/myimage.gif<br />
Note: This assumes the current theme and skin are default.</p>
<h2>media</h2>
<p><span style="text-decoration: underline;">Description</span><br />
Outputs the Base Media URL.</p>
<p><span style="text-decoration: underline;">Parameters<br />
</span><strong>url : </strong>The url to prefix with the base media url.</p>
<p><span style="text-decoration: underline;">Usage</span><br />
{{media url=&#8221;images/myimage.gif&#8221;}}<br />
Outputs: http://www.mydomain.com/media/images/myimage.gif<br />
Note: This assumes Base Media URL is set to http://www.mydomain.com/media (See Admin-&gt;Configuration-&gt;Web)</p>
<h2>store</h2>
<p><span style="text-decoration: underline;">Description</span><br />
Outputs the store specific Base URL.</p>
<p><span style="text-decoration: underline;">Parameters<br />
</span><strong>direct_url : </strong>The url to prefix with the Base URL.  Note this method does NOT assume internal routing.<br />
<strong>url : </strong>The url to prefix with the Base URL.  Note this method DOES assume internal routing.<br />
<strong>&lt;parameter&gt; : </strong>Any additional parameters will be passed to the getSkinUrl() method.</p>
<p><span style="text-decoration: underline;">Usage<br />
</span>{{store direct_url=&#8221;images/myimage.gif&#8221;}}<br />
Outputs: http://www.mydomain.com/images/myimage.gif</p>
<p>{{store url=&#8221;mens&#8221;}}<br />
Outputs: http://www.mydomain.com/mens/</p>
<p>Note that the Base URL can be different in a multistore setup.</p>
<h2>htmlescape</h2>
<p><span style="text-decoration: underline;">Parameters<br />
</span><strong>var : </strong>The string to be html escaped.<br />
<strong>allowed_tags : </strong>Tags to be allowed in the escaped string</p>
<p><span style="text-decoration: underline;">Usage</span><br />
{{htmlescape var=&#8221;&lt;a href=&#8217;#'&gt;Click Here&lt;/a&gt;&#8221;}}<br />
Outputs: &lt;a href=&#8217;#'&gt;Click Here&lt;/a&gt;<br />
Note: The string is escaped so that the browser does not interpret it as HTML, instead it&#8217;s displayed as a human readable string.</p>
<h2>var</h2>
<p><span style="text-decoration: underline;">Description<br />
</span>Outputs template variables.</p>
<p><span style="text-decoration: underline;">Parameters</span><br />
<strong>variable</strong> : The variable being requested</p>
<p><span style="text-decoration: underline;">Usage<br />
</span>{{var myVariable}<br />
Outputs: Value stored in <strong>myVariable</strong></p>
<h2>protocol</h2>
<p><span style="text-decoration: underline;">Description</span><br />
Outputs the proper protocol (HTTP or HTTPS) depending on current context OR outputs the desired url based on the current protocol.</p>
<p><span style="text-decoration: underline;">Parameters</span><br />
<strong>store : </strong>The desired store<br />
<strong>url : </strong>The url to prefix with the proper protocol<br />
<strong>http : </strong>The url to use if the current protocol is HTTP<br />
<strong>https:</strong> The url to use if the current protocol is HTTPS</p>
<p><span style="text-decoration: underline;">Usage</span><br />
{{protocol url=&#8221;www.mydomain.com/images/checkout/cart.gif&#8221;}}<br />
Outputs: http://www.mydomain.com/images/checkout/cart.gif IF current protocol is HTTP<br />
Outputs: https://www.mydomain.com/images/checkout/cart.gif IF current protocol is HTTPS</p>
<p>{{protocol http=&#8221;http://unsecure.mydomain.com/images/checkout/cart.gif&#8221; https=&#8221;https://secure.mydomain.com/images/checkout/cart.gif&#8221;}}<br />
Outputs: http://unsecure.mydomain.com/images/checkout/cart.gif IF current protocol is HTTP<br />
Outputs: https://secure.mydomain.com/images/checkout/cart.gif IF current protocol is HTTPS</p>
<p>All of these directives are defined in Mage/Core/Model/Email/Template/Filter.php should you want to explore them further.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/04/magento-cms-tags-directives/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Magento Controller Override</title>
		<link>http://www.spinonesolutions.com/2010/03/magento-controller-override/</link>
		<comments>http://www.spinonesolutions.com/2010/03/magento-controller-override/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 16:00:11 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Custom]]></category>
		<category><![CDATA[Override]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=511</guid>
		<description><![CDATA[The Problem: You want to override a Controller&#8217;s action with a custom action. Magento Enterprise v1.6.0.0 The Solution: I ran into some issues trying to override a controller&#8217;s action yesterday. I think it mainly stems from a version change, but at any rate here&#8217;s the &#8220;new&#8221; way to do it. This comes from a helpful [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem:</h3>
<p>You want to override a Controller&#8217;s action with a custom action.</p>
<p>Magento Enterprise v1.6.0.0</p>
<h3>The Solution:</h3>
<p>I ran into some issues trying to override a controller&#8217;s action yesterday. I think it mainly stems from a version change, but at any rate here&#8217;s the &#8220;new&#8221; way to do it. This comes from a helpful <a href="http://www.magentocommerce.com/boards/viewthread/37244/">post</a> on the Magento forums.</p>
<p>In this example my custom modules&#8217;s namespace is &#8220;Spinonesolutions&#8221; and I&#8217;m going to override the <strong>createPostAction</strong> in <strong>Mage_Customer_AccountController.</strong></p>
<p>Start by creating a bare bones custom module; if you don&#8217;t know how to do this check out <a title="Magento – Part I : Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">Magento – Part I : Custom Module</a>.</p>
<p>I&#8217;ve only got two files in my custom module; <strong>controllers/AccountController.php</strong> and <strong>etc/config.xml</strong>.</p>
<p>config.xml:</p>
<pre class="php" name="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;config&gt;
&lt;modules&gt;
  &lt;Spinonesolutions_Customer&gt;
    &lt;version&gt;0.0.1&lt;/version&gt;
  &lt;/Spinonesolutions_Customer&gt;
&lt;/modules&gt;
&lt;frontend&gt;
  &lt;routers&gt;
    &lt;!-- This is the frontname to override
    EG: http://mydomainname.com/customer/  --&gt;
    &lt;customer&gt;
      &lt;args&gt;
        &lt;modules&gt;
          &lt;!-- Use the module Spinonesolutions_Customer BEFORE Mage_Customer --&gt;
          &lt;Spinonesolutions_Customer before="Mage_Customer"&gt;Spinonesolutions_Customer&lt;/Spinonesolutions_Customer&gt;
        &lt;/modules&gt;
      &lt;/args&gt;
    &lt;/customer&gt;
  &lt;/routers&gt;
&lt;/frontend&gt;
&lt;/config&gt;</pre>
<p>AccountController.php:</p>
<pre class="php" name="code">&lt;?php
/**
* Override Customer AccountController
*
* Override the createPost action
*
* @category Mage
* @package Mage_Customer
* @author Will Wright
*/

/*Controllers aren't included automatically, so we include it here so that we can extend it*/
include_once("Mage/Customer/controllers/AccountController.php");
class Spinonesolutions_Customer_AccountController extends Mage_Customer_AccountController {
  public function createPostAction() {
    die('here');
  }
}</pre>
<p>That&#8217;s it!  You should now have a working override.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/03/magento-controller-override/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Magento Partial Refund Amount Correction for Authorize.net</title>
		<link>http://www.spinonesolutions.com/2010/01/partial-refund-amount-correction-for-authorize-net/</link>
		<comments>http://www.spinonesolutions.com/2010/01/partial-refund-amount-correction-for-authorize-net/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 22:04:48 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Model]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/2009/11/partial-refund-amount-correction-for-authorize-net/</guid>
		<description><![CDATA[The Problem: You&#8217;ve enabled partial refunds in the Authorizenet Model, but it&#8217;s not refunding the proper amounts.  This is due to, in my view, a bug in the core which I&#8217;ll show you how to patch! The Solution: What you need to do is overload the refund method in the Authorizenet model. Create a new [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem:</h3>
<p>You&#8217;ve enabled partial refunds in the Authorizenet Model, but it&#8217;s not refunding the proper amounts.  This is due to, in my view, a bug in the core which I&#8217;ll show you how to patch!</p>
<h3>The Solution:</h3>
<p>What you need to do is overload the <strong>refund</strong> method in the Authorizenet model.</p>
<p>Create a new model that extends the original Authorizenet model.  You&#8217;ll need to follow the general instructions for how to <a title="Magento Custom Module Part I" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/" target="_blank">create a custom module</a> if you don&#8217;t already know how to do so.</p>
<pre class="php" name="code">
class Spinonesolutions_General_Model_Paygate_Authorizenet extends Mage_Paygate_Model_Authorizenet {
//Override Mage_Paygate_Model_Authorizenet

protected $_canRefund = true;

public function refund(Varien_Object $payment, $amount) {
  $error = false;
  if ($payment-&gt;getRefundTransactionId() &amp;&amp; $amount&gt;0) {
    $payment-&gt;setAnetTransType(self::REQUEST_TYPE_CREDIT);
    $request = $this-&gt;_buildRequest($payment, $amount);
    $request-&gt;setXTransId($payment-&gt;getRefundTransactionId());
    $result = $this-&gt;_postRequest($request);
    if ($result-&gt;getResponseCode()==self::RESPONSE_CODE_APPROVED) {
      $payment-&gt;setStatus(self::STATUS_SUCCESS);
    } else {
      $error = $result-&gt;getResponseReasonText();
    }
  } else {
    $error = Mage::helper('paygate')-&gt;__('Error in refunding the payment');
  }

  if ($error !== false) {
    Mage::throwException($error);
  }

  return $this;
}
}</pre>
<p>Now all we need to do is let Magento know that we&#8217;ve got a custom model.  In config.xml add</p>
<pre class="xml" name="code">
&lt;?xml version="1.0"?&gt;
&lt;config&gt;
  &lt;modules&gt;
    &lt;Spinonesolutions_General&gt;
      &lt;version&gt;0.0.1&lt;/version&gt;
    &lt;/Spinonesolutions_General&gt;
  &lt;/modules&gt;
  &lt;global&gt;
    &lt;models&gt;
      ...
      &lt;paygate&gt;
        &lt;rewrite&gt;
          &lt;authorizenet&gt;Imagistic_General_Model_Paygate_Authorizenet&lt;/authorizenet&gt;
        &lt;/rewrite&gt;
      &lt;/paygate&gt;
      ...
    &lt;/models&gt;
  &lt;/global&gt;
&lt;/config&gt;
</pre>
<p>That should do it!  Questions and comments welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/01/partial-refund-amount-correction-for-authorize-net/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Custom Magento Grid with Ambiguous Column on Filter</title>
		<link>http://www.spinonesolutions.com/2010/01/custom-magento-grid-with-ambiguous-column-on-filter/</link>
		<comments>http://www.spinonesolutions.com/2010/01/custom-magento-grid-with-ambiguous-column-on-filter/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 17:14:58 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=486</guid>
		<description><![CDATA[The Problem You&#8217;ve built a custom grid and the source collection has an ambiguous column in the where clause when applying a filter. The Solution I recently ran into this problem while I was building a custom grid.  The situation should be familiar to many of you.  I have a custom table storing addresses; for the [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem</h3>
<p>You&#8217;ve built a custom grid and the source collection has an ambiguous column in the where clause when applying a filter.</p>
<h3>The Solution</h3>
<p>I recently ran into this problem while I was building a custom grid.  The situation should be familiar to many of you.  I have a custom table storing addresses; for the region and country I store a region_id and country_id, respectively.  For display of the grid however I want to do a lookup to show the user the friendly names for both region and country.  To accomplish that I do an inner join on the original collection which yields the full dataset.</p>
<p>However, this also introduces a douplicate column into the collection which was causeing an ambigous column error in my SQL statement whenever I applied a filter (a WHERE clause).  Lets take a look at an example.</p>
<p>My tables:</p>
<p><span style="text-decoration: underline;">retailer</span></p>
<ul>
<li>id</li>
<li>street</li>
<li>city</li>
<li>postcode</li>
<li>country_id</li>
<li>region_id</li>
</ul>
<p><span style="text-decoration: underline;">directory_country_region</span></p>
<ul>
<li>region_id</li>
<li>country_id</li>
<li>code</li>
<li>default_name</li>
</ul>
<p>Now lets take a look at my <strong>_prepareCollection</strong> method.</p>
<pre class="php" name="code">
protected function _prepareCollection() {
  $collection = Mage::getResourceModel('spinonesolutions_storelocator/retailer_collection');
  $collection-&gt;getSelect()
    -&gt;join(array('dcr' =&gt; 'directory_country_region'),'dcr.region_id = main_table.region_id')
    -&gt;reset(Zend_Db_Select::COLUMNS)
    -&gt;columns(array('id','name','street','city','country_id'))
    -&gt;columns(array('default_name'),'dcr');
  $this-&gt;setCollection($collection);
  return parent::_prepareCollection();
}</pre>
<p>This will result in a collection containing all the data that I need for a friendly presentation.  However, if I want to filter by country_id (which I do!) then I&#8217;m going to get an ambiguous column error in my SQL if I simply add &#8220;WHERE country_id = ?&#8221;.  That&#8217;s because country_id is in both tables.</p>
<p>The solution is the &#8220;filter_index&#8221; property.  Here&#8217;s a snippet from <strong>_prepareColumns</strong> which generates the country column and uses filter_index.</p>
<pre class="php" name="code">
$this-&gt;addColumn('country_id', array(
  'header' =&gt; Mage::helper('spinonesolutions_storelocator')-&gt;__('Country'),
  'width' =&gt; '100px',
  'index' =&gt; 'country_id',
  'filter_index' =&gt; 'main_table.country_id',
  'type' =&gt; 'country', ));
</pre>
<p>Now when the SQL statement is generated the ambiguous column error will be fixed since I&#8217;ve provided enough specificity.  Simple!</p>
<p>Questions and comments welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/01/custom-magento-grid-with-ambiguous-column-on-filter/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Magento &#8211; Enable Paygate Refunds</title>
		<link>http://www.spinonesolutions.com/2009/10/magento-enable-paygate-refunds/</link>
		<comments>http://www.spinonesolutions.com/2009/10/magento-enable-paygate-refunds/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 21:43:26 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Model]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=435</guid>
		<description><![CDATA[The Problem: You want to issue a refund, electronically, through your payment gateway from Magento. The Solution: By default, the community edition of Magento has refunds disabled in the Paygate Models.  In order to enable them you need to create a custom Model and overwrite a protected variable.  Refer to Part IV: Extending Models for [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem:</h3>
<p>You want to issue a refund, electronically, through your payment gateway from Magento.</p>
<h3>The Solution:</h3>
<p>By default, the community edition of Magento has refunds disabled in the Paygate Models.  In order to enable them you need to create a custom Model and overwrite a protected variable.  Refer to <a title="Part IV - Extending Models" href="http://www.spinonesolutions.com/2009/10/magento-part-i…tending-models/">Part IV: Extending Models</a> for more details on extending a Model.</p>
<p>First, lets take a look at the native Model so that you can understand what&#8217;s standing in the way.  I&#8217;m going to use the Authorize.net gateway as my example.</p>
<p>The top portion of <strong>Mage_Paygate_Model_Authorizenet</strong> (/Mage/Paygate/Model/Authorizenet.php)</p>
<pre class="php" name="code">class Mage_Paygate_Model_Authorizenet extends Mage_Payment_Model_Method_Cc
{
    const CGI_URL = 'https://secure.authorize.net/gateway/transact.dll';

    const REQUEST_METHOD_CC     = 'CC';
    const REQUEST_METHOD_ECHECK = 'ECHECK';

    const REQUEST_TYPE_AUTH_CAPTURE = 'AUTH_CAPTURE';
    const REQUEST_TYPE_AUTH_ONLY    = 'AUTH_ONLY';
    const REQUEST_TYPE_CAPTURE_ONLY = 'CAPTURE_ONLY';
    const REQUEST_TYPE_CREDIT       = 'CREDIT';
    const REQUEST_TYPE_VOID         = 'VOID';
    const REQUEST_TYPE_PRIOR_AUTH_CAPTURE = 'PRIOR_AUTH_CAPTURE';

    const ECHECK_ACCT_TYPE_CHECKING = 'CHECKING';
    const ECHECK_ACCT_TYPE_BUSINESS = 'BUSINESSCHECKING';
    const ECHECK_ACCT_TYPE_SAVINGS  = 'SAVINGS';

    const ECHECK_TRANS_TYPE_CCD = 'CCD';
    const ECHECK_TRANS_TYPE_PPD = 'PPD';
    const ECHECK_TRANS_TYPE_TEL = 'TEL';
    const ECHECK_TRANS_TYPE_WEB = 'WEB';

    const RESPONSE_DELIM_CHAR = ',';

    const RESPONSE_CODE_APPROVED = 1;
    const RESPONSE_CODE_DECLINED = 2;
    const RESPONSE_CODE_ERROR    = 3;
    const RESPONSE_CODE_HELD     = 4;

    protected $_code  = 'authorizenet';

    /**
     * Availability options
     */
    protected $_isGateway               = true;
    protected $_canAuthorize            = true;
    protected $_canCapture              = true;
    protected $_canCapturePartial       = false;
    protected $_canRefund               = false;
    protected $_canVoid                 = true;
    protected $_canUseInternal          = true;
    protected $_canUseCheckout          = true;
    protected $_canUseForMultishipping  = true;
    protected $_canSaveCc = false;

    protected $_allowCurrencyCode = array('USD');</pre>
<p>The variable that we&#8217;re interested in is <strong>_canRefund</strong>.  The game plan is to create a custom Model that overrides <strong>Mage_Paygate_Model_Authorizenet</strong> and in that Model, override <strong>_canRefund</strong>.  If you&#8217;re thinking, why not just change false to true right here, right now!  Well my friend, you certainly could, but you&#8217;d certainly break your upgrade path too, check out <a title="Part IV - Extending Models" href="../2009/10/magento-part-i%E2%80%A6tending-models/">Part IV: Extending Models</a> and <a title="Part I - Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">Part I: Custom Module</a>.</p>
<p>I&#8217;m going to create the class: <strong>Spinonesolutions_Paygate_Model_Authorizenet</strong> (/local/Spineonesolutions/Paygate/Model/Authorizenet.php) and extend <strong>Mage_Paygate_Model_Authorizenet</strong>.  Now I just override <strong>_canRefund</strong> and we&#8217;re halfway there.</p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Paygate_Model_Authorizenet extends Mage_Paygate_Model_Authorizenet
{
 //Override Mage_Paygate_Model_Authorizenet
 protected $_canRefund = true;
}
?&gt;</pre>
<p>If you read <a title="Part IV - Extending Models" href="../2009/10/magento-part-i%E2%80%A6tending-models/">Part IV: Extending Models</a> you&#8217;ll know that there&#8217;s one last step, and that is to modify config.xml so that our custom Model overrides the native Model.</p>
<p>/Spinonesolutions/Paygate/etc/config.xml</p>
<pre class="xml" name="code">&lt;global&gt;
  &lt;models&gt;
  ...
    &lt;paygate&gt;
      &lt;rewrite&gt;
        &lt;authorizenet&gt;Spinonesolutions_Paygate_Model_Authorizenet&lt;/authorizenet&gt;
      &lt;/rewrite&gt;
    &lt;/paygate&gt;
  ...
  &lt;/models&gt;
&lt;/global&gt;</pre>
<p>That should do it!  If you&#8217;ve got everything else setup correctly this should enable the Model to post refunds electronically to your gateway.  Of course, if you want to enable more than one gateway, or perhaps a gateway that&#8217;s not Authorize.net you can do that by just following the same steps above with the Model for the gateway of your choice.</p>
<p>As always, questions and comments are welcome!</p>
<h3>Update: From Commenter Cindy</h3>
<p>Afer doing the above (and not forgetting to fill in app/etc/modules/MyNameSpace_All.xml to activate the new module), I still wasn’t getting authorize.net to really refund the cc.</p>
<p>I found that I needed to add the CC to the request, and then add the actual amount to be refunded. Now issuing a credit memo on the invoice will cause authorize.net to issue a refund to the CC.</p>
<p>Also, it appears that the ‘refund’ button only shows up if you click credit memo from an invoice – it doesn’t show up if you click credit memo on an order (only ‘refund offline’ shows up then).</p>
<p>Anyway, this is the code to make this work for me:</p>
<pre class="php" name="code">//
// Override Mage_Paygate_Model_Authorizenet
//    enable online refunds via credit memos
//    enable partial refunds
//
class Sbr_Paygate_Model_Authorizenet extends Mage_Paygate_Model_Authorizenet {
  protected $_canCapturePartial = true;
  protected $_canRefund = true;

  //
  // override _buildRequest to fill in the CC number as it is required yet not set peviously
  //
  protected function _buildRequest (Varien_Object $payment) {
    if (($payment-&gt;getAnetTransMethod() == self::REQUEST_METHOD_CC) &amp;&amp;($payment-&gt;getCcLast4()))
      $payment-&gt;setCcNumber($payment-&gt;getCcLast4());
   
      return parent::_buildRequest($payment);
  }

  // Override refund in order to fill out the amount
  //
  public function refund(Varien_Object $payment, $amount) {
    $error = false;
    if ($payment-&gt;getRefundTransactionId() &amp;&amp; $amount&gt;0) {
      $payment-&gt;setAnetTransType(self::REQUEST_TYPE_CREDIT);
      $request = $this-&gt;_buildRequest($payment);

      // set the amount (beginning of changes)
      $order = $payment-&gt;getOrder();
      $request-&gt;setXAmount($amount,2);
      $request-&gt;setXCurrencyCode($order-&gt;getBaseCurrencyCode());
      // (end of changes)

      $request-&gt;setXTransId($payment-&gt;getRefundTransactionId());
      $result = $this-&gt;_postRequest($request);

      if ($result-&gt;getResponseCode() == self::RESPONSE_CODE_APPROVED) {
        $payment-&gt;setStatus(self::STATUS_SUCCESS);
      } else {
        $error = $result-&gt;getResponseReasonText();
      }
    } else {
      $error = Mage::helper(’paygate’)-&gt;__(’Error in refunding the payment’);
    }

    if ($error !== false) {
      Mage::throwException($error);
    }

    return $this;
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2009/10/magento-enable-paygate-refunds/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
	</channel>
</rss>

