Skip to content

Commit 524ec71

Browse files
committed
GraphQL: Relational queries, category field usage
1 parent 26f3919 commit 524ec71

File tree

2 files changed

+236
-38
lines changed

2 files changed

+236
-38
lines changed

docs/5.x/development/graphql.md

Lines changed: 195 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -185,37 +185,9 @@ RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
185185
```
186186
:::
187187

188-
## Custom Fields
189-
190-
In addition to nave element properties, all your [custom field](../system/fields.md) content is accessible via the GraphQL API.
191-
192-
The keys you use to access that data often depends on how the fields are connected to each type of element via [field layouts](../system/fields.md#field-layouts). Craft defines interfaces for each of your element types’ variations (like entry types or category groups) and exposes fields using either their global or locally-overridden handle. Altogether, this means that you will often add custom fields within an inline fragment:
193-
194-
```graphql{5,10,13}
195-
query StationsQuery {
196-
entries(section: "weatherBeacons") {
197-
title
198-
id
199-
... on terrestrialStation_Entry {
200-
location {
201-
administrativeArea
202-
}
203-
}
204-
... on atmosphericStation_Entry {
205-
altitude
206-
}
207-
... on maritimeStation_Entry {
208-
douglasSeaScale
209-
}
210-
}
211-
}
212-
```
213-
214-
In this example, `title` and `id` are fields available on _all_ entries, whereas `location`, `altitude`, and `douglasSeaScale` are fields available only on specific entry type interfaces (`terrestrialStation_Entry`, `atmosphericStation_Entry`, and `maritimeStation_Entry`, respectively).
215-
216188
## Examples
217189

218-
### Query
190+
### Basic Query
219191

220192
Here’s what a [query](#query-reference) for two news entries might look like, complete with a formatted `dateCreated` and custom-transformed `featureImage`:
221193

@@ -272,25 +244,211 @@ Here’s what a [query](#query-reference) for two news entries might look like,
272244
```
273245
:::
274246

275-
#### Relations
247+
### Custom Fields
276248

277-
You can use relational arguments like `relatedToAssets` and `relatedToEntries` to limit results based on relationships to other elements. Their respective types (referenced below) look like `[*CriteriaInput]`, where `*` will be the name of the target element, and you can pass an array of one or more objects each having the same arguments you’d use in an [element query](element-queries.md).
249+
In addition to nave element properties, content stored in [custom fields](../system/fields.md) is accessible via the GraphQL API.
278250

