wpml-compatibility-audit
Audit whether a WordPress plugin or classic theme is WPML-compatible end to end. Use when asked "is this plugin WPML compatible?", "why does this shortcode/string/page not translate?", or when code has wpml-config.xml, stored page/product/term IDs, get_permalink/home_url, shortco
Install
npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/wpml/wpml-compatibility-audit
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
git clone https://github.com/Lonsdale201/wp-agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
WPML compatibility audit
Use this to produce a verdict on a plugin/theme's WPML compatibility. This is a workflow skill: it tells you what to inspect and how to classify problems. Use the narrower WPML skills for implementation details once a failing area is identified.
Compatibility verdicts
Report one of these:
- Compatible: static gettext, dynamic strings, stored IDs, queries, URLs, and background render paths work in the current language or deliberately snapshot original data.
- Partially compatible: most static strings work, but one or more dynamic strings, stored IDs, shortcodes, emails/PDFs, or custom tables need fixes.
- Not WPML-compatible: core user-facing flows hard-code one language or one object ID, or rely on direct meta/option strings with no translation path.
- Not testable: required WPML add-ons or plugin runtime dependencies are missing; still report source-level risks.
Audit workflow
- Identify the multilingual surface:
- Is WPML core active/installed?
defined( 'ICL_SITEPRESS_VERSION' ). - Is String Translation installed?
defined( 'WPML_ST_VERSION' )orwpml_is_st_loaded(). - If String Translation is missing, dynamic option/admin strings are not runtime-testable; the hook form still degrades to original text.
- Is WooCommerce Multilingual relevant for products/orders?
- Does the plugin also claim Polylang/TranslatePress compatibility?
- Is WPML core active/installed?
- Separate static gettext from dynamic strings:
- Static UI strings using
__(),_e(),esc_html__(), etc. are normal WordPress i18n. Check text domain, load timing,.pot,.po/.mo, and JS translations. - DB/admin-entered strings need WPML String Translation. They must be registered and translated on every output path.
- Static UI strings using
- Inventory stored object IDs:
- Options/meta/custom tables holding page, post, product, variation, term,
attachment, menu, or form IDs need runtime resolution with
wpml_object_idor a correctwpml-config.xmldeclaration. - URLs derived from those IDs need
get_permalink( $translated_id )orwpml_permalink.
- Options/meta/custom tables holding page, post, product, variation, term,
attachment, menu, or form IDs need runtime resolution with
- Inspect shortcode/block behavior:
- A shortcode's PHP-generated output still needs runtime string/ID handling.
- Shortcode attributes/content stored inside page content need
wpml-config.xml<shortcode-list>or rich<shortcodes>config when WPML should expose them to translators. - Block attributes need
<gutenberg-blocks>config when not covered by normal block translation.
- Inspect queries:
- Default WP queries usually follow the current WPML language.
- Queries for another language need
do_action( 'wpml_switch_language', $lang )and restore withnull. - Custom SQL/custom tables are not language-filtered by WPML; they need an explicit language column, translated joins, or deliberate snapshot logic.
- Inspect WooCommerce paths:
- Historical order item snapshots should usually stay as purchased.
- Current product/category/tag links or settings should resolve translated IDs before display.
- Product/category/tag meta compatibility belongs in
wpml-config.xmlcustom-field/custom-term-field declarations.
- Inspect async/non-page rendering:
- Emails, PDFs, cron, REST, exports, and webhooks do not automatically have the same language context as the frontend request.
- Store the request language when creating records, then switch language while rendering language-sensitive output and restore afterward.
Dynamic string checklist
Find option reads/writes, settings textareas, admin-entered labels, and template data that comes from the database.
WPML core exposes wpml_is_st_loaded() as defined( 'WPML_ST_VERSION' ).
The actual handlers are in the String Translation add-on: ST 3.5.3 registers
wpml_register_single_string in inc/functions.php and filters
wpml_translate_single_string with a 5-argument callback.
Correct pattern:
do_action( 'wpml_register_single_string', 'my-plugin', 'button_label', $value );
$label = apply_filters(
'wpml_translate_single_string',
$value,
'my-plugin',
'button_label',
$language_code // optional; omit for current language
);
Rules:
- Registering alone is not enough; output must call
wpml_translate_single_string. - Passing an explicit language is useful for emails, PDFs, exports, and jobs rendered outside the original frontend request.
- The hook form degrades safely when String Translation is absent.
- Legacy
icl_register_string()/icl_t()must be guarded withfunction_exists(). - Keep context and names stable. Changing them orphans existing translations.
- Prefer
<admin-texts>inwpml-config.xmlfor fixed option keys, but remember it needs String Translation.
Stored ID checklist
Flag every stored ID and decide whether it is a snapshot or a live reference:
- Live page/post/term/product ID for display: resolve with
wpml_object_id. - Live URL: use translated ID or
wpml_permalink. - Admin edit links and historical order/case snapshots can usually stay in the original object/language.
- Asset enqueueing based on
is_page( $stored_page_id )must also account for the translated page ID.
Typical page-option pattern:
$page_id = (int) get_option( 'my_page_id' );
$page_id = (int) apply_filters( 'wpml_object_id', $page_id, 'page', true );
$url = $page_id > 0 ? get_permalink( $page_id ) : '';
wpml-config.xml checklist
Check whether the plugin ships wpml-config.xml in the plugin root. If absent,
decide whether it needs one.
String Translation parses config through wpml_parse_config_file /
wpml_parse_custom_config. <admin-texts> entries are imported by ST and can
attach option_{$option} filters for translated option values and nested ID
translation. Without ST, <admin-texts> does not provide translated output.
Usually declare:
- CPTs/taxonomies the plugin owns:
<custom-types>/<taxonomies>. - Product/page/post/term meta that must copy/translate:
<custom-fields>/<custom-term-fields>. - Option strings:
<admin-texts>with nested keys. - Option IDs:
<key type="post-ids" sub-type="page" name="...">or the relevant post type. - Shortcodes:
<shortcode-list>or<shortcodes>when translators must edit shortcode content/attributes.
Validate config values strictly: translate, display-as-translated, and
automatic are 0|1; custom-field action is exactly
translate|copy|copy-once|ignore.
Common findings
- High: user-facing shortcode/form output reads DB option strings but never
calls
wpml_translate_single_string. - High: stored
withdrawal_page_id, product ID, term ID, or attachment ID is used directly on translated pages. - High: e-mail/PDF generation ignores the language used when the case/order was submitted.
- Medium: no
wpml-config.xmlfor plugin options/meta/shortcodes. - Medium:
<admin-texts>exists, but the audit/test environment has WPML core without String Translation, so option-string behavior is not testable. - Medium: custom table has no language column even though rows are language-sensitive.
- Medium: JS editor strings use
@wordpress/i18nbut the script never callswp_set_script_translations(). - Low: admin-only labels are gettext-ready but no translation file exists.
Report format
Return:
- Verdict: Compatible / Partially compatible / Not compatible / Not testable.
- Environment: WPML core version, String Translation version/presence, WCML presence, plugin version, active competing multilingual plugins if relevant.
- Findings: severity, file/line, what breaks, and why.
- Fix plan: minimal code/config changes, grouped by string, ID/URL, query, shortcode/block, Woo, and async rendering.
- Residual risk: what still needs browser/WPML admin verification.
Cross-references
- Use
wpml-overviewfor the WPML copy/translation mental model. - Use
wpml-configwhen creating or validatingwpml-config.xml. - Use
wpml-string-translationfor dynamic option/admin-entered strings. - Use
wpml-language-apifor current language, object IDs, permalinks, and language switching. - Use
wp-i18n-auditfor core WordPress gettext and Loco/PO/MO issues.
References
Validated against WPML Multilingual CMS 4.9.5 and WPML String Translation 3.5.3 local source:
- API hook registration:
sitepress.class.php - Runtime callbacks:
inc/template-functions.php - Config parsing:
classes/xml-config/class-wpml-config.php - String hook call sites:
classes/language-switcher/class-wpml-ls-settings-strings.php - Explicit-language string translate example:
classes/url-handling/class-wpml-endpoints-support.php - Config schema:
res/xsd/wpml-config.xsd - String Translation bootstrap/version:
wpml-string-translation/plugin.php wpml_register_single_string/wpml_translate_single_stringhandlers:wpml-string-translation/inc/functions.php- Admin text config parsing and option filters:
wpml-string-translation/inc/private-actions.phpandwpml-string-translation/inc/admin-texts/wpml-admin-texts.class.php - Official documentation: https://wpml.org/documentation/support/wpml-coding-api/
- Official documentation: https://wpml.org/documentation/support/language-configuration-files/
- Official documentation: https://wpml.org/documentation/getting-started-guide/string-translation/
- Verified source paths:
wp-content/plugins/sitepress-multilingual-cms/sitepress.phpwp-content/plugins/wpml-string-translation/inc/admin-texts/wpml-admin-text-configuration.php
Files (wp-agent-skills)
-
agents
-
openai.yaml 217 B
interface: display_name: "WPML Compatibility Audit" short_description: "Audit plugin/theme WPML compatibility" default_prompt: "Use $wpml-compatibility-audit to audit a WordPress plugin for WPML compatibility."
-
-
SKILL.md 10.3 KB
--- name: wpml-compatibility-audit description: >- Audit whether a WordPress plugin or classic theme is WPML-compatible end to end. Use when asked "is this plugin WPML compatible?", "why does this shortcode/string/page not translate?", or when code has wpml-config.xml, stored page/product/term IDs, get_permalink/home_url, shortcode attributes, get_option option strings, custom tables, WooCommerce order/product data, emails/PDFs/background jobs, wpml_register_single_string, wpml_translate_single_string, wpml_object_id, wpml_permalink, or wpml_switch_language. metadata: wp-skills-author: "Soczó Kristóf" wp-skills-contact: "mailto:lonsdale201@hotmail.com" wp-skills-plugin: "sitepress-multilingual-cms" wp-skills-plugin-version-tested: "4.9.5" wp-skills-wpml-string-translation-version-tested: "3.5.3" wp-skills-php-min: "7.4" wp-skills-last-updated: "2026-07-07" --- # WPML compatibility audit Use this to produce a verdict on a plugin/theme's WPML compatibility. This is a workflow skill: it tells you what to inspect and how to classify problems. Use the narrower WPML skills for implementation details once a failing area is identified. ## Compatibility verdicts Report one of these: - **Compatible**: static gettext, dynamic strings, stored IDs, queries, URLs, and background render paths work in the current language or deliberately snapshot original data. - **Partially compatible**: most static strings work, but one or more dynamic strings, stored IDs, shortcodes, emails/PDFs, or custom tables need fixes. - **Not WPML-compatible**: core user-facing flows hard-code one language or one object ID, or rely on direct meta/option strings with no translation path. - **Not testable**: required WPML add-ons or plugin runtime dependencies are missing; still report source-level risks. ## Audit workflow 1. Identify the multilingual surface: - Is WPML core active/installed? `defined( 'ICL_SITEPRESS_VERSION' )`. - Is String Translation installed? `defined( 'WPML_ST_VERSION' )` or `wpml_is_st_loaded()`. - If String Translation is missing, dynamic option/admin strings are not runtime-testable; the hook form still degrades to original text. - Is WooCommerce Multilingual relevant for products/orders? - Does the plugin also claim Polylang/TranslatePress compatibility? 2. Separate static gettext from dynamic strings: - Static UI strings using `__()`, `_e()`, `esc_html__()`, etc. are normal WordPress i18n. Check text domain, load timing, `.pot`, `.po/.mo`, and JS translations. - DB/admin-entered strings need WPML String Translation. They must be registered and translated on every output path. 3. Inventory stored object IDs: - Options/meta/custom tables holding page, post, product, variation, term, attachment, menu, or form IDs need runtime resolution with `wpml_object_id` or a correct `wpml-config.xml` declaration. - URLs derived from those IDs need `get_permalink( $translated_id )` or `wpml_permalink`. 4. Inspect shortcode/block behavior: - A shortcode's PHP-generated output still needs runtime string/ID handling. - Shortcode attributes/content stored inside page content need `wpml-config.xml` `<shortcode-list>` or rich `<shortcodes>` config when WPML should expose them to translators. - Block attributes need `<gutenberg-blocks>` config when not covered by normal block translation. 5. Inspect queries: - Default WP queries usually follow the current WPML language. - Queries for another language need `do_action( 'wpml_switch_language', $lang )` and restore with `null`. - Custom SQL/custom tables are not language-filtered by WPML; they need an explicit language column, translated joins, or deliberate snapshot logic. 6. Inspect WooCommerce paths: - Historical order item snapshots should usually stay as purchased. - Current product/category/tag links or settings should resolve translated IDs before display. - Product/category/tag meta compatibility belongs in `wpml-config.xml` custom-field/custom-term-field declarations. 7. Inspect async/non-page rendering: - Emails, PDFs, cron, REST, exports, and webhooks do not automatically have the same language context as the frontend request. - Store the request language when creating records, then switch language while rendering language-sensitive output and restore afterward. ## Dynamic string checklist Find option reads/writes, settings textareas, admin-entered labels, and template data that comes from the database. WPML core exposes `wpml_is_st_loaded()` as `defined( 'WPML_ST_VERSION' )`. The actual handlers are in the String Translation add-on: ST 3.5.3 registers `wpml_register_single_string` in `inc/functions.php` and filters `wpml_translate_single_string` with a 5-argument callback. Correct pattern: ```php do_action( 'wpml_register_single_string', 'my-plugin', 'button_label', $value ); $label = apply_filters( 'wpml_translate_single_string', $value, 'my-plugin', 'button_label', $language_code // optional; omit for current language ); ``` Rules: - Registering alone is not enough; output must call `wpml_translate_single_string`. - Passing an explicit language is useful for emails, PDFs, exports, and jobs rendered outside the original frontend request. - The hook form degrades safely when String Translation is absent. - Legacy `icl_register_string()` / `icl_t()` must be guarded with `function_exists()`. - Keep context and names stable. Changing them orphans existing translations. - Prefer `<admin-texts>` in `wpml-config.xml` for fixed option keys, but remember it needs String Translation. ## Stored ID checklist Flag every stored ID and decide whether it is a snapshot or a live reference: - Live page/post/term/product ID for display: resolve with `wpml_object_id`. - Live URL: use translated ID or `wpml_permalink`. - Admin edit links and historical order/case snapshots can usually stay in the original object/language. - Asset enqueueing based on `is_page( $stored_page_id )` must also account for the translated page ID. Typical page-option pattern: ```php $page_id = (int) get_option( 'my_page_id' ); $page_id = (int) apply_filters( 'wpml_object_id', $page_id, 'page', true ); $url = $page_id > 0 ? get_permalink( $page_id ) : ''; ``` ## `wpml-config.xml` checklist Check whether the plugin ships `wpml-config.xml` in the plugin root. If absent, decide whether it needs one. String Translation parses config through `wpml_parse_config_file` / `wpml_parse_custom_config`. `<admin-texts>` entries are imported by ST and can attach `option_{$option}` filters for translated option values and nested ID translation. Without ST, `<admin-texts>` does not provide translated output. Usually declare: - CPTs/taxonomies the plugin owns: `<custom-types>` / `<taxonomies>`. - Product/page/post/term meta that must copy/translate: `<custom-fields>` / `<custom-term-fields>`. - Option strings: `<admin-texts>` with nested keys. - Option IDs: `<key type="post-ids" sub-type="page" name="...">` or the relevant post type. - Shortcodes: `<shortcode-list>` or `<shortcodes>` when translators must edit shortcode content/attributes. Validate config values strictly: `translate`, `display-as-translated`, and `automatic` are `0|1`; custom-field `action` is exactly `translate|copy|copy-once|ignore`. ## Common findings - **High**: user-facing shortcode/form output reads DB option strings but never calls `wpml_translate_single_string`. - **High**: stored `withdrawal_page_id`, product ID, term ID, or attachment ID is used directly on translated pages. - **High**: e-mail/PDF generation ignores the language used when the case/order was submitted. - **Medium**: no `wpml-config.xml` for plugin options/meta/shortcodes. - **Medium**: `<admin-texts>` exists, but the audit/test environment has WPML core without String Translation, so option-string behavior is not testable. - **Medium**: custom table has no language column even though rows are language-sensitive. - **Medium**: JS editor strings use `@wordpress/i18n` but the script never calls `wp_set_script_translations()`. - **Low**: admin-only labels are gettext-ready but no translation file exists. ## Report format Return: - **Verdict**: Compatible / Partially compatible / Not compatible / Not testable. - **Environment**: WPML core version, String Translation version/presence, WCML presence, plugin version, active competing multilingual plugins if relevant. - **Findings**: severity, file/line, what breaks, and why. - **Fix plan**: minimal code/config changes, grouped by string, ID/URL, query, shortcode/block, Woo, and async rendering. - **Residual risk**: what still needs browser/WPML admin verification. ## Cross-references - Use `wpml-overview` for the WPML copy/translation mental model. - Use `wpml-config` when creating or validating `wpml-config.xml`. - Use `wpml-string-translation` for dynamic option/admin-entered strings. - Use `wpml-language-api` for current language, object IDs, permalinks, and language switching. - Use `wp-i18n-audit` for core WordPress gettext and Loco/PO/MO issues. ## References Validated against WPML Multilingual CMS 4.9.5 and WPML String Translation 3.5.3 local source: - API hook registration: `sitepress.class.php` - Runtime callbacks: `inc/template-functions.php` - Config parsing: `classes/xml-config/class-wpml-config.php` - String hook call sites: `classes/language-switcher/class-wpml-ls-settings-strings.php` - Explicit-language string translate example: `classes/url-handling/class-wpml-endpoints-support.php` - Config schema: `res/xsd/wpml-config.xsd` - String Translation bootstrap/version: `wpml-string-translation/plugin.php` - `wpml_register_single_string` / `wpml_translate_single_string` handlers: `wpml-string-translation/inc/functions.php` - Admin text config parsing and option filters: `wpml-string-translation/inc/private-actions.php` and `wpml-string-translation/inc/admin-texts/wpml-admin-texts.class.php` - Official documentation: <https://wpml.org/documentation/support/wpml-coding-api/> - Official documentation: <https://wpml.org/documentation/support/language-configuration-files/> - Official documentation: <https://wpml.org/documentation/getting-started-guide/string-translation/> - Verified source paths: - `wp-content/plugins/sitepress-multilingual-cms/sitepress.php` - `wp-content/plugins/wpml-string-translation/inc/admin-texts/wpml-admin-text-configuration.php`
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.