Magento 2 – Useful Snippets for Frontend

1) Store Information

inject in your function __construct

public function __construct(\Magento\Store\Model\StoreManagerInterface $storeManager) {
        $this->storeManager = $storeManager;
}

Get store ID:

$id = $this->storeManager->getStore()->getId();

Get Base URL :

$baseUrl = $this->storeManager->getStore()->getBaseUrl();

Get Base Currency Code or (getBaseCurrency() , getDefaultCurrencyCode(), getDefaultCurrency()):

$baseCurrency = $this->storeManager->getStore()->getBaseCurrencyCode();

Get Current Currency Code or (getCurrentCurrency(), getAvailableCurrencyCodes(),getAllowedCurrencies()) :

$currentCurrency = $this->storeManager->getStore()->getCurrentCurrencyCode();

Retrieve Base Media directory path :

$baseMediaDir  = $this->storeManager->getStore()->getBaseMediaDir();

Retrieve Base Static directory path :

$baseStaticDir = $this->storeManager->getStore()->getBaseStaticDir();

For other function like website_id, group_id, code name or secure test explore class Magento\Store\Model\Store

2) Cart Data

inject in your function __construct

public function __construct(Magento\Checkout\Model\Cart $cart) {
        $this->cart = $cart;
}

Get Total Number Items:

$cartCount = $this->cart->getItemsCount();

Get Quote Data :

$cartQuote= $this->cart->getQuote()->getData();
print_r($cartQuote);

You can fetch [base_currency_code], [store_currency_code], [quote_currency_code], [grand_total] or [base_grand_total] and many others

echo $cartQuote['base_grand_total'];

Iterate items of cart from session:

inject in your function __construct

public function __construct(Magento\Checkout\Model\Session $session) {
        $this->session  =  $session;
}
foreach ($this->session->getQuote()->getAllItems() as $item) {
    echo $item->getName();
}

Clear Quote:

$this->session ->clearQuote();

3) Catalog:

inject in your function __construct

public function __construct(\Magento\Framework\Registry $registry) {
        $this->registry = $registry;
}

Get Current Category:

$category = $this->registry->registry('current_category');

Get Cuurent Category Id:

$cid = $this->registry->registry('current_category')->getId();

Get Current Category level:

$level = $this->registry->registry('current_category')->getLevel();

Get Current Product:

$pid = $this->registry->registry('current_product');

Retrieve Crosssell Products from Current Product:

$products = [];
foreach ($this->registry->registry('current_product')->getCrossSellProducts() as $product) {
	$products[$product->getId()] = ['position' => $product->getPosition()];
}
print_r($products);

Retrieve Related Products from Current Product:

$products = [];
foreach ($this->registry->registry('current_product')->getRelatedProducts() as $product) {
	$products[$product->getId()] = ['position' => $product->getPosition()];
}
print_r($products);

Retrieve Upsell Products from Current Product:

$products = [];
foreach ($this->registry->registry('current_product')->getUpSellProducts() as $product) {
	$products[$product->getId()] = ['position' => $product->getPosition()];
}
print_r($products);

Check if Current Product is registered:

if ($this->registry->registry('current_product')) {
$product = $this->registry->registry('current_product');
} else {
throw new \LogicException('Product is not defined');
}

4) CMS:

inject in your function __construct

public function __construct(\Magento\Framework\Registry $registry) {
        $this->registry = $registry;
}

Get Current CMS Page :

$page = $this->registry->registry('cms_page');

Get Id of Current CMS Page:

$cmsId = $this->registry->registry('cms_page')->getId();

Check if CMS Page exist in table:

if ($this->registry->registry('cms_page')->getId()) {
	return $this->registry>registry('cms_page')->getTitle();
} else {
	return __('New Page');
}

5) View:

Inside any block that extend \Magento\Framework\View\Element\Template you can use:

//getting assets elements url from your extension in current theme

$loader = $this->getViewFileUrl("ibnab_lazy::images/loader.svg");

//or getting from assets of current theme :

$js = $this->getViewFileUrl("js/my.js");
Advertisements

Magento 2 Data Migration Tool – Migrate Settings

