Skip to content

Scheduled actions are shared across locales — locale-aware filtering is needed #222

Description

@shoh7767

Bug Description

When using strapi-plugin-publisher with Strapi v5's i18n plugin, scheduled publish/unpublish actions are shared across all locales of the same document. Setting a publish timer on one locale (e.g., Japanese) causes the timer to appear on other locales (e.g., English) as well, preventing locale-specific scheduling.

Steps to Reproduce

  1. Enable i18n and publisher plugins on a content type
  2. Open an entry in locale A (e.g., ja) and set a publish timer
  3. Switch to locale B (e.g., en) of the same document
  4. Observe that the timer from locale A is displayed, and you cannot set a separate timer for locale B

Expected Behavior

Each locale should have independent publish/unpublish timers. Setting a timer on one locale should not affect other locales.

Root Cause Analysis

There are three issues:

1. locale attribute missing from action schema

The action content type schema does not include a locale field, so there is no way to store which locale a scheduled action belongs to.

2. Strapi v5 sanitizeQuery strips locale from attribute filters

Even if locale is added to the schema and passed as filters[locale]=ja from the frontend, Strapi v5's core controller sanitizeQuery treats locale as a system-level i18n parameter and removes it from the attribute filters. This means the default find controller ignores the locale filter entirely.

3. Frontend does not pass locale to the action query

The getAction() hook does not include locale in the filters passed to the API, nor in the React Query cache key. This means all locales share the same cached result.

Suggested Fix

  1. Add locale to the action content type schema (type: 'string', required: false)
  2. Override find in actionController to restore the locale filter after sanitizeQuery:
    const actionController = factories.createCoreController('plugin::publisher.action', ({ strapi }) => ({
      async find(ctx) {
        const sanitizedQuery = await this.sanitizeQuery(ctx);
        const { filters: rawFilters } = ctx.query || {};
        if (rawFilters?.locale !== undefined) {
          const { locale } = rawFilters;
          if (locale === null || locale === '' || locale === 'null') {
            if (!sanitizedQuery.filters) sanitizedQuery.filters = {};
            sanitizedQuery.filters.locale = null;
          } else if (typeof locale === 'string') {
            if (!sanitizedQuery.filters) sanitizedQuery.filters = {};
            sanitizedQuery.filters.locale = locale;
          }
        }
        const { results, pagination } = await strapi.plugin('publisher').service('action').find(sanitizedQuery);
        const sanitizedResults = await this.sanitizeOutput(results, ctx);
        return this.transformResponse(sanitizedResults, { pagination });
      }
    }));
  3. Pass locale to getAction() filters and include it in the React Query cache key to ensure locale-specific caching.

Environment

  • Strapi: v5.x
  • strapi-plugin-publisher: 2.0.9
  • i18n plugin: enabled

Additional Context

We are currently using patch-package to work around this issue. Happy to submit a PR if the maintainers agree with the approach above.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions