Inside Prestashop – SEO Friendly URLs (1/2)

Prestashop Friendly URL’s, how it works (part 1)

You want to develop your own modules or want to change the way Pretashop behaves. This article is for you.

According to SEO experts, friendly URL’s is one of the important features your website needs to implement. In this article, I will give you detailed explanations on how Prestashop has technically implemented these friendly URL’s. So, we’re going to talk about PHP, Model View Controller, object-oriented programming…

Audience

You need to have some knowledge of PHP, Prestashop, object-oriented programming, model-view-controller architecture and SQL databases.

Prestashop version

These articles relate to Prestashop 1.7, more specifically version 1.7.2.4 which is the one I’m using at the time of writing this article.

Background

If you want to know why I decided to dive into the heart of Prestashop and PHP, read this article: the FadeurParts.be project.

In short, in needed for this project to add a parameter to the URL, to keep track of the filter selected by the customer. My custom development didn’t work when Friendly URL (URL Simplifiées) is on. To keep track of the selected filter (tractor), I added a parameter id_tractor at the end of the category and product URL, in the form « ?id_tractor=n », where n is the database id of the tractor selected by the user. URL looks like this:

index.php?id_category=1012&controller=category&id_lang=2&id_tractor=159

Of course, when you turn on friendly URL, this does not work anymore! So, I needed to replace ugly URL with pretty URL like:

fr/159-john-deere-6320/1069-u-joints

And to do this, I needed again to open the hood and understand how Prestashop works internally. In this article, I will  share with you what I’ve understood of the inside, technical details, of the Prestashop core PHP code when dealing with URL. I will also describe the general MVC (Model View Controller) as implemented within Prestashop.

You’ll find more information on this in the PrestaShop (1.7) Module Developer Guide.

Why do you need IDs in friendly URL ?

In the above example, 159 is the database id of the tractor and 1069 is the id of the category. This is required because Prestashop still needs a unique identifier for the tractor and the category and the names, john-deere-6320 and u-joints, are not guaranteed to be unique (if you look at the database, there is no uniqueness constraint on the column _category_lang.link_rewrite).

I’ve seen Prestashop modules claiming they remove the id’s from the friendly URL. I’ve not tested them, but in my understanding, there is always a risk that two products or two categories could have the same URL. As far as I know, Prestashop does not enforce category name, or link_rewrite uniqueness. Same for product. I’m just curious to see how this works.

Configuring Prestashop to show Friendly URL

You do this by going to the back-office, Shop Parameters > Traffic and SEO. You need to scroll down and locate the section Setup URLS and select Friendly URL = Yes (and click save!).

Quick note: if you have developed your own front controller or if you want to change the friendly URL for existing front controllers, you can do this in the first part of the Traffic and SEO page.

Now, if you scroll down further, you’ll find a section Schema of URLS. Let’s explain the purpose of this section.

Schema of URLS (Prestashop friendly URL routes)

Route to category configuration

I’m not too sure why they call that a « route », but let’s have a closer look at the Route to category configuration (BO):

{id}-{rewrite}

This configuration is used to generate the friendly URL:

  • {id} will be substituted by id_category (this field is mandatory);
  • {rewrite} will be substituted by the value of column link_rewrite from table _category_lang. This is language specific. You can set the value of this column in the product page (BO) and it can be different for each language.
  • You can also use meta_keywords or meta_title instead of rewrite.

This will produce the URL: …fr/1001-catalogue.

If you change the configuration to: category/{id}-{rewrite}

The URL will look like: …fr/category/1001-catalogue.

Route to products configuration

The configuration of the route to products works the same way but is a bit more complex:

{category:/}{id}{-:id_product_attribute}-{rewrite}{-:ean13}.html

  • {category:/} is the name of default category of the product.
  • {id} is the id_product.
  • etc.
  • When a configuration field has no data for the displayed product, the field will be omitted from the URL.

Let’s now have a look on how this affects the internal behavior of the core Prestashop code. We need to have a look at the class Dispatcher.php, where the URL are processed. Read an overview of the controller mechanism implemented by Prestashop <todo: provide link to article>

Dispatcher.php URL decoding

Most of the logic of the friendly URL is contained in the class Dispatcher (classes/dispatcher.php). Here is what happens when Prestashop receive a request.

Initializing the class dispatcher.php

This is done by index.php. Here are the interesting things happening about URLS:

  • In the __construct() method, the property $use_routes is set to true if friendly URLS are on (_configuration table, key PS_REWRITING_SETTINGS).
  • The property $request_uri is set with the value of the incoming URL (either $_SERVER[‘REQUEST_URI’] or $_SERVER[‘HTTP_X_REWRITE_URL’].
  • The method load_routes():
    • Loads the property $routes (array) with the routes defined for the front controllers (from tables _meta and _meta_lang). As I wrote above, you can change these values in BO > Traffic and SEO page (first part of the page).
    • Adds to the property $routes all the routes defined for category, supplier, manufacturer, cms, cms_category, module, product and layered (product when the faceted search module is enabled). The data are loaded from the table _configuration and from the property $default_routes. You should have a look at dispatcher.php, array property $default_routes because this will help you understand how Prestashop friendly URL are decoded by the dispatcher.

How does Prestashop recognize friendly URL type

Dispatcher->dispatch() is called by index.php. At the end of this method, you’ll see a call to getController(). This one will actually process the requested URI and, if it is a friendly URL, will assign parameters to the $_GET global array so that the controller (that will be invoked later) can do his job. This happens at the end of the method, around line 782 (PS 1.7.2.4).

Now, your certainly wondering how Prestashop knows if the URL relates to a category, a product or something else ? The nature of the URL will be determined on its pattern, using regular expression. For example:

  • regexp for category:
    #^/(?P<id_category>[0-9]+)\-([_a-zA-Z0-9\pL\pS-]*)$#u
  • regexp for product:
    #^/(([_a-zA-Z0-9-\pL]*)/)?(?P<id_product>[0-9]+)(\-(?P<id_product_attribute>[0-9]+))?\-(?P<rewrite>[_a-zA-Z0-9\pL\pS-]*)(\-([0-9\pL]*))?\.html$#u"

Default route configuration table

RouteConfiguration
Category{id}-{rewrite}
Category while filtered{id}-{rewrite}{/:selected_filters}
Supplier{id}__{rewrite}
Brand{id}_{rewrite}
CMS pagecontent/{id}-{rewrite}
CMS categorycontent/category/{id}-{rewrite}
Modulesmodule/{module}{/:controller}

If for example, the URI matches the regexp for category (the category_rule route), then

  • $_GET[‘controller’] will be set to ‘category’;
  • $_GET[1] will be set to &id_category=n.

Conclusion

Now have we a better understanding on how Prestashop interprets friendly URL and transform them back to regular URL. But we are just half way. We need to understand how these URLS are built upfront. Mainly the category and product URL that will be sent to the server when a customer clicks on a category or on a product in the FO. We will have a look at this in the next article: Inside Prestashop – SEO Friendly URLs (2/2).