Magento 1.8 URL Rewrite – How to Always Give /catalog/product/view/id/ Style URL for Products

magento-1.8url-rewrite

I want Magento to always generate product urls in the format:

www.example.com/catalog/product/view/id/123/s/product-name.html

instead of the rewritten

www.example.com/product-name.html

The reason for this is mainly so that I don't have to worry if something happens to all my rewrites, or so I can feel free to truncate and rebuild core_url_rewrite if something goes wrong and it gets too big.

I don't want to stop using rewritten urls entirely. I like them for categories. I have fewer categories, and I very rarely change the names. I hate feeling like I can't change the name of a product because it will make the core_url_rewrite table grow and mess up any backlinks I've generated if I lose my rewrites. Also, I still want my current urls to work for as long as possible along with the /product/view/id urls.

Is there an easy way to do this without rewriting methods that I'm missing?

Or do I have to override some getProductUrl method? It looks like the answer lies in the getProductUrl() method in Mage_Catalog_Model_Product? That class seems to use the getProductUrl() method in Mage_Catalog_Model_Product_Url.

But again, if there's some simple configuration setting that would do the trick, I'd rather do that.

Edit:
I haven't had a chance to dig through this yet, but on a related matter while working on something else, I accidentally found that there is something called getCategoryIdUrl() that does for categories what I want to done for products. I searched for the obvious getProductIdUrl and came up with nothing.

Edit:

The accepted answer given by fschmengler works really well and answers the question. But it turns out that the urls for the sitemap aren't generated with the getProductUrl() method. The sitemap is made in Mage_Sitemap_Model_Sitemap by the generateXml() method.

/**
 * Generate categories sitemap
 */
$changefreq = (string)Mage::getStoreConfig('sitemap/category/changefreq', $storeId);
$priority   = (string)Mage::getStoreConfig('sitemap/category/priority', $storeId);
$collection = Mage::getResourceModel('sitemap/catalog_category')->getCollection($storeId);
foreach ($collection as $item) {
    $xml = sprintf(
        '<url><loc>%s</loc><lastmod>%s</lastmod><changefreq>%s</changefreq><priority>%.1f</priority></url>',
        htmlspecialchars($baseUrl . $item->getUrl()),
        $date,
        $changefreq,
        $priority
    );
    $io->streamWrite($xml);
}
unset($collection);

I overrode it with something like this:

/**
 * Generate products sitemap
 */
$changefreq = (string)Mage::getStoreConfig('sitemap/product/changefreq', $storeId);
$priority   = (string)Mage::getStoreConfig('sitemap/product/priority', $storeId);
//$collection = Mage::getResourceModel('sitemap/catalog_product')->getCollection($storeId);

$rootCatId = Mage::app()->getStore($storeId)->getRootCategoryId();
$product_collection = Mage::getModel('catalog/category')->load($rootCatId)->getProductCollection()->setStoreId($storeId);
//Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($product_collection);
$product_collection->addFieldToFilter('visibility', Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
->addAttributeToFilter('status',Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
->addAttributeToSelect('url_key')
;

foreach ($product_collection as $item) {
    $url = $baseUrl.'catalog/product/view/id/'.$item->getId().'/s/'.$item->getData('url_key').'/';
    $xml = sprintf(
        '<url><loc>%s</loc><lastmod>%s</lastmod><changefreq>%s</changefreq><priority>%.1f</priority></url>',
        htmlspecialchars($url),
        $date,
        $changefreq,
        $priority
    );
    $io->streamWrite($xml);
}

//unset($collection);

It's not the most elegant solution, but it seems to work so far.

Best Answer

You have to rewrite the product URL model.

This is the relevant method in Mage_Catalog_Model_Product_Url

protected function _getProductUrl($product, $requestPath, $routeParams)
{
    if (!empty($requestPath)) {
        return $this->getUrlInstance()->getDirectUrl($requestPath, $routeParams);
    }
    $routeParams['id'] = $product->getId();
    $routeParams['s'] = $product->getUrlKey();
    $categoryId = $this->_getCategoryIdForUrl($product, $routeParams);
    if ($categoryId) {
        $routeParams['category'] = $categoryId;
    }
    return $this->getUrlInstance()->getUrl('catalog/product/view', $routeParams);
}

$requestPath is the path from the URL rewrite - you see that if a rewrite is found, this is used directly as URL, if not, the catalog/product/view URL is used.

Remove the first part to always get non-rewritten URLs:

//if (!empty($requestPath)) {
//    return $this->getUrlInstance()->getDirectUrl($requestPath, $routeParams);
//}
Related Topic