Magento – Widgets sort order in different design packages

cmssortingwidgets

I'm wondering if I'm doing something wrong, or there's a 'bug' in Magento.

When I add a couple of widgets in the same package/theme, say 'base/default', the sort order works just fine.

But, when I want to add a widget in a different package (customer/default) that has to show between those widgets, it's not working, this widget shows up at the end of all the base/default widgets.

So for example:

  1. Widget 1 – base/default – Sort order 1
  2. Widget 2 – base/default – Sort order 2
  3. Widget 3 – customer/default – Sort order 3
  4. Widget 4 – base/default – Sort order 4

This is not working correctly, Widget 3 shows up after Widget 4.
Is this a bug, or am I doing something wrong, or does this work 'as designed'?

Thanks in advance!

Best Answer

I was struggling with widget sort order today, too, and I found this to be strange behaviour. The root cause of this issue is /app/code/core/Mage/Core/Model/Resource/Layout.php in current 1.9 core (which looked the same down in 1.6):

/**
 * Retrieve layout updates by handle
 *
 * @param string $handle
 * @param array $params
 * @return string
 */
public function fetchUpdatesByHandle($handle, $params = array())
{
    $bind = array(
        'store_id'  => Mage::app()->getStore()->getId(),
        'area'      => Mage::getSingleton('core/design_package')->getArea(),
        'package'   => Mage::getSingleton('core/design_package')->getPackageName(),
        'theme'     => Mage::getSingleton('core/design_package')->getTheme('layout')
    );

    foreach ($params as $key => $value) {
        if (isset($bind[$key])) {
            $bind[$key] = $value;
        }
    }
    $bind['layout_update_handle'] = $handle;
    $result = '';

    $readAdapter = $this->_getReadAdapter();
    if ($readAdapter) {
        $select = $readAdapter->select()
            ->from(array('layout_update' => $this->getMainTable()), array('xml'))
            ->join(array('link'=>$this->getTable('core/layout_link')), 
                    'link.layout_update_id=layout_update.layout_update_id',
                    '')
            ->where('link.store_id IN (0, :store_id)')
            ->where('link.area = :area')
            ->where('link.package = :package')
            ->where('link.theme = :theme')
            ->where('layout_update.handle = :layout_update_handle')
            ->order('layout_update.sort_order ' . Varien_Db_Select::SQL_ASC);

        $result = join('', $readAdapter->fetchCol($select, $bind));
    }
    return $result;
}

What happens here is that sort order is only used for sorting layout updates for a unique combination of store, area (e.g. frontend, package (base or customer in your case), theme (default) and layout handle (e.g. catalog_category_view).

Therefore, across different combinations, sort order does not yield the expected results.

I found a solution by rewriting two core classes and put it in an extension here: https://github.com/gruenspar/magento-sorted-db-layouts

It is untested in this exact form (as we have some more rewrites on these classes, unfortunately), but the main idea is working flawlessly for us.

If you encounter issues when installing it, let me know.

Related Topic