Cms: Q: What is the best way to query an elements "altenative" slug for one or more other sites?

Created on 11 May 2020  路  4Comments  路  Source: craftcms/cms

Description

We're using a fairly simple multisite approach where we have two languages, each as it's own site. We're using Craft in headless mode and querying all entries via graphQL.

Now I have a fairly common use case where I have a language switcher on top of the page, which should redirect to the page's URI in another language.

Given that the entire navigation is built around the slugs in the URL, I wanted to ask Craft for the current entry across different sites, like this:

query getSlugForAllSites($slug: [String!]!) {
    entries(slug: $slug, site: "*", enabledForSite: false) { slug, siteId }
}

Given that the slug is the same across all sites, this will return a result for all the sites.

However, if I have a different slug for each site/language, it will not show me this alternative slug. This makes a certain amount of sense given how GraphQL works. However, I wasn't able to figure out a really good alternative besides querying the element by its (u)id, which will result in having to fire two queries instead:

        // Determine the UID belonging to the current URI
        const { data } = await executeCraftQuery.call(this, gql`
            query getUidFromUri($uri: [String!]!, $siteId: String!) {
                entry(uri: $uri, siteId: $siteId) { uid }
            }
        `, { uri: this.$route.path.replace(/^\/en\/|(\/)/, '') });

        if (data.entry && data.entry.uid) {
            // Find out what the slug for the current entry is in another language.
            const results = await executeCraftQuery.call(this, gql`
                query getSlugForAllSites($uid: [String!]!, $sites: [String!]!) {
                    entries(uid: $uid, site: $sites, enabledForSite: false) { uri, siteId }
                }
            `, { siteId: null, sites: '*', uid: data.entry.uid });
        }

If there isn't a way to do this with the current GQL-api, perhaps we can find some way to introduce this feature? (perhaps a "translate"-directive for getting alternatives for certain fields?)

enhancement graphql

Most helpful comment

Currently there鈥檚 no way to do this besides to split it up into multiple GraphQL requests.

I was hoping it might be possible to do this with multiple GraphQL queries on the _same_ request, with one query to fetch the element ID, and a second to fetch its URIs, passing the ID result as a parameter on the second, but alas that鈥檚 not possible because all GraphQL queries are run simultaneously rather than sequentially. (Found this Stack Overflow post with someone looking to the exact same thing.)

That said, I think we can solve this by adding a new localized field onto elements, which returns the same element in other locales. For example:

query {
  entry(uri: $uri, site: $site) {
    localized {
      siteId
      url
    }
  }
}

Which would return something like:

{
  "data": {
    "entry": {
      "localized": [
        {
          "siteId": 2,
          "url": "https://site-b.com/entry/uri"
        },
        {
          "siteId": 3,
          "url": "https://site-c.com/entry/uri"
        }
      ]
    }
  }
}

Just added a new getLocalized() method to elements in a feature branch (c5b10b55a9543feb2aff7173179985ba3366d8a7), and we鈥檒l look into whether it鈥檚 feasible to get that hooked up to GraphQL.

All 4 comments

Currently there鈥檚 no way to do this besides to split it up into multiple GraphQL requests.

I was hoping it might be possible to do this with multiple GraphQL queries on the _same_ request, with one query to fetch the element ID, and a second to fetch its URIs, passing the ID result as a parameter on the second, but alas that鈥檚 not possible because all GraphQL queries are run simultaneously rather than sequentially. (Found this Stack Overflow post with someone looking to the exact same thing.)

That said, I think we can solve this by adding a new localized field onto elements, which returns the same element in other locales. For example:

query {
  entry(uri: $uri, site: $site) {
    localized {
      siteId
      url
    }
  }
}

Which would return something like:

{
  "data": {
    "entry": {
      "localized": [
        {
          "siteId": 2,
          "url": "https://site-b.com/entry/uri"
        },
        {
          "siteId": 3,
          "url": "https://site-c.com/entry/uri"
        }
      ]
    }
  }
}

Just added a new getLocalized() method to elements in a feature branch (c5b10b55a9543feb2aff7173179985ba3366d8a7), and we鈥檒l look into whether it鈥檚 feasible to get that hooked up to GraphQL.

Hey Brandon! Cool, that would be great to have :)

It would be great if we could query it with some optional additional args as well, just in case we have tons of sites / localisations and we may only want one or two:

query {
  entry(uri: $uri, site: $site) {
    localized(siteId: "1,2") {
      siteId
      url
    }
  }
}

Or even

query {
  entry(uri: $uri, site: $site) {
    localized(language: "["nl-NL", "en-GB"]") {
      siteId
      url
    }
  }
}

@FreekVR Yeah that should be doable.

This has been added for Craft 3.5

Also, created a new issue for filtering using parameters.

Was this page helpful?
0 / 5 - 0 ratings