Magento – Fixing Category URL Key Removal After Reindexing

categorymagento-enterprisereindex

Problem

I'm having a strange issue with my url_key field reverting to NULL on my catalog_category_flat_store_1 table following a reindex, but only on categories that I have created since enabling the Flat Category index.

As a result, when I attempt to fetch the category via url_key as so:

    $category = Mage::getModel('catalog/category')
        ->getCollection()
        ->addAttributeToFilter('url_key', 'my-url-key')
        ->getFirstItem();

    $category->load($category->getId());

I am unable to do so. If I go back and re-save the category, the url_key is added back to the flat table and I'm able to retrieve the category.

Has anyone else had this problem or am I missing something regarding the way flat tables operate?

What I've Found/Tried

Because the value would initially save and then disappear, I examined the catalog_category_entity files. Here's what I found:

  1. The url_key value is saving properly in catalog_category_entity_url_key
  2. However, neither the url_key nor the url_path attributes are saving in catalog_category_entity_varchar as they were with categories that I created before enabling Flat tables.
  3. If I manually add the url_key to catalog_category_entity_varchar, values are preserved and copied to catalog_category_flat_store_1 as expected when reindexing.

I have tried disabling the flat tables and while the url_key value is still not saved to catalog_category_entity_varchar, I am able to category via the url_key using my code above.

FWIW, I'm using Enterprise 1.13.

Update

I used MAGMI to import my products/categories; because CE uses varchar attributes rather than a separate table as the newer versions of enterprise do, this may be a non-issue. I created a fresh install of Enterprise and added the categories manually. I'm noticing that the url_key and url_path fields are not copied over to the flat tables anyway.

Best Answer

In Magento Enterprise 1.13 (or 1.12) url_key attribute was moved to its own table catalog_category_entiry_url_key (similarly product url_key attribute has its own table catalog_product_entiry_url_key). Also in 1.13 indexers were changed and are now run by the cronjob instead of manually. The problem is that indexer only takes values from catalog_category_entity_(varchar|int|decimal|text|datetime) and not catalog_category_entiry_url_key. Quick fix is to create a new module and rewrite enterprise_catalog/index_action_category_flat_refresh model with:

<enterprise_catalog>
    <rewrite>
        <index_action_category_flat_refresh>Mynamespace_Mymodule_Model_Refresh</index_action_category_flat_refresh>
    </rewrite>
</enterprise_catalog>

and in the class add url_key to $attributesType array

class Mynamespace_Mymodule_Model_Refresh extends Enterprise_Catalog_Model_Index_Action_Category_Flat_Refresh {

/**
 * Return attribute values for given entities and store
 *
 * @param array $entityIds
 * @param integer $storeId
 * @return array
 */
protected function _getAttributeValues($entityIds, $storeId) {
    if (!is_array($entityIds)) {
        $entityIds = array($entityIds);
    }
    $values = array();

    foreach ($entityIds as $entityId) {
        $values[$entityId] = array();
    }
    $attributes = $this->_getAttributes();
    $attributesType = array(
        'varchar',
        'int',
        'decimal',
        'text',
        'datetime',
        'url_key'   //add url_key to attributes type; otherwise url_key value will not be saved in the flat tables
                    //as it was moved to its own table in EE 1.13
    );
    foreach ($attributesType as $type) {
        foreach ($this->_getAttributeTypeValues($type, $entityIds, $storeId) as $row) {
            if (isset($row['entity_id']) && isset($row['attribute_id'])) {
                $attributeId = $row['attribute_id'];
                if (isset($attributes[$attributeId])) {
                    $attributeCode = $attributes[$attributeId]['attribute_code'];
                    $values[$row['entity_id']][$attributeCode] = $row['value'];
                }
            }
        }
    }
    return $values;
    }

}

This will add url_key to flat tables during reindex but it probably won't work with MAGMI import module.

Related Topic