WPML

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 language argument fall back to the default language. Always pass language for 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