WPML handles standard WordPress posts and pages well, but custom post types (CPTs) require specific configuration before translations work correctly. The common symptoms – translated posts not appearing on the front end, the wrong language showing, or custom fields not being included in translation – each have specific causes that are straightforward to fix once you know where to look.
Why WPML Needs Special Configuration for Custom Post Types
WordPress registers custom post types through register_post_type(). WPML does not automatically know which of your CPTs should be translatable, which should share a single version across languages, or which should be excluded from translation entirely. Without explicit configuration, WPML defaults to making CPTs translatable but this can produce confusing results if the CPT was registered without considering multilingual use.
The three translation modes WPML offers for CPTs are meaningfully different. Translatable with different slugs per language means each language has its own version of the post with its own URL. Translatable with the same slug means a shared URL with language-specific content served based on the visitor’s language. Not translatable means a single global version shown to all languages. The wrong mode choice is behind many of the confusing WPML CPT behaviours developers report.
Step 1: Configure the CPT in WPML Settings
Go to WPML -> Settings -> Custom Posts. For each registered CPT, select the translation mode:
- If each language should have its own distinct translated content (a blog post, a service description): choose “Translatable – use different posts for different languages”
- If the content is global and the same for all languages (a pricing plan, a system status): choose “Not translatable – show the same content for all languages”
After changing a CPT’s translation mode, flush the WordPress rewrite rules by going to Settings -> Permalinks and saving without changes.
Step 2: Translated Posts Not Appearing on the Front End
This is the most common WPML CPT problem and it usually has one of three causes. The first is that the translated post exists but is in Draft status rather than Published. Go to the secondary language admin, find the CPT list, and verify the translated post is published. WPML creates translation placeholders in Draft status; someone must actively publish each translation.
The second cause is that the WP_Query used to display the CPT is not passing language information to WPML correctly. If you have a custom archive template or custom query, WPML may not intercept it to filter by language. Add the language filter explicitly:
$args = array(
'post_type' => 'your_cpt',
'post_status' => 'publish',
'lang' => ICL_LANGUAGE_CODE, // current WPML language
);
$query = new WP_Query($args);
The third cause is a CPT registered without has_archive => true. Without archives enabled, WPML cannot create language-specific archive URLs. Enable archives in your CPT registration and re-save permalinks.
Still stuck after trying these steps? Describe the exact issue and get a free estimate from a developer who has seen this before.
Step 3: ACF Fields Not Translating With WPML
Advanced Custom Fields and WPML require WPML’s String Translation plugin and specific ACF field configuration. By default, ACF field values are not included in WPML’s translation workflow – you see the original language values on translated posts.
The fix requires configuring each ACF field group for WPML. Go to WPML -> Settings -> Custom Fields Translation. For each ACF meta key that appears, select the translation behaviour:
- Copy – the original value is copied to the translated post and can be edited independently
- Copy once – copied on first translation but then managed separately
- Translate – the field appears in the WPML translation editor for manual translation
- Don’t translate – shared across all languages
For text fields containing content (descriptions, titles, body copy): choose Translate. For fields that are language-agnostic (prices, dates, boolean flags): choose Copy or Don’t translate.
Step 4: Fixing Wrong Language Appearing in Custom Queries
Sometimes a CPT archive or custom template shows posts from the wrong language. This happens when a WP_Query runs before WPML has initialised its language filter, or when using get_posts() with suppress_filters => true (which bypasses WPML’s language filtering). Always use WP_Query rather than get_posts() for CPT queries on multilingual sites, and avoid suppress_filters.
To explicitly suppress WPML’s auto-filtering for a specific query (useful when you intentionally want all languages):
// Remove WPML language filter for this query
remove_filter('pre_get_posts', array($GLOBALS['sitepress'], 'pre_get_posts'));
$all_languages_query = new WP_Query($args);
// Restore the filter
add_filter('pre_get_posts', array($GLOBALS['sitepress'], 'pre_get_posts'));
Step 5: CPT Slugs Returning 404 in Secondary Languages
When WPML is configured to translate CPT slugs (the URL segment for the CPT archive), the slug in each language must be explicitly set. Go to WPML -> Settings -> URL Format -> Custom Post Types and Taxonomies. Enter the slug for each language for each CPT. After saving, go to Settings -> Permalinks and save to flush rewrite rules. 404 errors on translated CPT archives are almost always a missing slug translation or unflushed rewrite rules.