Path Builder: define how path is formed from slugs/etc per model

Dato should know the final relative path associated with each record. To tell it, for each model, I would like to be able to define rules for how the record’s final relative frontend path is formed from its slug, related slugs, or related fields.

The benefits of this would be:

  1. When pulling record data from the API, we can also pull it with a correct related front-end path (because we have told Dato how to generate that path)
  2. DatoCMS could include a link picker (far more user friendly) when inserting inline links: the editor selects a record, Dato generates the correct path and inserts it
  3. DatoCMS slug field can show the actual final path in its prefix element automatically (more user-friendly for editors)
  4. Easily offer a link to click from viewing a record in DatoCMS to viewing the live page (in different deployment environments) – much more user-friendly “preview” experience

The Path Builder rules would be specified in Settings, under a new “Path Builder” tab. There is always a “Default” rule which is just “slug” (i.e. the path is the slug of the record); but more rules can be added. Each model then references the rule that it should use, in its settings. Again, the default for all models is to use the Default rule.

When creating a new Path Builder rule, we are offered a number of possible path-fragments, which we can add together in a list. These include an explicit /.

  • Field: slug + “.html”
  • “about” + / + Field: slug
  • Field: category + / + Field: slug
  • “info” + / + Field: slug <Options: tree-recurse, separator: / (default)>

The final example there addresses the key use case, which is tree collections. The most common use case is that the path is formed by the slugs of all ancestors, concatenated with “/”.

In example 3, we specify that the path is formed from the value of the category field within the record, plus the record’s slug. So, how do we handle fields that aren’t slug fields? It depends on the field’s type:

  • Link: use the slug of the (first) linked record
  • Date: format it (use can specify e.g. <Option: format: yyyy-mm>)
  • Anything else: stringify, and then slugify, the field value

At present, all path building logic is done after data is pulled down from Dato. That works, but it makes sense to me to be able to configure this at the CMS side, which may be a faster and simpler workflow for many types of app/site. Furthermore, if Dato knows the path, we can gain a number of UX improvements inside Dato as well.

I really like this suggestion. On a few occasions I’ve thought to suggest something along these lines but never posted because as I thought about it I realised how big a feature it is and I couldn’t come up with a solution with a small implementation surface area. A couple of other thoughts:

  • I like the idea of overloading the slug field type, so it’s all in one place
  • I love the idea of integrating links to markdown content areas etc, since Dato would have real information on models’ live URLs; valid model links could be labelled as such to avoid errors
  • As you stated, Dato could have a a really nice UI for viewing preview and live model pages
  • You could drag and drop tokens representing model fields to build the path; if you dragged a relationship field, then that path segment would be resolved to the related model so you could do eg: /products/category-slug/product-slug
  • If you went down the drag-and-drop token route, it would set a good precedent for using that pattern elsewhere (I’ve been frustrated before about page titles for example, where you can either use a static user-entered string via Dato’s SEO field type, or build your own dynamic titles on the front end, but lose access to the nice meta tags helpers; an ideal solution would be to be able to build dynamic titles within Dato just like your suggestion for the paths)

I’d love to see this done well in usual lightweight Dato style. A great counter-example to look at to see what not to do is Prismic’s link resolver system. It relies on using either their client library or writing your own link resolver code, and parsing their markdown-style text content to resolve inline links. It all works, and it’s ok for a team of developers, but it’s very heavy and not at all maintainable for small teams and solo developers.

1 Like

As a simpler way to implement path builder rules, rather than a drag-and-drop interface, just allow us to type in a function, e.g.

function (record) {
   return "/about/" + record.parents.join('/') + record.slug + '.html
}

I guess JS would be the best language to implement such a path-building function in, as then this can just run right there in the browser when it’s needed in the editor interface?