Document Service API: publicationFilter
Page summary:Use the optional
publicationFilterparameter 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 withfindOne(),findFirst(),findMany(), andcount(), and combines with other query parameters.statusstill 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.
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:
| Value | Selects |
|---|---|
never-published | Documents never published in a given locale |
never-published-document | Documents never published in any locale |
modified | Documents whose draft was edited since it was last published |
unmodified | Documents whose draft has not changed since it was last published |
published-without-draft | Published documents with no draft counterpart |
published-with-draft | Published documents that also have a draft |
has-published-version | Documents that have both a draft and a published version |
has-published-version-document | Documents 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.
- Unknown values raise a validation error.
- Values ending in
-documentconsider all locales of a document, which matters when Internationalization (i18n) is enabled: for example,never-published-documentexcludes 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.
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 drafts | draft | never-published |
| Find drafts never published in any locale | draft | never-published-document |
| Find modified documents | draft or published | modified |
| Find unmodified documents | draft or published | unmodified |
| Find published documents without a draft | published | published-without-draft |
| Find published documents with a draft | published | published-with-draft |
| Find documents with a published version | draft or published | has-published-version |
| Find documents published in at least one locale | draft or published | has-published-version-document |
Use with findOne() and findFirst() | draft or published | any value |
| Count only matching documents | draft or published | any value |
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'draft',
publicationFilter: 'never-published',
});[
{
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'draft',
publicationFilter: 'never-published-document',
});[
{
documentId: "d41r46wac4xix5vpba7561at",
name: "New Restaurant",
publishedAt: null,
locale: "en", // default locale
// …
}
// …
]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).
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'draft',
publicationFilter: 'modified',
});[
{
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'published',
publicationFilter: 'modified',
});[
{
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'draft',
publicationFilter: 'unmodified',
});[
{
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'published',
publicationFilter: 'unmodified',
});[
{
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'published',
publicationFilter: 'published-without-draft',
});[
{
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.
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'published',
publicationFilter: 'published-with-draft',
});[
{
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'draft',
publicationFilter: 'has-published-version',
});[
{
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'published',
publicationFilter: 'has-published-version',
});[
{
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.
await strapi.documents('api::restaurant.restaurant').findMany({
status: 'draft',
publicationFilter: 'has-published-version-document',
});[
{
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.
await strapi.documents('api::restaurant.restaurant').findOne({
documentId: 'a1b2c3d4e5f6g7h8i9j0klm',
status: 'draft',
publicationFilter: 'never-published',
});null // the documentId exists, but the document does not match never-publishedCount 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):
const neverPublishedCount = await strapi
.documents('api::restaurant.restaurant')
.count({
status: 'draft',
publicationFilter: 'never-published',
});
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.