Magento 2 has now been officially launched and comes with a brand new architecture and database design.  To ease up upgrade process, Magento released official Data Migration Tool that will help developers migrate store data from Magento 1 to Magento 2.
Refer to Migration Guide and Migration Tool on Github  for all the Migration Overview, Preconditons and Data Migration Tool installation guide. You can also request Whitepaper.

How migration works ?

Data Migration Tool:

To assist you with your migration, Magento provides the Data Migration Tool, a command-line interface (CLI) that provides verification, progress tracking, logging, and testing functions. The migration tool operates in three modes to transfer and adapt data from Magento 1 to Magento 2:

  • Settings mode: Migrates all possible configuration settings from Magento 1 to Magento 2. This includes settings, websites and stores to M2. Most of Magento data is related to websites and stores.
  • Data mode: Bulk migrates data from your Magento 1 database to your Magento 2 database. Data migration will transfer categories, products, customers, orders, wishlists, ratings, everything you can think of into M2.
  • Delta mode: Incremental ‘catch-up’ migration after the initial bulk data migration. Migrates incremental changes (for example, orders and inventory).After successful data migration, you can always just append new M1 entries to M2 database with delta migration, it will continue where it stopped last time. Delta doesn’t migrate new or changed products or categories (at the moment of writing), only customers, orders, and similar customer related data.While doing data migration, set of m2_* tables are created in your M1 database with set of triggers that enables tracking changes. It will reduce migration time to minimum when going live with M2.

Also you can Migrate Media. You need to simply copy/paste media files to appropriate places in M2 after products and categories are migrated, simple as that.

Each mode consists of several steps that perform tasks specific to the mode. (For example, URL rewrite step, EAV step, settings step.) Each step initially checks data integrity in the Magento 1 and Magento 2 databases and, after verification succeeds, performs the transfer, and verifies data again after it’s done.

Today, we will see how Settings are migrated from 1.x CE to 2.0 CE

Configure Migration

After you install the data migration tool, the following directory contains mapping and configuration files:

Magento CE:

<your Magento 2 install dir>/vendor/magento/data-migration-tool/etc/ce-to-ce

To create a configuration file navigate to the following Directory :

<your Magento 2 install dir>/vendor/magento/data-migration-tool/etc/<migration-edition>/<version>
Eg. D:\Xamp\htdocs\mage2\vendor\magento\data-migration-tool\etc\ce-to-ce\1.9.2.2
  • Copy and Paste config.xml.dist and rename it config.xml
  • Rename map.xml.dist to map.xml

Open config.xml and enter following at minimum for Database:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="../../config.xsd">
<source version="{your magento 1.X version}">
<database host="localhost" name="{magento1 db name}" user="root"/>
</source>
<destination version="{your magento 2 version}">
<database host="localhost" name="{magento2 db name}" user="root"/>
</destination>
<options>
<crypt>
<key>{magento1 key}</key>
</crypt>
</options>
</config>

Note:
The <crypt_key> tag is mandatory to fill. Location of Magento1 crypt key : <your Magento 1 install dir>/app/etc/local.xml in <key> tag.
Add <source_prefix>tbl_</source_prefix> incase your magento tables contain prefix such as “_tbl”.

 

Migrate Settings

  1. Change to the following directory : <your Magento 2 install dir>/vendor/magento/data-migration-tool/etc/<migration edition>/<ce or version>
  2. Copy and Paste settings.xml.dist and name it settings.xml
  3. Open <your Magento 2 install dir>/vendor/magento/data-migration-tool/etc/<migration edition>/<ce or version>/config.xml and update file as follows:
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xs=http://www.w3.org/2001/XMLSchema-instance xs:noNamespaceSchemaLocation="../../config.xsd">
<!--START migrate settings - store settings-->
<steps mode="settings">
<step title="Settings Step">
<integrity>Migration\Step\Settings\Integrity</integrity>
<data>Migration\Step\Settings\Data</data>
</step>
<step title="Stores Step">
<integrity>Migration\Step\Stores\Integrity</integrity>
<data>Migration\Step\Stores\Data</data>
<volume>Migration\Step\Stores\Volume</volume>
</step>
</steps>
<!--END migrate settings - store settings-->
<source version="{your magento 1.X version}">
<database host="localhost" name="{magento1 db name}" user="root"/>
</source>
<destination version="{magento 2 version}">
<database host="localhost" name="{magento2 db name}" user="root"/>
</destination>
<options>
<map_file>etc/ce-to-ce/1.9.2.2/map.xml</map_file>
<settings_map_file>etc/ce-to-ce/settings.xml</settings_map_file>
<crypt>
<key>{magento1 key}</key>
</crypt>
</options>
</config>

