Setting Category & Product Attribute Defaults in Magento 1

When creating a new attribute, we can specify a default value to be saved alongside that attribute. However, these values do not propagate to categories or products which already exist. We can, however use load_after events to remedy this.

Confix XML


Note: To set the default of a category use catalog_product_load_after instead

class Namespace_Module_Model_Observer
    public function setDefaults($observer)
        $category = $observer->getCategory();

        if($category->getShowSizeRollover() === NULL){

In this example we set the attribute ‘show_size_rollover’ to true if it’s not already been given a value. Because we’ve added this event in the global space, this value will propagate for both frontend and adminhtml.

Requiring Cookies For a Controller Action in Magento

Magento provides a convenient mechanism for the detection and redirection of the user if they’re not enabled. Magento’s preDispatch() method in Mage_Core_Controller_Varien_Action is responsible for this functionality where the current action name is compared against the _cookieCheckActions and the user is redirected if necessary.

To add particular actions to the cookie check, simply add them to the _cookieCheckActions array in the controller’s preDispatch method:

    public function preDispatch()
        $this->_cookieCheckActions[] = 'index';
        $this->_cookieCheckActions[] = 'guest';


And voilà, the user will be redirected to the enable cookies page!

Useful Installer Snippets

To perform database operations from within an installer script, we can get the connection object. Connection objects provide functionality to modify tables, columns, indexes. From model resources, connections can be retrieved using getReadConnection() and _getWriteAdapter(), which is a protected method. Connection objects are instances of the Magento_Db_Adapter_Pdo_Mysql which extends Magento_Db_Adapter_Pdo_Mysql.

All of the following assume that the variable $installer has been assigned as $this from the installer class.

Defining an Installer

        <foo_bar_setup> // Individual namespace for a resource
            <setup>      // Setup information
                <class>Mage_Core_Model_Resource_Setup</class> // Class to run from within

At a first glance it appears odd to have to include the module name in the setup node, however because all XML is merged into one big file, Magento has no way of knowing who the originating module of the setup declaration was.

Getting a table’s name


This calls the Mage::getSingleton(‘core/resource’)->getTableName($tableName) and caches the result for future calls.

Generating Index Names

Although any name could be used as an index name, Magento includes a handy method to automatically generate index names to ensure there are no clashes between them.

$installer->getIdxName($tableName, $fields, $indexType = '');

– Table name can be retrieved with the installer’s getTableName() method.
$fields is an array which contains all of the fields the index is for.
$indexType can be one of the following:


Adding an index to a table


addIndex() accepts three parameters; the first is the index name where we use getIdxName() and pass in the table name, the fields, and the index type. The second parameter an array of columns for the index, and the third is the type of index we’re creating.

Checking a Table Exists


Converting a Date to MySQL Format


Running SQL

$installer->run('DROP table `{$installer->getTable('wishlist/wishlist')}`');

This aliases the connection’s multiQuery method in Varien_Db_Adapter_Pdo_Mysql.
Note: $connection->query() could also be used.

Generating Foreign Key Names

Just like indexes, Magento provides a useful method for generating foreign key names:

$installer->getFkName($priTableName, $priColumnName, $refTableName, $refColumnName) 

Renaming a Column

$installer->run("ALTER TABLE table_name CHANGE `column_name` `new_column_name` VARCHAR(255);

Adding a Foreign Key When Creating A Table

$table->addForeignKey($installer->getFkName('catalogsearch/result', 'product_id', 'catalog/product', 'entity_id'),
        $installer->getTable('catalogsearch/result'), 'product_id',
        Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE)

– Would create a from the catalogsearch/result table to the catalog/product table from the column product_id to entity_id

Adding a Foreign Key to an Existing Table

    $installer->getFkName('catalogsearch/result', 'product_id', 'catalog/product', 'entity_id'),

– The first parameter is the foreign key name, which we generate using Magento’s getFkName() method.
– The second and third parameters are the primary table and column.
– The fourth and fifth parameters are the reference table and column.
– The sixth parameter is the database action to perform when the primary column is deleted.
– The seventh parameter is the database action to perform when the primary column is updated.

Possible options for the onDelete and onUpdate parameters are:


Removing a Foreign Key

As far as I’m aware, Magento doesn’t offer a utility method for removing foreign keys. Instead, we can use the run command and build the foreign key’s name with getFkName().

$wishlistTable = $installer->getTable('wishlist/wishlist');
$fkName = $installer->getFkName('wishlist/wishlist', 'customer_id', 'customer/entity', 'entity_id');

$installer->run("ALTER TABLE {$wishlistTable} DROP foreign key {$fkName}", array());

Adding a Column to an Existing Table

		'type' => Varien_Db_Ddl_Table::TYPE_TEXT,
		'length' => 255 // Will be created as VARCHAR
		'nullable' => true,
		'default' => null,
		'comment' => 'Created At’ // A comment must be provided

– The first column is the table name and the second is the name of the column we’re adding. The third is an array of attributes for the new column; a list of types can be ascertained from the Varien_Db_Ddl_Table class.
Note: To create a column with a type of varchar, use TYPE_TEXT with a length of 255. TYPE_VARCHAR, has been deprecated and the constant is only kept in for the MySQL adapter.

Column Types

const TYPE_BOOLEAN          = 'boolean';
const TYPE_SMALLINT         = 'smallint';
const TYPE_INTEGER          = 'integer';
const TYPE_BIGINT           = 'bigint';
const TYPE_FLOAT            = 'float';
const TYPE_NUMERIC          = 'numeric';
const TYPE_DECIMAL          = 'decimal';
const TYPE_DATE             = 'date';
const TYPE_TIMESTAMP        = 'timestamp'; // Capable to support date-time from 1970 + auto-triggers in some RDBMS
const TYPE_DATETIME         = 'datetime'; // Capable to support long date-time before 1970
const TYPE_TEXT             = 'text';
const TYPE_BLOB             = 'blob'; // Used for back compatibility, when query param can't use statement options
const TYPE_VARBINARY        = 'varbinary'; // A real blob, stored as binary inside DB

Displaying Magento’s Configurable Options as Radio Buttons (Quick and Dirty)

By default Magento displays a product’s configurable options as select drop downs. This isn’t always appropriate for the project however; some clients prefer radio buttons, and longer product names will cause some of the text in the select box to be cut off on mobile devices.

Here’s a quick and dirty way to display those selects as radio buttons (this assumes a descendent of the RWD theme is being used and hasn’t been tested with a base theme). We don’t mess about with changing templates with this method – it’s all done in JavaScript.


        <reference name="head">
            <action method="addItem">

JavaScript – configurable.js

    var loadOptions = Product.Config.prototype.loadOptions;
    var containerClass = "options-list"

    // Create an option array for each of the configurable options
    Product.Config.prototype.loadOptions = function() {
        var self = this;

            var attributeId =[a-z]*/, '');
            var options = self.getAttributeOptions(attributeId);
            var radioId = attributeId + "-radio";

            var $optionContainer = $j('<ul />').addClass(containerClass);

                for(var i=0;i<options.length;i++){
                    var $radio = $j("<input type='radio' />" ).attr("name", radioId).addClass('radio');
                    var $li = $j("<li />");
                    var foundValue = $j(element).find('option[value="' + options[i].id + '"]').html();
                    var $span = $j("<span class='label' / >").append($j('<label />').html(foundValue));

                    $radio.attr('value', options[i].id);


                    $radio.on('click', function(ev){
                        var val = $j(this).val();

                'height': '0px',
                'position': 'absolute'
  • We monkey patch the Product.Config object and add our own loadOptions method. This runs the original method, then recreates the select as a list of radio options in the same container as where the select box resides.
  • The select box is then hidden, however instead of applying a display: none on it, we change its visibility, height and position. This because Magento will not validate hidden options by default so appling this method allows us to keep Magento’s built in validation.
  • When the user changes the selected radio button, all the script does is changes the value of the hidden select box and then calls the reloadPrice() method.

Useful Snippets

Factory Methods


About Magento


Check a Module is Enabled



// Get the increment id of the current user's last order
$lastOrderId = Mage::getSingleton('checkout/session')->getLastRealOrderId();

// Load the last order for the current user
$order = Mage::getModel('sales/order')->loadByIncrementId($lastOrderId);

Data store

Mage::register('name', 'value')

Paths & URLs

Mage::getRoot(); // Application root absolute path
Mage::getBaseDir($type); // The base dir of the install pass in 'media', 'app', 'base', 'design', 'etc', 'lib', 'locale', 'skin', 'var', 'tmp', 'cache', 'log', 'session', 'upload', 'export'
Mage::getUrl($route, $params); // Get a url (uses core/url model), possible params are _secure => true, and _forced_secure => true

Mage::getBaseUrl($type); // The base url of the install

The following constants can be passed into the getBaseUrl() method:
Mage_Core_Model_Store::URL_TYPE_WEB – Store URL

Mage::getModuleDir($type, $moduleName); // Get the module path
$type can be 'etc', 'controllers', 'sql', 'locale'.  If manually including an controller file, use this method as they are not autoloaded.
Mage::helper('core/url')->getCurrentUrl(); // Get the current URL
Mage::helper('core/url')->getHomeUrl(); // Get the home URL
Mage::helper('checkout/url')->getCheckoutUrl() // Get the checkout URL
Mage::getUrl('checkout/cart') // Get the cart URL using getUrl

Formatting a string as a URL

Mage::getModel(‘catalog/product_url’)->formatUrlKey(‘string to be converted’);

URLs in a block

$this->getSkinUrl('path/to/resource.png'); // Normal
$this->getSkinUrl('images/ sampleimage.gif', array('_secure'=>true)) // Secure

Redirecting within a controller

$this->_forward($action, $controller = null, $module = null, array $params);

Alternate redirect method



Mage::app()->getStore(); // Get the current Store object


Mage::getStoreConfig($path, $store = null); // Retrieve a config value, store is the default store by default
Mage::getStoreConfigFlag($path, $store = null); // Retrieve a boolean config value
Mage::getConfig() Get the config object

Observers & Events

Mage::addObserver($eventName, $callback, $data, $observername, $observerClass);
Mage::dispatchEvent($name, $data);


Mage::exception($module, $message, $code);
Mage::throwException($message, $messageStorage);
Mage::logException(Exception $e);


Mage::log($message, $level, $file, $forceLog); // Logging var/log - use file from dev/log/file
// Will be logged in system.log unless $file is specified.  Won’t be logged if dev/log/active is off in the admin, unless $forceLog is true
Mage::log($message, $level, $file, $forceLog);




Mage::helper('core/http')->getRemoteAddr(); // Get the user's IP address

Product Image Resizing

Mage::helper('catalog/image')->init($product, $attributeName, $imageFile = null)
->resize($width, $height)
->keepAspectRatio(bool) // The image won't be stretched
->keepFrame(bool) // The image won't be cropped
->constrainOnly(bool) // The image will only be scaled down

$attributeName is a media attribute. Incidentally, a watermark will automatically be added to catalog images if the admin control has been turned on.

Image Resizing Using Varien_Image

$_imageUrl = Mage::getBaseDir(‘media’) . DS . $image;

$imageResized = Mage::getBaseDir(‘media’) . DS . "resized" . $image;

$imageObj = new Varien_Image($_imageUrl);




$imageObj->resize(140, 140);



  • Products are assigned to a Website. Products aren’t visible unless they are.
  • Products can’t be set to enabled / disabled on a store view.
  • Store Groups can contain a different root catalog, but the same products will still be available.

EAV Attributes

// Load a product attribute object baset on its code (replace 'catalog_product' to load other attribute types
$attributeModel = Mage::getModel('eav/entity_attribute')->loadByCode('catalog_product', 'attribute_code');

Outputting Product Attributes

// For Dropdowns:

// For any attribute

// Formatting Attributes
Mage::helper('catalog/output')->productAttribute($product, $attributeHtml, $attributeName);

Formatting attributes respects any product attribute settings such as encoding HTML output

Setup and Installers

  • data installers go in the module’s data/ folder
  • installers go in the module’s sql/ folder

Running indexers within installers

They won’t run properly unless the store is set to admin and the following is set:

Mage::register('isSecureArea', 1);

Controller Events

The following are dispatched from the preDispatch method of Mage_Core_Controller_Varien_Action
– *controller_action_predispatch_routeName * Eg. controller_action_predispatch_catalog
– *controller_action_fullActionName * Eg. controller_action_predispatch_catalog_product_view

Controllers, Actions & Request Object

// Get the module, controller and action name separated by underscores. Used to attach design XML elements to pages. Eg. catalogsearch_result_index

// Get the current action class (outside of the controller)

Translate Inline & Emails

Before sending an email, translate inline should be turned off to prevent input boxes being rendered in the email’s contents. It should be turned back on afterwards.

$translate = Mage::getSingleton('core/translate');


The flow of Magento’s routing begins from Mage_Core_Controller_Varien_Front which calls *dispatch** which then attempts to match against a router.

The standard routers included in Magento are:
– Mage_Core_Controller_Varien_Router_Standard (Frontend)
– Mage_Core_Controller_Varien_Router_Admin (Admin)
– Mage_Core_Controller_Varien_Router_Default (Default)

Which then sets the following on the request object:


Store Information

Get the Admin Store Model

<?php Mage::getModel('core/store')->load('admin', 'code');

Get the Base Website

<?php Mage::getModel('core/website')->load('base', 'code');

Get the Admin Store ID (Constant)

<?php Mage_Store_Model_App::ADMIN_STORE_ID;


Reindex everything

/* @var $indexCollection Mage_Index_Model_Resource_Process_Collection */
$indexCollection = Mage::getModel('index/process')->getCollection();
foreach ($indexCollection as $index) {
/* @var $index Mage_Index_Model_Process */

Reindex a Particular Indexer

$process = Mage::getModel('index/indexer')->getProcessByCode('catalog_product_price');

Temporarily disable a cache type

In particular instances, it may be necessary to disable a type of layout cache. For instance, you may AJAX a call to a page which loads a layout handle for the root node and returns it as an JSON response. It may be it necessary to later load another layout handle as the root node, but with layout caches on this erroneously loads the first layout handle. The following solution will temporarily prevent the layout XML from being cached:

    protected function _disableLayoutCache()
        $cache = Mage::app()->getCacheInstance();