How to Query Multilingual Content With WPGraphQL – Language Filtering and Translations
Learn how to query language-specific content, fetch translations, and expose multilingual menus through WPGraphQL on a headless WordPress site. WPML GraphQL adds a language argument and a translations field to the WPGraphQL schema, so Next.js, Nuxt, Astro, Gatsby, or any other front-end can pull the right language’s content in one round-trip.
Before You Start
Install and activate these plugins:
- WPGraphQL (the open-source plugin from the WPGraphQL project).
- WPML and WPML String Translation.
- WPML GraphQL (the add-on this page covers).
If you also use Advanced Custom Fields:
- Advanced Custom Fields Multilingual (ACFML).
- WPGraphQL for Advanced Custom Fields (from the WPGraphQL project).
Your source content needs to be translated in WPML before the queries below have anything to return. With Translate Everything Automatically on (the WPML 5 default), translations get produced in the background as you publish content. For a manual setup, send content for translation from WPML > Translations > Dashboard. The translated posts and terms are what the GraphQL queries below filter and return.
The GraphQL IDE – Where to Test Queries
WPGraphQL adds a GraphQL > GraphQL IDE screen to the WordPress admin. The IDE’s Query Composer lists every available field, including WPML’s language argument and translations field, and runs queries against your live site. Test queries there before wiring them into your front-end framework.
Query Content per Language
Add where: { language: "<code>" } to any list query: posts, custom post types, taxonomy terms, menus, menu items, comments. The language code is the same code WPML uses everywhere (en, es, fr, pt-pt, and so on). Pass language: "all" to return content from every language at once.
query PostsES {
posts(where: { language: "es" }) {
nodes {
slug
uri
categories {
nodes { name }
}
}
}
}
When a top-level node is filtered by language, connected items (categories, tags, custom taxonomies) automatically follow the same language. The query above returns posts in Spanish with categories in Spanish, no extra arguments needed.
Fetch Every Translation of a Node in One Query
Add the translations field to any post or taxonomy query to return the node’s other-language versions in the same payload:
query PostsWithTranslations {
posts(where: { language: "en" }) {
nodes {
slug
uri
language { code }
translations {
slug
uri
language { code }
}
}
}
}
Each post comes back with its English fields plus an array of its other-language slugs and URIs. That’s the shape a language switcher rendered next to the page content uses: one request, every alternative the visitor can switch to.
Query a Specific Post by ID or Slug in Any Language
To fetch a single translated post directly (by its translated slug or by database ID), use the singular post query with idType:
query PostBySlug {
post(id: "hola-mundo", idType: SLUG) {
title
slug
uri
language { code }
}
}
query PostById {
post(id: "2", idType: DATABASE_ID) {
title
slug
uri
language { code }
}
}
Both queries return the translated post (title, slug, URI) without further filtering on the front-end.
Multilingual Menus
Query menus and menu items per language with the same language argument:
query NavES {
menu(language: "es", id: "primary", idType: SLUG) {
menuItems {
nodes {
label
url
path
}
}
}
}
Each menu item’s label and url come back in the queried language. Menu items that link to translated posts resolve to the translated URI automatically. This support was added in WPML GraphQL 1.1.0.
Installed Languages – For a Language Switcher
For a global language switcher (independent of any single post), use the languages and defaultLanguage queries to list every language on the site:
query SiteLanguages {
languages {
code
country_flag_url
default_locale
native_name
translated_name
url
}
defaultLanguage {
code
native_name
}
}
Returns one node per active language with the flag URL, native name, translated name, and the language’s home URL. That’s enough data to render a flag-and-label switcher without hard-coding the language list.
Query ACF Custom Fields per Language
When ACFML and WPGraphQL for ACF are active, ACF fields on posts and custom post types automatically follow the host post’s language. No extra argument needed. For ACF Options Pages, which aren’t tied to a single post, add the language argument to the Options Page query:
query Settings {
myOptionPage(language: "de") {
addressFieldGroup {
addressTitle
repeaterAddressDetails { addressDetails }
}
}
}
The argument expects a language code that matches one of your site’s active languages.
Known Limitations and Workarounds
- Author and user metadata doesn’t return translated values. If you display author bios per language, store the translated bio in an ACF field on the user and query that field instead.
- Translated URIs in some query shapes. When fetching a translated post by URI (
contentNode(id: "/de/some-slug/", idType: URI)), verify the returned URI matches what’s published in the language – some query shapes return inconsistent paths. Test in the GraphQL IDE before wiring into routing. - ACF Options Pages without
languageargument fall back to the default language. Always passlanguagefor Options Page queries on multilingual sites.
If you hit an integration issue not listed here, the WPML support team covers the WPML side of the WPGraphQL stack 24/7.
Written by Amir · Last updated July 2, 2026