Skip to content

Instantly share code, notes, and snippets.

@quicksketch
Created August 4, 2022 21:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quicksketch/1fbb69d00d7294d1a2e3a9953dbe4dfd to your computer and use it in GitHub Desktop.
Save quicksketch/1fbb69d00d7294d1a2e3a9953dbe4dfd to your computer and use it in GitHub Desktop.

Documentation of URL Paths

This is intended to be a new sub-page in the User Guide, at User Guide > Using Backdrop > Layouts and templates > Deep dive: advanced layout options > URL paths, which would come after Visibility Conditions and Contexts sub-pages.

[Callout] URL paths allow layouts to be used on multiple menu router paths.

Layout overrides are quite powerful because a single layout can be used on multiple paths if its primary path is dynamic (i.e., contains a placeholder "%"). However, once we have defined the primary path for a layout, it won't be used on any paths whose menu router path is different. Fortunately, layouts provide a setting, "URL paths," that can allow a layout to be used on many different paths.

URL paths are a powerful feature of layouts, but they come with some new concepts and require some subtle distinctions that we have not previously delved into. So we begin this section with some useful background information.

Background: the different types of "path"

In Backdrop, there are several different types of "path", and when it comes to layouts, it is important to distinguish between them:

  • A menu router path is the type of path that you enter as the primary path of a layout. Internally, it appears in Backdrop's menu router table. It can contain placeholders (%), which stand in for some text delimited by /s. An example of a menu router path with a placeholder is node/%/edit.
  • A system path, also called a normal path, is a specific example of a router path with all placeholders filled in, e.g., node/1/edit.
  • A URL alias is a path that can be used instead of a normal path for the same web page. For example, post/title-of-my-post could be a URL alias of normal path node/1.
  • The request path is the path in the URL bar of the browser. It is usually either a normal path or a URL alias, but it can also be something longer than either, because if Backdrop doesn't recognize the request path, it tries trimming off parts to find a valid normal path. For example, the request path admin/content/foobar will load the page with normal path admin/content.

For every request path that leads to a valid web page, there is a normal path and a menu router path. There may or may not be a URL alias.

When you enter the primary path for a layout, the type of path you are entering is a menu router path. Backdrop will attempt to use that layout for any request path whose menu router path matches the layout's primary path (subject to the visibility conditions in the layout). So, for example, if the layout's primary path is node/%, then a request path of node/1 will match that layout, because the menu router path for node/1 is node/%. Similarly, if you have created aliases for nodes, like post/title-of-my-post, the layout will still match that node because the URL alias post/title-of-my-post has normal path node/1, whose menu router path is node/%.

A problem can arise, though, if there are multiple pages with similar request paths that have different menu router paths. An example of this is the case of creating a View with multiple page displays: for example, a View with pages myview/1, myview/2, and myview/3. Those three pages have three different menu router paths, namely, myview/1, myview/2, and myview/3. It might seem like entering a primary path of myview/% in the layout would let the layout apply to all three, but that's not the case, because the menu router path myview/% is different from the menu router paths myview/1, myview/2, and myview/3. So using a single layout on all three of those View pages is not possible with just the primary path setting of layouts.

It is possible, however, with a new setting in Layouts: the "URL paths" setting, which we now turn to.

URL paths

The "URL paths" setting in a layout specifies alternative paths that the layout should be considered to be used on (as always, subject to visibility conditions). URL paths can match either normal paths or URL aliases. Most importantly, they can contain wildcards, indicated by the asterisk ("*") character, which can represent any sequence of characters in the request path.

If this sounds familiar, it should; URL paths with wildcards behave almost exactly like the "URL path" visibility condition that can be applied to both layouts themselves and to blocks within layouts. You can enter any number of paths with wildcards into the "URL paths" field of a layout override, and the layout will be considered for use on request paths that match those entries, in addition to request paths whose menu router path matches the primary path of the layout.

(Note, though, that you can only enter URL paths for layout overrides, not for layout-created pages. URL paths are intended only for layouts that override existing pages.)

Since you can enter URL paths in layouts, and enter URL path visibility conditions in layouts, one might wonder, what's the difference? The key distinction is:

  • Adding layout URL paths increase the number of pages that a layout might be considered for;
  • Adding URL path visibility conditions decreases the number of pages that the layout might be considered for.

Since you can create both, you can construct fairly complex Boolean logic with URL paths, using the layout URL paths setting to expand a layout's range of applicability, then applying visibility conditions to filter that applicability down in other ways.

