WPML GraphQL - WordPress Plugin
WPML GraphQL provides an essential functionality by seamlessly integrating multilingual capabilities into the WPGraphQL schema for WordPress. By effectively bridging the gap between the WPML plugin and the GraphQL API, this plugin enhances the multilingual experience for users and developers alike. With the ability to retrieve and manipulate multilingual content using GraphQL queries, this plugin significantly simplifies the process of creating, managing, and displaying content in multiple languages within a WordPress site.

Plugin Features
One of the key advantages of this plugin is its ability to extend the capabilities of the WPGraphQL plugin, which acts as a GraphQL layer for WordPress. By integrating seamlessly with WPML, this plugin allows users to access translations of content, such as posts, pages, custom post types, taxonomies, and more, using GraphQL queries. This makes it easier to retrieve and display translated content without the need for complex programming or additional plugins.
WPML GraphQL provides a comprehensive set of features for managing multilingual content. Users can create translations for existing content or create new content directly in the desired language. This flexibility allows content creators to seamlessly work with translations in their preferred language, making the localization process more efficient and convenient.
The plugin also offers robust support for language-specific content filtering. With this feature, users can retrieve content specific to a particular language, eliminating the need to manually filter through large amounts of content to find the desired translations. This not only saves time but also improves the overall performance of the website by reducing unnecessary data requests.
The integrations provided by this plugin ensure compatibility with other popular WordPress plugins and themes. This means that users can enjoy the benefits of multilingual content management without sacrificing the functionality and features provided by their preferred plugins or themes. The plugin seamlessly integrates with popular page builders, custom post type plugins, and e-commerce plugins, ensuring a smooth and hassle-free multilingual experience.
Furthermore, WPML GraphQL offers an intuitive and user-friendly interface for managing translations. Users can easily switch between languages, edit translations, or add new translations for various content elements. The translation management interface is designed to be simple and straightforward, eliminating the need for extensive training or technical knowledge.
In summary, this plugin is an invaluable tool for WordPress users looking to enhance their websites with multilingual capabilities. By seamlessly integrating WPML with WPGraphQL, this plugin streamlines the process of managing and displaying multilingual content, providing a smooth and efficient experience for both users and developers. With its robust features, compatibility with other plugins, and user-friendly interface, this plugin is a must-have for anyone aiming to create a truly global WordPress website.
How to Configure and Validate WPML GraphQL for Headless WordPress
WPML GraphQL is not meant for a standard language switcher inside a WordPress theme. It is built for a more technical setup: content lives in WordPress and WPML, while the website frontend or app pulls data through WPGraphQL. In that kind of project, it is not enough to return a list of posts. You need the post, menu, categories, translations, and global fields to come back in the correct language, with clear relationships between language versions.
This guide covers installation, the initial schema check, language filtering, translation queries, menus, ACF Options Pages, routing by slug and uri, troubleshooting, and safe result validation. It is written for developers, webmasters, or technical site owners who already understand the basics of GraphQL and want to turn WordPress with WPML into a reliable data source for a multilingual frontend.
This article does not replace the official documentation and does not promise universal compatibility with every plugin stack. Its goal is more practical: to show which checks to run after enabling WPML GraphQL, which queries should become your baseline checks, where language handling most often breaks down, and how to tell a plugin issue from a mistake in the query, cache, routing, or WPML settings.
Where WPML GraphQL Actually Matters
A standard multilingual WordPress site often works fine without a separate GraphQL layer: the theme renders posts, WPML selects the current language, menus are synced through the admin panel, and the visitor sees a finished page. WPML GraphQL becomes important when WordPress is no longer the only place where pages are rendered. For example, content editors still manage content in WordPress, but the interface is built with Gatsby, Next.js, Astro, Vue, Svelte, or another app that reads data through GraphQL.
In that architecture, a GraphQL query needs to understand more than a basic post list. It needs to know which language version of the page to return, what translations exist for that page, which categories and tags match the selected language version, what the language home URL is, which menu items to show the visitor, and which global fields from ACF Options Pages should populate the header, footer, or contact block. WPML GraphQL adds language fields and filters to the WPGraphQL schema so those tasks can be handled from a single data source instead of a collection of manual workarounds.
The plugin is especially useful in projects that already use WPML and have decided to build the frontend separately from the WordPress theme. But if the site runs entirely on a standard WordPress theme and does not use WPGraphQL, there is no reason to install WPML GraphQL just to check a box. It will not improve translations by itself, it will not replace WPML language setup, and it will not create a frontend. It is a compatibility layer between WPML and WPGraphQL, not a standalone translation system.
What the Plugin Helps You Do
The main benefit of WPML GraphQL is predictable access to multilingual data in the WPGraphQL schema. Once the plugin is enabled, a developer can verify an object's language, request translations, filter connections by language, and build application navigation based on the site's configured languages. In a real project, that turns into several practical use cases:
- Render a page or post in a specific language using a language filter, identifier,
slug, oruri, if that is supported by your current stack. - Build a language switcher on the frontend using the list of installed languages and each language's home URL.
- Fetch linked translations for a post, page, category, or custom post type so the interface can show links to other language versions.
- Load menus and menu items in the correct language so the site header does not mix English, Spanish, German, or Russian items.
- Query global ACF fields by language if the site uses ACF Options Pages for phone numbers, addresses, links, banners, or footer settings.
These tasks look similar, but they fail in different ways. A translation issue for a post usually shows up as an empty translations array. A menu issue may appear as the correct page with the wrong-language menu. A routing issue usually looks like null when querying by slug or uri. That is why this guide explains not only "how to make the query" but also how to tell exactly where the chain broke.
Who This Product Is For and Who It Is Not For
WPML GraphQL is a good fit for teams that have already chosen WPML as the main multilingual layer in WordPress and use WPGraphQL as the API for the frontend. It makes particular sense for projects with multiple languages, custom post types, complex navigation, ACF fields, and a separate application that needs ready-to-use data without manual database workarounds.
The plugin may be unnecessary if the site is not a headless project, does not use WPGraphQL, does not have multilingual content, or only relies on REST API integrations. It also does not solve organizational translation questions: who translates the content, how fields are synchronized, which strings are sent to translators, or how languages, URLs, and translatable custom types are configured. Those questions still belong to WPML, ACFML, the theme, the editorial workflow, and the site's overall architecture.
Practical rule of thumb: if the frontend needs to decide for itself which language version of a post, menu, or global field to show the visitor, WPML GraphQL is worth evaluating. If all language handling already happens inside the WordPress theme, you probably do not need it.
What to Check Before Installation and Why the Order Matters
WPML GraphQL has several required dependencies. According to the official documentation, the basic setup requires WPGraphQL, WPML, WPML String Translation, and WPML GraphQL itself. For ACF-related use cases, you also need Advanced Custom Fields Multilingual and WPGraphQL for Advanced Custom Fields. This is not just a formality: if one part of the chain is missing, the schema may still load, but the language fields, filters, or ACF objects you need will not be there.
Before installation, do not start with the frontend app. First, make sure WordPress as a data source already understands its languages, translations, menus, custom post types, and fields correctly. Otherwise, GraphQL will honestly expose a broken data state, and the developer will start looking for an API issue when the real problem is in WPML or the editorial content.
Pre-Enable Checklist
- WPML is configured, languages are added, and test pages have real translations rather than drafts or empty duplicates.
- WordPress permalinks are not set to
Plainif you expect to use a normal/graphqlendpoint. - WPGraphQL is installed and opens the GraphiQL IDE in the WordPress admin panel.
- Any custom post types and taxonomies that should appear in GraphQL are actually available in the WPGraphQL schema.
- Menus have been created and translated through WPML if the frontend will pull navigation from WordPress.
- ACF fields have a clear translation model in ACFML if the project reads custom fields or Options Pages.
- Cache, CDN, and security rules are not interfering with GraphQL query testing on the site copy.
The most common mistake at this stage is testing only the main post in the default language. That proves almost nothing. For WPML GraphQL, it is much more useful to prepare a small control set: one post with translations, one page with a translated slug, one category or term, one menu, and one ACF block or Options Page. Then, after enabling the plugin, you can quickly tell whether the full chain works instead of just the home page.
How to Choose a Test Content Set
For the first pass, it helps to create a dedicated test page that is easy to find in the admin panel and safe to delete afterward. It should have at least two language versions, different slug values, and simple content. If the site uses custom post types, repeat the test with one of those as well: for example, project, event, product, or article. For taxonomies, prepare one term with a translation. For menus, add one clearly different item in each language.
This may seem excessive, but it saves hours of troubleshooting. If the post comes back correctly but the menu does not, the issue is narrowed down to menus. If menus work but the ACF Options Page still shows the default-language value, the focus shifts to ACFML and WPGraphQL for ACF. If everything works in GraphiQL IDE but breaks in the app, then you need to inspect the client query, cache, route variables, and response handling.
Installation, Activation, and the First Schema Check
Installing WPML GraphQL is technically similar to installing any other WordPress plugin, but you need to validate it as part of the API schema. After activation, the question is not whether a new visual block appears in the theme. The real question is whether the required GraphQL fields and arguments are now available. That is why your first working screen is not the frontend, but GraphQL - GraphQL IDE in the admin panel.
It is best to keep the activation order strict. First activate WPGraphQL and make sure a basic post query works. Then verify WPML: languages, translations, and URLs. After that, enable WPML GraphQL, and only then add ACFML or WPGraphQL for ACF if the project needs them. If you switch everything on at once, it becomes much harder to see which layer failed to provide the field you expected.
Basic Sequence
- Install and activate WPGraphQL, then open the
GraphQL IDEand run a simple query againstpostsorpages. - Confirm that WPML is already configured: languages are available, the test post has translations, and language URLs open in the browser.
- Activate WPML GraphQL and refresh the schema in GraphiQL IDE if the interface is still showing stale data.
- Look for the
language,languageCode, andtranslationsfields in the schema docs for the types you use. - Run a baseline language query and compare the response with what you see in the WPML admin panel.
If WPGraphQL is being installed for the first time, pay attention to permalinks. The WPGraphQL documentation notes that with standard permalink settings the endpoint is available at /graphql, while with the plain structure it may use /index.php?graphql. That is not critical for local troubleshooting, but for the frontend app it is better to standardize the endpoint early and avoid mixing different URL patterns across environments.
Your First Baseline Query
Start with a small query that returns not just the post, but also its language data. Do not try to pull in every page field, menu, SEO field, ACF field, and related post right away. The smaller the query, the easier it is to see which part of the schema did not behave as expected.
query PostsByLanguage {
posts(where: { language: "en" }) {
nodes {
title
slug
uri
languageCode
language {
code
native_name
url
}
translations {
title
slug
uri
languageCode
}
}
}
}
This query has several checkpoints. languageCode should match the post language. translations should return the language versions if they exist and are published. uri helps you understand how WPML builds the path for a specific language. If the post appears in the response but translations do not, check the translation relationship inside WPML. If the translation exists in the admin panel but does not appear in GraphQL, move on to schema and component version troubleshooting.
Required step: save several working queries as your baseline checks. You will need them after updating WPML, WPGraphQL, the theme, ACFML, or the caching layer.
How to Tell Whether the Schema Was Actually Extended
In GraphiQL IDE, open the schema documentation and inspect the types your site actually uses. Do not stop at Post if the project is built around a custom post type. For pages, check Page; for categories, check the relevant taxonomies; for menus, inspect menus and menu items. The whole point of WPML GraphQL is that language data should be available exactly where your query needs it.
If the fields you need are missing, do not build a workaround in the frontend app before checking dependencies. Make sure the plugin is active, WPGraphQL exposes the required post type, WPML is configured for that type, and any ACF or menu-related plugins do not require separate setup. Client-side workarounds only make sense after the server-side schema has been verified, otherwise the application ends up compensating for bad data and becomes fragile.
Language Filtering and Translations in Queries
Language filtering is the central WPML GraphQL use case. It matters not only for post lists, but for every place where the frontend needs to preserve language consistency: related categories, tags, comments, menus, and menu items. The official documentation specifically notes that when a top-level item is filtered by language, related items should follow that language as well. In practice, that means a query for Spanish posts should not suddenly return English categories if the data has been translated correctly.
The right strategy is to avoid mixing all languages in one query unless you truly need that. For a page the visitor is opening, you almost always need one current language and, separately, a list of translations for the language switcher. If you query language: all, do it intentionally, for example for an administrative content map, a search index, or static generation of all pages. For normal page rendering, filtering by the current language is simpler, faster, and safer for caching.
Querying the Current Language
A minimal working query should accept the language as a variable. That way the same document can be reused across languages, and the frontend does not need to store several nearly identical queries.
query PostsForArchive($language: String!) {
posts(where: { language: $language }) {
nodes {
title
slug
uri
languageCode
categories {
nodes {
name
slug
languageCode
}
}
}
}
}
When validating, compare more than just the number of posts. Also check the language of the related categories. If the post comes back in the correct language but the category stays in the default language, that is a sign to inspect the term translation, the taxonomy settings in WPML, and the WPGraphQL schema for that relationship type. Do not rush to patch it in the app by manually replacing text. That kind of fix usually breaks as soon as you apply it to a different content type.
Fetching Translations for the Language Switcher
The translations field is convenient for a language switcher on a post or term page. The key limitation is that it shows translations for the current object, not "all site languages." If a post does not have a German version, the switcher should not send the visitor to a URL that does not exist. For the site-wide header, you also need a query for installed languages, which gives you codes, names, flags, and each language's home URL.
In practice, the language switcher is often built from two sources. The first is the current post and its translations, so you can show the versions available for that exact page. The second is the languages query, so you know the full list of languages and their home URLs. If a translation is missing, the interface can send the visitor to the language home page, hide that language, or show it as inactive. The UX decision depends on the site, but the data behind that decision should be explicit.
What Counts as a Successful Validation
- The current post returns the correct
languageCode. - The
translationsarray contains only real linked translations. - Each translation has its own
slugandurithat match the WPML settings. - Related categories or terms do not mix languages without a reason.
- The frontend does not build a translation link that is missing from the response.
Routes, slug, and URI in a Multilingual Frontend
Routing is one of the most sensitive areas in headless WordPress. In a standard WordPress theme, the URL has already been handled by WordPress core, WPML, and permalink rules. In a separate application, the route usually comes in as a string such as /es/blog/hola-mundo/, /de/projekte/beispiel/, or a similar path. The app must turn that path into a GraphQL query and retrieve the correct language version of the content.
The WPML GraphQL documentation and release notes show that support for queries by slug, id, and uri evolved separately, and known issues with slug/URI have appeared in errata and support discussions. That means you cannot consider routing validated just because a language-filtered post list works. A real site needs separate tests: a query by slug, a query by uri, a query for a custom post type, and a missing-translation case.
Route Validation Matrix
Build a small table of baseline URLs. It should include the default language, a secondary language, a post, a page, a custom post type, and one case with a translated slug. You do not need to keep that table inside the article or codebase, but you do need it for release validation.
| Case | What to Query | Expected Outcome | If It Does Not Match |
|---|---|---|---|
| Post in the default language | post(id: "...", idType: SLUG) |
The post is returned with the correct languageCode
|
Check basic WPGraphQL behavior and whether the post is exposed in the schema |
| Translated post |
post(id: "...", idType: SLUG) or nodeByUri
|
The translation is returned, not the original and not null
|
Check known issues, translated slug values, and third-party sorting plugins |
| Custom post type | The matching single-item type query | The type is available in GraphQL and respects the language version | Check type registration, WPML settings, and GraphQL exposure |
| Page URL | nodeByUri(uri: "...") |
The URI resolves to the correct language page | Compare permalinks, the language prefix, and WPML GraphQL release notes |
There is one important conclusion after working through this table: not every route issue is a WPML GraphQL issue. The frontend app may be normalizing the path incorrectly. The client may strip the language prefix. The cache may return the response for another language. A custom post type may not be exposed in WPGraphQL. A sorting plugin may interfere with slug-based queries. That is why route troubleshooting must inspect the whole chain: the browser URL, the GraphQL variable, the GraphiQL IDE response, the WPML record state, and the network response from the app.
When to Use slug and When to Use URI
slug works well when the URL structure is simple and the content type is known in advance. For example, a blog archive already knows it is opening a post and only passes the last part of the URL. uri is more convenient when the frontend works with the full path and does not want to decide ahead of time whether the target is a page, post, or custom post type. On multilingual sites, uri is often closer to the visitor's real route, but it needs separate validation for your exact WPML GraphQL and WPGraphQL version combination.
If the project uses translated slugs, nested pages, language prefixes, different URL structures by language, or custom post types, do not mix approaches casually. Choose one primary routing method, document it in code, and keep one fallback diagnostic query for complex cases. That way the team knows which route pattern is officially supported in the project and which is only used for troubleshooting.
Menus, Navigation, and the Language Switcher
Multilingual navigation often fails more quietly than page content. A visitor may open a Spanish article and not notice right away that the menu is still in English until they click an item. In a headless project, that is especially risky: the site header is usually cached, reused across pages, and loaded through a separate query. If the menu is not tied to the language, the problem will repeat across the entire site.
WPML GraphQL added support for menus and menu items in a separate update, so menus should be validated as a distinct capability, not as a side effect of post translations. Menus need language metadata, and the queries need to return either the menu for a specific language or all language versions when that is needed during build time. In most frontend use cases, menus are requested by the current page language.
How to Validate Menus
Create or select a menu where at least one item is obviously different across languages. For example, "About" and "Sobre", or "Contact" and "Contacto". Then run a menu query in GraphiQL IDE and verify three things: the language of the menu itself, the language of the menu items, and the URL of each item. If the item text is correct but the URL points to a different language, the problem is not solved.
- Check the source menus in WPML. Make sure the translated menus are linked and published.
- Check the GraphQL schema. See which language fields are available for menus and menu items in your version.
- Check the response without cache. For the first test, it is better to rule out CDN and client caching so an old response is not mistaken for a schema issue.
- Check the frontend. Open a page in each language and compare the menu with the GraphiQL IDE response.
You should not load menus through one global query with no language if the interface only shows the current language. That approach may be convenient for static generation or an internal site map, but for a normal site header it increases response size and makes caching harder. It is usually better to pass the language explicitly, just as you do in post queries.
Language Switcher: Site Languages and Page Translations
The language switcher often needs more than one query. The languages query shows which languages are installed on the site, along with their codes, names, flags, and URLs. The translations field on the current post shows which translations exist for that specific page. If you rely only on the language list, you can end up building links to languages where the current content does not exist. If you rely only on translations, you lose the full site-wide language list.
A practical approach is to keep the installed language list in the header, then match it against the current object's translations on each page. If a translation exists, the link points to it. If it does not, the interface can show that language as inactive or link to the language home page with a clear fallback behavior. That part is a frontend decision, but WPML GraphQL needs to expose enough data to support it.
ACF and Global Settings: When One Page Is Not Enough
Many headless sites use ACF not only for post fields, but also for global settings: logo, phone number, address, social links, banner content, footer text, shipping notices, or regional information. If those values differ by language, a simple post query will not help. You need WPGraphQL for ACF, ACFML, and WPML GraphQL working together to return ACF data in the correct language version.
The official WPML GraphQL documentation specifically covers the ACF Options Pages use case: WPGraphQL for ACF exposes Options Pages as root objects, and WPML GraphQL together with ACFML adds a language parameter for those queries. That is an important capability because global fields often create hidden localization issues. The page may be translated, while the phone number, address, or footer text still comes from the default language.
What to Prepare in ACFML
Before validating GraphQL, configure the translation model for your ACF fields. ACFML supports different approaches: shared structure with translatable values, separate fields by language, and expert mode with manual field preferences. For GraphQL, the exact mode name matters less than the expected behavior: which values should differ, which should be copied, which should stay synchronized, and which fields should appear in the schema at all.
For example, in an "Office" block, the phone number might be copied across languages while the address, button label, and note text are translated. In a "Team" block, the employee structure may stay the same while bios and job titles are translated. In a promo banner, images may differ by language if that matches the editorial workflow. If those rules are not configured, GraphQL cannot infer the editor's intent.
Example Options Page Query
Below is a simplified example query. The root object name and field names depend on your ACF setup and how WPGraphQL for ACF exposes them in the schema. The purpose of the example is to show the language parameter and how to validate values in a specific language.
query SiteSettings($language: String!) {
siteSettings(language: $language) {
footerContacts {
phone
address
openingHours
}
headerPromo {
text
link {
url
title
}
}
}
}
After running the query, compare the response with what you see in WPML and ACF in the admin panel. If phone is the same across all languages, that may be correct. If address is supposed to be different but is not, check the field's translation setting in ACFML. If the siteSettings object is missing entirely, first verify Show in GraphQL and your WPGraphQL for ACF settings. If the language parameter is not recognized, check your plugin versions and the WPML GraphQL documentation.
How to Design Queries Without Mixing Languages
After the first successful validation, it is tempting to build one large GraphQL document and use it for every page. That may be convenient in a small prototype, but in a production multilingual project it often creates subtle bugs. WPML GraphQL helps you fetch language-aware data, but it does not force the frontend to correctly separate page context, menu data, global settings, related posts, and cache behavior. That discipline needs to be built into your query design.
A good query answers one clear question. For example: "give me the page for the current URI and language," "give me the menu for the current language," "give me the footer settings for the current language," or "give me the language list for the switcher." If one document requests the page, all translations, all languages, menus, the ACF Options Page, related posts, and multiple archives at the same time, errors become hard to isolate. The wrong language may come from any part of the response, while the developer only sees the final rendered output.
Separate Page Context from Global Data
A page or post has a specific route. It has its own slug, uri, languageCode, and translation set. Menus and global settings do not belong to that post directly; they belong to the site language. So the page query and the header query can share the same language variable without having to live in the same document. That is especially useful for caching: menus change infrequently, while posts may update more often.
For static generation, you can build a multi-step flow. First fetch the languages. Then, for each language, fetch the list of URIs or posts that need to be generated. Then request the page content for each URI. After that, fetch menus and global settings separately for that language. This may look longer, but it reflects the real site behavior more accurately: language becomes part of every step, not just a random string inside one oversized query.
Do Not Rely on the Current URL Alone
The URL matters, but by itself it does not prove that GraphQL returned the correct language. The frontend app may parse the route incorrectly, remove the language prefix, confuse a regional code, or apply an outdated route map. That is why, after the GraphQL response comes back, you should compare the expected route language with the object's actual languageCode. If they do not match, the page should not be rendered as a success.
This rule is especially important for sites where the language is determined by the domain or subdomain, for example one domain for English and another for Spanish. In that case the page URL may not contain an obvious language prefix, and the language comes from the domain configuration. Pass that language explicitly into the query. Do not make the app guess the language from the response when it already knows the route context.
Treat Missing Translations as a Normal Case
In a real editorial workflow, not every piece of content is translated at the same time. Sometimes a new post is already published in the default language and the translation will come later. Sometimes one language version is intentionally missing because the service is not available in every country. WPML GraphQL can expose the absence of a translation through data, but the frontend still needs to handle that correctly.
There are several safe fallback patterns. You can hide that language in the switcher on the current page. You can send the visitor to the language home page. You can show a 404. You can display a neutral message for an internal portal or documentation site. The main rule is not to show content from another language under the current URL unless you made that decision explicitly. For SEO and user trust, that is worse than honestly acknowledging that the page is unavailable.
Use GraphQL Types as Project Documentation
The GraphQL schema is useful because it describes the available types and fields for you. After enabling WPML GraphQL, study not only the examples from the docs, but your actual schema. Different projects have different custom types, ACF groups, menus, and taxonomies. What appears in a demo query may use a different name in your setup. And your schema may contain fields that do not appear in the general examples.
A good practice is to keep working query fragments next to the frontend components that use them. For example, the language switcher component can contain a fragment for translations and languages, the post card component can contain a fragment for title, uri, and languageCode, and the page template can contain a fragment for the main content. That keeps the data structure closer to where it is used and makes language-related issues easier to catch during development.
Example Responsibility Split
| Frontend Area | Required Data | Main Validation |
|---|---|---|
| Post template | Title, content, uri, languageCode, translations |
The response language matches the route language |
| Site header | Menu, language list, language home URLs | Menu items and links do not point to another language |
| Site footer | ACF Options Page or global WPML strings | Translatable values change by language, copied values stay shared |
| Post archive | Object list with a language filter and related terms |
Categories and tags match the archive language |
This is not the only valid structure, but it helps the team align on the data flow. If multilingual data suddenly gets mixed, you know which query to inspect. If you need to optimize caching, you can start with menus or global settings without touching page routes. If an editor reports that "the translation exists, but the site is not showing it," the developer can go straight to the layer where that translation should appear.
Component Updates and Regression Validation
WPML GraphQL does not live in isolation. It sits inside a stack that includes WPML, WPML String Translation, WPGraphQL, ACFML, WPGraphQL for ACF, the theme, custom post types, cache, and the frontend app. That means updating one component can change the behavior of another. This is not a reason to avoid updates, but it is a reason to handle them deliberately and validate the scenarios that matter most to your multilingual GraphQL API.
The official WPML GraphQL release notes show ongoing work around menus, URI-based queries, ACF Options Pages, and various compatibility fixes. Those are good improvements, but in a production project every improvement still needs to pass through your own validation matrix. That matters even more if the frontend depends on uri-based routing, translatable ACF fields, or WooCommerce and custom post types.
Update Related Components Together
WPML recommends in its release notes that you avoid mixing new and old WPML component versions. That matters even more in a project with WPML GraphQL, because language behavior may pass through several add-ons. If you update only one component and leave the rest on older versions, the failure may look like a GraphQL problem when the real issue is version incompatibility inside the WPML stack.
A safe sequence looks like this: create a site copy, update the related components together, clear caches, run your baseline queries, validate the frontend, and only then deploy the updates to production. If the site is large, do not try to test everything manually. A small set of representative content is enough: one post, one page, one custom type, one menu, one taxonomy, one ACF Options Page, and one URL with no translation.
What to Include in Regression Validation
- The
languagesanddefaultLanguagequeries return the expected language set. - The post list query for each language returns objects only in that language.
- The
translationsquery on the test post shows all published translations. - The single-item query for your chosen routing method returns the correct language version.
- Menus and menu items match the current language.
- The ACF Options Page returns translatable values in the correct language.
- After cache is cleared, the site does not serve stale responses, and repeated requests do not mix languages.
- The frontend handles missing translations correctly.
If one item breaks after an update, do not immediately roll back the whole site without diagnosing it. First identify the layer. If GraphiQL IDE returns the correct response, the issue is probably in the app or the cache. If GraphiQL IDE also shows the problem, check the release notes, known issues, WPML settings, and third-party plugin compatibility. A rollback makes sense when the issue affects the live site and the fix is not obvious or quick.
How to Document Changes
It helps to keep a short log of API checks for the team. There is no need for a long report. It is enough to record which components were updated, which baseline queries were run, which languages were checked, and whether any changes appeared in routes, ACF, menus, or caching. That kind of log makes it much easier a few months later to see when a mismatch first appeared instead of troubleshooting blindly.
This is especially important for agencies and support teams. Clients often report problems in plain language: "the Spanish page shows the wrong menu" or "the translation disappeared in the app." If you have a log and a set of baseline queries, troubleshooting starts from a repeatable process instead of guesswork. That makes WPML GraphQL a more predictable maintenance tool rather than a one-time setup nobody remembers.
Practical Example: A Multilingual Article in Next.js or Gatsby
Consider a typical production use case. WordPress stores a blog in two or three languages. The frontend is built separately and fetches posts through WPGraphQL. You need to open an article by URL, display the title and content in the correct language, output categories, build a language switcher, and avoid mixing data from different languages.
Goal
The goal of this example is to fetch one post in the current language together with its translations, so the frontend can build both the page and the language switcher. The key success criterion is this: if the user is on the Spanish page, the content, categories, and translation links must match the Spanish version. If a translation is missing, the interface should see that in the data rather than linking to an invalid URL.
Preparation
- WordPress has a published post in the default language and at least one published translation.
- WPGraphQL, WPML, WPML String Translation, and WPML GraphQL are active.
- The post and its taxonomies are exposed in the WPGraphQL schema.
- Permalinks are configured the same way the frontend will use them.
- A basic query with
languageCodeandtranslationsalready works in GraphiQL IDE.
Steps
- In the frontend route, determine the current language from the URL, domain, application settings, or another chosen mechanism.
- Pass the language code into the GraphQL query as a variable instead of hardcoding it into the query string.
- Query the post using your chosen routing method:
slug,uri, or a dedicated single-item post type query. - Inside the response, request
languageCode,translations,uri, and related categories. - Build the page only after confirming that the response is not
nulland that the response language matches the route. - For the language switcher, match
translationsagainst the full language list if the header needs it.
If the frontend uses static generation, the same principle applies at build time: first fetch the list of URIs or posts for each language, then generate pages with language context. If the site uses server-side rendering or dynamic loading, the language check has to run on every request. In both cases, you should not render the page if GraphQL returns a post in a different language. That is almost always a sign of a routing or cache problem.
Validating the Outcome
Open the page in each language and compare it with the GraphiQL IDE response. Check the title, URL, category language, translation links, and any global elements if they are loaded through a separate query. Then intentionally open the URL of a missing translation. A good frontend should show the correct fallback behavior: a 404 page, a redirect to the language home page, or another clearly defined behavior chosen by your team. The bad outcome is to silently show the default-language post while keeping the secondary-language URL.
Quick summary: this practical example is only considered complete when the page, related data, language switcher, and missing-translation behavior have all been validated together. One successful post query does not prove that a multilingual route is production-ready.
Validating the Result After Setup
After installation and the first queries, you should run a baseline validation as a small acceptance test. This is useful not only for the developer, but also for the site owner: it confirms that the frontend receives data from WordPress predictably and will not mix languages by accident. The validation should be short, repeatable, and easy for the team to understand.
Do not validate WPML GraphQL only through the browser on the frontend. The browser shows the final output, but hides part of the chain. When something breaks, you need to determine what failed: the GraphQL schema, WPML data, the client query, the cache, or routing. That is why the result should be checked in three places: the WordPress/WPML admin panel, GraphiQL IDE, and the frontend itself.
Acceptance Validation Set
- Schema. GraphiQL IDE shows language fields for the required types: posts, pages, taxonomies, menus, and comments if they are used.
-
Filter. A query with
where: { language: "..." }returns the expected set of objects. -
Translations. The
translationsfield returns real linked translations instead of an empty array when published translations exist. - Relationships. Categories, tags, and other connected items match the language of the top-level object.
-
Route. A query by
slugorurireturns the exact object the visitor would open. - Menus. Frontend navigation does not stay in the default language on pages in other languages.
- ACF. Global fields and ACF values differ or stay copied across languages according to the ACFML rules.
- Cache. A repeated request does not return an old response from a different language.
How to Record the Validation for the Team
Save your baseline queries in the frontend repository, the project documentation, or the internal knowledge base. Alongside them, note which variables need to be passed and which minimum fields should be returned. You do not have to turn them into automated tests immediately, but they will help when updating components, moving the site to different hosting, or changing permalink settings.
For projects under active development, it is also useful to add automated checks at the application level, for example a test that confirms a Spanish route returns a languageCode with the Spanish code rather than a default-language post. These tests do not replace WPML validation, but they quickly catch mistakes in variable handling, caching, and routing.
Performance, Caching, and Query Security
WPML GraphQL is not a caching plugin by itself. It adds language awareness to the GraphQL schema, while performance depends on WPGraphQL, hosting, data volume, query size, caching, the frontend app, and how carefully your GraphQL documents are designed. That is why optimization should come after you validate language correctness. Caching the wrong response faster is not a success. It is just a faster way to spread an error.
The WPGraphQL documentation recommends considering GET requests for read-only use cases because they work better with CDN, browser, and proxy caching. WPGraphQL Smart Cache adds tag-based invalidation and persisted queries. That is useful for multilingual sites, but only if the language is explicitly part of the query or the persisted query setup. Otherwise the cache may return an English response for a Spanish route, or the other way around.
Safe Optimization Order
- First confirm that GraphiQL IDE returns the correct language with CDN and client caching disabled.
- Reduce query size: do not request all languages and all translations where you only need the current language.
- Split independent data sources: for example, the page, menu, and global settings can use different caching strategies if they change at different rates.
- For read-only queries, consider GET and persisted queries if they fit your client and infrastructure.
- Verify that the language is included in the query variables, cache key, or persisted query document.
- After enabling caching, rerun the same baseline queries for each language.
You should not immediately build one giant "entire page" query that includes the post, translations, menu, ACF fields, SEO fields, related content, and all languages. That kind of query is harder to cache, harder to troubleshoot, and harder to maintain. Sometimes a large query is justified, but in a multilingual project several smaller queries with explicit language variables are often easier to manage. This becomes especially obvious when menus change rarely but posts are published frequently.
Security and Endpoint Exposure
The GraphQL endpoint is usually public for reading data that is already available to public visitors. That does not mean security can be ignored. Review which post types and fields are exposed in the schema, whether private data can leak into public queries, how authenticated requests are handled, and which cache rules apply to logged-in users. The WPGraphQL changelog has included fixes related to authenticated requests and permission checks, so keeping WPGraphQL updated is also part of API security.
If the project uses persisted queries or an allowlist of approved queries, decide early how language-specific variants will be handled. Do not block arbitrary queries on the live site before saving every document the frontend actually needs. At the same time, do not leave unrestricted execution of expensive queries unmonitored if the site receives significant traffic.
Safe Practical Techniques Without Editing Core
For WPML GraphQL, do not invent PHP snippets if the official documentation does not describe the required hook or filter for that exact use case. Editing WordPress core, WPML, WPGraphQL, or the add-on itself is not acceptable: updates will overwrite those changes, and a mistake in resolver logic can damage responses across the entire API. Instead, use safer practices at the level of queries, environments, and data validation.
Use Small Baseline Queries
The most useful "hack" for WPML GraphQL is really a set of short queries that are easy to run in GraphiQL IDE. One query checks the language list, a second checks the post and its translations, a third checks the menu, and a fourth checks the ACF Options Page. When something breaks, you do not have to dissect a huge frontend page document. You can quickly identify the failing layer.
query LanguageHealthCheck {
languages {
code
native_name
translated_name
url
}
defaultLanguage {
code
native_name
}
}
This query does not fix anything, but it quickly answers a basic question: does GraphQL see the installed languages the same way the frontend expects them? If the required language is already missing here, or if the URL does not match expectations, then it is too early to troubleshoot the page itself.
Separate Environments and Variables
In a headless project, you often have local, staging, and production environments. Each may have its own endpoint, languages, test posts, and caching policy. Do not hardcode the default language as if it were the same everywhere. It is better to keep the endpoint and default language in the application configuration, and pull the language list from GraphQL or from a synchronized build-time source.
If the frontend builds pages statically, keep a build log by language: how many pages were created for each language, which URLs were skipped, and which queries returned null. That kind of log helps distinguish a content issue from a GraphQL issue. For example, if a language has no translations, the build should report the skip explicitly instead of silently generating a page with content from another language.
Do Not Hide Language Errors on the Client
A risky habit is to automatically show the default-language post when the requested language query returns nothing. That may seem convenient early on, but for users and SEO it creates confusion: a URL for one language starts showing text from another. It is better to choose an explicit behavior: a 404, a redirect to an available translation, a link to the language home page, or a message that the translation is unavailable. Which option makes sense depends on the project, but the choice should be deliberate.
Rollback rule: if you see language mixing after changing the query, cache, or routing, first disable the new optimization layer and go back to your baseline GraphiQL queries. Do not try to patch the frontend interface first.
Troubleshooting Common Problems
WPML GraphQL issues almost always show up as a mismatch between the expected language and the actual response. Sometimes the response is empty, sometimes it falls back to the default language, and sometimes translations exist but the routes do not match. The cases below are specific to the WPML + WPGraphQL stack, language filters, slug/URI handling, menus, ACF, and caching.
The Query Returns Posts in the Wrong Language
Symptom: the query should return posts in the selected language, but the response includes posts from another language or a mixed set. Possible causes include a missing where: { language: "..." } clause, an incorrect language code, a stale schema in GraphiQL IDE, a client variable bug, or a WPML setting issue for that specific post type.
First run a minimal query in GraphiQL IDE and pass the language explicitly. Then inspect languageCode on each node. If GraphiQL shows the correct response but the frontend does not, inspect the client code, variables, persisted query, and cache. If GraphiQL also returns mixed languages, check the WPML settings for that post type, the translation state, and component versions.
The translations Field Is Empty Even Though Translations Exist
Symptom: the post has translations in the WPML admin panel, but the translations field in GraphQL is empty. Possible causes include an unpublished translation, a missing translation relationship, the wrong content type being queried, the schema lacking the required field, or the public query resolving to a different post.
Check the translation relationships in WPML and the publication status of each translation. Then request the current post with id, slug, uri, languageCode, and translations. If the current post turns out to be the wrong one, fix the route. If it is the right post but translations are still missing, inspect the translation linkage and support for that specific post type.
A Query by slug or URI Returns null
Symptom: a language-filtered post list works, but a single-item query by slug or uri returns null for a secondary language. Possible causes include a known issue in that version or stack, an incorrect slug, an unhandled language prefix, a custom post type that is not exposed in WPGraphQL, or a third-party plugin changing query order or filters.
First check the same object through a language-filtered list query. If it appears there, compare the actual slug and uri from the response with what the frontend is sending. Then review the WPML errata and release notes for your version. If the issue appears to involve a third-party sorting plugin, temporarily disable the suspicious setting on a site copy and rerun the test.
The Menu Stays in the Default Language
Symptom: the page opens in the correct language, but the menu items are not translated. Possible causes include menus not being synced in WPML, the menu query not being filtered by language, header cache ignoring the language, or the frontend reusing an old response.
Check the menus in the WPML admin panel, then run a dedicated GraphQL query for the menu only. If GraphQL returns the correct menu, fix the client cache and loading keys. If GraphQL returns the default menu, inspect menu language field support in your WPML GraphQL version and check how the menus are linked in WPML.
The ACF Options Page Shows Values from the Wrong Language
Symptom: the post title is translated, but global footer, contact, or banner fields still appear in the default language. Possible causes include ACFML not being configured for those fields, the Options Page not being translated, WPGraphQL for ACF not exposing the field in the schema, or the query not passing the language parameter.
Check the field's translation settings in ACFML and confirm that a value exists in the target language. Then run a dedicated Options Page query with a language variable. If the field does not appear in the schema, verify Show in GraphQL and the WPGraphQL for ACF configuration. If the field exists but the value does not change, return to the ACFML translation preferences.
Languages Start Mixing After Caching Is Enabled
Symptom: GraphiQL IDE returns the correct response with cache disabled, but the frontend sometimes receives data from another language. Possible causes include the language not being part of the cache key, a persisted query that does not distinguish variables, GET requests being cached without respecting the query string, or a CDN serving a stale document.
Temporarily disable external caching and rerun the baseline queries. Then re-enable each layer one by one: server cache, CDN, client cache, persisted queries. For each layer, make sure the language is part of the key or variables. If you cannot guarantee that, do not cache that query aggressively.
When WPML GraphQL May Not Be the Right Fit
WPML GraphQL is not a universal replacement for an entire multilingual architecture. It works well for the "WPML + WPGraphQL + headless frontend" model, but it may be awkward if the project is built around a different multilingual plugin, if the team does not want to maintain WPML, if the frontend uses only the REST API, or if the content model is unusual enough to require custom resolvers.
It is also worth assessing the team's comfort level. GraphQL gives you precise queries, but it also requires discipline: variables, types, baseline checks, caching, and error handling. If the project does not have a developer who is prepared to maintain that layer, a standard WordPress theme with WPML may be easier and less expensive to support. That is not a weakness in WPML GraphQL. It is a question of choosing the right tool for the job.
Signs That Another Approach May Be Better
- The site is not headless and has no plans to use WPGraphQL.
- The main goal is translating content inside a standard theme, not serving data to an external application.
- The project already uses Polylang or another multilingual layer and does not plan to migrate to WPML.
- The frontend only needs a few simple data points that are already available through the REST API.
- The team is not prepared to validate the GraphQL schema, routes, cache behavior, and language edge cases after updates.
If you are unsure, start with a staging environment and one real use case: a post with translations, a menu, ACF global fields, and a frontend page. If that use case works cleanly, you can expand the integration. If it already requires a long list of workarounds, it is better to revisit the architecture before it becomes the foundation of the entire site.
Questions to Ask Before Implementing WPML GraphQL
Can WPML GraphQL be used without WPGraphQL?
No. WPML GraphQL extends the WPGraphQL schema, so without WPGraphQL there is nothing for it to extend. The base endpoint and GraphiQL IDE need to work first. Then you add WPML GraphQL and validate the language fields.
Does every project need ACFML?
No. ACFML is needed when the site uses ACF fields and those fields must be translated correctly or synchronized across languages. For regular posts, pages, taxonomies, and menus, ACFML is not a universal requirement, but for ACF Options Pages and translatable ACF values it becomes part of the working stack.
Why does the list query work while the slug query cannot find the translation?
A language-filtered list query and a single-item query by slug go through different logic paths. Check the actual slug returned by the list query, whether a language prefix is involved, support for the custom post type, known WPML GraphQL issues, and the effect of third-party plugins, especially those that change query order or filters.
Can GraphQL queries with language parameters be cached?
Yes, but only after correctness has been validated and only if the language is part of the cache key, query variables, or persisted query definition. If the cache does not distinguish languages, it can return the response for one language on a route for another.
Is the plugin suitable for WooCommerce?
Use it cautiously in WooCommerce scenarios. The WPML GraphQL release notes mention a fix for WooGraphQL product translations, but that does not guarantee automatic compatibility for every store, checkout flow, catalog setup, and extension stack. For eCommerce, always build a separate validation matrix: products, categories, variations, URLs, cart behavior, and caching.
Should you write custom PHP filters to fix GraphQL responses?
Only if you clearly understand the public extension point and have checked the current documentation. With WPML GraphQL, it is safer to start with WPML, WPGraphQL, and ACFML settings, baseline queries, and correct variables. Do not invent hooks or edit plugin core just to get a quick result.
What if an exact feature is not confirmed in the documentation?
Do not build the architecture around it. Check the official docs, release notes, compatibility page, and support or errata. If there is no confirmation, document the limitation in the project and choose a fallback: a different query, an explicit missing-translation behavior, or avoiding that questionable use case altogether.
When WPML GraphQL Is Worth Using
WPML GraphQL is a strong choice if you already have WordPress with WPML, the content is genuinely multilingual, and the frontend needs to consume data through WPGraphQL. In that setup, the plugin closes an important gap: it brings language data, translations, filtering, and related capabilities into the GraphQL layer so the application does not have to assemble multilingual behavior manually from disconnected sources.
Before adopting it, do more than install it. Check the dependencies, prepare test content, run baseline queries, validate menus, ACF global fields, and routes by slug and uri, then enable caching and connect the frontend app. That order only feels slow at the beginning. On a real project, it reduces the risk of mixed languages, empty pages, incorrect menus, and hard-to-trace issues after component updates.
If the validated use case matches your architecture, you can download WPML GraphQL and test it on a site copy. The best next step is not to migrate the entire application at once, but to build one complete route: post, translation, menu, ACF setting, frontend page, and diagnostic query. If that route works cleanly, you can gradually roll the product into your production headless architecture.


