Reverse Relationships Icon

Reverse Relationships

Documentation

How It Works

Imagine you have a comments collection where each comment has an entries field called post that points to a blog post. You want the blog post to show all its comments.

Without this addon: You'd have to manually maintain a list of comment IDs on each blog post, keeping both sides in sync.

With this addon: Add the reverse_relationship fieldtype to your blog post blueprint, point it at the comments collection and the post field, and you're done. The addon figures out which comments reference each post at runtime — from a single source of truth.

Setup

1. You already have a forward relationship

In the comments blueprint, there's an entries field pointing to blog posts:

# blueprints/collections/comments/comment.yaml
- handle: post
field:
type: entries
collections:
- blog

2. Add the reverse relationship field

In the blog blueprint, add a reverse_relationship field that points back:

# blueprints/collections/blog/post.yaml
- handle: comments
field:
type: reverse_relationship
display: Comments
collection: comments # look in this collection
field: post # for entries whose "post" field
# points to the current entry

You can also add this through the CP blueprint editor — the fieldtype has a UI for all options.

3. Use it in your templates

The field behaves just like Statamic's native entries fieldtype. It returns a query builder, which means Antlers resolves it lazily and you get full access to filtering, sorting, and pagination — exactly like you'd expect.

Templating

Basic loop

{{# On a blog post template — show all comments for this post #}}
<h1>{{ title }}</h1>
 
{{ comments }}
<article>
<h3>{{ author }}</h3>
<p>{{ content }}</p>
</article>
{{ /comments }}

Limit and offset

{{# Latest 3 comments #}}
{{ comments limit="3" sort="date:desc" }}
<p>{{ author }} — {{ content | truncate:80 }}</p>
{{ /comments }}
 
{{# Skip the first 2, show the next 5 #}}
{{ comments limit="5" offset="2" }}
<p>{{ author }}: {{ content }}</p>
{{ /comments }}

Sort

{{# Sort by date, newest first #}}
{{ comments sort="date:desc" }}
<p>{{ author }} — {{ date format="d M Y" }}</p>
{{ /comments }}
 
{{# Sort by author name #}}
{{ comments sort="author:asc" }}
<p>{{ author }}: {{ content }}</p>
{{ /comments }}

Count

<p>{{ comments | count }} comments on this post</p>

Conditional display

{{ if comments }}
<h2>Comments ({{ comments | count }})</h2>
{{ comments sort="date:desc" }}
<p>{{ author }}: {{ content }}</p>
{{ /comments }}
{{ else }}
<p>No comments yet.</p>
{{ /if }}

Scoped variables

Use scope to avoid variable name collisions inside nested loops:

{{ collection:blog }}
<h2>{{ title }}</h2>
 
{{ comments scope="comment" }}
{{# "title" would be the post title here, so use the scope #}}
<p>{{ comment:author }} commented on {{ title }}</p>
{{ /comments }}
{{ /collection:blog }}

Pagination

{{ comments paginate="10" as="items" }}
{{ items }}
<div>
<strong>{{ author }}</strong>
<p>{{ content }}</p>
</div>
{{ /items }}
 
{{ paginate }}
{{ if prev_page }}<a href="{{ prev_page }}">Previous</a>{{ /if }}
{{ if next_page }}<a href="{{ next_page }}">Next</a>{{ /if }}
{{ /paginate }}
{{ /comments }}

Real-world example: Blog post with comments

<article>
<h1>{{ title }}</h1>
{{ content }}
 
<section>
{{ if comments }}
<h2>Comments ({{ comments | count }})</h2>
{{ comments sort="date:desc" }}
<div>
<strong>{{ author }}</strong>
<time>{{ date format="d M Y" }}</time>
<p>{{ content }}</p>
</div>
{{ /comments }}
{{ else }}
<p>No comments yet. Be the first!</p>
{{ /if }}
</section>
</article>

Real-world example: Product with reviews

<h1>{{ title }}</h1>
<p>{{ price }}</p>
 
{{ if reviews }}
<h2>Customer Reviews ({{ reviews | count }})</h2>
{{ reviews sort="rating:desc" }}
<div>
<span>{{ rating }}/5</span>
<strong>{{ author }}</strong>
<p>{{ body }}</p>
</div>
{{ /reviews }}
{{ /if }}

Real-world example: Series with episodes

<h1>{{ title }}</h1>
<p>{{ episodes | count }} episodes</p>
 
{{ episodes sort="episode_number" }}
<a href="{{ url }}">
Ep. {{ episode_number }}: {{ title }}
</a>
{{ /episodes }}

Antlers Tag

For cases where you don't have a blueprint field — or need to query reverse relationships from a different context — there's a standalone Antlers tag:

{{ reverse_relationship collection="comments" field="post" }}
<p>{{ author }}: {{ content }}</p>
{{ /reverse_relationship }}

The tag uses the current entry's ID by default. You can also pass any ID explicitly:

{{# Show comments for a specific blog post #}}
{{ reverse_relationship collection="comments" field="post" id="my-first-post" }}
{{ author }}: {{ content }}
{{ /reverse_relationship }}
 
{{# Or from a variable #}}
{{ reverse_relationship collection="comments" field="post" :id="related_post" }}
{{ author }}: {{ content }}
{{ /reverse_relationship }}
 
{{# Count #}}
{{ reverse_relationship:count collection="comments" field="post" }}
 
{{# With all the bells and whistles #}}
{{ reverse_relationship collection="comments" field="post" limit="5" sort="date:desc" as="comments" }}
{{ comments }}
{{ author }} — {{ content }}
{{ /comments }}
{{ if no_results }}No comments yet{{ /if }}
{{ /reverse_relationship }}

Tag parameters

Parameter Required Default Description
collection Yes* Collection to search (entries mode)
taxonomy Yes* Taxonomy to search (terms mode)
container Yes* Asset container to search (assets mode)
field Yes Field handle on related items that stores the reference
id No Current entry The ID to look up references for
mode No entries entries, terms, or assets
limit No Max items to return
offset No Skip this many items
sort No Sort order, e.g. title:desc
paginate No Items per page
as No Wrap results in a named variable

*One of collection, taxonomy, or container is required depending on mode.

Fieldtype Reference

Blueprint options

Option Type Required Default Description
mode entries / terms / assets No entries What type of content to look up
collection handle When mode=entries Which collection to search
taxonomy handle When mode=terms Which taxonomy to search
container handle When mode=assets Which asset container to search
field handle Yes The field on related items that stores the reference
sort handle No title Field to sort results by
editable boolean No false Allow adding/removing related items from the CP

More YAML examples

One-to-many — A blog post has many comments:

# On the blog blueprint — show comments that reference this post
- handle: comments
field:
type: reverse_relationship
display: Comments
collection: comments
field: post
sort: date

One-to-many — A series has many episodes:

- handle: episodes
field:
type: reverse_relationship
display: Episodes
collection: episodes
field: series
sort: episode_number

Many-to-many — Show which articles reference each topic:

# On the topics blueprint — show articles that tag this topic
- handle: articles
field:
type: reverse_relationship
display: Articles
collection: articles
field: topics

Terms mode — Find taxonomy terms that reference an entry:

- handle: related_tags
field:
type: reverse_relationship
display: Related Tags
mode: terms
taxonomy: tags
field: related_entry

Assets mode — Find assets that reference an entry:

- handle: related_files
field:
type: reverse_relationship
display: Related Files
mode: assets
container: documents
field: linked_article

Editable mode

When editable: true, the CP field becomes interactive — you can search, attach, and detach related items directly from the parent entry. Changes are saved to the related entry's field (the source of truth), not to the parent.

- handle: comments
field:
type: reverse_relationship
display: Comments
collection: comments
field: post
editable: true