279-
We could use the `relatedToCategories` argument, for example, to narrow our previous example’s news articles to those related to an “Announcements” category:
251+
The keys you use to access that data often depends on how the fields are connected to each type of element via [field layouts](../system/fields.md#field-layouts). Craft defines interfaces for each of your element types’ variations (like entry types or category groups) and exposes fields using either their global or locally-overridden handle. Altogether, this means that you will often add custom fields within an inline fragment:
280252

281-
```graphql{2}
282-
{
283-
entries (section: "news", relatedToCategories: [{slug: "announcements"}]) {
253+
```graphql{5,10,13}
254+
query StationsQuery {
255+
entries(section: "weatherBeacons") {
284256
title
257+
id
258+
... on terrestrialStation_Entry {
259+
location {
260+
administrativeArea
261+
}
262+
}
263+
... on atmosphericStation_Entry {
264+
altitude
265+
}
266+
... on maritimeStation_Entry {
267+
douglasSeaScale
268+
}
285269
}
286270
}
287271
```
288272

273+
In this example, `title` and `id` are fields available on _all_ entries, whereas `location`, `altitude`, and `douglasSeaScale` are fields available only on specific entry type interfaces (`terrestrialStation_Entry`, `atmosphericStation_Entry`, and `maritimeStation_Entry`, respectively).
274+
275+
While specific interfaces are required for _selecting_ fields, they aren’t required when using custom fields as query arguments. Here, we’re using a `sentiment` field to narrow a query for “Review” entries:
276+
277+
```graphql
278+
query PositiveReviews {
279+
entries(section: "reviews", sentiment: "awesome") {
280+
postDate@formatDateTime(format: "F j, Y")
281+
title
282+
body
283+
}
284+
}
285+
```
286+
287+
::: tip
288+
Mouseover any token in the GraphiQL editor to view introspections, or open the **Documentation Explorer** to learn about the acceptable argument types for each [field type](../reference/field-types/README.md).
289+
:::
290+
291+
#### Relationships
292+
293+
The GraphQL API exposes Craft’s powerful, field-driven [relations](../system/relations.md) system in a familiar way.
294+
295+
::: tip
296+
The following examples include server-rendered Twig “equivalents,” which are necessarily bound to HTML output.
297+
:::
298+
299+
- Select fields from related elements:
300+
301+
::: code
302+
```graphql GraphQL
303+
query Posts {
304+
entries(section: "blog") {
305+
title
306+
url
307+
308+
... on post_Entry {
309+
# Assets:
310+
featureImage {
311+
url
312+
width
313+
height
314+
}
315+
316+
317+
# Categories:
318+
primaryCategory {
319+
title
320+
url
321+
}
322+
323+
topics {
324+
title
325+
url
326+
}
327+
}
328+
}
329+
}
330+
```
331+
```twig Twig
332+
{% set posts = craft.entries()
333+
.section('blog')
334+
.all() %}
335+
336+
{% for post in posts %}
337+
{{ post.primaryCategory.eagerly().one().title }}
338+
339+
{% set image = post.featureImage.eagerly().one() %}
340+
341+
{% if image %}
342+
{{ image.getImg() }}
343+
{% endif %}
344+
345+
{{ post.title }}
346+
347+
<ul>
348+
{% for category in post.topics.eagerly().all() %}
349+
<li>{{ category.getLink() }}</li>
350+
{% endfor %}
351+
</ul>
352+
{% endfor %}
353+
```
354+
:::
355+
356+
Selections can be arbitrarily deep, but they must be explicit—GraphQL does not provide a means of recursively querying data.
357+
358+
- Narrow results using a specific field:
359+
360+
::: code
361+
```graphql GraphQL
362+
query TopicPosts {
363+
entries(section: "blog", primaryCategory: [1234]) {
364+
title
365+
url
366+
367+
# ...
368+
}
369+
}
370+
```
371+
```twig Twig
372+
{% set topicPosts = craft.entries()
373+
.section('blog')
374+
.primaryCategory(category)
375+
.all() %}
376+
377+
{% for post in topicPosts %}
378+
{# ... #}
379+
{% endfor %}
380+
```
381+
:::
382+
383+
You may need to pre-flight a query to translate an identifier (like a slug) into a valid category ID:
384+
385+
```graphql
386+
query CategoryLookup($slug: String) {
387+
category(slug: [$slug]) {
388+
id
389+
}
390+
}
391+
```
392+
393+
- Find elements using abstract relational criteria:
394+
395+
::: code
396+
```graphql GraphQL
397+
query TopicPosts {
398+
entries(
399+
section: "blog"
400+
relatedToCategories: [
401+
{
402+
slug: ["travel", "winter-sports"]
403+
group: "topics"
404+
relatedViaField: "topics"
405+
}
406+
]
407+
) {
408+
title
409+
url
410+
411+
# ...
412+
}
413+
}
414+
```
415+
```twig{1-4,8-11} Twig
416+
{% set categoryIds = craft.categories()
417+
.group('topics')
418+
.slug(['travel', 'winter-sports'])
419+
.ids() %}
420+
421+
{% set relatedPosts = craft.entries()
422+
.section('blog')
423+
.relatedTo({
424+
targetElement: categoryIds,
425+
field: 'topics',
426+
})
427+
.all() %}
428+
```
429+
:::
430+
431+
The criteria for `relatedToCategories` (or any of the `relatedTo*` arguments) are the same as the corresponding element query types (like `category()` and `categories()`).
432+
289433
::: tip
290-
See [Relations](../system/relations.md) for more on Craft’s relational field types.
434+
By default, relational criteria are logically joined with “or.” To query for elements that match _all_ the relational criteria, prepend `"and"` to the list of IDs passed to the `relatedTo` query argument.
291435
:::
292436

293-
Advanced relational conditions are possible using the `relatedViaField` and `relatedViaSite` params. <Since ver="5.4.0" feature="Site- and field-specific relational criteria" />
437+
Advanced relational conditions are possible using the `relatedViaField` (seen above) and `relatedViaSite` params. <Since ver="5.4.0" feature="Site- and field-specific relational criteria" />
438+
439+
### Search
440+
441+
Craft’s search index is also exposed via GraphQL via the `search` query argument:
442+
443+
```graphql
444+
query SearchResults($terms: String) {
445+
entries(search: $terms, orderBy: "score") {
446+
title
447+
url
448+
searchScore
449+
}
450+
}
451+
```
294452

295453
### Mutation
296454

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

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,49 @@ For example, you could create a list of checkboxes for each of the possible rela
317317
```
318318

319319
::: tip
320-
Note that it’s not possible to customize the order that categories will be related in, and if a nested category is related, so will each of its ancestors.
320+
When the **Maintain Hierarchy** [setting](#settings) is _enabled_, Craft enforces an order for the selected categories and normalizes the selections to “fill in” gaps in the tree.
321+
322+
With the setting _disabled_, only the explicitly-selected categories will be related, in the order they appear in the request—most often, their order in the form’s HTML.
321323
:::
322324

325+
### GraphQL
326+
327+
Categories related via a categories field can be selected along with the source of the relationship:
328+
329+
```graphql{7-10}
330+
query Posts {
331+
entries(section: "blog") {
332+
title
333+
url
334+
335+
... on post_Entry {
336+
topics {
337+
title
338+
url
339+
}
340+
}
341+
}
342+
}
343+
```
344+
345+
You can also use categories fields as query arguments, to narrow the results:
346+
347+
```graphql{4}
348+
query TopicPosts {
349+
entries(
350+
section: "blog"
351+
topics: [1234, 5678]
352+
) {
353+
title
354+
url
355+
}
356+
}
357+
```
358+
359+
Some relational queries may require that you translate category identifiers (like slugs or UUIDs) to IDs.
360+
361+
<See path="../../development/graphql.md" hash="relationships" label="Relational Fields in GraphQL" description="Get the most out of Craft’s relational fields via the GraphQL API." />
362+
323363
## See Also
324364

325365
- [Category Queries](../element-types/categories.md#querying-categories)

0 commit comments

Comments
 (0)