<?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</title>
	<atom:link href="http://www.spinonesolutions.com/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>Wed, 20 Jan 2010 22:07:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<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 model that extends the [...]]]></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>0</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 region and country [...]]]></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>4</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 more details on [...]]]></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>5</slash:comments>
		</item>
		<item>
		<title>Magento &#8211; Part V: Data Layer</title>
		<link>http://www.spinonesolutions.com/2009/10/magento-part-v-data-layer/</link>
		<comments>http://www.spinonesolutions.com/2009/10/magento-part-v-data-layer/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 21:03:35 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[Data Layer]]></category>
		<category><![CDATA[Model]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=439</guid>
		<description><![CDATA[The Problem:
You need a custom Model to interact with a database.
The Solution:
By now you’ve read all the previous posts, right, and you want to take your custom module to the next level.  You not only have business logic to perform, but you need to read and write data to a custom database table.  No problem, let’s [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem:</h3>
<p>You need a custom Model to interact with a database.</p>
<h3>The Solution:</h3>
<p>By now you’ve read all the previous posts, right, and you want to take your custom module to the next level.  You not only have business logic to perform, but you need to read and write data to a custom database table.  No problem, let’s take a look at Magento’s database layer.</p>
<p>There’s a lot of voodoo that goes into the Database layer, most of the confusion stems from a heavy reliance on naming conventions.  Once you understand these conventions you’ll have a much easier time getting data in and out of your database.</p>
<p>As always I’m going to use an example.  Let’s say that you need to create a Widget Model that stores Widgets into a database table.  We’ll need a Model to describe our Widget, a Class for the data layer, and the appropriate config files to let Magento know about our customizations.</p>
<p>I’m going to start with the Widget Model since it’s already been covered and should be the most familiar.</p>
<p>/app/code/local/Spinonesolutions/Helloworld/Model/Widget.php:</p>
<pre class="php" name="code">class Spinonesolutions_Helloworld_Model_Widget extends Mage_Core_Model_Abstract {
  function __construct() {
    parent::__construct();
    $this-&gt;_init("spinonesolutions_helloworld/widget");
  }

  public function save() {
    $this-&gt;setCreated(now());
    $this-&gt;setUpdated(now());

    parent::save();
    return $this;
  }
}</pre>
<p>There are a couple of important things to make note of in the Class above.  First, I’ve extended <strong>Mage_Core_Model_Abstract</strong>, this is Magento’s basic Data Layer Class and it will provide the functions that we need to interact with the database.</p>
<p>Second, the <strong>_init()</strong> function’s parameter should match your config.xml, as we’ll see in just a moment.  Lastly, I’ve put a little bit of business logic in the <strong>save()</strong> method.  As we’ll see this sets the created, and modified fields in our table to the current datetime when we call <strong>save()</strong>.</p>
<p>/app/code/local/Spinonesolutions/etc/config.xml:</p>
<pre class="xml" name="code">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;config&gt;
  &lt;modules&gt;
    &lt;Spinonesolutions_Helloworld&gt;
      &lt;version&gt;0.1.0&lt;/version&gt;
    &lt;/Spinonesolutions_Helloworld&gt;
  &lt;/modules&gt;
  &lt;frontend&gt;
    &lt;routers&gt;
      &lt;spinonesolutions&gt; &lt;!-- I make this match my front name but I'm not sure it matters --&gt;
        &lt;use&gt;standard&lt;/use&gt; &lt;!-- Use standard routing as opposed to admin. IE: frontend vs admin --&gt;
        &lt;args&gt;
          &lt;module&gt;Spinonesolutions_Helloworld&lt;/module&gt; &lt;!-- The module to search for controllers --&gt;
          &lt;frontName&gt;spinonesolutions&lt;/frontName&gt; &lt;!-- The first descriminator in the path. "spinonesolutions" in http://localhost/spinonesolutions/ --&gt;
        &lt;/args&gt;
      &lt;/spinonesolutions&gt;
    &lt;/routers&gt;
  &lt;/frontend&gt;
  &lt;global&gt;
    &lt;models&gt;
      &lt;spinonesolutions_helloworld&gt; &lt;!-- This is used when istanting your Model EG: Mage::getModel("spinonesolutions_helloworld/hellworld") --&gt;
        &lt;class&gt;Spinonesolutions_Helloworld_Model&lt;/class&gt; &lt;!-- That class to use when isntanting objects of type above. --&gt;
        &lt;resourceModel&gt;spinonesolutions_helloworld_mysql4&lt;/resourceModel&gt; &lt;!-- Use a custom table instead of EAV, the Model is defomed below --&gt;
      &lt;/spinonesolutions_helloworld&gt;
      &lt;spinonesolutions_helloworld_mysql4&gt; &lt;!-- Define a new Model to represent the Data Layer --&gt;
        &lt;class&gt;Spinonesolutions_Helloworld_Model_Mysql4&lt;/class&gt;
        &lt;entities&gt;
          &lt;widget&gt;&lt;table&gt;widget&lt;/table&gt;&lt;/widget&gt; &lt;!-- map a table (widget) to an entity "widget" --&gt;
        &lt;/entities&gt;
      &lt;/spinonesolutions_helloworld_mysql4&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;resources&gt;
     &lt;spinonesolutions_helloworld_write&gt;
       &lt;connection&gt;&lt;use&gt;core_write&lt;/use&gt;&lt;/connection&gt;
     &lt;/spinonesolutions_helloworld_write&gt;
     &lt;spinonesolutions_helloworld_read&gt;
       &lt;connection&gt;&lt;use&gt;core_read&lt;/use&gt;&lt;/connection&gt;
     &lt;/spinonesolutions_helloworld_read&gt;
   &lt;/resources&gt;
  &lt;/global&gt;
&lt;/config&gt;</pre>
<p>Let’s start at the top and work our way down.  Note: I’m going to skip the custom Model stuff and just focus on what’s new for this post.</p>
<pre class="xml" name="code">&lt;spinonesolutions_helloworld&gt; &lt;!-- This is used when istanting your Model EG: Mage::getModel("spinonesolutions_helloworld/hellworld") --&gt;
  &lt;class&gt;Spinonesolutions_Helloworld_Model&lt;/class&gt; &lt;!-- That class to use when isntanting objects of type above. --&gt;
  &lt;resourceModel&gt;spinonesolutions_helloworld_mysql4&lt;/resourceModel&gt; &lt;!-- Use a custom table instead of EAV, the Model is defomed below --&gt;
&lt;/spinonesolutions_helloworld&gt;</pre>
<p>We just mapped a new resource Model (<strong>spinonesolutions_helloworld_model_mysql4</strong>) to <strong>spinonesolutions_helloworld</strong>.  You’ll notice that the Model itself is defined right after this line.</p>
<pre class="xml" name="code">&lt;spinonesolutions_helloworld_mysql4&gt; &lt;!-- Define a new Model to represent the Data Layer --&gt;
  &lt;class&gt;Spinonesolutions_Helloworld_Model_Mysql4&lt;/class&gt;
  &lt;entities&gt;
    &lt;widget&gt;&lt;table&gt;widget&lt;/table&gt;&lt;/widget&gt; &lt;!-- map a table (widget) to an entity "widget" --&gt;
  &lt;/entities&gt;
&lt;/spinonesolutions_helloworld_mysql4&gt;</pre>
<p>Just as we did for our custom Model before, we’ve now defined a new Model (<strong>spinonesolutions_helloworld_mysql4</strong>) and told Magento what its class is (<strong>Spinonesolutions_Helloworld_Model_Mysql4</strong>).  Notice that we’ve already used this new Model as the resourceModel for <strong>spinonesolutions_helloworld</strong>.</p>
<p>As well as linking this Model to its Class we’ve also mapped a table to it in the entities section.  Now the “widget” entity maps to the table “widget” in our magento database.</p>
<p>We need one more file; we’ve mapped <strong>spinonesolutions_helloworld_mysql4</strong> to the class <strong>Spinonesolutions_Helloworld_Model_Mysql4</strong> so we need to create a file to house this code.</p>
<p>/app/code/local/Spinonesolutions/Helloworld/Model/Mysql4/Widget.php:</p>
<pre class="php" name="code">class Spinonesolutions_Helloworld_Model_Mysql4_Widget extends Mage_Core_Model_Mysql4_Abstract {
  public function _construct() {
    $this-&gt;_init("spinonesolutions_helloworld/widget", "id");
  }
}</pre>
<p>Throughout this tutorial I’ve been following Magento’s naming conventions for Class definitions and file names.</p>
<p>The first parameter passed to the <strong>_init()</strong> function is the Model that defines our table, and the second parameter is the name of the PrimaryKey field.</p>
<p>Last but not least we have the “resources” section of the config.xml.  The read and write sections tell Magento what connection to use for read operations and write operations.  As long as you keep true to the naming conventions you shouldn’t need to change these values too much.</p>
<p>Let’s put it all together and do a test.  I’m going to create a table “widgets”:</p>
<p><span style="text-decoration: underline;">widgets<br />
</span>id (int) – PK<br />
title (varchar255)<br />
description (varchar255)<br />
created(datetime)<br />
modified(datetime)</p>
<p>Now we’ll create a controller to manage CRUD for our new Model.  I’ll call it WidgetController.</p>
<p>/app/code/local/Spinonesolutions/Helloworld/controllers/WidgetController.php</p>
<pre class="php" name="code">class Spinonesolutions_Helloworld_WidgetController extends Mage_Core_Controller_Front_Action {
  //indexAction is the default Action for any controller
  function indexAction() {
    echo "Spinonesolutions_Helloworld_WidgetController.indexAction()";
  }

  //{base}/spinonesolutions/widget/create/
  function createAction() {
    echo "Spinonesolutions_Helloworld_WidgetController.createAction()";
    $widget = Mage::getModel("spinonesolutions_helloworld/widget");
    $data = array(
      "title" =&gt; "My new title",
      "description" =&gt; "My new description"
    );

    $widget-&gt;setData($data);
    $widget-&gt;save();
  }
}</pre>
<p>Requesting {base}/spinonesolutions/widget/create/ results in the insertion of a new record into my widget table!  Let’s deconstruct what I’ve done a little bit to gain some understanding.</p>
<p>You’ll recognize the instantiation of the Model from my previous posts on custom Modules and Models.  Magento stores all of an object’s data in an array which is stored in a private variable <strong>_data</strong>.  Each of the array elements corresponds to a field in the table.  All Models derived from the abstract classes have getters and setters for their variables.  You can always call them by using the “get” and “set” prefix followed by camel case variable name.</p>
<p>So if the field in my database table is named “foo_bar”.  In the object, the value will be stored in <strong>_data[“foo_bar”]</strong>.  I can set the value by calling <strong>$object-&gt;setFooBar(“value”)</strong>.  I can get the value by calling <strong>$object-&gt;getFooBar()</strong>;</p>
<p>That’s all for this post!  I’ll go over widget CRUD in the next!</p>
<p>Download the source &#8211; <a title="Helloworld Source V4" href="http://www.spinonesolutions.com/wp-content/uploads/2009/11/Helloworld_v4.rar">Helloworld_v4</a></p>
<ol>
<li><a title="Part I : Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">Part I : Custom Module</a></li>
<li><a title="Part II : Models" href="http://www.spinonesolutions.com/2009/10/magento-part-ii-models/">Part II : Models</a></li>
<li><a title="Part III : Controllers" href="http://www.spinonesolutions.com/2009/10/magento-part-iii-controllers/">Part III : Controllers</a></li>
<li><a title="Part IV : Extending Models" href="http://www.spinonesolutions.com/2009/10/magento-part-iv-extending-models/">Part IV : Extending Models</a></li>
<li><a title="Part V: Data Layer" href="http://www.spinonesolutions.com/2009/10/magento-part-v-data-layer/">Part V : Data Layer</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2009/10/magento-part-v-data-layer/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Magento &#8211; Part IV : Extending Models</title>
		<link>http://www.spinonesolutions.com/2009/10/magento-part-iv-extending-models/</link>
		<comments>http://www.spinonesolutions.com/2009/10/magento-part-iv-extending-models/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 15:09:55 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Models]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=413</guid>
		<description><![CDATA[The Problem:
You want to expand upon or change some functionality within Magento.
The Solution:
Extend a Model!  I’m going to use a real world example here because I believe that examples are the best tools for teaching.
I was faced with a request for additional functionality in regards to the Authorize.net payment method.  Basically, the customer wanted an [...]]]></description>
			<content:encoded><![CDATA[<h2>The Problem:</h2>
<p>You want to expand upon or change some functionality within Magento.</p>
<h2>The Solution:</h2>
<p>Extend a Model!  I’m going to use a real world example here because I believe that examples are the best tools for teaching.</p>
<p>I was faced with a request for additional functionality in regards to the Authorize.net payment method.  Basically, the customer wanted an email to be sent to an administrator if the gateway experienced an error while trying to processes a payment; a very reasonable request.</p>
<p>To accomplish this I extended <strong>Mage_Paygate_Model_Authorizenet</strong>, the model responsible for Authorize.net.  There are two very important reasons why I went about it the way I did.</p>
<p>First, as I mentioned earlier, all custom code should go in the /local/ directory.  If I had made my changes directly to <strong>Mage_Paygate_Model_Authorizenet</strong> (/core/Mage/Paygate/Model/Authorizenet) then the modifications would be in serious danger if the core were ever updated, essentially breaking the upgrade path.</p>
<p>Secondly, by extending the core class I can make reference to anything contained in the parent class.  This is good OOP architecture; I’m just adorning the parent class with additional functionality, leveraging all the work that has come before and maintaining good compartmentalization.</p>
<p>There are two basic steps to extending a core class.  Firstly, you need to create your new (custom) class in a custom Module living in /local/.  I’ll continue expanding upon my previous examples and make a new Model within Spinonesolutions/Helloworld.  I’m going to put the new Model in its own folder, mirroring the structure of the core.</p>
<p>Parent Class Path:<br />
/Mage/Paygate/Model/Authorizenet.php</p>
<p>Custom Class Path:<br />
/Spinonesolutions/Helloworld/Model/Paygate/Authorizenet.php</p>
<p>Naming conventions dictate that my custom Class’s name be:<br />
<strong>Spinonesolutions_Helloworld_Model_Paygate_Authorizenet</strong></p>
<p>Let’s jump right into the source and dissect what’s going on.</p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Helloworld_Model_Paygate_Authorizenet extends Mage_Paygate_Model_Authorizenet {

  private $_order;

  function __construct() {
    parent::__construct();     
  }

  public function capture(Varien_Object $payment, $amount) {
    $this-&gt;_order = $payment-&gt;getOrder();
    try {
      parent::capture($payment,$amount);
    } catch (Exception $error) {
      $this-&gt;_sendEmail($error);
      throw $error;
    }           
    return $this;
  }
}</pre>
<p>The declaration is import to note because this is where we do the actual extending.  Although it’s not necessary for this example I’ve included a call to the constructor, and placed a call to the parent constructor within it.  This way, both the custom and parent model are instantiated correctly.</p>
<p>OK, onto the meat, the <strong>capture()</strong> function.  To fully understand this we need to understand what we’re trying to extend.  Looking at <strong>Mage_Paygate_Model_Authorizenet</strong> (/Mage/Paygate/Model/Authorizenet.php) will yield the answer.</p>
<p>As you can see <strong>Mage_Paygate_Model_Authorizenet</strong> contains a capture method with the exact same signature: <strong>public function capture(Varien_Object $payment, $amount)</strong>.  What I’m doing is overriding this method with my method.  I add my additional functionality and then call the parent method at the appropriate time to drop the system back into its default workflow.</p>
<p>Notice that all I’m doing is wrapping the parent method call in a try catch block so that if an Exception is thrown I can catch it and send an email.  I’ve successfully extended the core functionality without touching a line of the core code!</p>
<p>I’ve left out one small, but hugely important bit of information.  In order to get this to work we have to let Magento know that there’s a custom Model which overrides this particular Model.  To accomplish this we turn to the <strong>config.xml</strong>.</p>
<pre class="xml" name="code">&lt;?xml version=<em>"1.0"</em> encoding=<em>"UTF-8"</em> ?&gt;
&lt;config&gt;
      &lt;modules&gt;
            &lt;Spinonesolutions_Helloworld&gt;
                  &lt;version&gt;0.1.0&lt;/version&gt;
            &lt;/Spinonesolutions_Helloworld&gt;
      &lt;/modules&gt;
    &lt;frontend&gt;
        &lt;routers&gt;
            &lt;spinonesolutions&gt;      &lt;!-- I make this match my front name but I'm not sure it matters --&gt;
                &lt;use&gt;standard&lt;/use&gt; &lt;!-- Use standard routing as opposed to admin.  IE: frontend vs admin --&gt;
                &lt;args&gt;
                    &lt;module&gt;Spinonesolutions_Helloworld&lt;/module&gt;  &lt;!-- The module to search for controllers --&gt;
                    &lt;frontName&gt;spinonesolutions&lt;/frontName&gt; &lt;!-- The first descriminator in the path.  "spinonesolutions" in http://localhost/spinonesolutions/ --&gt;
                &lt;/args&gt;
            &lt;/spinonesolutions&gt;
        &lt;/routers&gt;
    &lt;/frontend&gt;
      &lt;global&gt;
            &lt;models&gt;
                  &lt;spinonesolutions_helloworld&gt; &lt;!-- This is used when istanting your Model EG: Mage::getModel("spinonesolutions_helloworld/hellworld") --&gt;
                        &lt;class&gt;Spinonesolutions_Helloworld_Model&lt;/class&gt;      &lt;!-- That class to use when isntanting objects of type above. --&gt;
                  &lt;/spinonesolutions_helloworld&gt;
              &lt;paygate&gt;
                  &lt;rewrite&gt;
                        &lt;authorizenet&gt;Spinonesolutions_Helloworld_Model_Paygate_Authorizenet&lt;/authorizenet&gt;
                  &lt;/rewrite&gt;
              &lt;/paygate&gt;
            &lt;/models&gt;
      &lt;/global&gt;
&lt;/config&gt;</pre>
<p>Notice line:24 and the <strong>paygate</strong> element.  This is the element that is telling Magento to now look in our custom class for the Model, and not the core.</p>
<p>That’s all there is to it!  You can now extend Magento’s core functionality to your heart’s content.</p>
<p>I bet you astute readers out there noticed that ALL of the models thus far have extended a core class.  My first Model <strong>Spinonesolutions_Helloworld_Model_Helloworld</strong> extends <strong>Varien_Object</strong>.  Even the controllers extend <strong>Mage_Core_Controller_Front_Action</strong>.</p>
<p>Oh Snap!</p>
<p>Download the source &#8211; <a href="http://www.spinonesolutions.com/wp-content/uploads/2009/10/Helloworld_v3.rar">Helloworld_v3</a></p>
<ol>
<li><a title="Part I : Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">Part I : Custom Module</a></li>
<li><a title="Part II : Models" href="http://www.spinonesolutions.com/2009/10/magento-part-ii-models/">Part II : Models</a></li>
<li><a title="Part III : Controllers" href="http://www.spinonesolutions.com/2009/10/magento-part-iii-controllers/">Part III : Controllers</a></li>
<li><a title="Part IV : Extending Models" href="http://www.spinonesolutions.com/2009/10/magento-part-iv-extending-models/">Part IV : Extending Models</a></li>
<li><a title="Part V: Data Layer" href="http://www.spinonesolutions.com/2009/10/magento-part-v-data-layer/">Part V : Data Layer</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2009/10/magento-part-iv-extending-models/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Magento &#8211; Part III : Controllers</title>
		<link>http://www.spinonesolutions.com/2009/10/magento-part-iii-controllers/</link>
		<comments>http://www.spinonesolutions.com/2009/10/magento-part-iii-controllers/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 16:38:05 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Controller]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=392</guid>
		<description><![CDATA[The Problem:
I need to write Part III of the Magento series.
The Solutions:
This article&#8230; TADA!
First, let’s talk about the controller.  The default controller for a module is always named IndexController.php.  If you haven’t requested a specific controller (in the URL), than the system is going to look for IndexController.php and load it.  Similarly, the default Magento [...]]]></description>
			<content:encoded><![CDATA[<h2>The Problem:</h2>
<p>I need to write Part III of the Magento series.</p>
<h2>The Solutions:</h2>
<p>This article&#8230; TADA!</p>
<p>First, let’s talk about the controller.  The default controller for a module is always named <strong>IndexController.php</strong>.  If you haven’t requested a specific controller (in the URL), than the system is going to look for <strong>IndexController.php</strong> and load it.  Similarly, the default Magento action is <strong>indexAction()</strong>.</p>
<p>Applying this logic to my custom Module; if I simply type {base}/spinonesolutions/ into the address bar, Magento is going to load up <strong>Spinonesolutions_Helloworld_IndexController</strong> and invoke <strong>indexAction()</strong>.  Remember that “spinonesolutions” is the frontname that I defined for this module in the <strong>config.xml</strong> (See <a title="Part II : Models" href="http://www.spinonesolutions.com/2009/10/magento-part-ii-models/">Part II : Models</a> for source).</p>
<pre class="php" name="code">&lt;?php
//IndexController is the default controller
//EG: http://localhost/spinonesolutions/
//Notice there's no parameters being passed as a parameter (Nothing after trailing "/")
//IndexController will be called since it's the default.
//"spinonesolutions" is the frontname as defined in confg.xml
class Spinonesolutions_Helloworld_IndexController extends Mage_Core_Controller_Front_Action {
      //indexAction is the default Action for any controller
      function indexAction() {
            echo "indexAction";
            $helloworld = Mage::getModel("spinonesolutions_helloworld/helloworld");
            $helloworld-&gt;helloworld("helloworld");
      }
}</pre>
<pre class="xml" name="code">&lt;?xml version=<em>"1.0"</em> encoding=<em>"UTF-8"</em> ?&gt;
&lt;config&gt;
      &lt;modules&gt;
            &lt;Spinonesolutions_Helloworld&gt;
                  &lt;version&gt;0.1.0&lt;/version&gt;
            &lt;/Spinonesolutions_Helloworld&gt;
      &lt;/modules&gt;
    &lt;frontend&gt;
        &lt;routers&gt;
            &lt;spinonesolutions&gt;      &lt;!-- I make this match my front name but I'm not sure it matters --&gt;
                &lt;use&gt;standard&lt;/use&gt; &lt;!-- Use standard routing as opposed to admin.  IE: frontend vs admin --&gt;
                &lt;args&gt;
                    &lt;module&gt;Spinonesolutions_Helloworld&lt;/module&gt;  &lt;!-- The module to search for controllers --&gt;
                    &lt;frontName&gt;spinonesolutions&lt;/frontName&gt; &lt;!-- The first descriminator in the path.  "spinonesolutions" in http://localhost/spinonesolutions/ --&gt;
                &lt;/args&gt;
            &lt;/spinonesolutions&gt;
        &lt;/routers&gt;
    &lt;/frontend&gt;
      &lt;global&gt;
            &lt;models&gt;
                  &lt;spinonesolutions_helloworld&gt; &lt;!-- This is used when istanting your Model EG: Mage::getModel("spinonesolutions_helloworld/hellworld") --&gt;
                        &lt;class&gt;Spinonesolutions_Helloworld_Model&lt;/class&gt;      &lt;!-- That class to use when isntanting objects of type above. --&gt;
                  &lt;/spinonesolutions_helloworld&gt;
            &lt;/models&gt;
      &lt;/global&gt;
&lt;/config&gt;</pre>
<p>Let’s start adding pieces onto our URL and explore what happens in Magento.  Adding one piece yields {base}/spinonesolutions/foo/.  This is asking Magento to invoke the <strong>indexAction()</strong> of the <strong>FooController</strong>, more specifically <strong>Spinonesolutions_Helloworld_FooController</strong>.</p>
<p>That Class doesn’t exist in our current code base so we need to create it.  Following Magento’s naming conventions and our choices in config.xml the filename and path for <strong>Spinonesolutions_Helloworld_FooController</strong> must be: <strong>/Spinonesolutions/Helloworld/controllers/FooController.php</strong>.</p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Helloworld_FooController extends Mage_Core_Controller_Front_Action {
      //indexAction is the default Action for any controller
      function indexAction() {
            echo "Spinonesolutions_Helloworld_FooController.indexAction()";
      }    
}</pre>
<p>Now we’ll take it to the next level and add another piece to the URL yielding {base}/spinonesolutions/foo/bar/.  This is asking Magento to invoke the <strong>barAction()</strong> of the <strong>FooController</strong> (<strong>Spinonesolutions_Helloworld_FooController</strong>). Let’s add that action to our growing controller.</p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Helloworld_FooController extends Mage_Core_Controller_Front_Action {
      //indexAction is the default Action for any controller
      function indexAction() {
            echo "Spinonesolutions_Helloworld_FooController.indexAction()";
      }

      //{base}/spinonesolutions/bar/
      function barAction() {
            echo "Spinonesolutions_Helloworld_FooController.barAction()";
      }
}</pre>
<p>That covers the basics for controllers.  Setup your route in the <strong>config.xml</strong> then follow the proper naming conventions when creating your classes and you should be all set.</p>
<p>Download the source &#8211; <a href="http://www.spinonesolutions.com/wp-content/uploads/2009/10/Helloworld_v2.rar">Helloworld_v2</a></p>
<ol>
<li><a title="Part I : Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">Part I : Custom Module</a></li>
<li><a title="Part II : Models" href="http://www.spinonesolutions.com/2009/10/magento-part-ii-models/">Part II : Models</a></li>
<li><a title="Part III : Controllers" href="http://www.spinonesolutions.com/2009/10/magento-part-iii-controllers/">Part III : Controllers</a></li>
<li><a title="Part IV : Extending Models" href="http://www.spinonesolutions.com/2009/10/magento-part-iv-extending-models/">Part IV : Extending Models</a></li>
<li><a title="Part V: Data Layer" href="http://www.spinonesolutions.com/2009/10/magento-part-v-data-layer/">Part V : Data Layer</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2009/10/magento-part-iii-controllers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Magento &#8211; Part II : Models</title>
		<link>http://www.spinonesolutions.com/2009/10/magento-part-ii-models/</link>
		<comments>http://www.spinonesolutions.com/2009/10/magento-part-ii-models/#comments</comments>
		<pubDate>Fri, 02 Oct 2009 16:18:49 +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=362</guid>
		<description><![CDATA[The Problem:
You need to work with Magento Models, how chic!
The Solution:
Well, let&#8217;s be honest&#8230; I don&#8217;t have THE solution, but I do have some useful snippets of information to pass along.
Models are the meat of an MVC application.  They contain the definitions for your application&#8217;s components.  Stop for a moment and think conceptually about your [...]]]></description>
			<content:encoded><![CDATA[<h2>The Problem:</h2>
<p>You need to work with Magento Models, how chic!</p>
<h2>The Solution:</h2>
<p>Well, let&#8217;s be honest&#8230; I don&#8217;t have THE solution, but I do have some useful snippets of information to pass along.</p>
<p>Models are the meat of an MVC application.  They contain the definitions for your application&#8217;s components.  Stop for a moment and think conceptually about your application.  Anything that is represented by a database table is most likely going to be a Model.  Anything that can be mentally packaged up and labeled could be a Model.  How are Models built, used, and made use of in Magento?  Let&#8217;s find out.</p>
<p>In the Previous <a title="Part I - Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">post</a> I showed you how to create a custom Module and one of the main pieces of that Module was the Model <strong>Helloworld</strong>.</p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Helloworld_Model_Helloworld extends Varien_Object {
  function __construct() {
    parent::__construct();
  }

  function helloworld($arg) {
    echo "&lt;br&gt;Hello World! My argument is : " . $arg;
  }
}</pre>
<p>I&#8217;m going to examine it now, in more detail, to flush out some of the intricacies of Magento.</p>
<p>Notice the class definition:</p>
<p><strong>Spinonesolutions_Helloworld_Model_Helloworld</strong></p>
<p>It&#8217;s important to maintain this naming convention since Magento uses an autoloader to load class files when they&#8217;re called for.  If they&#8217;re not named correctly it will look at the wrong place in the file system for the file which SHOULD contain the class it&#8217;s looking for, but alas it will not be there, and thus; it will not find it and you will receive an error.</p>
<p>Deconstructing the above:</p>
<p><strong>Spinonsolutions_Helloworld_Model_Helloworld</strong><br />
{Namespace}_{Module}_Model_{Model}.php</p>
<p>Let’s look at some permutations to get a deeper understanding:</p>
<p><strong>Spinonesolutions_Helloworld_Model_Worldhello</strong><br />
\Spinonesolutions\Helloworld\Model\Worldhello.php</p>
<p><strong>Spinonesolutions_Helloworld_Model_Foo_Bar<br />
</strong>\Spinonesolutions\Helloworld\Model\Foo\Bar.php</p>
<p><strong>Spinonesolutions_Helloworld_Model_Foo_Helloworld<br />
</strong>\Spinonesolutions\Helloworld\Model\Foo\Helloworld.php</p>
<p>Picking up the pattern?  Good!</p>
<p> The _<strong>_consruct</strong> method is called when Magento builds an instance of this Model.  My constructors always contain, at least, a call to the parent constructor and sometimes more depending on the Model.</p>
<p> To instantiate an instance of a Model use <strong>Mage::getModel($modelClass,$arguments)</strong> or <strong>Mage::getSingleton($modelClass,$arguments)</strong>.  The parameter <strong>$modelClass</strong> is a string, the construction of which is partially determined by the <strong>config.xml</strong> and partly by the Model’s class definition.  Let’s look at <strong>IndexController</strong> from <a title="Part I: Magento Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">Part I</a>, line 23.</p>
<pre class="php" name="code">&lt;?php
//IndexController is the default controller
//EG: http://localhost/spinonesolutions/
//Notice there's no parameters being passed as a parameter (Nothing after trailing "/")
//IndexController will be called since it's the default.
//"spinonesolutions" is the frontname as defined in confg.xml
class Spinonesolutions_Helloworld_IndexController extends Mage_Core_Controller_Front_Action {

  //indexAction is the default Action for any controller
  function indexAction() {
    echo "indexAction";
    $helloworld = Mage::getModel("spinonesolutions_helloworld/helloworld");
    $helloworld-&gt;helloworld("helloworld");
  }
}</pre>
<p>The piece of <strong>$modelClass</strong> that comes before the backslash (spinonesolutions_helloworld) is defined in the <strong>config.xml</strong> file included in the <strong>etc</strong> directory of your Module.</p>
<pre class="xml" name="code">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;config&gt;
&lt;modules&gt;
&lt;Spinonesolutions_Helloworld&gt;
&lt;version&gt;0.1.0&lt;/version&gt;
&lt;/Spinonesolutions_Helloworld&gt;
&lt;/modules&gt;
&lt;frontend&gt;
&lt;routers&gt;
&lt;spinonesolutions&gt; &lt;!-- I make this match my front name but I'm not sure it matters --&gt;
&lt;use&gt;standard&lt;/use&gt; &lt;!-- Use standard routing as opposed to admin. IE: frontend vs admin --&gt;
&lt;args&gt;
&lt;module&gt;Spinonesolutions_Helloworld&lt;/module&gt; &lt;!-- The module to search for controllers --&gt;
&lt;frontName&gt;spinonesolutions&lt;/frontName&gt; &lt;!-- The first descriminator in the path. "spinonesolutions" in http://localhost/spinonesolutions/ --&gt;
&lt;/args&gt;
&lt;/spinonesolutions&gt;
&lt;/routers&gt;
&lt;/frontend&gt;
&lt;global&gt;
&lt;models&gt;
&lt;spinonesolutions_helloworld&gt; &lt;!-- This is used when istanting your Model EG: Mage::getModel("spinonesolutions_helloworld/hellworld") --&gt;
&lt;class&gt;Spinonesolutions_Helloworld_Model&lt;/class&gt; &lt;!-- That class to use when isntanting objects of type above. --&gt;
&lt;/spinonesolutions_helloworld&gt;
&lt;/models&gt;
&lt;/global&gt;
&lt;/config&gt;</pre>
<p>Notice the <strong>models</strong> element.  It’s defining a label for the class (and folder) <strong>Spinonesolutions_Helloworld_Model</strong>.  Said in another way; given <strong>spinonesolutions_helloworld</strong>, the <strong>models</strong> element tells Magento what class and, by naming convention, what folder to look in for the second piece; that which comes after the backslash.</p>
<p>The piece that comes after the backslash (helloworld) tells Magento what particular Model you’re looking for.  In my example, it’s simply <strong>helloworld</strong>, so the autoloader is going to be looking for a file named <strong>Helloworld.php</strong> that contains a class definition <strong>Spinonesolutions_Helloworld_Model_Helloworld</strong>.  Lets extend the permutations that we used earlier adding how to instantiate each.</p>
<p><strong>Spinonesolutions_Helloworld_Model_Worldhello</strong><br />
\Spinonesolutions\Helloworld\Model\Worldhello.php<br />
$objModel = Mage::getModel(‘spinonesolutions_helloworld/worldhello’);</p>
<p><strong>Spinonesolutions_Helloworld_Model_Foo_Bar<br />
</strong>\Spinonesolutions\Helloworld\Model\Foo\Bar.php<br />
$objModel = Mage::getModel(‘spinonesolutions_helloworld/foo_bar’);</p>
<p><strong>Spinonesolutions_Helloworld_Model_Foo_Helloworld<br />
</strong>\Spinonesolutions\Helloworld\Model\Foo\Helloworld.php<br />
$objModel = Mage::getModel(‘spinonesolutions_helloworld/foo_helloworld’);</p>
<p>A great way to get a handle on how the naming conventions work is to meander through the <strong>core</strong> and note of name of the file and the folder structure it’s been placed in; then compare that to the class definition contained within.</p>
<p>One more time; since it took me a while to figure this out!</p>
<p><span style="color: #ff0000;">\Spinonesolutions\Helloworld\Model</span>\<span style="color: #3366ff;">Helloworld.php</span></p>
<p><span style="color: #ff0000;">Spinonesolutions_Helloworld_Model</span>_<span style="color: #3366ff;">Helloworld</span></p>
<p><span style="color: #339966;">&lt;spinonesolutions_helloworld&gt;</span><br />
    &lt;class&gt;<span style="color: #ff0000;">Spinonesolutions_Helloworld_Model</span>&lt;/class&gt;<br />
<span style="color: #339966;">&lt;/spinonesolutions_helloworld&gt;<strong></strong></span></p>
<p>$objModel = Mage::getModel(‘<span style="color: #339966;">spinonesolutions_helloworld</span>/<span style="color: #3366ff;">helloworld</span>);</p>
<p>Do you see it!  Do you!?</p>
<p>One awesome, and very useful, property of Models is that they can extend any other Model you want.  This is, in general, how you extend <strong>core</strong> Models with your own functionality.</p>
<p>This is absolutely essential when you want to add on to the Magento code base.  If you just fire up your text editor and make your changes to the <strong>core,</strong> the next time you upgrade Magento, there’s a relatively good chance you’ll lose all your work.</p>
<p>That’s all for Models! Not really though, I’ve just covered the basics here, read on for more as I cover extending!</p>
<p>Download the source &#8211; <a href="http://www.spinonesolutions.com/wp-content/uploads/2009/09/Helloworld.rar">Helloworld</a></p>
<ol>
<li><a title="Part I : Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">Part I : Custom Module</a></li>
<li><a title="Part II : Models" href="http://www.spinonesolutions.com/2009/10/magento-part-ii-models/">Part II : Models</a></li>
<li><a title="Part III : Controllers" href="http://www.spinonesolutions.com/2009/10/magento-part-iii-controllers/">Part III : Controllers</a></li>
<li><a title="Part IV : Extending Models" href="http://www.spinonesolutions.com/2009/10/magento-part-iv-extending-models/">Part IV : Extending Models</a></li>
<li><a title="Part V: Data Layer" href="http://www.spinonesolutions.com/2009/10/magento-part-v-data-layer/">Part V : Data Layer</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2009/10/magento-part-ii-models/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Magento &#8211; Part I : Custom Module</title>
		<link>http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/</link>
		<comments>http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 04:00:01 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Module]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=336</guid>
		<description><![CDATA[This article was written while using Magento v1.3.2.3.
Greetings!  This is installment number one of the the exiting Magento Custom Module series.  There&#8217;s basically two paths to the end of the fairytale:
Path 1: You follow this series and get down and dirty with Magento, learning a lot along the way.
Path 2: You go out and download [...]]]></description>
			<content:encoded><![CDATA[<p>This article was written while using Magento v1.3.2.3.</p>
<p>Greetings!  This is installment number one of the the exiting <em>Magento Custom Module</em> series.  There&#8217;s basically two paths to the end of the fairytale:</p>
<p>Path 1: You follow this series and get down and dirty with Magento, learning a lot along the way.</p>
<p>Path 2: You go out and download the Module Creator (<a href="http://www.magentocommerce.com/wiki/custom_module_with_custom_database_table">http://www.magentocommerce.com/wiki/custom_module_with_custom_database_table</a>) and head straight to GO!</p>
<p>Your choice!</p>
<p>Note: Magento is an MVC application so I&#8217;m going to assume you have a basic understanding of <a title="MVC" href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" target="_blank">MVC</a>.  Also, Magento is built (I believe) on the <a title="Zend Framework" href="http://framework.zend.com/" target="_blank">Zend framework</a>, so there&#8217;s some Zend specific syntax that I&#8217;m also not going to dive into.  Huzzzah!</p>
<h2>The Problem:</h2>
<p>You need to create a custom Module in Magento!  Why&#8230;?  Hell, I don&#8217;t know; you just do.  That&#8217;s enough of that, let&#8217;s get down to it.</p>
<h2>The Solution:</h2>
<p>All of your customizations need to go into the [root]\app\code\local folder.  This is where Magento expects to find them and it&#8217;s also a factor in maintaining your upgrade path.  When the next version of Magento is released you&#8217;ll be able to backup your &#8220;local&#8221; folder and blow away everything else.</p>
<p>Before we get too far into this let’s setup our development environment, go to:<br />
Admin -&gt; System -&gt; Cache Management: Cache Control – All Cache = Disable</p>
<p>This will save you many hours of self-torture while you’re developing.</p>
<p>A couple of other developer settings that I’ve found helpful:<br />
Admin -&gt; System -&gt; Configuration -&gt; Developer: Debug &#8211; Profiler = yes<br />
Log Settings &#8211; Enabled = yes</p>
<p>Now open up [root]\index.php and at the very end you&#8217;ll see three lines that are commented out; un-comment them and save.</p>
<p>Finally, turn SEO friendly URLs on:<br />
Admin -&gt; System -&gt; Configuration -&gt; Web: Search Engine Optimization &#8211; Use Web Server Rewrites = Yes</p>
<p>All of the URLs that I’ll be presenting as examples below assume that SEO friendly URLs are enabled.</p>
<p>Magento is now correctly configured for development so let’s dive into building a custom module.</p>
<p>Sample file structure:<br />
[root]\app\code\local\{Namespace}\{Modulename}<br />
[root]\app\code\local\{Namespace}\{Modulename}\controllers<br />
[root]\app\code\local\{Namespace}\{Modulename}\etc<br />
[root]\app\code\local\{Namespace}\{Modulename}\etc\config.xml<br />
[root]\app\code\local\{Namespace}\{Modulename}\Helper<br />
[root]\app\code\local\{Namespace}\{Modulename}\Helper\Data.php<br />
[root]\app\code\local\{Namespace}\{Modulename}\Model<br />
[root]\app\code\local\{Namespace}\{Modulename}\{Modulename}.php</p>
<p><strong>{Namespace}</strong> is a user defined variable.  Basically it&#8217;s just a mechanism that allows the user to create disparate classes that would otherwise have the same names.<br />
<strong>{Modulename}</strong> this is the name of your module.</p>
<p>For my examples I&#8217;m going to use &#8220;Spinonesolutions&#8221; as my namespace and &#8220;Helloworld&#8221; as my Module.  I&#8217;m not entirely sure if it matters or not, but as a general rule I always capitalize the first letter and leave the rest lower case.  Don&#8217;t use underscores in your names either, we&#8217;ll see why later.</p>
<p><strong>controllers</strong> is where all the controllers go, crazy right?  I’ll get into the controller structure in another part of this series.  For now a sample will suffice.</p>
<pre class="php" name="code">&lt;?php
//IndexController is the default controller
//EG: http://localhost/spinonesolutions/
//Notice there's no parameters being passed as a parameter (Nothing after trailing "/")
//IndexController will be called since it's the default.
//"spinonesolutions" is the frontname as defined in confg.xml
class Spinonesolutions_Helloworld_IndexController extends Mage_Core_Controller_Front_Action {
  //indexAction is the default Action for any controller
  function indexAction() {
    echo "indexAction";
    $helloworld = Mage::getModel("spinonesolutions_helloworld/helloworld");
    $helloworld-&gt;helloworld("helloworld");
  }
}</pre>
<p><strong>Data.php</strong> is just a helper file for the Magento internals, I&#8217;m not exactly sure what it does but it appears to be exactly the same in every module except for its class definition.</p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Helloworld_Helper_Data extends Mage_Core_Helper_Abstract {

}</pre>
<p><strong>Model</strong> holds all of the models for your module.  It&#8217;s customary to name your main model after your {Modulename}.  You’ll most likely have at least one model and if you browse through the Magento core you&#8217;ll notice that most modules contain many models.</p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Helloworld_Model_Helloworld extends Varien_Object {
  function __construct() {
    parent::__construct();
  }

  function helloworld($arg) {
    echo "&lt;br&gt;Hello World! My argument is : " . $arg;
  }
}</pre>
<p><strong>config.xml</strong> is where you connect all your code up to Magento.  There&#8217;s a lot of voodoo going on in here and I&#8217;m not entirely sure how it all works.  I might even write a full post on the <strong>config.xml</strong> as a forthcoming part of this series.</p>
<pre class="xml" name="code">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;config&gt;
 &lt;modules&gt;
   &lt;Spinonesolutions_Helloworld&gt;
   &lt;version&gt;0.1.0&lt;/version&gt;
   &lt;/Spinonesolutions_Helloworld&gt;
 &lt;/modules&gt;
 &lt;frontend&gt;
   &lt;routers&gt;
     &lt;spinonesolutions&gt;    &lt;!-- I make this match my front name but I'm not sure it matters --&gt;
       &lt;use&gt;standard&lt;/use&gt;    &lt;!-- Use standard routing as opposed to admin.  IE: frontend vs admin --&gt;
       &lt;args&gt;
         &lt;module&gt;Spinonesolutions_Helloworld&lt;/module&gt;    &lt;!-- The module to search for controllers --&gt;
         &lt;frontName&gt;spinonesolutions&lt;/frontName&gt;    &lt;!-- The first descriminator in the path.  "spinonesolutions" in http://localhost/spinonesolutions/ --&gt;
       &lt;/args&gt;
     &lt;/spinonesolutions&gt;
   &lt;/routers&gt;
 &lt;/frontend&gt;
 &lt;global&gt;
   &lt;models&gt;
     &lt;spinonesolutions_helloworld&gt;    &lt;!-- This is used when istanting your Model EG: Mage::getModel("spinonesolutions_helloworld/hellworld") --&gt;
       &lt;class&gt;Spinonesolutions_Helloworld_Model&lt;/class&gt;    &lt;!-- That class to use when isntanting objects of type above. --&gt;
     &lt;/spinonesolutions_helloworld&gt;
   &lt;/models&gt;
 &lt;/global&gt;
&lt;/config&gt;</pre>
<p>That takes care of all the code needed in the module directory. There’s one more configuration file we need to create and it’s an exception to the local folder rule:<br />
[root]\app\etc\modules\{Namespace}_{Modulename}.xml</p>
<pre class="xml" name="code">&lt;?xml version="1.0"?&gt;
&lt;config&gt;
 &lt;modules&gt;
   &lt;Spinonesolutions_Helloworld&gt;
     &lt;active&gt;true&lt;/active&gt;
     &lt;codePool&gt;local&lt;/codePool&gt;
   &lt;/Spinonesolutions_Helloworld&gt;
 &lt;/modules&gt;
&lt;/config&gt;</pre>
<p>This file tells Magento that there&#8217;s a new module out there that it needs to load.  Alternatively, you can name your file [root]\app\etc\modules\{Namespace}_All.xml to tell Magento to load up all the modules in that namespace.</p>
<p>Once you have this file in place you can navigate to Admin-&gt;System -&gt; Configuration -&gt; Advanced and you should see your module enabled here.</p>
<p>You now have a functioning custom module, hurray!</p>
<p>Download the source &#8211; <a href="http://www.spinonesolutions.com/wp-content/uploads/2009/09/Helloworld.rar">Helloworld</a></p>
<ol>
<li><a title="Part I : Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">Part I : Custom Module</a></li>
<li><a title="Part II : Models" href="http://www.spinonesolutions.com/2009/10/magento-part-ii-models/">Part II : Models</a></li>
<li><a title="Part III : Controllers" href="http://www.spinonesolutions.com/2009/10/magento-part-iii-controllers/">Part III : Controllers</a></li>
<li><a title="Part IV : Extending Models" href="http://www.spinonesolutions.com/2009/10/magento-part-iv-extending-models/">Part IV : Extending Models</a></li>
<li><a title="Part V: Data Layer" href="http://www.spinonesolutions.com/2009/10/magento-part-v-data-layer/">Part V : Data Layer</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>JavaScript reports 0 (Zero) Height and Width for hidden image</title>
		<link>http://www.spinonesolutions.com/2009/07/javascript-reports-0-zero-height-and-width-for-hidden-image/</link>
		<comments>http://www.spinonesolutions.com/2009/07/javascript-reports-0-zero-height-and-width-for-hidden-image/#comments</comments>
		<pubDate>Thu, 09 Jul 2009 23:00:14 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[FF]]></category>
		<category><![CDATA[FireFox]]></category>
		<category><![CDATA[IE]]></category>
		<category><![CDATA[Internet Explorer]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=298</guid>
		<description><![CDATA[The Problem:
I was recently modifying an image gallery for a customer that used a pretty slick JavaScript Carousel for the presentation.  The Basic idea was that the images were all outputted within an LI, hidden via CSS, and then the JavaScript carousel used that LI as the datasource to build the gallery.
Everything worked great except [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem:</h3>
<p>I was recently modifying an image gallery for a customer that used a pretty slick JavaScript Carousel for the presentation.  The Basic idea was that the images were all outputted within an LI, hidden via CSS, and then the JavaScript carousel used that LI as the datasource to build the gallery.</p>
<p>Everything worked great except that the images were being re-sized and their aspect ratio was not being maintained.  The solution was to obtain their original size so that the aspect ratio could be computed, and then applied during the re-sizing process.</p>
<p>The issue I ran into is that JavaScript (jQuery) always reported that the height and width was 0 (zero) for the images.</p>
<p>After some digging I found that elements marked &#8220;display:none&#8221; don&#8217;t <em>have</em> to load their hidden contents into the DOM and therefore there was no IMG object for JavaScript to report on!</p>
<div id="attachment_323" class="wp-caption aligncenter" style="width: 710px"><a href="http://www.spinonesolutions.com/wp-content/uploads/2009/07/ie11.jpg"><img class="size-medium wp-image-323" title="IE" src="http://www.spinonesolutions.com/wp-content/uploads/2009/07/ie11-700x525.jpg" alt="IE" width="700" height="525" /></a><p class="wp-caption-text">IE</p></div>
<div id="attachment_324" class="wp-caption aligncenter" style="width: 710px"><a href="http://www.spinonesolutions.com/wp-content/uploads/2009/07/ie21.jpg"><img class="size-medium wp-image-324" title="IE Display None" src="http://www.spinonesolutions.com/wp-content/uploads/2009/07/ie21-700x525.jpg" alt="IE Display None" width="700" height="525" /></a><p class="wp-caption-text">IE Display None</p></div>
<div id="attachment_325" class="wp-caption aligncenter" style="width: 710px"><a href="http://www.spinonesolutions.com/wp-content/uploads/2009/07/moz11.jpg"><img class="size-medium wp-image-325" title="Mozilla Display None" src="http://www.spinonesolutions.com/wp-content/uploads/2009/07/moz11-700x521.jpg" alt="Mozilla Display None" width="700" height="521" /></a><p class="wp-caption-text">Mozilla Display None</p></div>
<pre class="html" name="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"&gt;

&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"&gt;
&lt;title&gt;Untitled Document&lt;/title&gt;
&lt;style type="text/css" media="screen"&gt;
 #myImage {
 border:1px solid red;
 }
 .hidden {
 display:none;
 float:left;
 margin:10px;
 }
&lt;/style&gt;

&lt;script type="text/javascript" src="scripts/jquery-1.3.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
$(document).ready(function(){
 var imgHeight = $("#myImage").height();
 var imgWidth = $("#myImage").width();
 alert("Height = " + imgHeight + "px\nWidth = " + imgWidth + "px");

});
&lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;

 &lt;p&gt;
 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam hendrerit mauris quis ante mollis sit amet dapibus erat semper. Nunc vitae nisi sapien, at ultricies neque. Ut interdum eleifend iaculis. Ut a auctor turpis. Sed in neque eget nulla vestibulum porttitor. Donec urna magna, feugiat vel interdum vitae, vestibulum vel nibh. Integer pellentesque bibendum pulvinar. Praesent orci turpis, porttitor id laoreet eget, fringilla in tortor. Nam sollicitudin mi vitae odio luctus nec fringilla mauris rutrum. Aenean tristique mi felis. Fusce eget justo eros, vel rhoncus dui.
 &lt;div&gt;&lt;img id="myImage" src="images/lol_cat.jpg" /&gt;&lt;/div&gt;
 &lt;/p&gt;
 &lt;p&gt;
 Curabitur feugiat ornare sapien, eu placerat magna aliquet placerat. Curabitur at vestibulum felis. Maecenas sagittis, lorem ac imperdiet mattis, nisi diam porta nibh, vel molestie odio turpis ut nisl. In hac habitasse platea dictumst. Quisque augue massa, tempor nec molestie id, facilisis non tortor. Pellentesque dapibus, massa a ornare placerat, erat urna blandit justo, sagittis sodales lectus odio et lacus. Suspendisse congue ipsum quis massa ornare vel vehicula sapien gravida. Mauris pretium elit ut mi malesuada pellentesque. Phasellus pulvinar nulla at sem eleifend ac sollicitudin est tincidunt. Proin lorem urna, viverra quis gravida in, scelerisque at dui.
 &lt;/p&gt;
 &lt;p&gt;
 Nullam et erat vitae lacus porttitor pharetra. Nullam tincidunt tempor fermentum. Nulla rutrum, urna ac dapibus consequat, nisl lectus commodo arcu, ultrices auctor ante elit eget enim. Etiam enim massa, volutpat in venenatis mattis, placerat id sapien. Duis vel ante sit amet neque accumsan sollicitudin ac consequat sapien. Proin dapibus rhoncus libero vitae tristique. Quisque at neque in metus sodales vestibulum. Cras lacinia eleifend sapien, a pellentesque arcu pellentesque at. In hac habitasse platea dictumst. Ut porta sodales euismod. Donec ligula arcu, aliquet sed pretium vitae, aliquam quis lorem. Morbi fermentum semper volutpat. Sed porttitor posuere augue et imperdiet. Cras gravida diam at diam accumsan accumsan. Duis turpis erat, mollis ac tempor eu, elementum faucibus mi. Fusce et urna id dui pharetra consectetur. Nulla facilisis feugiat libero, eu ullamcorper purus placerat sed. Donec nisi sem, volutpat eu pellentesque non, consequat eget nibh.
 &lt;/p&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<h3>The Solution:</h3>
<p>The solution to this issue is to alter the method in which we hide the content.  Using &#8220;visibility:hidden&#8221; works; the height and width are reported correctly, but the browser allocates space for the content which &#8220;breaks&#8221; the layout.</p>
<div id="attachment_326" class="wp-caption aligncenter" style="width: 710px"><a href="http://www.spinonesolutions.com/wp-content/uploads/2009/07/ie31.jpg"><img class="size-medium wp-image-326" title="IE Visibility Hidden" src="http://www.spinonesolutions.com/wp-content/uploads/2009/07/ie31-700x521.jpg" alt="IE Visibility Hidden" width="700" height="521" /></a><p class="wp-caption-text">IE Visibility Hidden</p></div>
<pre class="html" name="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"&gt;

&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"&gt;
&lt;title&gt;Untitled Document&lt;/title&gt;
&lt;style type="text/css" media="screen"&gt;
 #myImage {
 border:1px solid red;
 }
 .hidden {
 visibility:hidden;
 float:left;
 margin:10px;
 }
&lt;/style&gt;

&lt;script type="text/javascript" src="scripts/jquery-1.3.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
$(document).ready(function(){
 var imgHeight = $("#myImage").height();
 var imgWidth = $("#myImage").width();
 alert("Height = " + imgHeight + "px\nWidth = " + imgWidth + "px");

});
&lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;

 &lt;p&gt;
 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam hendrerit mauris quis ante mollis sit amet dapibus erat semper. Nunc vitae nisi sapien, at ultricies neque. Ut interdum eleifend iaculis. Ut a auctor turpis. Sed in neque eget nulla vestibulum porttitor. Donec urna magna, feugiat vel interdum vitae, vestibulum vel nibh. Integer pellentesque bibendum pulvinar. Praesent orci turpis, porttitor id laoreet eget, fringilla in tortor. Nam sollicitudin mi vitae odio luctus nec fringilla mauris rutrum. Aenean tristique mi felis. Fusce eget justo eros, vel rhoncus dui.
 &lt;div&gt;&lt;img id="myImage" src="images/lol_cat.jpg" /&gt;&lt;/div&gt;
 &lt;/p&gt;
 &lt;p&gt;
 Curabitur feugiat ornare sapien, eu placerat magna aliquet placerat. Curabitur at vestibulum felis. Maecenas sagittis, lorem ac imperdiet mattis, nisi diam porta nibh, vel molestie odio turpis ut nisl. In hac habitasse platea dictumst. Quisque augue massa, tempor nec molestie id, facilisis non tortor. Pellentesque dapibus, massa a ornare placerat, erat urna blandit justo, sagittis sodales lectus odio et lacus. Suspendisse congue ipsum quis massa ornare vel vehicula sapien gravida. Mauris pretium elit ut mi malesuada pellentesque. Phasellus pulvinar nulla at sem eleifend ac sollicitudin est tincidunt. Proin lorem urna, viverra quis gravida in, scelerisque at dui.
 &lt;/p&gt;
 &lt;p&gt;
 Nullam et erat vitae lacus porttitor pharetra. Nullam tincidunt tempor fermentum. Nulla rutrum, urna ac dapibus consequat, nisl lectus commodo arcu, ultrices auctor ante elit eget enim. Etiam enim massa, volutpat in venenatis mattis, placerat id sapien. Duis vel ante sit amet neque accumsan sollicitudin ac consequat sapien. Proin dapibus rhoncus libero vitae tristique. Quisque at neque in metus sodales vestibulum. Cras lacinia eleifend sapien, a pellentesque arcu pellentesque at. In hac habitasse platea dictumst. Ut porta sodales euismod. Donec ligula arcu, aliquet sed pretium vitae, aliquam quis lorem. Morbi fermentum semper volutpat. Sed porttitor posuere augue et imperdiet. Cras gravida diam at diam accumsan accumsan. Duis turpis erat, mollis ac tempor eu, elementum faucibus mi. Fusce et urna id dui pharetra consectetur. Nulla facilisis feugiat libero, eu ullamcorper purus placerat sed. Donec nisi sem, volutpat eu pellentesque non, consequat eget nibh.
 &lt;/p&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Almost there.  All we need to do now is get rid of the space that&#8217;s been allocated for the element.  There are a number of different strategies for doing this and you&#8217;ll probably have to pick a particular one based on the other attributes of your layout.  I&#8217;m just going to use &#8220;postition:absolute&#8221; because it&#8217;s an easy one liner.</p>
<div id="attachment_327" class="wp-caption aligncenter" style="width: 710px"><a href="http://www.spinonesolutions.com/wp-content/uploads/2009/07/ie41.jpg"><img class="size-medium wp-image-327" title="IE Visibility Hidden Position Absolute" src="http://www.spinonesolutions.com/wp-content/uploads/2009/07/ie41-700x525.jpg" alt="IE Visibility Hidden Position Absolute" width="700" height="525" /></a><p class="wp-caption-text">IE Visibility Hidden Position Absolute</p></div>
<pre class="html" name="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"&gt;

&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"&gt;
&lt;title&gt;Untitled Document&lt;/title&gt;
&lt;style type="text/css" media="screen"&gt;
 #myImage {
 border:1px solid red;
 }
 .hidden {
 visibility:hidden;
 float:left;
 margin:10px;
 position:absolute;
 }
&lt;/style&gt;

&lt;script type="text/javascript" src="scripts/jquery-1.3.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
$(document).ready(function(){
 var imgHeight = $("#myImage").height();
 var imgWidth = $("#myImage").width();
 alert("Height = " + imgHeight + "px\nWidth = " + imgWidth + "px");

});
&lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;

 &lt;p&gt;
 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam hendrerit mauris quis ante mollis sit amet dapibus erat semper. Nunc vitae nisi sapien, at ultricies neque. Ut interdum eleifend iaculis. Ut a auctor turpis. Sed in neque eget nulla vestibulum porttitor. Donec urna magna, feugiat vel interdum vitae, vestibulum vel nibh. Integer pellentesque bibendum pulvinar. Praesent orci turpis, porttitor id laoreet eget, fringilla in tortor. Nam sollicitudin mi vitae odio luctus nec fringilla mauris rutrum. Aenean tristique mi felis. Fusce eget justo eros, vel rhoncus dui.
 &lt;div&gt;&lt;img id="myImage" src="images/lol_cat.jpg" /&gt;&lt;/div&gt;
 &lt;/p&gt;
 &lt;p&gt;
 Curabitur feugiat ornare sapien, eu placerat magna aliquet placerat. Curabitur at vestibulum felis. Maecenas sagittis, lorem ac imperdiet mattis, nisi diam porta nibh, vel molestie odio turpis ut nisl. In hac habitasse platea dictumst. Quisque augue massa, tempor nec molestie id, facilisis non tortor. Pellentesque dapibus, massa a ornare placerat, erat urna blandit justo, sagittis sodales lectus odio et lacus. Suspendisse congue ipsum quis massa ornare vel vehicula sapien gravida. Mauris pretium elit ut mi malesuada pellentesque. Phasellus pulvinar nulla at sem eleifend ac sollicitudin est tincidunt. Proin lorem urna, viverra quis gravida in, scelerisque at dui.
 &lt;/p&gt;
 &lt;p&gt;
 Nullam et erat vitae lacus porttitor pharetra. Nullam tincidunt tempor fermentum. Nulla rutrum, urna ac dapibus consequat, nisl lectus commodo arcu, ultrices auctor ante elit eget enim. Etiam enim massa, volutpat in venenatis mattis, placerat id sapien. Duis vel ante sit amet neque accumsan sollicitudin ac consequat sapien. Proin dapibus rhoncus libero vitae tristique. Quisque at neque in metus sodales vestibulum. Cras lacinia eleifend sapien, a pellentesque arcu pellentesque at. In hac habitasse platea dictumst. Ut porta sodales euismod. Donec ligula arcu, aliquet sed pretium vitae, aliquam quis lorem. Morbi fermentum semper volutpat. Sed porttitor posuere augue et imperdiet. Cras gravida diam at diam accumsan accumsan. Duis turpis erat, mollis ac tempor eu, elementum faucibus mi. Fusce et urna id dui pharetra consectetur. Nulla facilisis feugiat libero, eu ullamcorper purus placerat sed. Donec nisi sem, volutpat eu pellentesque non, consequat eget nibh.
 &lt;/p&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>All done!  We now have a hidden element and jQuery is reporting the correct dimensions for the img within it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2009/07/javascript-reports-0-zero-height-and-width-for-hidden-image/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mozilla Strict Three Column Layout with UL</title>
		<link>http://www.spinonesolutions.com/2009/06/mozilla-strict-three-column-layout-with-ul/</link>
		<comments>http://www.spinonesolutions.com/2009/06/mozilla-strict-three-column-layout-with-ul/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 15:08:03 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[clearfix]]></category>
		<category><![CDATA[FF]]></category>
		<category><![CDATA[FireFox]]></category>
		<category><![CDATA[UL]]></category>
		<category><![CDATA[Unordered List]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=274</guid>
		<description><![CDATA[The Problem:
Note: This only applies to XHTML 1.0 Strict Doctypes and Mozilla.
I make this type of layout all the time!  Two fixed width columns on either side of a fluid column.  Recently I had to put a list of article teasers into the center (fluid) column.  No problem, I marked up an unordered list, floated [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem:</h3>
<p>Note: This only applies to XHTML 1.0 Strict Doctypes and Mozilla.</p>
<p>I make this type of layout all the time!  Two fixed width columns on either side of a fluid column.  Recently I had to put a list of article teasers into the center (fluid) column.  No problem, I marked up an unordered list, floated the thumbnail to the left and let the title and teaser paragraph do their thing.  The only problem was that in order to get the box model for the &#8220;li&#8221; to fully wrap the inner content I had to apply &#8220;clearfix&#8221; to it.  That&#8217;s when everything broke and I started working on a fix which I shall now share with you!</p>
<p>First things first.  Let&#8217;s go over the three column layout:</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2009/06/three_column_layout.jpg"><img class="aligncenter size-medium wp-image-277" title="Three Column Layout" src="http://www.spinonesolutions.com/wp-content/uploads/2009/06/three_column_layout-548x408.jpg" alt="Three Column Layout" width="548" height="408" /></a></p>
<pre class="html" name="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd</a>"&gt;
&lt;html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>" xml:lang="en" lang="en" dir="ltr"&gt;

&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"&gt;
&lt;title&gt;Untitled Document&lt;/title&gt;
&lt;style type="text/css" media="screen"&gt;
.layout_left {
 background-color:yellow;
 float:left;
 width:250px;
}
.layout_right {
 background-color:green;
 float:right;
 width:250px;
}
.layout_center {
 background-color:grey;
 margin:0px 270px;
}
&lt;/style&gt;

&lt;/head&gt;
&lt;body&gt;

 &lt;div class="layout_left" &gt;
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at elementum mauris. In ultricies lobortis dictum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent pellentesque, tortor nec rutrum auctor, tellus velit feugiat tellus, id consectetur orci augue in lorem. Donec tempor posuere ligula a ullamcorper. Quisque aliquam lacinia convallis. Sed eget placerat nisi. Etiam dignissim gravida lorem sit amet auctor. In hac habitasse platea dictumst. Nunc blandit imperdiet rhoncus. Donec laoreet, nibh sed consectetur posuere, lacus eros adipiscing felis, eleifend eleifend purus libero ut nulla. Duis commodo felis vitae tellus accumsan non ultrices justo feugiat. Curabitur auctor dolor ut mi iaculis dapibus. Nunc posuere dolor in elit scelerisque cursus. Vestibulum libero lacus, auctor at mattis et, pretium eget massa.
 &lt;/div&gt;
 &lt;div class="layout_right &gt;
  Ut placerat tortor sed dui molestie eu fringilla risus ultricies. Phasellus faucibus turpis eu purus lacinia at blandit quam scelerisque. Etiam laoreet purus at augue varius a pellentesque diam accumsan. Nulla sodales auctor nibh, ac vehicula est bibendum a. In vitae quam vel dolor blandit sagittis. Proin ut congue lacus. Nulla facilisi. Sed viverra gravida justo, id feugiat nisl dignissim id. In hac habitasse platea dictumst. Proin faucibus congue pellentesque. Integer nec velit mauris, non ullamcorper leo. Duis sagittis rhoncus tincidunt. Phasellus erat metus, tristique vel lacinia non, tempus sit amet lacus.
 &lt;/div&gt;
 &lt;div class="layout_center &gt;
  Cras ac sapien ipsum. Proin orci eros, consectetur rhoncus tempus nec, ultricies sit amet metus. Vivamus condimentum tellus arcu. Mauris lorem risus, congue in tincidunt nec, tincidunt a diam. Aliquam non diam quis augue pellentesque auctor sed vel velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis ac lacus sit amet arcu imperdiet facilisis quis et turpis. Sed venenatis dignissim ligula at vestibulum. Nulla non ante elit, eu aliquet leo. Sed laoreet nulla ac justo volutpat ac facilisis nulla eleifend. Morbi nibh sapien, tincidunt ut egestas a, imperdiet eu purus. Suspendisse potenti. Sed eget sapien mi.
 &lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Yea!  Hot!  Now I&#8217;m going to add in my list of article teasers and we&#8217;ll see what the problem is:</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2009/06/three_column_layout_broken.jpg"><img class="aligncenter size-medium wp-image-278" title="Three Column Layout Broken" src="http://www.spinonesolutions.com/wp-content/uploads/2009/06/three_column_layout_broken-548x408.jpg" alt="Three Column Layout Broken" width="548" height="408" /></a></p>
<pre class="html" name="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd</a>"&gt;
&lt;html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>" xml:lang="en" lang="en" dir="ltr"&gt;

&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"&gt;
&lt;title&gt;Untitled Document&lt;/title&gt;
&lt;style type="text/css" media="screen"&gt;
.layout_left {
 background-color:yellow;
 float:left;
 width:250px;
}
.layout_right {
 background-color:green;
 float:right;
 width:250px;
}
.layout_center {
 background-color:grey;
 margin:0px 270px;
}

p {
 margin:0 0 1.5em;
}

ul {
 list-style-type:none;
 margin:0px;
 padding:0px;
}
 ul li {
  border:1px solid red;
 }

ul img {
 float:left;
 margin:0px 10px 0 0;
}

&lt;/style&gt;

&lt;/head&gt;
&lt;body&gt;

 &lt;div class="layout_left" &gt;
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at elementum mauris. In ultricies lobortis dictum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent pellentesque, tortor nec rutrum auctor, tellus velit feugiat tellus, id consectetur orci augue in lorem. Donec tempor posuere ligula a ullamcorper. Quisque aliquam lacinia convallis. Sed eget placerat nisi. Etiam dignissim gravida lorem sit amet auctor. In hac habitasse platea dictumst. Nunc blandit imperdiet rhoncus. Donec laoreet, nibh sed consectetur posuere, lacus eros adipiscing felis, eleifend eleifend purus libero ut nulla. Duis commodo felis vitae tellus accumsan non ultrices justo feugiat. Curabitur auctor dolor ut mi iaculis dapibus. Nunc posuere dolor in elit scelerisque cursus. Vestibulum libero lacus, auctor at mattis et, pretium eget massa.
 &lt;/div&gt;
 &lt;div class="layout_right" &gt;
  Ut placerat tortor sed dui molestie eu fringilla risus ultricies. Phasellus faucibus turpis eu purus lacinia at blandit quam scelerisque. Etiam laoreet purus at augue varius a pellentesque diam accumsan. Nulla sodales auctor nibh, ac vehicula est bibendum a. In vitae quam vel dolor blandit sagittis. Proin ut congue lacus. Nulla facilisi. Sed viverra gravida justo, id feugiat nisl dignissim id. In hac habitasse platea dictumst. Proin faucibus congue pellentesque. Integer nec velit mauris, non ullamcorper leo. Duis sagittis rhoncus tincidunt. Phasellus erat metus, tristique vel lacinia non, tempus sit amet lacus.
 &lt;/div&gt;
 &lt;div class="layout_center" &gt;
  &lt;ul&gt;
   &lt;li &gt;
    &lt;img src="images/action_1.gif" alt="All for Good" /&gt;
    &lt;a href=""&gt;All for good&lt;/a&gt;
    &lt;p&gt;Small actions add up to a big difference. All for Good helps you find and share ways to do good.&lt;/p&gt;
   &lt;/li&gt;
   &lt;li&gt;
    &lt;img src="images/action_2.gif" alt="Top Birthday Wish Fundraisers on Causes" /&gt;
    &lt;a href=""&gt;Top Birthday Wish Fundraisers on Causes&lt;/a&gt;
    &lt;p&gt;See the top birthday wish fundraisers on Causes and learn&lt;/p&gt;
   &lt;/li&gt;
   &lt;li&gt;
    &lt;img src="images/action_3.gif" alt="Raise Awareness for Your Cause" /&gt;
    &lt;a href=""&gt;Raise Awareness for Your Cause&lt;/a&gt;
    &lt;p&gt;Set-up a branded credit card through our partner Capital One&amp;reg; for your organization-with your logo.&lt;/p&gt;
   &lt;/li&gt;
   &lt;li&gt;
    &lt;img src="images/action_4.gif" alt="Title/Headline" /&gt;
    &lt;a href=""&gt;Title/Headline&lt;/a&gt;
    &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt.&lt;/p&gt;
   &lt;/li&gt;
  &lt;/ul&gt;
 &lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Snap yo!  That list be broken.  If you hit that with firebug you&#8217;ll see that the box model for that second teaser list item doesn&#8217;t wrap the image because it&#8217;s been floated to the left.  Since the text for that particular item isn&#8217;t that long, it doesn&#8217;t push the box model down past the right hand edge of the image and that is what&#8217;s causing the thrid list item to stack up to the right of it.</p>
<p>The way I usually make the box model wrap floated elements is to apply the &#8220;clearfix&#8221; class to the parent element (the li in our case).</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2009/06/three_column_layout_clearfix.jpg"><img class="aligncenter size-medium wp-image-279" title="Three Column Layout Clearfix" src="http://www.spinonesolutions.com/wp-content/uploads/2009/06/three_column_layout_clearfix-548x398.jpg" alt="Three Column Layout Clearfix" width="548" height="398" /></a></p>
<pre class="html" name="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd</a>"&gt;
&lt;html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>" xml:lang="en" lang="en" dir="ltr"&gt;

&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"&gt;
&lt;title&gt;Untitled Document&lt;/title&gt;
&lt;style type="text/css" media="screen"&gt;
.layout_left {
 background-color:yellow;
 float:left;
 width:250px;
}
.layout_right {
 background-color:green;
 float:right;
 width:250px;
}
.layout_center {
 background-color:grey;
 margin:0px 270px;
}

p {
 margin:0 0 1.5em;
}

ul {
 list-style-type:none;
 margin:0px;
 padding:0px;
}
 ul li {
  border:1px solid red;
  margin:0 0 10px 0;
  padding:0px;
 }

ul img {
 float:left;
 margin:0px 10px 0 0;
}

.clearfix:after {
 content: ".";
 display: block;
 clear: both;
 visibility: hidden;
 line-height: 0;
 height: 0;
}

.clearfix {
 display: inline-block;
}

html[xmlns] .clearfix {
 display: block;
}

* html .clearfix {
 height: 1%;
}

&lt;/style&gt;

&lt;/head&gt;
&lt;body&gt;

 &lt;div class="layout_left" &gt;
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at elementum mauris. In ultricies lobortis dictum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent pellentesque, tortor nec rutrum auctor, tellus velit feugiat tellus, id consectetur orci augue in lorem. Donec tempor posuere ligula a ullamcorper. Quisque aliquam lacinia convallis. Sed eget placerat nisi. Etiam dignissim gravida lorem sit amet auctor. In hac habitasse platea dictumst. Nunc blandit imperdiet rhoncus. Donec laoreet, nibh sed consectetur posuere, lacus eros adipiscing felis, eleifend eleifend purus libero ut nulla. Duis commodo felis vitae tellus accumsan non ultrices justo feugiat. Curabitur auctor dolor ut mi iaculis dapibus. Nunc posuere dolor in elit scelerisque cursus. Vestibulum libero lacus, auctor at mattis et, pretium eget massa.
 &lt;/div&gt;
 &lt;div class="layout_right" &gt;
  Ut placerat tortor sed dui molestie eu fringilla risus ultricies. Phasellus faucibus turpis eu purus lacinia at blandit quam scelerisque. Etiam laoreet purus at augue varius a pellentesque diam accumsan. Nulla sodales auctor nibh, ac vehicula est bibendum a. In vitae quam vel dolor blandit sagittis. Proin ut congue lacus. Nulla facilisi. Sed viverra gravida justo, id feugiat nisl dignissim id. In hac habitasse platea dictumst. Proin faucibus congue pellentesque. Integer nec velit mauris, non ullamcorper leo. Duis sagittis rhoncus tincidunt. Phasellus erat metus, tristique vel lacinia non, tempus sit amet lacus.
 &lt;/div&gt;
 &lt;div class="layout_center" &gt;
  &lt;ul&gt;
   &lt;li class="clearfix" &gt;
    &lt;img src="images/action_1.gif" alt="All for Good" /&gt;
    &lt;a href=""&gt;All for good&lt;/a&gt;
    &lt;p&gt;Small actions add up to a big difference. All for Good helps you find and share ways to do good.&lt;/p&gt;
   &lt;/li&gt;
   &lt;li class="clearfix" &gt;
    &lt;img src="images/action_2.gif" alt="Top Birthday Wish Fundraisers on Causes" /&gt;
    &lt;a href=""&gt;Top Birthday Wish Fundraisers on Causes&lt;/a&gt;
    &lt;p&gt;See the top birthday wish fundraisers on Causes and learn&lt;/p&gt;
   &lt;/li&gt;
   &lt;li class="clearfix" &gt;
    &lt;img src="images/action_3.gif" alt="Raise Awareness for Your Cause" /&gt;
    &lt;a href=""&gt;Raise Awareness for Your Cause&lt;/a&gt;
    &lt;p&gt;Set-up a branded credit card through our partner Capital One&amp;reg; for your organization-with your logo.&lt;/p&gt;
   &lt;/li&gt;
   &lt;li class="clearfix" &gt;
    &lt;img src="images/action_4.gif" alt="Title/Headline" /&gt;
    &lt;a href=""&gt;Title/Headline&lt;/a&gt;
    &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt.&lt;/p&gt;
   &lt;/li&gt;
  &lt;/ul&gt;
 &lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Well that worked, kinda.  It certainly did what it was supposed to do just not what I <em>wanted</em> to do.</p>
<p>The culprint is this line:</p>
<pre class="css" name="code">html[xmls] .clearfix {
display:block;
}</pre>
<h3>The Solution:</h3>
<p>Now that we know the problem, the solution is actually pretty simple.  All we have to do is write a selector to only target &#8220;clearfix&#8221; applied to &#8220;li&#8221;s that are in our three column layout.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2009/06/three_column_layout_fixed.jpg"><img class="aligncenter size-medium wp-image-281" title="three_column_layout_fixed" src="http://www.spinonesolutions.com/wp-content/uploads/2009/06/three_column_layout_fixed-548x408.jpg" alt="three_column_layout_fixed" width="548" height="408" /></a></p>
<pre class="html" name="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd</a>"&gt;
&lt;html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>" xml:lang="en" lang="en" dir="ltr"&gt;

&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"&gt;
&lt;title&gt;Untitled Document&lt;/title&gt;
&lt;style type="text/css" media="screen"&gt;
.layout_left {
 background-color:yellow;
 float:left;
 width:250px;
}
.layout_right {
 background-color:green;
 float:right;
 width:250px;
}
.layout_center {
 background-color:grey;
 margin:0px 270px;
}

p {
 margin:0 0 1.5em;
}

ul {
 list-style-type:none;
 margin:0px;
 padding:0px;
}
 ul li {
  border:1px solid red;
  margin:0 0 10px 0;
  padding:0px;
 }

ul li.clearfix {
  display:inline-block !important;
}

ul img {
 float:left;
 margin:0px 10px 0 0;
}

.clearfix:after {
 content: ".";
 display: block;
 clear: both;
 visibility: hidden;
 line-height: 0;
 height: 0;
}

.clearfix {
 display: inline-block;
}

html[xmlns] .clearfix {
 display: block;
}

* html .clearfix {
 height: 1%;
}

&lt;/style&gt;

&lt;/head&gt;
&lt;body&gt;

 &lt;div class="layout_left" &gt;
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at elementum mauris. In ultricies lobortis dictum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent pellentesque, tortor nec rutrum auctor, tellus velit feugiat tellus, id consectetur orci augue in lorem. Donec tempor posuere ligula a ullamcorper. Quisque aliquam lacinia convallis. Sed eget placerat nisi. Etiam dignissim gravida lorem sit amet auctor. In hac habitasse platea dictumst. Nunc blandit imperdiet rhoncus. Donec laoreet, nibh sed consectetur posuere, lacus eros adipiscing felis, eleifend eleifend purus libero ut nulla. Duis commodo felis vitae tellus accumsan non ultrices justo feugiat. Curabitur auctor dolor ut mi iaculis dapibus. Nunc posuere dolor in elit scelerisque cursus. Vestibulum libero lacus, auctor at mattis et, pretium eget massa.
 &lt;/div&gt;
 &lt;div class="layout_right" &gt;
  Ut placerat tortor sed dui molestie eu fringilla risus ultricies. Phasellus faucibus turpis eu purus lacinia at blandit quam scelerisque. Etiam laoreet purus at augue varius a pellentesque diam accumsan. Nulla sodales auctor nibh, ac vehicula est bibendum a. In vitae quam vel dolor blandit sagittis. Proin ut congue lacus. Nulla facilisi. Sed viverra gravida justo, id feugiat nisl dignissim id. In hac habitasse platea dictumst. Proin faucibus congue pellentesque. Integer nec velit mauris, non ullamcorper leo. Duis sagittis rhoncus tincidunt. Phasellus erat metus, tristique vel lacinia non, tempus sit amet lacus.
 &lt;/div&gt;
 &lt;div class="layout_center" &gt;
  &lt;ul&gt;
   &lt;li class="clearfix" &gt;
    &lt;img src="images/action_1.gif" alt="All for Good" /&gt;
    &lt;a href=""&gt;All for good&lt;/a&gt;
    &lt;p&gt;Small actions add up to a big difference. All for Good helps you find and share ways to do good.&lt;/p&gt;
   &lt;/li&gt;
   &lt;li class="clearfix" &gt;
    &lt;img src="images/action_2.gif" alt="Top Birthday Wish Fundraisers on Causes" /&gt;
    &lt;a href=""&gt;Top Birthday Wish Fundraisers on Causes&lt;/a&gt;
    &lt;p&gt;See the top birthday wish fundraisers on Causes and learn&lt;/p&gt;
   &lt;/li&gt;
   &lt;li class="clearfix" &gt;
    &lt;img src="images/action_3.gif" alt="Raise Awareness for Your Cause" /&gt;
    &lt;a href=""&gt;Raise Awareness for Your Cause&lt;/a&gt;
    &lt;p&gt;Set-up a branded credit card through our partner Capital One&amp;reg; for your organization-with your logo.&lt;/p&gt;
   &lt;/li&gt;
   &lt;li class="clearfix" &gt;
    &lt;img src="images/action_4.gif" alt="Title/Headline" /&gt;
    &lt;a href=""&gt;Title/Headline&lt;/a&gt;
    &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt.&lt;/p&gt;
   &lt;/li&gt;
  &lt;/ul&gt;
 &lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>That&#8217;s it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2009/06/mozilla-strict-three-column-layout-with-ul/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
