Skip to main content

Document Service API: publicationFilter

Page summary:

Use the optional publicationFilter parameter to query documents by the relationship between their draft and published versions, for example drafts that were never published, or entries modified since they were last published. It works with findOne(), findFirst(), findMany(), and count(), and combines with other query parameters. status still decides whether you get the draft or the published version.

The publicationFilter is a parameter that, combined with the status parameter, can help you cover complex queries to find exactly what you need with the Document Service API.

While status answers "do I want the draft or the published version?", the publicationFilter parameter answers a different question: "which documents do I want, based on how their draft and published versions relate?". This is useful for example to find drafts that were never published, or entries whose draft has unsaved changes compared to what is live.

Prerequisites

The Draft & Publish feature must be enabled on the content-type. If Draft & Publish is disabled, publicationFilter has no effect.

Available values

publicationFilter accepts one of the following values:

ValueSelects
never-publishedDocuments never published in a given locale
never-published-documentDocuments never published in any locale
modifiedDocuments whose draft was edited since it was last published
unmodifiedDocuments whose draft has not changed since it was last published
published-without-draftPublished documents with no draft counterpart
published-with-draftPublished documents that also have a draft
has-published-versionDocuments that have both a draft and a published version
has-published-version-documentDocuments published in at least one locale
(useful when i18n is enabled)

For detailed examples of how to use the publicationFilter values, including with the status parameter, see the possible use cases table.

Note
  • Unknown values raise a validation error.
  • Values ending in -document consider all locales of a document, which matters when Internationalization (i18n) is enabled: for example, never-published-document excludes a document as soon as one of its locales is published. All other values consider one locale at a time. Without i18n, both variants behave the same.
Caution: Different default behaviors for different APIs

The Document Service API returns draft versions of documents when status is omitted, while REST and GraphQL return the published ones instead, so REST API queries need an explicit status (see REST API: publicationFilter).

Possible use cases

The following table lists many possible use cases, illustrating how the status and publicationFilter parameters can be combined to find exactly what you need with the Document Service API. Click a use case to jump to a complete example:

I want to…Use status as…Use publicationFilter as…
Find never published draftsdraftnever-published
Find drafts never published in any localedraftnever-published-document
Find modified documentsdraft or publishedmodified
Find unmodified documentsdraft or publishedunmodified
Find published documents without a draftpublishedpublished-without-draft
Find published documents with a draftpublishedpublished-with-draft
Find documents with a published versiondraft or publishedhas-published-version
Find documents published in at least one localedraft or publishedhas-published-version-document
Use with findOne() and findFirst()draft or publishedany value
Count only matching documentsdraft or publishedany value
Note

Pairing a value with the opposite status from the table above is valid but returns nothing rather than an error: for example, never-published with status: 'published' returns an empty result, because these documents have no published version yet.

Examples

The following section lists the most common use cases summed up in the table above.

Find never published drafts

One of the most common use cases is to find the drafts that have never been published. To do so, pass status: 'draft' and publicationFilter: 'never-published'.

This parameter combination works only on a given locale; to find these documents across all locales, use never-published-document instead.

strapi.documents().findMany()

Return the drafts that have never been published for their locale.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'draft',
  publicationFilter: 'never-published',
});
Returns
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "New Restaurant",
    publishedAt: null,
    locale: "en", // default locale
    // …
  }
// …
]

Find drafts never published in any locale

publicationFilter: never-published-document returns documents that have never been published in any locale. It looks at the whole document across all its locales, not one locale at a time. To find these documents for a given locale only, use never-published instead.

A document counts as published as soon as one of its locales is published: the document is then left out, even the locales that only exist as a draft. The example below returns the draft versions of documents that were never published anywhere:

strapi.documents().findMany()

Return the drafts of documents never published in any locale.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'draft',
  publicationFilter: 'never-published-document',
});
Returns
[
  {
    documentId: "d41r46wac4xix5vpba7561at",
    name: "New Restaurant",
    publishedAt: null,
    locale: "en", // default locale
    // …
  }
// …
]

Find modified documents

publicationFilter: modified selects documents whose draft has modified but unpublished changes. status then decides which version of those documents you get back.

For instance, with status: 'draft', the query returns the draft versions:

strapi.documents().findMany()

Return the draft versions of documents with unpublished changes.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'draft',
  publicationFilter: 'modified',
});
Returns
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "Biscotte Restaurant (updated)",
    publishedAt: null,
    locale: "en", // default locale
    // …
  }
// …
]

With status: 'published', the same query returns the currently live version of those documents instead:

strapi.documents().findMany()

Return the currently live versions of documents with unpublished changes.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'published',
  publicationFilter: 'modified',
});
Returns
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "Biscotte Restaurant",
    publishedAt: "2024-03-14T15:40:45.330Z",
    locale: "en", // default locale
    // …
  }
// …
]

Find unmodified documents