Limitations of contexts

When a layout's primary path contains a placeholder, the layout automatically creates a context based on the value in the placeholder's position in the menu router path. For example, if the primary path is node/%, the layout creates a context based on the value in position 1.

For some menu router paths, the placeholder(s) result in the loading of an object based on the value in the placeholder position. The node/% path is an example of this. When you visit the path node/7, the system sees the 7 in position 1 and automatically loads Node 7 in preparation for its display. The Layout system sees this and automatically creates a Node context for position 1, which any blocks within the layout can make use of.

Since we can give any layout a URL path that might match some arbitrary menu router path, if the Layout is expecting to create (for example) a Node context, there is no guarantee that the menu router path that it matches would be loading the right kind of object (if any object at all). For example, if the layout's primary path is node/%, it will try to create a Node object from the value in position 1. But if its URL path happens to match the page at path user/10, then the layout would try to create a context based on Node 10—which may not even exist! For this reason, there is an additional restriction on path matching using URL paths:

  • A layout whose primary path loads objects will only be considered if the menu router path of the request path loads the same type of object(s) from the same positions in its menu router path.

This means that a layout with primary path node/% will not be considered for matching against a request path user/1, or any request path that doesn't load a Node from position 1.

But what if we want to use the same layout on both node/% and user/%? There is a way, which brings us to the next feature of URL paths in layouts.

Null layout paths

There is a special path in layouts, the "Null layout path", which doesn't lead to an actual web page, but can be used as the primary path of a layout for which all matching is done via URL paths. Null path layouts do not create any positioned contexts, so they can serve as "universal" layouts that could potentially be used on any path—with the range of paths defined by the URL paths of the layout, then filtered down by visibility conditions.

The default value of the null path is null, but you can change this value to anything you want, at admin/structure/layouts-null-path. (You might already have a page at null, and the null path may not be the same as any existing page's path.) If you're not using this feature, you can leave it blank.

Since null layout paths do not create positioned contexts, there is no way to pass any values in the path to blocks in the layout as contexts.

We will show an example of using a null layout path below.

Examples

Here are some typical use cases where URL paths can be used to display multiple pages with a single layout.

A static View with multiple page displays

Problem: We have a View with three page displays, staticview/1, staticview/2, and staticview/3, which we want to use a single layout for.

Solution: Create the layout with primary path staticview/1 and URL paths staticview/*.

Why it works: The layout will match staticview/1 via its primary path, and then the URL path staticview/* will match the other two pages (and any additional ones that get added whose paths are in the same form).

A dynamic View with multiple page displays

Problem: We have a View with two dynamic View pages that take arguments via contextual filters, so the page paths are dynamicview-a/% and dynamicview-b/%. We wish to use a single layout on paths like dynamicview-a/1 and dynamicview-b/1 and the like.

Solution: Create the layout with primary path dynamicview-a/% and URL path dynamicview-b/*.

Why it works: The layout matches dynamicview-a/1 on its primary path and dynamicview-b/1 on its URL path. The View does not create objects based on position, so context will not be a limitation.

A dynamic View with multiple page displays, different path lengths

Problem: We have a View with two dynamic View pages that take arguments via contextual filters, so the page paths are newdynamicview/% and newer/dynamic/view/%. We wish to use a single layout on paths like newdynamicview/1 and newer/dynamic/view/1 and the like.

Solution: Create the layout with primary path newdynamicview/% and URL path newer/dynamic/view/*.

Why it works: This still works, just like the previous example, however, the layout will be creating a string-pass-through context from the path argument at position 1. For newdynamicview/1, that value is 1. But for newer/dynamic/view/1, that value is dynamic. So you should not create any blocks that use that context if you are expecting it to be the Views contextual filter argument.

There is currently no way for a single layout to create contexts based on path arguments in different positions that depend on the specific URL path match.

Same layout for node/% and user/%.

Problem: We would like to use the same layout for both node and user pages like node/1 and user/1, but not for their administrative pages like node/1/edit or user/1/edit.

Solution: Create the layout with the path null (assuming that's the "Null layout path" setting) and URL paths node/* and user/*. Then create URL path visibility conditions that forbid node/*/* and user/*/*.

Why it works: Any null layout path does not try to create any objects from path arguments, so it can serve as a "universal" layout. A possible drawback is that the layout cannot create any contexts based on path positioned arguments, but then, since an argument value of 1 for a node page means something entirely different from an argument value of 1 for a user page, that is appropriate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment