Getting Elements

Comment Queries

You can fetch comments in your templates or PHP code using comment queries.

{# Create a new comment query #}
{% set myQuery = craft.comments.fetch() %}
// Create a new comment query
$myQuery = \verbb\comments\elements\Comment::find();

You can also pass parameters to craft.comments.fetch() as an object, such as craft.comments.fetch({ ownerId: entry.id, limit: 10 }), which sets them on the query in the same way as calling each one.

Once you’ve created a comment query, you can set parameters on it to narrow down the results, and then execute it by calling .all(). An array of Comment objects will be returned.

See Element Queries (opens new window) in the Craft docs to learn how element queries work.

Example

You can list the latest comments the logged-in user has posted, such as on their account page, by doing the following:

  1. Create a comment query with craft.comments.fetch().
  2. Set the userId and limit parameters on it, and orderBy to show the newest first.
  3. Fetch the comments with .all().
  4. Loop through them with a for (opens new window) tag to output each comment and a link to the entry it was made on.
{# Create a comment query with the 'userId', 'limit' and 'orderBy' parameters #}
{% set commentsQuery = craft.comments.fetch()
    .userId(currentUser.id)
    .limit(10)
    .orderBy('commentDate DESC') %}

{# Fetch the comments #}
{% set comments = commentsQuery.all() %}

{# Display their contents #}
{% for comment in comments %}
    <p>{{ comment.comment }}</p>
    <p>On <a href="{{ comment.owner.url }}">{{ comment.owner.title }}</a>, {{ comment.commentDate|date('short') }}</p>
{% endfor %}

By default, comment queries only return approved comments. The status parameter explains how to fetch others, and the defaultQueryStatus setting changes the default for every query.

Parameters

Comment queries support the following parameters.

ancestorDist

Narrows the query results to only comments that are up to a certain distance away from the comment specified by ancestorOf.

{# Fetch comments above this one #}
{% set comments = craft.comments.fetch()
    .ancestorOf(comment)
    .ancestorDist(3)
    .all() %}
// Fetch comments above this one
$comments = \verbb\comments\elements\Comment::find()
    ->ancestorOf($comment)
    ->ancestorDist(3)
    ->all();

ancestorOf

Narrows the query results to only comments that are ancestors of another comment.

Possible values include:

ValueFetches comments…
1above the comment with an ID of 1.
a Comment objectabove the comment represented by the object.
{# Fetch comments above this one #}
{% set comments = craft.comments.fetch()
    .ancestorOf(comment)
    .all() %}
// Fetch comments above this one
$comments = \verbb\comments\elements\Comment::find()
    ->ancestorOf($comment)
    ->all();

This can be combined with ancestorDist if you want to limit how far away the ancestor comments can be.

asArray

Causes the query to return matching comments as arrays of data, rather than Comment objects.

{# Fetch comments as arrays #}
{% set comments = craft.comments.fetch()
    .asArray()
    .all() %}
// Fetch comments as arrays
$comments = \verbb\comments\elements\Comment::find()
    ->asArray()
    ->all();

comment

Narrows the query results based on the comments’ text.

Possible values include:

ValueFetches comments…
'*Craft*'with text containing “Craft”.
'not *Craft*'with text not containing “Craft”.
{# Fetch comments that mention Craft #}
{% set comments = craft.comments.fetch()
    .comment('*Craft*')
    .all() %}
// Fetch comments that mention Craft
$comments = \verbb\comments\elements\Comment::find()
    ->comment('*Craft*')
    ->all();

commentDate

Narrows the query results based on the date the comments were posted.

Possible values include:

ValueFetches comments…
'>= 2018-04-01'that were posted on or after 2018-04-01.
'< 2018-05-01'that were posted before 2018-05-01.
['and', '>= 2018-04-01', '< 2018-05-01']that were posted between 2018-04-01 and 2018-05-01.
{# Fetch comments posted last month #}
{% set start = date('first day of last month')|atom %}
{% set end = date('first day of this month')|atom %}

{% set comments = craft.comments.fetch()
    .commentDate(['and', ">= #{start}", "< #{end}"])
    .all() %}
// Fetch comments posted last month
$start = (new \DateTime('first day of last month'))->format(\DateTime::ATOM);
$end = (new \DateTime('first day of this month'))->format(\DateTime::ATOM);

$comments = \verbb\comments\elements\Comment::find()
    ->commentDate(['and', ">= {$start}", "< {$end}"])
    ->all();

dateCreated

Narrows the query results based on the comments’ creation dates.

Possible values include:

ValueFetches comments…
'>= 2018-04-01'that were created on or after 2018-04-01.
'< 2018-05-01'that were created before 2018-05-01.
['and', '>= 2018-04-01', '< 2018-05-01']that were created between 2018-04-01 and 2018-05-01.
{# Fetch comments created last month #}
{% set start = date('first day of last month')|atom %}
{% set end = date('first day of this month')|atom %}

{% set comments = craft.comments.fetch()
    .dateCreated(['and', ">= #{start}", "< #{end}"])
    .all() %}
// Fetch comments created last month
$start = (new \DateTime('first day of last month'))->format(\DateTime::ATOM);
$end = (new \DateTime('first day of this month'))->format(\DateTime::ATOM);

$comments = \verbb\comments\elements\Comment::find()
    ->dateCreated(['and', ">= {$start}", "< {$end}"])
    ->all();

dateUpdated

Narrows the query results based on the comments’ last-updated dates.

Possible values include:

ValueFetches comments…
'>= 2018-04-01'that were updated on or after 2018-04-01.
'< 2018-05-01'that were updated before 2018-05-01.
['and', '>= 2018-04-01', '< 2018-05-01']that were updated between 2018-04-01 and 2018-05-01.
{# Fetch comments updated in the last week #}
{% set lastWeek = date('1 week ago')|atom %}

{% set comments = craft.comments.fetch()
    .dateUpdated(">= #{lastWeek}")
    .all() %}
// Fetch comments updated in the last week
$lastWeek = (new \DateTime('1 week ago'))->format(\DateTime::ATOM);

$comments = \verbb\comments\elements\Comment::find()
    ->dateUpdated(">= {$lastWeek}")
    ->all();

descendantDist

Narrows the query results to only comments that are up to a certain distance away from the comment specified by descendantOf.

{# Fetch comments below this one #}
{% set comments = craft.comments.fetch()
    .descendantOf(comment)
    .descendantDist(3)
    .all() %}
// Fetch comments below this one
$comments = \verbb\comments\elements\Comment::find()
    ->descendantOf($comment)
    ->descendantDist(3)
    ->all();

descendantOf

Narrows the query results to only comments that are descendants of another comment.

Possible values include:

ValueFetches comments…
1below the comment with an ID of 1.
a Comment objectbelow the comment represented by the object.
{# Fetch comments below this one #}
{% set comments = craft.comments.fetch()
    .descendantOf(comment)
    .all() %}
// Fetch comments below this one
$comments = \verbb\comments\elements\Comment::find()
    ->descendantOf($comment)
    ->all();

This can be combined with descendantDist if you want to limit how far away the descendant comments can be.

email

Narrows the query results based on the email address the comments were posted with. Guests enter this themselves, and comments from logged-in users store the user’s email address.

Possible values include:

ValueFetches comments…
'[email protected]'posted with an email of [email protected].
'not [email protected]'not posted with an email of [email protected].
'*@bar.baz'posted with an email that ends with @bar.baz.
{# Fetch comments from users with a .co.uk domain on their email address #}
{% set comments = craft.comments.fetch()
    .email('*.co.uk')
    .all() %}
// Fetch comments from users with a .co.uk domain on their email address
$comments = \verbb\comments\elements\Comment::find()
    ->email('*.co.uk')
    ->all();

fixedOrder

Causes the query results to be returned in the order specified by id.

{# Fetch comments in a specific order #}
{% set comments = craft.comments.fetch()
    .id([1, 2, 3, 4, 5])
    .fixedOrder()
    .all() %}
// Fetch comments in a specific order
$comments = \verbb\comments\elements\Comment::find()
    ->id([1, 2, 3, 4, 5])
    ->fixedOrder()
    ->all();

hasDescendants

Narrows the query results based on whether the comments have any descendants.

(This has the opposite effect of calling leaves.)

{# Fetch comments that have descendants #}
{% set comments = craft.comments.fetch()
    .hasDescendants()
    .all() %}
// Fetch comments that have descendants
$comments = \verbb\comments\elements\Comment::find()
    ->hasDescendants()
    ->all();

id

Narrows the query results based on the comments’ IDs.

Possible values include:

ValueFetches comments…
1with an ID of 1.
'not 1'not with an ID of 1.
[1, 2]with an ID of 1 or 2.
['not', 1, 2]not with an ID of 1 or 2.
{# Fetch the comment by its ID #}
{% set comment = craft.comments.fetch()
    .id(1)
    .one() %}
// Fetch the comment by its ID
$comment = \verbb\comments\elements\Comment::find()
    ->id(1)
    ->one();

This can be combined with fixedOrder if you want the results to be returned in a specific order.

inReverse

Causes the query results to be returned in reverse order.

{# Fetch comments in reverse #}
{% set comments = craft.comments.fetch()
    .inReverse()
    .all() %}
// Fetch comments in reverse
$comments = \verbb\comments\elements\Comment::find()
    ->inReverse()
    ->all();

ipAddress

Narrows the query results based on the IP address the comments were posted from. Comments only stores an IP address when Craft’s storeUserIps setting is enabled.

{# Fetch comments posted from an IP address #}
{% set comments = craft.comments.fetch()
    .ipAddress('203.0.113.7')
    .all() %}
// Fetch comments posted from an IP address
$comments = \verbb\comments\elements\Comment::find()
    ->ipAddress('203.0.113.7')
    ->all();

isFlagged

Narrows the query results based on whether the comments have been flagged at least once. Pass false to fetch only comments that have never been flagged.

{# Fetch comments that are flagged #}
{% set comments = craft.comments.fetch()
    .isFlagged(true)
    .all() %}
// Fetch comments that are flagged
$comments = \verbb\comments\elements\Comment::find()
    ->isFlagged(true)
    ->all();

leaves

Narrows the query results based on whether the comments are “leaves” (comments with no descendants).

(This has the opposite effect of calling hasDescendants.)

{# Fetch comments that have no descendants #}
{% set comments = craft.comments.fetch()
    .leaves()
    .all() %}
// Fetch comments that have no descendants
$comments = \verbb\comments\elements\Comment::find()
    ->leaves()
    ->all();

level

Narrows the query results based on the comments’ level within the structure.

Possible values include:

ValueFetches comments…
1with a level of 1.
'not 1'not with a level of 1.
'>= 3'with a level greater than or equal to 3.
[1, 2]with a level of 1 or 2.
['not', 1, 2]not with level of 1 or 2.
{# Fetch comments positioned at level 3 or above #}
{% set comments = craft.comments.fetch()
    .level('>= 3')
    .all() %}
// Fetch comments positioned at level 3 or above
$comments = \verbb\comments\elements\Comment::find()
    ->level('>= 3')
    ->all();

limit

Determines the number of comments that should be returned.

{# Fetch up to 10 comments  #}
{% set comments = craft.comments.fetch()
    .limit(10)
    .all() %}
// Fetch up to 10 comments
$comments = \verbb\comments\elements\Comment::find()
    ->limit(10)
    ->all();

name

Narrows the query results based on the name the comments were posted with. Guests enter this themselves.

Possible values include:

ValueFetches comments…
'Jane Smith'posted with the name “Jane Smith”.
'Jane*'posted with a name that starts with “Jane”.
{# Fetch comments posted by guests named Jane #}
{% set comments = craft.comments.fetch()
    .name('Jane*')
    .all() %}
// Fetch comments posted by guests named Jane
$comments = \verbb\comments\elements\Comment::find()
    ->name('Jane*')
    ->all();

nextSiblingOf

Narrows the query results to only the comment that comes immediately after another comment.

Possible values include:

ValueFetches the comment…
1after the comment with an ID of 1.
a Comment objectafter the comment represented by the object.
{# Fetch the next comment #}
{% set comment = craft.comments.fetch()
    .nextSiblingOf(comment)
    .one() %}
// Fetch the next comment
$comment = \verbb\comments\elements\Comment::find()
    ->nextSiblingOf($comment)
    ->one();

offset

Determines how many comments should be skipped in the results.

{# Fetch all comments except for the first 3 #}
{% set comments = craft.comments.fetch()
    .offset(3)
    .all() %}
// Fetch all comments except for the first 3
$comments = \verbb\comments\elements\Comment::find()
    ->offset(3)
    ->all();

orderBy

Determines the order that the comments should be returned in. Alongside the usual attributes, you can order by voteCount (upvotes minus downvotes) and flagCount (the number of flags).

{# Fetch all comments in order of date created #}
{% set comments = craft.comments.fetch()
    .orderBy('elements.dateCreated asc')
    .all() %}
// Fetch all comments in order of date created
$comments = \verbb\comments\elements\Comment::find()
    ->orderBy('elements.dateCreated asc')
    ->all();
{# Fetch the highest-rated comments on this entry #}
{% set topComments = craft.comments.fetch()
    .owner(entry)
    .orderBy('voteCount DESC')
    .limit(5)
    .all() %}
// Fetch the highest-rated comments on this entry
$topComments = \verbb\comments\elements\Comment::find()
    ->owner($entry)
    ->orderBy('voteCount DESC')
    ->limit(5)
    ->all();

owner

Sets the ownerId and siteId parameters based on a given element, so you get the comments made on that element in its site.

{# Fetch comments created for this entry #}
{% set comments = craft.comments.fetch()
    .owner(entry)
    .all() %}
// Fetch comments created for this entry
$comments = \verbb\comments\elements\Comment::find()
    ->owner($entry)
    ->all();

ownerEntryType

Narrows the query results to comments made on entries of the given entry types, per the entry types’ handles. You can also pass an EntryType object.

{# Fetch comments made on Article entries #}
{% set comments = craft.comments.fetch()
    .ownerEntryType('article')
    .all() %}
// Fetch comments made on Article entries
$comments = \verbb\comments\elements\Comment::find()
    ->ownerEntryType('article')
    ->all();

ownerEntryTypeId

Narrows the query results to comments made on entries of the given entry types, per the entry types’ IDs.

{# Fetch comments made on entries with an entry type ID of 4 #}
{% set comments = craft.comments.fetch()
    .ownerEntryTypeId(4)
    .all() %}
// Fetch comments made on entries with an entry type ID of 4
$comments = \verbb\comments\elements\Comment::find()
    ->ownerEntryTypeId(4)
    ->all();

ownerId

Narrows the query results based on the owner element of the comment, per the owners’ IDs.

Possible values include:

ValueFetches comments…
1created for an element with an ID of 1.
'not 1'not created for an element with an ID of 1.
[1, 2]created for an element with an ID of 1 or 2.
['not', 1, 2]not created for an element with an ID of 1 or 2.
{# Fetch comments created for an element with an ID of 1 #}
{% set comments = craft.comments.fetch()
    .ownerId(1)
    .all() %}
// Fetch comments created for an element with an ID of 1
$comments = \verbb\comments\elements\Comment::find()
    ->ownerId(1)
    ->all();

ownerSection

Narrows the query results to comments made on entries in the given sections, per the sections’ handles. You can also pass a Section object.

{# Fetch comments made on entries in the News and Blog sections #}
{% set comments = craft.comments.fetch()
    .ownerSection(['news', 'blog'])
    .all() %}
// Fetch comments made on entries in the News and Blog sections
$comments = \verbb\comments\elements\Comment::find()
    ->ownerSection(['news', 'blog'])
    ->all();

ownerSectionId

Narrows the query results to comments made on entries in the given sections, per the sections’ IDs.

{# Fetch comments made on entries in the section with an ID of 22 #}
{% set comments = craft.comments.fetch()
    .ownerSectionId(22)
    .all() %}
// Fetch comments made on entries in the section with an ID of 22
$comments = \verbb\comments\elements\Comment::find()
    ->ownerSectionId(22)
    ->all();

ownerSite

Narrows the query results to comments made on elements in the given site, per the site’s handle. You can also pass a Site object. This also sets siteId, as a comment is only stored in its owner’s site.

{# Fetch comments made in the French site #}
{% set comments = craft.comments.fetch()
    .ownerSite('fr')
    .all() %}
// Fetch comments made in the French site
$comments = \verbb\comments\elements\Comment::find()
    ->ownerSite('fr')
    ->all();

ownerSiteId

Narrows the query results to comments made on elements in the given site, per the site’s ID. This also sets siteId.

{# Fetch comments made in the site with an ID of 2 #}
{% set comments = craft.comments.fetch()
    .ownerSiteId(2)
    .all() %}
// Fetch comments made in the site with an ID of 2
$comments = \verbb\comments\elements\Comment::find()
    ->ownerSiteId(2)
    ->all();

ownerType

Narrows the query results to comments made on a given element type, such as only those on entries (opens new window). Pass the full element class name.

{# Fetch comments for specific element type #}
{% set comments = craft.comments.fetch()
    .ownerType('craft\\elements\\Entry')
    .all() %}
// Fetch comments for specific element type
$comments = \verbb\comments\elements\Comment::find()
    ->ownerType(craft\elements\Entry::class)
    ->all();

positionedAfter

Narrows the query results to only comments that are positioned after another comment.

Possible values include:

ValueFetches comments…
1after the comment with an ID of 1.
a Comment objectafter the comment represented by the object.
{# Fetch comments after this one #}
{% set comments = craft.comments.fetch()
    .positionedAfter(comment)
    .all() %}
// Fetch comments after this one
$comments = \verbb\comments\elements\Comment::find()
    ->positionedAfter($comment)
    ->all();

positionedBefore

Narrows the query results to only comments that are positioned before another comment.

Possible values include:

ValueFetches comments…
1before the comment with an ID of 1.
a Comment objectbefore the comment represented by the object.
{# Fetch comments before this one #}
{% set comments = craft.comments.fetch()
    .positionedBefore(comment)
    .all() %}
// Fetch comments before this one
$comments = \verbb\comments\elements\Comment::find()
    ->positionedBefore($comment)
    ->all();

prevSiblingOf

Narrows the query results to only the comment that comes immediately before another comment.

Possible values include:

ValueFetches the comment…
1before the comment with an ID of 1.
a Comment objectbefore the comment represented by the object.
{# Fetch the previous comment #}
{% set comment = craft.comments.fetch()
    .prevSiblingOf(comment)
    .one() %}
// Fetch the previous comment
$comment = \verbb\comments\elements\Comment::find()
    ->prevSiblingOf($comment)
    ->one();

Narrows the query results to only comments that match a search query.

See Searching (opens new window) for a full explanation of how to work with this parameter.

{# Get the search query from the 'q' query string param #}
{% set searchQuery = craft.app.request.getQueryParam('q') %}

{# Fetch all comments that match the search query #}
{% set comments = craft.comments.fetch()
    .search(searchQuery)
    .all() %}
// Get the search query from the 'q' query string param
$searchQuery = \Craft::$app->getRequest()->getQueryParam('q');

// Fetch all comments that match the search query
$comments = \verbb\comments\elements\Comment::find()
    ->search($searchQuery)
    ->all();

siblingOf

Narrows the query results to only comments that are siblings of another comment.

Possible values include:

ValueFetches comments…
1beside the comment with an ID of 1.
a Comment objectbeside the comment represented by the object.
{# Fetch comments beside this one #}
{% set comments = craft.comments.fetch()
    .siblingOf(comment)
    .all() %}
// Fetch comments beside this one
$comments = \verbb\comments\elements\Comment::find()
    ->siblingOf($comment)
    ->all();

site

Determines which site the comments should be queried in, per the site’s handle. Defaults to the current site. Pass '*' to query every site.

{# Fetch comments from the French site #}
{% set comments = craft.comments.fetch()
    .site('fr')
    .all() %}
// Fetch comments from the French site
$comments = \verbb\comments\elements\Comment::find()
    ->site('fr')
    ->all();

siteId

Determines which site the comments should be queried in, per the site’s ID. Defaults to the current site.

{# Fetch comments from the site with an ID of 2 #}
{% set comments = craft.comments.fetch()
    .siteId(2)
    .all() %}
// Fetch comments from the site with an ID of 2
$comments = \verbb\comments\elements\Comment::find()
    ->siteId(2)
    ->all();

status

Narrows the query results based on the comments’ statuses. The default comes from the defaultQueryStatus setting, which is approved unless you change it. The trashed status is separate from Craft’s soft-deleted elements, which trashed() fetches.

Possible values include:

ValueFetches comments…
'approved' (default)that are approved.
'pending'that are pending.
'spam'that are marked as spam.
'trashed'that are trashed (not deleted).
['approved', 'pending']that are approved or pending.
nullwith any status.
{# Fetch comments with any status #}
{% set comments = craft.comments.fetch()
    .status(null)
    .all() %}
// Fetch comments with any status
$comments = \verbb\comments\elements\Comment::find()
    ->status(null)
    ->all();
{# Fetch pending comments #}
{% set comments = craft.comments.fetch()
    .status('pending')
    .all() %}
// Fetch pending comments
$comments = \verbb\comments\elements\Comment::find()
    ->status('pending')
    ->all();

uid

Narrows the query results based on the comments’ UIDs.

{# Fetch the comment by its UID #}
{% set comment = craft.comments.fetch()
    .uid('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')
    .one() %}
// Fetch the comment by its UID
$comment = \verbb\comments\elements\Comment::find()
    ->uid('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')
    ->one();

url

Narrows the query results based on the URL of the page the comments were posted from.

{# Fetch comments posted from the blog #}
{% set comments = craft.comments.fetch()
    .url('*/blog/*')
    .all() %}
// Fetch comments posted from the blog
$comments = \verbb\comments\elements\Comment::find()
    ->url('*/blog/*')
    ->all();

userAgent

Narrows the query results based on the user agent of the browser the comments were posted from.

{# Fetch comments posted from Firefox #}
{% set comments = craft.comments.fetch()
    .userAgent('*Firefox*')
    .all() %}
// Fetch comments posted from Firefox
$comments = \verbb\comments\elements\Comment::find()
    ->userAgent('*Firefox*')
    ->all();

userId

Narrows the query results based on the user, per their ID.

Possible values include:

ValueFetches comments…
1with a user with an ID of 1.
'not 1'not with a user with an ID of 1.
[1, 2]with a user with an ID of 1 or 2.
['not', 1, 2]not with a user with an ID of 1 or 2.
{# Fetch the current user's comments #}
{% set comments = craft.comments.fetch()
    .userId(currentUser.id)
    .all() %}
// Fetch the current user's comments
$user = Craft::$app->getUser()->getIdentity();

$comments = \verbb\comments\elements\Comment::find()
    ->userId($user->id)
    ->all();