Skip to content

Commit 4361649

Browse files
committed
Category fields in queries
1 parent 323e4de commit 4361649

File tree

1 file changed

+89
-35
lines changed

1 file changed

+89
-35
lines changed

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

Lines changed: 89 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@ Double-click on a related category to edit it in a [slideout](../../system/contr
7878

7979
### Querying Elements with Categories Fields
8080

81-
When [querying for elements](../../development/element-queries.md) that have a Categories field, you can filter the results based on the Categories field data using a query param named after your field’s handle.
82-
83-
Possible values include:
81+
When [querying for elements](../../development/element-queries.md) that may have a categories field, you can use values compatible with [relational query params](../../system/relations.md) to narrow the results:
8482

8583
| Value | Fetches elements…
8684
| - | -
@@ -90,44 +88,102 @@ Possible values include:
9088
| `[100, 200]` | that are related to a category with an ID of 100 or 200.
9189
| `[':empty:', 100, 200]` | with no related categories, or are related to a category with an ID of 100 or 200.
9290
| `['and', 100, 200]` | that are related to the categories with IDs of 100 and 200.
93-
| a [Category](craft5:craft\elements\Category) object | that are related to the category.
91+
| one or more [Category](craft5:craft\elements\Category) elements | that are related to the category/categories.
9492
| a [CategoryQuery](craft5:craft\elements\db\CategoryQuery) object | that are related to any of the resulting categories.
9593

96-
::: code
94+
In general, you won’t know a specific category’s ID up-front. Here’s how you might use a category field param to fetch entries belonging to a particular category, in a blog:
95+
9796
```twig
98-
{# Fetch entries with a related category #}
99-
{% set entries = craft.entries()
100-
.myFieldHandle(':notempty:')
97+
{% set posts = craft.entries()
98+
.section('posts')
99+
.myCategoriesField(category)
101100
.all() %}
102101
```
103-
```php
104-
// Fetch entries with a related category
105-
$entries = \craft\elements\Entry::find()
106-
->myFieldHandle(':notempty:')
107-
->all();
102+
103+
This example assumes we’re loading entries from a [category’s template](../element-types/categories.md#routing-and-templates), where the `category` variable is automatically injected. This same approach would work if we were instead looking for related content, on an individual post page:
104+
105+
```twig
106+
{# Fetch IDs of the current post’s categories: #}
107+
{% set currentPostCategories = entry.myCategoriesField.ids() %}
108+
109+
{# Use them in a new entries query: #}
110+
{% set relatedPosts = craft.entries()
111+
.section('posts')
112+
.myCategoriesField(currentPostCategories)
113+
.limit(5)
114+
.all() %}
115+
```
116+
117+
This query will return entries related to _any_ of the current post’s categories. Prepend `and` to the array to find entries that share _all_ their categories with the current post:
118+
119+
```twig
120+
['and', ...currentPostCategories]
121+
```
122+
123+
All the examples so far are achievable using generic [relational query methods](../../system/relations.md#the-relatedto-parameter), but automatically ensure that relationships are defined in a specific field, and in a specific direction (as _targets_). An equivalent query using `.relatedTo()` might look something like this:
124+
125+
```twig{5-8}
126+
{% set currentPostCategories = entry.myCategoriesField.ids() %}
127+
128+
{% set relatedPosts = craft.entries()
129+
.section('posts')
130+
.relatedTo({
131+
field: 'myCategoriesField',
132+
targetElement: currentPostCategories,
133+
})
134+
.limit(5)
135+
.all() %}
136+
```
137+
138+
The last example we’ll look at uses the [special `:empty:` token](../../system/relations.md#sources-and-targets) to find post entries with _no_ categories related to the field:
139+
140+
```twig{3}
141+
{% set uncategorized = craft.entries()
142+
.section('posts')
143+
.myCategoriesField(':empty:')
144+
.all() %}
145+
```
146+
147+
::: warning
148+
This query may still return entries related to categories via _other_ fields! You can combine multiple category field params to better define “uncategorized:”
149+
150+
```twig{3-4}
151+
{% set uncategorized = craft.entries()
152+
.section('posts')
153+
.topics(':empty:')
154+
.productFamilies(':empty:')
155+
.all() %}
156+
157+
{# ...or... }
158+
159+
{% set uncategorized = craft.entries()
160+
.section('posts')
161+
.relatedTo({
162+
targetElement: ':empty:',
163+
field: ['topics', 'productFamilies'],
164+
})
165+
.all() %}
108166
```
109167
:::
110168

111169
### Working with Categories Field Data
112170

113-
If you have an element with a Categories field in your template, you can access its related categories using your Categories field’s handle:
171+
If you have an element with a categories field in your template, you can access the related category elements using the field’s handle:
114172

115173
::: code
116174
```twig
117-
{% set query = entry.myFieldHandle %}
175+
{% set query = entry.myCategoriesField %}
118176
```
119177
```php
120-
$query = $entry->myFieldHandle;
178+
$query = $entry->myCategoriesField;
121179
```
122180
:::
123181

124-
That will give you a [category query](../element-types/categories.md#querying-categories), prepped to output all the related categories for the given field.
125-
126-
To loop through all the related categories as a flat list, call [all()](craft5:craft\db\Query::all()) and then loop over the results:
182+
That will give you a [category query](../element-types/categories.md#querying-categories), prepped to return all the related categories for the given field. You can use the results as a list…
127183

128184
::: code
129185
```twig
130-
{% set relatedCategories = entry.myFieldHandle.all() %}
186+
{% set relatedCategories = entry.myCategoriesField.all() %}
131187
{% if relatedCategories|length %}
132188
<ul>
133189
{% for rel in relatedCategories %}
@@ -137,7 +193,7 @@ To loop through all the related categories as a flat list, call [all()](craft5:c
137193
{% endif %}
138194
```
139195
```php
140-
$relatedCategories = $entry->myFieldHandle->all();
196+
$relatedCategories = $entry->myCategoriesField->all();
141197
if (count($relatedCategories)) {
142198
foreach ($relatedCategories as $rel) {
143199
// do something with $rel->url and $rel->title
@@ -146,10 +202,10 @@ if (count($relatedCategories)) {
146202
```
147203
:::
148204

149-
Or you can show them as a hierarchical list with the [nav](../twig/tags.md#nav) tag:
205+
…or you can show them as a hierarchical list with the [nav](../twig/tags.md#nav) tag:
150206

151207
```twig
152-
{% set relatedCategories = entry.myFieldHandle.all() %}
208+
{% set relatedCategories = entry.myCategoriesField.all() %}
153209
{% if relatedCategories|length %}
154210
<ul>
155211
{% nav rel in relatedCategories %}
@@ -170,13 +226,13 @@ If you only want the first related category, call [one()](craft5:craft\db\Query:
170226

171227
::: code
172228
```twig
173-
{% set rel = entry.myFieldHandle.one() %}
229+
{% set rel = entry.myCategoriesField.one() %}
174230
{% if rel %}
175231
<p><a href="{{ rel.url }}">{{ rel.title }}</a></p>
176232
{% endif %}
177233
```
178234
```php
179-
$rel = $entry->myFieldHandle->one();
235+
$rel = $entry->myCategoriesField->one();
180236
if ($rel) {
181237
// do something with $rel->url and $rel->title
182238
}
@@ -187,12 +243,12 @@ If you need to check for related categories without fetching them, you can call
187243

188244
::: code
189245
```twig
190-
{% if entry.myFieldHandle.exists() %}
246+
{% if entry.myCategoriesField.exists() %}
191247
<p>There are related categories!</p>
192248
{% endif %}
193249
```
194250
```php
195-
if ($entry->myFieldHandle->exists()) {
251+
if ($entry->myCategoriesField->exists()) {
196252
// do something with related categories
197253
}
198254
```
@@ -202,21 +258,19 @@ You can set [parameters](../element-types/categories.md#parameters) on the categ
202258

203259
::: code
204260
```twig
205-
{% set relatedCategories = entry.myFieldHandle
261+
{% set relatedCategories = entry.myCategoriesField
206262
.leaves()
207263
.all() %}
208264
```
209265
```php
210-
$relatedAssets = $entry->myFieldHandle
266+
$relatedAssets = $entry->myCategoriesField
211267
->leaves()
212268
->all();
213269
```
214270
:::
215271

216272
::: tip
217-
<Todo notes="Extract this into a snippet." />
218-
219-
In Craft 3, we recommended cloning these query objects using the [`clone` keyword](https://www.php.net/manual/en/language.oop5.cloning.php) or [`clone()`](../twig/functions.md#clone) Twig function before applying params. **This is no longer required in Craft 4**, because a new copy of the query is returned each time you access the field property.
273+
Each time you access a category field by its handle, Craft returns a new element query.
220274
:::
221275

222276
### Saving Categories Fields
@@ -228,7 +282,7 @@ For example, you could create a list of checkboxes for each of the possible rela
228282
```twig
229283
{# Include a hidden input first so Craft knows to update the existing value
230284
if no checkboxes are checked. #}
231-
{{ hiddenInput('fields[myFieldHandle]', '') }}
285+
{{ hiddenInput('fields[myCategoriesField]', '') }}
232286
233287
{# Get all of the possible category options #}
234288
{% set possibleCategories = craft.categories()
@@ -237,7 +291,7 @@ For example, you could create a list of checkboxes for each of the possible rela
237291
238292
{# Get the currently related category IDs #}
239293
{% set relatedCategoryIds = entry is defined
240-
? entry.myFieldHandle.ids()
294+
? entry.myCategoriesField.ids()
241295
: [] %}
242296
243297
<ul>
@@ -246,7 +300,7 @@ For example, you could create a list of checkboxes for each of the possible rela
246300
<label>
247301
{{ input(
248302
'checkbox',
249-
'fields[myFieldHandle][]',
303+
'fields[myCategoriesField][]',
250304
possibleCategory.id,
251305
{ checked: possibleCategory.id in relatedCategoryIds }
252306
) }}

0 commit comments

Comments
 (0)