SEO

ViUR offers the possibility to make URLs SEO-friendly in multiple languages. For this you can define seo-identifiers for each url component.

Module

The module name is the first part of a URL. SEO-identifiers have to be set as class-attribute seo_language_map of type dict[str, str] in the module. It maps a language to the according identifier.

modules/myorders.py
from viur.core.prototypes import List

class MyOrders(List):
    seo_language_map = {
        "de": "bestellungen",
        "en": "orders",
    }

By default the module would be available under /myorders, the lowercase module name. With the defined seo_language_map, it will become available as /de/bestellungen and /en/orders.

Great, this part is now user and robot friendly :)

Method

The method name is usually the second part of a URL. SEO-Identifiers can be provided to the exposed decorator of type dict[str, str]. It maps a language to the according identifier.

modules/myorders.py
from viur.core.prototypes import List
from viur.core import exposed

class MyOrders(List):
    seo_language_map = {
        "de": "bestellungen",
        "en": "orders",
    }

    @exposed({
        "de": "warenkorb",
        "en": "cart",
    })
    def view_the_cart(self):
        ...

By default the method would be available under /myorders/view_the_cart. With the defined seo_language_map, it will become available as /de/bestellungen/warenkorb and /en/orders/cart.

Great, this part is now user and robot friendly as well :)

Entry

The entry key is usually used as third part of a URL if you use explicit the view method. By default the index method of the List prototype can handle keys or seo-identifiers of an entry as well.

SEO-Identfiers of an entry (a Skeleton instance) are defined in the method getCurrentSEOKeys inside your Skeleton. This gives you the possibility to use whatever you want as identifier: A timestamp, a bone value, a composition of bones values, ….

skeletons/myorders.py
from typing import Union, Dict

from viur.core.skeleton import Skeleton
from viur.core.bones import *

class MyOrdersSkel(Skeleton):
    first_name = stringBone(
        descr="Customer's firstname",
    )
    last_name = stringBone(
        descr="Customer's lastname",
    )
    # [...]

    order_number = numericBone(
        descr="Ordernumber",
        required=True
    )

    @classmethod
    def getCurrentSEOKeys(cls, skelValues) -> Union[None, Dict[str, str]]:
        """Return the seo-identifiers for this entry.

        Return a dictionary of language -> SEO-Friendly key
        this entry should be reachable under.

        The German and English identifiers are identical,
        they consist of the lastname (of the customer)
        and the (6 chars zero padded) order number.

        If the name is already in use for this module,
        the core will automatically append some random string
        to make it unique.
        """
        return {
            "de": f"{skelValues['last_name']}-{skelValues['order_number']:06}",
            "en": f"{skelValues['last_name']}-{skelValues['order_number']:06}",
        }

You can now reach your entries under /de/bestellungen/Mustermann-001234

Great, we did it!

Warning

Keep in mind that you can very easily guess the identifiers in this example. For obvious reasons orders should not be visible to everyone. In cases like this make the website noindexed and define a suitable canView method inside your module, to restrict the access only to the account of the customer and seller.