My config.xml looks like below

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="../../config.xsd">
 <!--START migrate settings - store settings-->
 <steps mode="settings">
 <step title="Settings Step">
 <integrity>Migration\Step\Settings\Integrity</integrity>
 <data>Migration\Step\Settings\Data</data>
 </step>
 <step title="Stores Step">
 <integrity>Migration\Step\Stores\Integrity</integrity>
 <data>Migration\Step\Stores\Data</data>
 <volume>Migration\Step\Stores\Volume</volume>
 </step>
 </steps>
 <!--END migrate settings - store settings-->
 <source version="1.9.2.2">
 <database host="localhost" name="magento9" user="root"/>
 </source>
 <destination version="2.0.2">
 <database host="localhost" name="mage2" user="root"/>
 </destination>
 <options>
 <map_file>etc/ce-to-ce/1.9.2.2/map.xml</map_file>
 <settings_map_file>etc/ce-to-ce/settings.xml</settings_map_file>
 <crypt>
 <key>1bc968bd50b96ee18388feaed3bc1f1d</key>
 </crypt>
 </options>
</config>

Run following command for settings migration:

bin/magento migrate:settings -r {path to config.xml} which will look like below

php bin/magento migrate:settings -r vendor/magento/data-migration-tool/etc/ce-to-ce/1.9.2.2/config.xml

Note : {path to config.xml} is the absolute file system path to config.xml; this argument is required. While -r is an optional argument that starts migration from the beginning. If migrated successfully, below message will be displayed in CLI:

Data Migration Completed

To check whether Migration is working properly, make changes in Magento1 Settings (eg. Country Option -> Default Country). Then run the above command and check for the change in Magento2.

Cheers !!!

Magento: Difference between getAllVisibleItems() and getAllItems()

Both the functions, getAllVisibleItems() and getAllItems() are used to get all order items, as shown below

// load form order ID
  $order_id = 1234;
  $order = Mage::getModel("sales/order")->load($order_id);
  OR
  // Get current order ID
  $order_id = Mage::getSingleton('checkout/session')->getLastRealOrderId();
  $order = Mage::getModel('sales/order')->loadByIncrementId($order_id);
  //$order->getSubtotal() ; $order->getGrandTotal() ;
  $items = $order->getAllItems(); OR $order->getAllVisibleItems();
  $itemcount=count($items);
  foreach ($items as $itemId => $item)
  {
  $item->getName();
  $item->getPrice();
  $item->getSku();
  $item->getProductId();
  $item->getQtyOrdered(); //$item->getQtyToInvoice();
  }

Let’s look at the code of both methods first.

Method getAllItems()

public function getAllItems()
  {
  $items = array();
  foreach ($this->getItemsCollection() as $item) {
  if (!$item->isDeleted()) {
  $items[] = $item;
  }
  }
  return $items;
  }

Method getAllVisibleItems()

public function getAllVisibleItems()
  {
  $items = array();
  foreach ($this->getItemsCollection() as $item) {
  if (!$item->isDeleted() && !$item->getParentItemId()) {
  $items[] = $item;
  }
  }
  return $items;
  }

From the code we can see, the only difference is getAllVisibleItems() has an
additional check for each item i.e.

!$item->getParentItemId()

which will allow parent item only. It means if you have Configurable Product in your order, getAllVisibleItems will show you only the parent item while getAllItem will show both products.

$order->getAllItems() refers to the all items parent and it’s child (ref: configurable product and it’s child items)

img1

$order->getAllVisibleItems() refers to the Parent items only (Ref: configurable product only)

img2

If you need to show order product or do some sort of calculation on total ordered items getAllVisibleItems() is more preferable.

Magento: Accessing a Custom Attribute At CHECKOUT/CART Page

So you have added a new custom product attribute. It is not a problem to access and use it in Product View. And you probably know that you should enable it under the attribute settings page of Magento backend in order to make it available for the Product List (or category view) section.

To display it on checkout/cart page we can use following

Simple attribute (text):
(In your default.phtml)