publicationFilter: unmodified selects documents whose draft has not changed since it was last published. status then decides which version of those documents you get back.

For instance, with status: 'draft', the query returns the draft versions:

strapi.documents().findMany()

Return the draft versions of documents unchanged since their last publication.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'draft',
  publicationFilter: 'unmodified',
});
Returns
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "Biscotte Restaurant",
    publishedAt: null,
    locale: "en", // default locale
    // …
  }
// …
]

With status: 'published', the same query returns the currently live version of those documents instead:

strapi.documents().findMany()

Return the currently live versions of documents unchanged since their last publication.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'published',
  publicationFilter: 'unmodified',
});
Returns
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "Biscotte Restaurant",
    publishedAt: "2024-03-14T15:40:45.330Z",
    locale: "en", // default locale
    // …
  }
// …
]

Find published documents without a draft

publicationFilter: published-without-draft selects published documents that have no draft counterpart.

published-without-draft must be paired with status: 'published':

strapi.documents().findMany()

Return published documents with no matching draft version for the same locale.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'published',
  publicationFilter: 'published-without-draft',
});
Returns
[
{
  documentId: "j0klm1n2o3p4q5r6s7t8u9v",
  name: "Legacy Restaurant",
  publishedAt: "2024-01-10T09:15:00.000Z",
  locale: "en", // default locale
  // …
}
// …
]

Find published documents with a draft

publicationFilter: published-with-draft selects published documents that also have a draft. Unlike published-without-draft, it keeps only the published documents that still have a draft counterpart.

published-with-draft must be paired with status: 'published':

strapi.documents().findMany()

Return published documents that also have a matching draft version for the same locale.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'published',
  publicationFilter: 'published-with-draft',
});
Returns
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "Biscotte Restaurant",
    publishedAt: "2024-03-14T15:40:45.330Z",
    locale: "en", // default locale
    // …
  }
// …
]

Find documents with a published version

publicationFilter: has-published-version selects documents that have both a draft and a published version for the same locale. status then decides which version of those documents you get back. Unlike published-without-draft, it excludes published documents that have no draft counterpart.

For instance, with status: 'draft', the query returns the draft versions:

strapi.documents().findMany()

Return the draft versions of documents that also have a published version for the same locale.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'draft',
  publicationFilter: 'has-published-version',
});
Returns
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "Biscotte Restaurant",
    publishedAt: null,
    locale: "en", // default locale
    // …
  }
// …
]

With status: 'published', the same query returns the currently live version of those documents instead:

strapi.documents().findMany()

Return the currently live versions of documents that also have a published version for the same locale.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'published',
  publicationFilter: 'has-published-version',
});
Returns
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "Biscotte Restaurant",
    publishedAt: "2024-03-14T15:40:45.330Z",
    locale: "en", // default locale
    // …
  }
// …
]

Find documents published in at least one locale

publicationFilter: has-published-version-document considers all locales, so it matches a document as soon as one of its locales is published. With status: 'draft', it returns the draft versions of every locale of those documents, including locales that were never published themselves:

strapi.documents().findMany()

Return the draft versions of documents published in at least one locale.

GETstrapi.documents().findMany()
await strapi.documents('api::restaurant.restaurant').findMany({
  status: 'draft',
  publicationFilter: 'has-published-version-document',
});
Returns
[
  {
    documentId: "a1b2c3d4e5f6g7h8i9j0klm",
    name: "Biscotte Restaurant",
    publishedAt: null,
    locale: "en", // published in at least one locale
    // …
  }
// …
]

Use with findOne() and findFirst()

If the requested document (and locale, when applicable) does not match the filter, findOne() and findFirst() return null even when the documentId exists:

strapi.documents().findOne()

Return the document only if it matches the filter, null otherwise.

GETstrapi.documents().findOne()
await strapi.documents('api::restaurant.restaurant').findOne({
  documentId: 'a1b2c3d4e5f6g7h8i9j0klm',
  status: 'draft',
  publicationFilter: 'never-published',
});
Returns
null // the documentId exists, but the document does not match never-published

Count only matching documents

Without publicationFilter, count({ status: 'draft' }) counts every draft version, including drafts whose document already has a published version. Add publicationFilter to count only the documents that match a given value (see the status documentation):

strapi.documents().count()

Count only the documents that match a given value.

GETstrapi.documents().count()
const neverPublishedCount = await strapi
  .documents('api::restaurant.restaurant')
  .count({
    status: 'draft',
    publicationFilter: 'never-published',
  });
Returns
12 // the number of never-published drafts

Combination with other parameters

publicationFilter is combined with other query parameters as a logical AND, including filters and populate. When populating draft & publish relations, nested queries inherit the same filter logic.

Content Manager mapping

In the Content Manager, the Draft (never published) list filter maps to status: 'draft' and publicationFilter: 'never-published-document' (document-scoped, not the per-locale never-published).

Was this page helpful?