A Guide To Using Urls in Magento

In developing web apps, and, more specifically, Magento stores, it is vital to ensure the site is implementing proper urls. Improper use of urls displayed on a page will result in user frustration and a very high exit rate, both consequences that will negatively impact the site. Proper implementations, however, will lead the user around the site in its intended flow and generate a clean, intuitive user experience.

Always Use Absolute Urls

magento
When adding a href or an src attribute to an <a> or <img> tag, you can pass in a relative url, such as “contact-us.html”, or you can pass in an absolute url, such as “http://www.magentohost.com/contact-us.html”. While some developers may tell you that relative urls are a better practice to follow because they are not absolutely bound to the base url (that is to say, you could use the same link on a development and production site), this should not apply to Magento. Magento comes with a slew of url functions that will programatically build the base url based on the site’s configuration, and appends the proper extensions and parameters based on the specified arguments.

Using relative urls will cause other problems as well, as it could lead the user to a 404 page if not specified properly, which can happen often with global links. For example, having a link in the footer with the following markup: <a href=”contact-us.html”>…</a> will link you to the current url with “contact-us.html” appended to it. If a user was on the homepage, this would work as expected, taking the user to http://magentohost.com/contact-us.html, but if they were on any other page, say the cart page, they would be taken to the wrong url, in that case http://magentohost.com/checkout/cart/contact-us.html, sending the user to a 404 page. There are also other unintended consequences of using relative urls, such as bots and crawlers building incorrect sitemaps (a phenomenon I have seen multiple times).

So for the rest of this tutorial, I will be invoking Magento functions that apply absolute urls in order to ensure the user arrives at his or her destination of choice.

Related: Optimizing Google Enhanced eCommerce for Magento

Starting From the Top

Right in app/Mage.php there is a static getUrl function that allows two arguments, $route (the specified route – relative to the base path) and $params (an associative array of named params). These arguments will default to an empty string and an empty array, respectively. This function calls the getUrl() function in Mage_Core_Model_Url.

The important thing to note is that these functions will programatically add your specified path to the base_url of the current store, as it is configured in the database. This way, you can also achieve environmentally independent urls that still follow best practices. Check out the following function, Mage_Core_Model_Url::getRouteUrl(), which is called by the earlier Mage_Core_Model_Url::getUrl(). See how it appends the specified path to $this->getBaseUrl()? That way it gets the base url from system configuration instead of hardcoded locations. This way, if the domain were to ever change, the links would still work properly despite only changing the url in the database.

/**
* Retrieve route URL
*
* @param string $routePath
* @param array $routeParams
*
* @return string
*/
public function getRouteUrl($routePath = null, $routeParams = null)
{
$this->unsetData('route_params');
if (isset($routeParams['_direct'])) {
if (is_array($routeParams)) {
$this->setRouteParams($routeParams, false);
}
return $this->getBaseUrl() . $routeParams['_direct'];
}
if (!is_null($routePath)) {
$this->setRoutePath($routePath);
}
if (is_array($routeParams)) {
$this->setRouteParams($routeParams, false);
}
$url = $this->getBaseUrl() . $this->getRoutePath($routeParams);
return $url;
}
view raw getRouteUrl_sample hosted with ❤ by GitHub

Related: The Magento Upgrade Guide

Specific Url Types

URL types
Now that I have (hopefully) convinced you that absolute urls are to be used absolutely in Magento, let’s look at how to find a usable function from wherever you are in the code base. Let’s start with a common issue, using proper urls in CMS pages and static blocks.

CMS Pages and Static Blocks (and Email Templates!!)

It’s actually quite simple to use absolute urls with Magento’s functionality in the cms. All you need to do is specify a variable like so:  {{store url=’contact-us.html’}} and the CMS processor will automatically strip out the variable and replace it with a proper, absolute url. To grab a media or skin image from the CMS, simply replace the `store` above with `media` or `skin` respectively. For example, try {{media url=’wysiwyg/upload_xyz.png’}} or {{skin url=’images/down-arrow.png’}}. These paths will be added onto the base url and form an absolute path to the specified resource.

