Skip to content

Commit 83cbcbb

Browse files
committed
Entry and category URI formats
1 parent 947c663 commit 83cbcbb

File tree

2 files changed

+76
-28
lines changed

2 files changed

+76
-28
lines changed

docs/5.x/reference/element-types/categories.md

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ Read more about this [transition](https://craftcms.com/blog/entrification) on ou
3535
Every category belongs to a _category group_, which defines…
3636

3737
- …a name;
38-
- …a handle (used when referencing the group in queries and templates);
38+
- …a handle (used when referencing the group in [queries](#querying-categories) and templates);
3939
- …the maximum number of levels categories can be nested, within the group;
40-
- …the format of category URIs;
41-
- …which template should be rendered when a category’s URL is accessed;
40+
- …the format of category URIs used for [routing](#routing-and-templates);
41+
- …which [template](#routing-and-templates) should be rendered when a category’s URL is accessed;
4242
- …which [fields](../../system/fields.md) categories in the group should have;
4343

44-
To create a new category group, go to **Settings****Categories** and click **New Category Group**.
44+
To create a new category group, go to <Journey path="Settings, Categories" /> and click **New Category Group**.
4545

4646
## Category Field Layout
4747

48-
Each category group has its own _field layout_, which allows you to customize the data that’s associated with each category in the group. By default, every category will have a **Title** field (the category name). Any available field type can be added to a category group’s field layout.
48+
Each category group has its own _field layout_, which allows you to customize the data that’s associated with each category in the group. By default, categories only have a **Title** and **Slug**, but you can add as many other [custom fields](../../system/fields.md) as necessary to satisfy your content architecture.
4949

5050
<See path="../../system/fields.md" />
5151

@@ -74,18 +74,36 @@ When you create a category, you have the following options:
7474

7575
- Fill out the category fields (if you didn’t define any, the only field available will be **Title**)
7676
- Edit the slug (it’s automatically populated based on the title).
77-
- Choose a Parent category. The new category will have a hierarchical relationship with its parent. This is helpful for creating taxonomies with multiple levels. You also have the option of creating a new category while assigning the Parent.
77+
- Choose a **Parent** category. The new category will have a hierarchical relationship with its parent. This is helpful for creating taxonomies with multiple levels. You also have the option of creating a new category while assigning the Parent.
7878

7979
::: tip
80-
You can only nest categories up to the level specified in the **Max Level** field Category Group settings. If it’s empty, the nesting level is unlimited.
80+
You can only nest categories up to the level specified in the **Max Level** field Category Group settings. By default, there is no limit to how deeply-nested categories can be.
8181
:::
8282

8383
## Assigning Categories
8484

85-
To assign categories to things (entries, assets, users, etc.), you must first create a [Categories field](../field-types/categories.md).
85+
To assign categories to things (entries, assets, users, etc.), you must first create a [categories field](../field-types/categories.md).
8686

8787
Each Categories field is connected to a single category group. Whatever you attach the field to will store [relations](../../system/relations.md) to categories selected from that group.
8888

89+
## Routing and Templates
90+
91+
Category groups’ **URI Format** setting is equivalent to that of [entries](entries.md), so any of the [object template](../../system/object-templates.md) strategies discussed in [this section](entries.md#entry-uri-formats) apply to categories, as well.
92+
93+
When a category’s URL is requested, Craft renders the template defined by its group, and makes a special `category` variable available. Supposing a _Flavors_ category group had a **URI Format** of `flavors/{slug}` and was configured to use `_categories/flavors.twig` as its **Template**:
94+
95+
```twig
96+
{{ category.title }}
97+
{# -> "Sour Aromatics" #}
98+
99+
{{ category.ancestors.collect()
100+
.select('title')
101+
.join(' / ') }}
102+
{# -> "Sour & Fermented / Sour" #}
103+
```
104+
105+
Custom fields attached to the group’s field layout are also available via the `category` variable.
106+
89107
## Querying Categories
90108

91109
You can fetch categories in your templates or PHP code using **category queries**.
@@ -107,17 +125,17 @@ Once you’ve created a category query, you can set [parameters](#parameters) on
107125

108126
### Example
109127

110-
We can display a navigation for all the categories in a category group called “Topics” by doing the following:
128+
We can display a navigation for all the categories in a _Flavors_ category group by doing the following:
111129

112130
1. Create a category query with `craft.categories()`.
113-
2. Set the [group](#group) parameter on it.
131+
2. Set the [group](#group) parameter on it using its handle.
114132
3. Fetch the categories with `.all()`.
115133
4. Loop through the categories using a [nav](../twig/tags.md#nav) tag to create the navigation HTML.
116134

117135
```twig
118136
{# Create a category query with the 'group' parameter #}
119137
{% set myCategoryQuery = craft.categories()
120-
.group('topics') %}
138+
.group('flavors') %}
121139
122140
{# Fetch the categories #}
123141
{% set categories = myCategoryQuery.all() %}
@@ -137,11 +155,13 @@ We can display a navigation for all the categories in a category group called
137155
</ul>
138156
```
139157

158+
Keep in mind that this only holds value for category groups with multiple hierarchical levels. If you were working with a “flat” taxonomy, the template above can use a `{% for %}` tag in lieu of Craft’s `{% nav %}` tag.
159+
140160
::: tip
141161
To maintain the exact order you see in the control panel, add `orderBy('lft ASC')` to your query:
142162
```twig
143163
{% set myCategoryQuery = craft.categories()
144-
.group('topics')
164+
.group('flavors')
145165
.orderBy('lft ASC') %}
146166
```
147167
:::
@@ -150,19 +170,33 @@ To maintain the exact order you see in the control panel, add `orderBy('lft ASC'
150170

151171
When you’ve attached a [categories field](../field-types/categories.md) to another type of element, you can query for those elements when you have a reference to a category.
152172

153-
For example, if we were building a blog with dedicated “Topic” (category) pages, we might build a query like this to look up posts:
173+
For example, if we were building a “Tasting Notes” database with dedicated _Flavor_ (category) pages, we might build a query like this to look up records:
154174

155175
```twig
156-
{% set posts = craft.entries()
176+
{% set records = craft.entries()
157177
.relatedTo({
158178
targetElement: category,
159-
field: 'topics',
179+
field: 'flavors',
160180
})
161181
.all() %}
162182
```
163183

184+
::: tip
185+
Here, `flavors` also happens to be the handle of the relational field. _You do not need to follow any kind of convention when naming relational fields_; the groups available for selection in a given categories field are explicitly defined on that field.
186+
:::
187+
164188
<See path="../../system/relations.md" description="Read about querying with relational fields." />
165189

190+
You can also use the field’s query method to set up the relational constraint, automatically:
191+
192+
```twig
193+
{% set records = craft.entries()
194+
.flavors(category)
195+
.all() %}
196+
```
197+
198+
In both cases, we’re assuming the `category` variable comes from Craft, when loading an individual category’s [template](#routing-and-templates).
199+
166200
### Parameters
167201

168202
Category queries support the following parameters:

docs/5.x/reference/element-types/entries.md

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,32 @@ You can supplement the automatic [sources](../../system/elements.md#sources) pre
156156

157157
### Entry URI Formats
158158

159-
Channel and structure sections can choose whether their entries should be assigned URLs in the system by filling in the **Entry URI Format** setting. Singles have a “URI” setting, but it is typically defined statically or omitted (if it doesn’t need its own URL).
159+
Channel and structure sections can choose whether their entries should be given URLs in the system by filling in the **Entry URI Format** setting. Singles also have this setting, but it is typically a static path or omitted (if it doesn’t need its own URL, like a [global set](globals.md)).
160160

161161
The entry URI format is an [object template](../../system/object-templates.md), which gets evaluated each time an entry in the section is saved. The result is saved as the entry’s **URI** in the system, and is used to generate URLs (i.e. via `entry.url`) and when Craft is determining how to [route](../../system/routing.md) a request.
162162

163163
When Craft matches a request to an entry, its section’s designated **Template** is rendered. That template is automatically provided an `entry` variable, set to the resolved <craft5:craft\elements\Entry> object, and ready to output any of its attributes or custom field data.
164164

165+
#### URI Recipes
166+
167+
Consider these tips for creating special URIs:
168+
169+
- A URI that evaluates to `__home__` (and nothing more) will be available at your site’s base path;
170+
- An empty URI means the entry does not get a route and will not have a public URL—unless you define one manually via `routes.php`;
171+
- Any Twig statement can be used to output values in a URI template—including ones that query for other elements, e.g. `{{ craft.entries().section('mySingle').one().slug }}/news` (see note below);
172+
- [Aliases](../../configure.md#aliases-and-environment-variables) can be evaluated with the [`alias()` function](../twig/functions.md#alias): `{{ alias('@basePressUri') }}/news`, `{{ alias('@mySectionUri') }}`.
173+
- The [null-coalescing operator](https://twig.symfony.com/doc/3.x/templates.html#other-operators) (`??`) can silently swallow undefined variable errors (like `parent.uri`, above);
174+
175+
::: warning
176+
Elements accessed via the current `object` (like authors or relational fields) will be loaded in the appropriate site, but _new_ element queries (like the example above that uses `craft.entries()`), must explicitly use `.site()` to avoid loading elements in the default site:
177+
178+
```
179+
{craft.entries().section('mySingle').site(object.siteId).one().slug}
180+
```
181+
182+
The current element’s site ID can always be accessed via `object.siteId`.
183+
:::
184+
165185
#### Hierarchical URIs
166186

167187
Structure sections may benefit from nested paths, for child entries:
@@ -186,21 +206,15 @@ The above template could also be expressed with this syntax:
186206

187207
With the above Entry URI Format, a top-level entry’s URI would be `earth/south-america`, with a nested entry having `earth/south-america/chile`.
188208

189-
::: tip
190-
Consider these tips for creating special URIs:
191-
192-
- A URI that evaluates to `__home__` (and nothing more) will be available at your site’s base path;
193-
- An empty URI means the entry does not get a route and will not have a public URL—unless you define one manually via `routes.php`;
194-
- Any Twig statement can be used to output values in a URI template—including ones that query for other elements, e.g. `{{ craft.entries().section('mySingle').one().slug }}/news`;
195-
- [Aliases](../../configure.md#aliases-and-environment-variables) can be evaluated with the [`alias()` function](../twig/functions.md#alias): `{{ alias('@basePressUri') }}/news`, `{{ alias('@mySectionUri') }}`.
196-
- The [null-coalescing operator](https://twig.symfony.com/doc/3.x/templates.html#other-operators) (`??`) can silently swallow undefined variable errors (like `parent.uri`, above);
197-
:::
198-
199209
#### Nested Entry URLs
200210

201-
[Nested entries](#nested-entries) in Matrix fields can also be configured to have URLs—but the settings are part of the field, not a section.
211+
[Nested entries](#nested-entries) in [Matrix fields](../field-types/matrix.md) can also be configured to have URLs—but the settings are part of the field, not a section. As a result, entries of a given [type](#entry-types) may have URLs in some contexts, and not in others!
202212

203-
A single entry type may have URLs in some contexts, and not in others!
213+
In a nested entry’s URI format, you can access the _owner_’s attributes using `{owner.someAttribute}`:
214+
215+
```
216+
{owner.uri}/steps/{slug}
217+
```
204218

205219
### Preview Targets <Badge type="edition" vertical="middle" title="Preview Targets are configurable in Craft Team">Team</Badge> <Badge type="edition" vertical="middle" title="Preview Targets are configurable in Craft Pro">Pro</Badge>
206220

0 commit comments

Comments
 (0)