<?php $_item = $this->getItem()?>
<?php $_product= Mage::getSingleton('catalog/product')->load($_item->getProductId()) ?>
<?php echo $_product->getResource()->getAttribute('attribute_code')->getFrontend()->getValue($_product); ?>

The issue with above code is $_item->getProduct()->load() will reload all product data from the database. While this will work, bear in mind that every time you call load() Magento will execute database query.

Attribute is not being loaded by default. During the checkout process we have to deal with quotes, so our goal is to add an attribute to the list of attributes that are loading with quote object. This can be done with XML by adding the following code to your config.xml. It  offers much better performance by loading the attribute along with the quote item. Just create a custom module and add this to the config.xml

<global>
    <sales>
        <quote>
            <item>
                <product_attributes>
                    <one_custom_attribute_code />
                    <another_custom_attribute_code />
                </product_attributes>
            </item>
        </quote>
    </sales>
</global>

where one_custom_attribute_code and another_custom_attribute_code 

are your attribute codes. Having done that, you can access your custom attribute without additional database queries using below code.

$_item->getProduct()->getAnotherCustomAttributeCode();

Magento : Reducing Bounce and Exit Rates

Your site is up, and your product is out there for the world to see. Before you know it, you have visitors trickling in to see what you have to offer.

Despite the depths of the Internet and the billions of pages offered, users are arriving at your website, and then without any explanation—they’re leaving.

They come and then they go, maybe after a minute, maybe even less. After all of the hours you’ve put in, the majority of your visitors aren’t staying around long enough to get past your landing page. Many of them visit once and never return.

We’re going to go over some ways to change this trend for the better.

Exit Rate
An Exit Rate is specific to each page; it’s the percentage of people who leave after viewing the page. Your exit rate lets you know the last page that users view before they move on. A very high exit rate on a specific page can be a red flag.

For example, if your product tour page that details the benefits of what you sell has one of the highest exit rates, you are likely not connecting the true value of your product with your visitors.

Bounce Rate
Your Bounce Rate is the number of visitors who leave your website after visiting a single page. Each page has its own bounce rate, but initially you probably want to address look at the bounce rates for three pages:

  • Landing pages that you’re sending paid traffic to through ads
  • Pages where you are attempting to make conversions happen
  • High traffic pages–pages that most of your visitors see

The higher your bounce rate, the lower your percentage of engaged users. Your bounce rate can be affected by your page, but also by the quality of the traffic coming to your site.

All of the following ways of leaving your site constitute a bounce:

  • Hit the back button
  • Type a different URL
  • Close the window or tab
  • Click on an external link
  • Timeout

But how do you find your bounce rate?

This is where your analytics come in. A basic analytics report will give you an overall bounce rate, with options to dig deeper and find out the bounce rates for individual pages. In Google Analytics, you’ll find this by going to Content > Site Content > Pages.

chapter_7_bounce_rates

Here are some of the most common culprits:

Your website is visually unappealing. Sometimes the fix is obvious. A visitor has stumbled across your site, and they are unimpressed by your cheesy stock images andchoice of Comic Sans as a font. Never underestimate the power of an attractive, easy-on-the-eyes website compared to a cluttered eye-sore. Great design creates credibility.

Your website is difficult to use. Maybe your site copy makes perfect sense to you, but visitors are left confused or, even worse, offended. It could also be that users are not visiting more pages because they can’t find them. Either because of poor layout, poor information architecture, technical errors, or malfunctioning buttons and page errors, users are left stranded.

Your website doesn’t meet user expectations. Unlike in the previous scenario, in which the user can’t easily leave the landing page, in this situation someone visits your website based on a promise that isn’t kept. If you do offer what they’re looking for it might not be easily located from the page they landed on. Users lack themotivation or time to scour every page you have, so it is crucial to remove the obstacles that cause them to give up and look elsewhere.

The people coming to your website aren’t the right people. The type of person viewing the page is just as important–if not more so–than the page itself. If people are bouncing it may be because they arrived based on a false promise. This is traffic you can’t really optimize, because they are going to bounce regardless. To avoid this, be sure your ads accurately represent your product and keywords align with your site’s mission.

