WP Manifestindependent plugin directory
manifest / i18n / gds-content-translation

GDS Content Translation WP Registry grade A. No security issues foundWP RegistryNo security issues foundOpen the reportA

Polylang Pro helpers for block translation rules, link remapping, and editorial translation status

★ 0stars
v1.1.1latest · 22d ago

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/generoi/gds-content-translation/archive/refs/heads/master.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

WordPress plugin for Polylang Pro editorial workflows: translation status dashboard, one-click machine translation or source-language copy, block attribute translation rules, post ID sync, and internal link remapping.

Requires Polylang Pro with optional DeepL machine translation.

Requirements

  • PHP >= 8.0
  • WordPress >= 6.0
  • Polylang Pro >= 3.3

Installation

composer require generoi/gds-content-translation
wp plugin activate gds-content-translation

For local path development (before the package is on Packagist):

{
  "repositories": [
    {
      "type": "path",
      "url": "web/app/plugins/gds-content-translation",
      "options": { "symlink": true }
    }
  ],
  "require": {
    "generoi/gds-content-translation": "@dev"
  }
}

Features

Translation status admin

Polylang → Content translation status: overview of missing translations, proof-read flags, open block notes, and two ways to create a missing translation per language:

  • AI translation — machine-translates the source post with Polylang Pro's configured service (DeepL). Only shown when machine translation is enabled and a service is configured.
  • Copy original — creates the translation as a verbatim copy of the source (default) language, with no machine translation involved. Needs no service, so it also works when DeepL is unconfigured or out of quota.

Both run through Polylang Pro's translation pipeline, so blocks, internal links, post IDs, terms and metas are remapped to the target language either way, and both create the translation as a draft and open it in the editor.

Polylang → Content translation settings: choose which post types appear as tabs on the status screen. Unchecked types are hidden from the dashboard UI.

Programmatic exclusions still work via filter (always applied on top of saved settings):

add_filter('gds_content_translation_excluded_post_types', function (array $postTypes): array {
    return array_merge($postTypes, ['shop_order']);
});

Polylang block integration

The plugin registers Polylang Pro hooks and exposes project-specific rules via WordPress filters. Themes (or site-specific mu-plugins) declare which custom block attributes are translatable strings, which hold post/attachment IDs, and which hold internal URLs.

Built-in defaults (no theme code required):

  • core/query handpicked posts (query.include) → sync post IDs
  • core/button url attribute + <a href> in block HTML → rewrite internal links

Configuring block rules (themes)

Add filters in your theme app/filters.php (or a small mu-plugin). The plugin merges your rules into Polylang’s native filters.

1. Translatable text attributes (DeepL / XLIFF)

Use for RichText and other string attributes stored in block JSON (not inner HTML).

Maps to Polylang’s pll_blocks_rules_for_attributes.

add_filter('gds_content_translation_pll_blocks_rules_for_attributes', function (array $rules): array {
    return array_merge($rules, [
        'my-theme/hero' => [
            'heading' => true,
            'intro' => true,
        ],
        'my-theme/feature-list' => [
            'items' => [
                '*' => [
                    'title' => true,
                    'description' => true,
                ],
            ],
        ],
    ]);
});

2. Post / attachment ID sync

Use when a block stores a numeric ID that should point at the translated post or attachment after machine translation or content sync.

Maps to Polylang’s pll_sync_block_rules_for_attributes.

add_filter('gds_content_translation_pll_sync_block_rules_for_attributes', function (array $rules): array {
    return array_merge($rules, [
        'my-theme/post-teaser' => [
            'post' => [
                'postId' => true,
            ],
        ],
        'my-theme/media-card' => [
            'attachment' => [
                'mediaId' => true,
            ],
        ],
    ]);
});

Types: post, term, attachment, wp_block.

3. Internal URL attributes

Use when a block stores a URL string (not an ID) in attributes — e.g. card blocks with a url field.

The plugin also rewrites <a href> inside block HTML (buttons, paragraphs). This filter adds attribute-based URLs.