From Magento Blocks and Templates

Any block that extends Mage_Core_Block_Abstract can call $this->getUrl($route), where $route is the path beyond the base url of the site. This function ends up calling the Mage_Core_Model_Url::getUrl() function discussed above. This is a really quick and handy way to build absolute urls programatically and is the best practice.

Another handy function located within Mage_Core_Block_Abstract is getSkinUrl(). This function actually finds the current design package and theme, and builds the url path based on that dynamic data. The argument that needs to be passed to this function should be the path relative to the theme directory, meaning if my current package were enterprise/demac/, I would call $this->getSkinUrl(‘images/sample_image.png’), and the url generated would be http://magentohost.com/skin/frontend/enterprise/demac/images/sample_image.png.

For media urls, there is no dynamic function to be used. You can either call $this->getUrl() . 'media/path/to/resource.gif' or you can call Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA) . ‘path/to/resource.gif’. Both of these will build the same url.

Outside the Blocks

If you are working in a helper or model, you can use the static function from Mage.php to build an absolute url. Calling Mage::getUrl() from anywhere in Magento will result in a call to the Mage_Core_Model_Url::getUrl() function and build your url from there. It is generally a good idea to use this Mage.php function, since there may not be a getUrl() function in the current class you are working with.

Additionally, there are a number of getUrl() functions littered through Models in Magento that have custom logic specific to the class. For example, calling getUrl() on an instance of Mage_Catalog_Model_Product_Image will run custom logic to get that specific image’s url. As well, Mage_Adminhtml_Model_Url::getUrl() will deal with additional logic for finding the proper admin frontname as specified in app/etc/local.xml. Since there are a number of additional getUrl() functions, it is important to be cognizant of which class’ function you are actually calling.

Product Media Images

This here is a good opportunity to go over product media image urls, since I have often seen image urls being constructed improperly.

Product media galleries can be difficult to understand initially, but they can be roughly understood as a Magento collection object stored as a product attribute. Getting a product’s default image can be as simple as calling $product->getImageUrl(), but this is an inflexible function since you can’t actually load the whole image collection this way. Let’s have a look at a stripped down section of app/design/frontend/base/default/template/catalog/product/view/media.phtml from Magento 1.8 to identify a good practice for displaying media images.

<?php
$_product = $this->getProduct();
$_helper = $this->helper('catalog/output');
?>
...
<?php foreach ($this->getGalleryImages() as $_image): ?>
<li>
<a href="#" title="<?php echo $this->escapeHtml($_image->getLabel()) ?>">
<img src="<?php echo $this->helper('catalog/image')->init($this->getProduct(), 'thumbnail', $_image->getFile())->resize(56); ?>" width="56" height="56" alt="<?php echo $this->escapeHtml($_image->getLabel()) ?>" />
</a>
</li>
<?php endforeach; ?>
view raw media.phtml hosted with ❤ by GitHub

This Block first calls getGalleryImages() which returns a collection of the product’s media gallery images. As it loops through the collection it utilizes the helper function Mage_Catalog_Helper_Image::init() and passes the product, the attribute name (either ‘image’, ‘small_image’ or ‘thumbnail’), and the image file. This init() function will build the proper url to the given image, returning a placeholder url if the file is not found. This is the ideal way to grab media gallery images, as it builds absolute urls and has a fallback, so you will not end up with a broken image on the frontend.

What we Learned

I hope the guide above was interesting and informative, and that you picked up some good habits along the way. You should now know never to use relative urls (even in the cms and email templates!!) and understand how to programatically build absolute urls within the scope of the Magento configuration. You should also understand which functions are available to be called from within the code base and the backend. Finally, you should have a basic understanding of the process used to get and display product images properly. Congratulations are in order, as you should now have an SEO friendly web application that will be adaptable to change.

Related: 8 Easy Ways to Improve Magento Site Speed