There is no Call to Action. This issue is quite comparable to to the “lack of usability/navigation” issue, though likely even more detrimental to your bounce rate. Users arrive to your site one way or another, and simply don’t know where to go next—the shopping cart is nowhere to be found, it’s not clear how to subscribe to yourblog, etc. Whatever the activity you’ve designated as conversion, if the user has no idea what you want them to do, there is a huge problem.

Now, lets take another look at the above issues:

Your website is unattractive.

When a user arrives at your website, is he or she greeted with a simple, easy-to-navigate site? Or is the user bogged down with pop-up ads, dated graphics, and a disorganized layout? Your goal is to provide exactly what they are looking for. If any visual element of your site stands in the way of this, you are creating friction,and friction kills conversion.

Your website is unusable or lacks navigation.

The easiest fix here is to actually put yourself in your users’ shoes and explore your site.

  • Does every link work?
  • Do you run into any technical errors?
  • How is the load time?
  • Can you easily follow your own navigation to your desired goal?

To take it a step further, consider asking a few close friends to try out your site and complete a task. Watch them and document their experience—specifically any problems they have. For the best possible representation, use friends from all over the spectrum, those inside your field and those who have no idea what you do or sell.

Your website doesn’t meet user expectation.

First, ask yourself these questions:

  • What search terms did visitors use to get here?
  • What website or ad did your visitors come from?

If the answers to these questions are readily available, you can make some assumptions about what visitors are looking for and expecting to get from your site. Again, this will come from analytics. To find this out in Google Analytics, you’ll use the All Traffic, Referrals, and Search Engines reports under Traffic Sources.

Many users will arrive via search engines, so it is important to know the their intent and make sure your site matches those expectations. For example, if you are sell marketing automation software but have a large percentage of visitors showing up looking up performance-based marketing agencies, you have a percentage of visitors who will never buy from you, no matter how optimized your landing pages are.

In addition to analytics, you should ask visitors what they’re looking for when they arrive on your site. This lets you determine visitor intent, going beyond keywords to the actual reasons a person is on your site.

For example, if you have a mobile photography iOS app and a visitor arrives on your site from searching “iPhone mobile photos” you don’t know if they’re looking for a photo taking app, photo editing app, how to backup their photos, or how to take better pictures with their phone. You can only get that information by asking.

There is no Call to Action.

If a user is lost, the best tip is for the site to be a guide. You need to guide the users towards your goal. The users shouldn’t have too think too much or look too hard when arriving at your site. Make certain that your Call to Action is prominently placed on your landing page. Also consider these tips to help guide your users to your CTA:

Situate a “search function” in clear view for users
Match keywords in ads you run to your CTA, this way the users naturally spot what they expected to find

Too Many Calls to Action.

With too many distractions comes the potential for the user to get anxious and hit the back button. There are many tools you can use to figure out exactly where you users scroll on the page, which will be covered in Chapter 9. But know for now that the most sure way to guide your user to your CTA is to give them little other choice. There should be a clear path upon the user arriving on the page to fulfilling the goal you set out.

These are of course just some examples. Your bounce rates are contingent on your website’s unique challenges and user base. Still, when attempting to lower your bounce keep the above tips in mind. The important thing is this—in order for visitors to convert into users, they have to stick around. In its most basic form, lowering your bounce rate is simply figuring out why people are leaving and fixing it.

Magento : Conversion Rate Optimization

Let’s start by defining conversion…

What we mean when we talk about conversion is when a visitor to your website takes an action that you want them to take.

But what does that look like to you? It could be signing up for an email newsletter, creating an account with a login and password, making a purchase, downloading your app, or something else entirely.

Whatever it is you want your visitors to do, this action is what you are going to measure and what you are looking to optimize.

In the introduction, we briefly defined CRO as the method of using analytics and user feedback to improve the performance of your website. Here’s an even simpler definition: conversion rate optimization is finding why visitors aren’t converting and fixing it.

Conversion Rate Optimization Is…

A structured and systematic approach to improving the performance of your website
Informed by insights—specifically, analytics and user feedback
Defined by your website’s unique objectives and needs (KPIs)
Taking the traffic you already have and making the most of it

Conversion Rate Optimization Is Not…

Based on guesses, hunches, or what everyone else is doing
Driven by the highest paid person’s opinion
About getting as many users as possible, regardless of quality or engagement

A Few Key Terms…