add_filter('gds_content_translation_link_url_attributes_by_block', function (array $attributesByBlock): array {
    return array_merge($attributesByBlock, [
        'my-theme/numbered-card' => ['url'],
        'my-theme/info-card' => ['url'],
    ]);
});

4. Post meta (custom fields)

Use for plain register_post_meta() / meta box values that are frontend text and should be machine-translated.

Maps to Polylang’s pll_post_metas_to_export. Keys are grouped by post type.

add_filter('gds_content_translation_pll_post_metas_to_export', function (array $rulesByPostType): array {
    return array_merge($rulesByPostType, [
        'person' => [
            'person_job_title' => 1,
            'person_department' => 1,
            'person_sales_area' => 1,
        ],
    ]);
});

Use 1 for scalar string metas. Nested array metas use the same shape as Polylang’s export rules (sub-key => 1).

Keep locale-invariant metas (phone, email, attachment IDs) on pll_copy_post_metas sync only — do not list them here.

5. ACF fields

Polylang Pro handles ACF via field-level translation modes. Set defaults for fields that are not configured in the ACF UI:

add_filter('gds_content_translation_acf_field_translations', function (array $modesByFieldName): array {
    return array_merge($modesByFieldName, [
        'material_file' => 'copy_once', // attachment ID
        'hero_intro' => 'translate',    // frontend text
    ]);
});

Modes: translate, translate_once, copy_once, sync, ignore.

LOFS / GDS theme example

The lofs theme registers its gds/* blocks in app/filters.php:

add_filter('gds_content_translation_pll_blocks_rules_for_attributes', function (array $rules): array {
    return array_merge($rules, [
        'gds/timeline' => ['tag' => true, 'heading' => true],
        'gds/check-list' => [
            'items' => ['*' => ['title' => true, 'description' => true]],
        ],
        // …
    ]);
});

add_filter('gds_content_translation_pll_sync_block_rules_for_attributes', function (array $rules): array {
    return array_merge($rules, [
        'gds/post-teaser' => ['post' => ['postId' => true]],
        'gds/media-card' => ['attachment' => ['mediaId' => true]],
    ]);
});

add_filter('gds_content_translation_link_url_attributes_by_block', function (array $attributesByBlock): array {
    return array_merge($attributesByBlock, [
        'gds/numbered-card' => ['url'],
        'gds/info-card' => ['url'],
    ]);
});

When rules run

Feature When Persisted?
Text attributes Machine translation, XLIFF import, sync Yes — saved in post content
Post meta text Machine translation, XLIFF import Yes — saved in post meta
ACF text fields Machine translation, XLIFF import Yes — saved in post meta
ID sync (postId, etc.) Machine translation, Polylang content sync Yes
Link remapping (sync hook) Machine translation, Polylang content sync Yes
Link remapping (render hook) Every frontend block render No — runtime fallback for old content

If a translation does not exist for a linked post, IDs become 0 (teaser hidden) and URLs are left unchanged.

Development

cd web/app/plugins/gds-content-translation
composer install
composer lint:fix

Testing

Tests run against a real WordPress install with Polylang active, provided by wp-env (requires Docker).

npx @wordpress/env start
npx @wordpress/env run tests-cli --env-cwd=wp-content/plugins/gds-content-translation vendor/bin/phpunit
npx @wordpress/env stop

tests/Unit covers the rule-merging filters, tests/Integration covers block translation against configured en / fi languages. Tests that need Polylang skip themselves when it is not installed.

License

MIT

Releases

8 releases.

Tag
Published
v1.1.1 latest
Oct 1, 2026 22d ago
Oct 1, 2026 22d ago
Oct 1, 2026 22d ago
Oct 1, 2026 22d ago
Aug 25, 2026 1mo ago
Aug 12, 2026 2mo ago
Jun 24, 2026 4mo ago
Jun 24, 2026 4mo ago

These releases are tags only. The author does not attach a packaged zip, so there are no download counts to report.

A grade

Security

GDS Content Translation 1.0.0 · audited by WP Registry

No security issues found.

Audited release
1.0.0
Findings
none
Worst severity
—
Content hash
f1e16cee07128e4863148919…

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.