Skip to content

Commit

Permalink
Entry and category URI formats
Browse files Browse the repository at this point in the history
  • Loading branch information
AugustMiller committed Dec 17, 2024
1 parent 947c663 commit 83cbcbb
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 28 deletions.
64 changes: 49 additions & 15 deletions docs/5.x/reference/element-types/categories.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ Read more about this [transition](https://craftcms.com/blog/entrification) on ou
Every category belongs to a _category group_, which defines…

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

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

## Category Field Layout

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.
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.

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

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

- Fill out the category fields (if you didn’t define any, the only field available will be **Title**)
- Edit the slug (it’s automatically populated based on the title).
- 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.
- 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.

::: tip
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.
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.
:::

## Assigning Categories

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

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.

## Routing and Templates

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.

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**:

```twig
{{ category.title }}
{# -> "Sour Aromatics" #}
{{ category.ancestors.collect()
.select('title')
.join(' / ') }}
{# -> "Sour & Fermented / Sour" #}
```

Custom fields attached to the group’s field layout are also available via the `category` variable.

## Querying Categories

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

### Example

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

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

```twig
{# Create a category query with the 'group' parameter #}
{% set myCategoryQuery = craft.categories()
.group('topics') %}
.group('flavors') %}
{# Fetch the categories #}
{% set categories = myCategoryQuery.all() %}
Expand All @@ -137,11 +155,13 @@ We can display a navigation for all the categories in a category group called
</ul>
```

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.

::: tip
To maintain the exact order you see in the control panel, add `orderBy('lft ASC')` to your query:
```twig
{% set myCategoryQuery = craft.categories()
.group('topics')
.group('flavors')
.orderBy('lft ASC') %}
```
:::
Expand All @@ -150,19 +170,33 @@ To maintain the exact order you see in the control panel, add `orderBy('lft ASC'

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.

For example, if we were building a blog with dedicated “Topic” (category) pages, we might build a query like this to look up posts:
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:

```twig
{% set posts = craft.entries()
{% set records = craft.entries()
.relatedTo({
targetElement: category,
field: 'topics',
field: 'flavors',
})
.all() %}
```

::: tip
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.
:::

<See path="../../system/relations.md" description="Read about querying with relational fields." />

You can also use the field’s query method to set up the relational constraint, automatically:

```twig
{% set records = craft.entries()
.flavors(category)
.all() %}
```

In both cases, we’re assuming the `category` variable comes from Craft, when loading an individual category’s [template](#routing-and-templates).

### Parameters

Category queries support the following parameters:
Expand Down
40 changes: 27 additions & 13 deletions docs/5.x/reference/element-types/entries.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,32 @@ You can supplement the automatic [sources](../../system/elements.md#sources) pre

### Entry URI Formats

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).
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)).

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.

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.

#### URI Recipes

Consider these tips for creating special URIs:

- A URI that evaluates to `__home__` (and nothing more) will be available at your site’s base path;
- 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`;
- 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);
- [Aliases](../../configure.md#aliases-and-environment-variables) can be evaluated with the [`alias()` function](../twig/functions.md#alias): `{{ alias('@basePressUri') }}/news`, `{{ alias('@mySectionUri') }}`.
- 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);

::: warning
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:

```
{craft.entries().section('mySingle').site(object.siteId).one().slug}
```

The current element’s site ID can always be accessed via `object.siteId`.
:::

#### Hierarchical URIs

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

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`.

::: tip
Consider these tips for creating special URIs:

- A URI that evaluates to `__home__` (and nothing more) will be available at your site’s base path;
- 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`;
- 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`;
- [Aliases](../../configure.md#aliases-and-environment-variables) can be evaluated with the [`alias()` function](../twig/functions.md#alias): `{{ alias('@basePressUri') }}/news`, `{{ alias('@mySectionUri') }}`.
- 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);
:::

#### Nested Entry URLs

[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.
[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!

A single entry type may have URLs in some contexts, and not in others!
In a nested entry’s URI format, you can access the _owner_’s attributes using `{owner.someAttribute}`:

```
{owner.uri}/steps/{slug}
```

### 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>

Expand Down

0 comments on commit 83cbcbb

Please sign in to comment.