These are concepts and ideas that will come up again and again in this guide, so now is the time to familiarize yourself with them.

Call to Action (CTA)
The primary button, link or other user interface element that asks the user to take an action that leads to (or towards) a conversion. A “Buy Now” button on Amazon.com, a “Sign Up” button on an email registration field, a “Download Now” on an app landing page are examples of different Calls to Action.

Conversion Funnel
The primary pathway (or flow) of the user experience where visitors complete a conversion. On Amazon.com the funnel may be Home page > search results page > product page > checkout.

A/B or Split Testing
The testing of one version of a page or interface element against another version of the same thing. Each element is measured by its effectiveness in comparison to the other. For example, a red button measured in effectiveness to a green button. In A/B testing only one thing is tested at a time.

Multivariate Testing (MVT)
The testing of multiple variations of many different page elements in various combinations to determine the best performing elements and combinations. For example, a multivariate landing test may test many variations of the pictures, copy, and calls to action used on the page in many combinations to find the best performer.

Now About Those Statistics…

Here’s an overview of the things you are going to measure in order to gauge your current rate of conversion, identify the trouble spots, and design a plan of action.You can get these numbers through Google Analytics, KISSmetrics, or another analytics service of your choosing. The numbers critical to CRO are as follows:

Let’s start with the numbers we’re looking to improve—Conversion Rates

1) Your Total Conversions is number of people who did whatever it is defined as converting (email newsletter, made a purchase, and so on).

2) To get your Conversion Rate, you divide the above total number of conversions by the number of visitors to your site.

For example, a site with 5000 visitors and 50 conversions has a conversion rate of 1%.

But how long are people spending on your site? Which pages are they visiting while there? This next set of numbers can help you to form some testable hypotheses. Looking at your Bounce and Exit Rates, as well as your Engagement Metrics, is the first step in making sense of your conversion rate.

Bounce Rate
Your Bounce Rate is the percentage of people who leave after viewing a single page. A high bounce rate is not a good thing–for whatever reason, people aren’t findingwhat they’re looking for so they leave almost immediately.

Exit Rate
You also have a specific Exit Rate for each page; it’s the percentage of people who leave after viewing the page. Your exit rate lets you know the last page that users view before they move on. A very high exit rate on a specific page can be a red flag.

Average Time on Site
An Engagement Metric, the Average Time on Site of users gives you a general idea how long people are sticking around. A high bounce rate means a low average time on site—visitors aren’t sticking around long enough to do whatever it is you want them to do.

Average Page Views
Similarly, Average Page Views is an Engagement Metric that tells you how many pages the average visitor through before leaving. More page views can mean engagement but also can mean a lack of clarity in your conversion funnel, if there is no conversion.

These are the metrics that matter. Take the example above—the site with 5,000 visitors per month but only 50 conversions could either pat themselves on the back for all those unique visitors or recognize that their conversion rate could be much better than 1% and then work to optimize those numbers.

Magento: Custom Grid with Ambiguous Column on Filter / Mysql Ambiguous Error in Admin Grid Filter

The Problem

You’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 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.

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.

My tables:

retailer

  • id
  • street
  • city
  • postcode
  • country_id
  • region_id

directory_country_region

  • region_id
  • country_id
  • code
  • default_name

Now lets take a look at my _prepareCollection method.

protected function _prepareCollection() {
 $collection = Mage::getResourceModel('spinonesolutions_storelocator/retailer_collection');
 $collection->getSelect()
 ->join(array('dcr' => 'directory_country_region'),'dcr.region_id = main_table.region_id')
 ->reset(Zend_Db_Select::COLUMNS)
 ->columns(array('id','name','street','city','country_id'))
 ->columns(array('default_name'),'dcr');
 $this->setCollection($collection);
 return parent::_prepareCollection();
}

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’m going to get an ambiguous column error in my SQL if I simply add “WHERE country_id = ?”.  That’s because country_id is in both tables.

The solution is the “filter_index” property.  Here’s a snippet from_prepareColumns which generates the country column and uses filter_index.

$this->addColumn('country_id', array(
 'header' => Mage::helper('spinonesolutions_storelocator')->__('Country'),
 'width' => '100px',
 'index' => 'country_id',
 'filter_index' => 'main_table.country_id',
 'type' => 'country', ));