We we're in the similar situation as you James. After a lot of digging this is what I came up with:
The core_url_rewrite
table is now deprecated, instead Magento EE 1.13 now stores the rewrites in enterprise_url_rewrite
.
Tables:
enterprise_*_category_rewrite
use catalog_*_entity_url_key
tables to rebuild the two rewrite tables when you run php indexer.php --reindex catalog_url_*
When you add a 'URL Redirect' in admin Catalog->URL Redirects for a custom URL it gets added to the enterprise_url_rewrite_redirect
table and the flag for Magento that the index is now outdated is entered into enterprise_url_rewrite_redirect_cl
table which when running php indexer.php --reindex url_redirect
rebuilds the enterprise_url_rewrite_redirect_rewrite
table.
Quick note, any table ending in _cl is safe to truncate, the 'CL' stands for Change Log and is used by Magento to check if re-indexing is required.
As far as the URL Key tables go, I'm still a bit clueless as to why there two URL Key entries one in catalog_*_entity_url_key
and one in catalog_*_entity_varchar
(attribute id 90), but I assume this is what happens:
When you create a new product/category Magento uses the name to generate a url_key which is placed in catalog_*_entity_url_key
AND in the catalog_*_entity_varchar
, but the primary table used by Magento is the catalog_*_entity_url_key
because if you truncate it and run php indexer.php --reindex catalog_url_*
your enterprise_*_category_rewrite
tables will be empty and products/categories in the frontend will display ugly urls i.e. http://example.com/catalog/product/view/id/123/etc/etc
(not SOE friendly) I believe the two tables are related and are used to build the enterprise_url_rewrite
table because this table stores a 'request_path' most likely the url_key inside the catalog_*_entity_varchar
table and an 'identifier' which is the primary URL Key from the catalog_*_entity_url_key
table. I could be completely wrong about url_key and varchar tables, so I'm just thinking out loud.
Anyway to successfully truncate and rebuilt all rewrite tables you can execute:
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE `core_url_rewrite`;
TRUNCATE TABLE `enterprise_catalog_category_rewrite`;
TRUNCATE TABLE `enterprise_catalog_product_rewrite`;
TRUNCATE TABLE `enterprise_url_rewrite`;
TRUNCATE TABLE `enterprise_url_rewrite_category_cl`;
TRUNCATE TABLE `enterprise_url_rewrite_product_cl`;
TRUNCATE TABLE `enterprise_url_rewrite_redirect_cl`;
TRUNCATE TABLE `enterprise_url_rewrite_redirect_rewrite`;
SET FOREIGN_KEY_CHECKS = 1;
and then run:
sudo php indexer.php --reindex catalog_url_product
sudo php indexer.php --reindex catalog_url_category
sudo php indexer.php --reindex url_redirect
If you also truncate enterprise_url_rewrite_redirect
then you will loose all of your custom redirects that you see in your admin panel, perhaps this is your goal since you were left with a ton of useless URLs. As long as you DO NOT truncate the '*_entity_url_key' tables you'll be fine.
Our story was a little different, because we had duplicate URL Keys and major problems with product names from excel imports after upgrading to 1.13 from 1.11 so I wrote this quick script to reset the catalog_product_entity_url_key
table and the URL keys and URL paths in the catalog_product_entity_varchar
table using product names. I attached the code below, but if you use it, use it at your own risk.
<?php
include_once('app/Mage.php');
Mage::app();
$dbHandle = Mage::getSingleton('core/resource')->getConnection('core_write');
$productCounter = 0;
$nameFixCounter = 0;
$vUrlKeyFixCounter = 0;
$urlPathCounter = 0;
$urlKeyCounter = 0;
$productCollection = $dbHandle->query("SELECT entity_id, sku FROM catalog_product_entity");
while($product = $productCollection->fetch()) {
$dataString = null;
$oldProductName = $dbHandle->query("SELECT value FROM catalog_product_entity_varchar WHERE entity_id = '".$product['entity_id']."' AND attribute_id = 65")->fetch();
$oldVarcharUrlKey = $dbHandle->query("SELECT value FROM catalog_product_entity_varchar WHERE entity_id = '".$product['entity_id']."' AND attribute_id = 90")->fetch();
$oldUrlPath = $dbHandle->query("SELECT value FROM catalog_product_entity_varchar WHERE entity_id = '".$product['entity_id']."' AND store_id = 0 AND attribute_id = 91")->fetch();
$oldUrlKey = $dbHandle->query("SELECT value FROM catalog_product_entity_url_key WHERE entity_id = '".$product['entity_id']."'")->fetch();
$newProductName = preg_replace('/\s+/', ' ', trim(preg_replace('/[^\x20-\x21\x23-\x2B\x2D-\xE7]/', ' ', $oldProductName['value'])));
$newUrlKey = preg_replace('/\s+/', '-', trim(preg_replace('/[^\x30-\x39\x61-\x7A]/', ' ', strtolower($newProductName))));
if (strcmp($oldProductName['value'], $newProductName)) {
echo "-[".$oldProductName['value']."]\n";
echo "+[".$newProductName."]\n";
$dbHandle->query('UPDATE catalog_product_entity_varchar SET value = "'.$newProductName.'" WHERE entity_id = "'.$product['entity_id'].'" AND attribute_id = 65');
++$nameFixCounter;
}
if (strcmp($oldVarcharUrlKey['value'], $newUrlKey)) {
echo "-[".$oldVarcharUrlKey['value']."]\n";
echo "+[".$newUrlKey."]\n";
if ($oldVarcharUrlKey['value'] === null) {
$dbHandle->query("INSERT INTO catalog_product_entity_varchar (entity_type_id, attribute_id, store_id, entity_id, value) VALUES ('4', '90', '0', '".$product['entity_id']."', '".$newUrlKey."')");
} else {
$dbHandle->query("UPDATE catalog_product_entity_varchar SET value = '".$newUrlKey."' WHERE entity_id = '".$product['entity_id']."' AND attribute_id = 90");
}
++$vUrlKeyFixCounter;
}
if (strcmp($oldUrlPath['value'], $newUrlKey.'.html')) {
echo "-[".$oldUrlPath['value']."]\n";
echo "+[".$newUrlKey.".html]\n";
if ($oldUrlPath['value'] === null) {
$dbHandle->query("INSERT INTO catalog_product_entity_varchar (entity_type_id, attribute_id, store_id, entity_id, value) VALUES ('4', '91', '0', '".$product['entity_id']."', '".$newUrlKey.".html')");
} else {
$dbHandle->query("UPDATE catalog_product_entity_varchar SET value = '".$newUrlKey.".html' WHERE entity_id = '".$product['entity_id']."' AND store_id = 0 AND attribute_id = 91");
}
++$urlPathCounter;
}
if (strcmp($oldUrlKey['value'], $newUrlKey)) {
echo "-[".$oldUrlKey['value']."]\n";
echo "+[".$newUrlKey."]\n";
if ($oldUrlKey['value'] === null) {
$dbHandle->query("INSERT INTO catalog_product_entity_url_key (entity_type_id, attribute_id, store_id, entity_id, value) VALUES ('4', '90', '0', '".$product['entity_id']."', '".$newUrlKey."')");
} else {
$dbHandle->query("UPDATE catalog_product_entity_url_key SET value = '".$newUrlKey."' WHERE entity_id = '".$product['entity_id']."'");
}
++$urlKeyCounter;
}
$report = "[".++$productCounter."] ";
$report .= "NAME: [".(strcmp($oldProductName['value'], $newProductName)?'!=':'==')."] ";
$report .= "V_KEY: [".(strcmp($oldVarcharUrlKey['value'], $newUrlKey)?'!=':'==')."] ";
$report .= "PATH: [".(strcmp($oldUrlPath['value'], $newUrlKey.'.html')?'!=':'==')."] ";
$report .= "KEY: [".(strcmp($oldUrlKey['value'], $newUrlKey)?'!=':'==')."]\n";
echo $report;
}
echo 'Total Products: ['.$productCounter.'] Names: ['.$nameFixCounter.'] V_Keys: ['.$vUrlKeyFixCounter.'] Paths: ['.$urlPathCounter.'] Keys: ['.$urlKeyCounter.']';
The code can be tweaked to use Magentos formatKey method here: http://www.magentocommerce.com/wiki/3_-_store_setup_and_management/seo/url_key_characters_conversion unfortunately I came across the wiki after I updated all the keys so I didn't bother reupdating everything again.
Hope that helps :)!
You're not going to get out of this without a little debugging. The following applies to Magento CE, but should be relevant for Magento EE. Also, this post summarizes a lot of material found in my Magento Dispatch series. If you want to really engage in some bottom up debugging, start there.
To start, most of the Magento problems I see boil down to "I was really sure this one thing was X, but it was actually Y". Even if you're absolutely sure about something I tell you to check, make sure you actually check it.
The routing for Magento's homepage is handled by the Mage_Core_Controller_Varien_Router_Standard
object. The first key part is this line
#File: app/code/core/Mage/Core/Controller/Varien/Router/Standard.php
$p = explode('/', $this->_getDefaultPath());
The _getDefaultPath
method looks at your Magento store config for the set value.
protected function _getDefaultPath()
{
return Mage::getStoreConfig('web/default/front');
}
which is the configuration that corresponds to
System -> Configuration -> Web -> Default Pages -> Default Web URL
Tripple check that this value is set to the string
`cms`
and that your core_config_data
table
select * from core_config_data where path = 'web/default/front';
doesn't contain any unexpected scoped values.
Once you've done the above, add some temporary debugging code to peek at the value of $p
after that call.
$p = explode('/', $this->_getDefaultPath());
var_dump($p);
//or
Mage::Log($p);
//or
file_put_contents('/tmp/test.log',"$p\n",FILE_APPEND);
You should see output something like this
array (size=1)
0 => string '' (length=0)
array (size=1)
0 => string 'cms' (length=3)
The reason you have two items being dumped/logged is the match
method is shared between the admin router and the standard router object. If the second item isn't a one element array with cms
, that's your problem. Figure out what that's not happening, and you'll be on your way to solving the problem.
Assuming that's not the problem, Magento should now dispatch to the indexAction
method in the IndexController.php
file in the Mage_Cms
module. Ensure this is the case by adding the following two lines to the start of indexAction
#File: app/code/core/Mage/Cms/controllers/IndexController.php
public function indexAction($coreRoute = null)
{
$pageId = Mage::getStoreConfig(Mage_Cms_Helper_Page::XML_PATH_HOME_PAGE);
if (!Mage::helper('cms/page')->renderPage($this, $pageId)) {
$this->_forward('defaultIndex');
}
}
You should see Mage_Cms_IndexController::indexAction
dumped to the browser window. If this doesn't happen, then there's something about your system that's preventing standard routing from being used — jump back up into the match
method and figure out why $controller
, $controllerClassName
, $controllerInstance
, and $action
variables don't point to the indexAction
method in the IndexController.php
file in the Mage_Cms
module. (If this is the case, say so in the comments and I'll provide an update debugging scanrio for this)
Assuming you are being routed to this controller file and action correctly, remove the
var_dump(__METHOD__);
exit;
and instead add a new var_dump
$pageId = Mage::getStoreConfig(Mage_Cms_Helper_Page::XML_PATH_HOME_PAGE);
var_dump($pageId);
Magento allows you to configure the identifier of the page that should be used as the home page. The Mage_Cms_Helper_Page::XML_PATH_HOME_PAGE
should corresponds with the store config path web/default/cms_home_page
, which corresponds with the
System -> Configuration -> Web -> Default Pages -> CMS Home Page
section. This is where you tell Magento which CMS page you want to use as your homepage. You should see something like
string 'home' (length=4)
or
string 'about-magento-demo-store' (length=4)
or etc. dumped to your screen. This is the CMS home page identifier. If you're setting an unexpected value, try running the following
select * from core_config_data where path = 'web/default/cms_home_page';
to check for scoped values. Regardless of what you CMS Home Page ID is, check for the page's existence with the following SQL statement (assuming a value of home
).
select * from cms_page where identifier = 'home';
If Magento can't find the configured page in your system, it will forward to the 404 page. You can see that with the following code in indexAction
if (!Mage::helper('cms/page')->renderPage($this, $pageId)) {
$this->_forward('defaultIndex');
}
If renderPage
returns false
, then we're forwarded to the defaultIndexAction
method which renders the 404 page.
public function defaultIndexAction()
{
$this->getResponse()->setHeader('HTTP/1.1','404 Not Found');
$this->getResponse()->setHeader('Status','404 File not found');
$this->loadLayout();
$this->renderLayout();
}
That should be enough to find 90% of your "no route to homepage" problems, and point you in a debugging direction for the other 10%.
Best Answer
Firsly the model is now
Enterprise_UrlRewrite_Model_Url_Rewrite
:Secondly the options have changed slightly to.
Options
Note: category and product id are optional only for category and product rewrites
So assuming that your code is not for product or category rewrites: