Extended EntryInterface fields
Hej, thank you for this plugin! We're using it to make craft truly headless.
We ran into a few problems that we needed to solve:
- The
urifield is"__home__"for the home page which is not particularly useful if you're not craft - The
urifield does not contain the url prefix from sites (which are used for languages in our case [/en, /de]) - The
urlfield does contain the language prefix, but also contains the full url including "https://something.bla/", which again is not particularly helpful since the frontend is not necessarily hosted where the cms is - There is no way (coming from an Entry) to figure out to which site it belongs
- There is no way (coming from an Entry) to figure out what the entries with the same id's for other sites are. (Example: "I'm the English version of an Entry, what are the Entries in other Languages related to me.")
To solve this I've added some fields:
fullUricontains a fully qualified url no matter what.siteis just the site the entry belongs tosupportedSitesis the array of supportedSites (copied from craft)alternateEntriesis an Array of a new Type calledEntryInterfaceAlternatethat just contains an Entry and a booleanisSelf. The entries are the ones with the same id in all sites where the entry is active. Think of this as enabling you to simply make a site-(/language-)switcher based on that data.languageis just a convenience field that pulls the language from the site. (Yea... kinda unnecessary — I'm actually indifferent about this one)
This code is more or less a proof of concept and I'm almost certain that my implementation is not very nice and might have some quirks. Nevertheless I'd love to make CraftQL more helpful for us.
Do you think those (or some of those) additions make sense?
How can I improve them?
If some additions do not make sense... is there a way to extend the Schema like this without needing to fork CraftQL?
Let's talk :)
Screenshot of how it looks currently:

Loves,
- I love the addition of
siteon theEntryInterface supportedSitesmakes sense to me but I'm not sure why you need the custom resolver, won't the native code do the same thing?- Grabbing alternate entries is a neat idea. Does Craft support this natively through the
.twiginterfaces? If so then it's definitely worth bring in here. If it's not supported by.twigthen this may be better suited for theEntryConnectiontype.
Some critiques,
languageseems redundant if you can get the same info out ofEntryInterface.site.languageI'm also worried aboutlanguageconflicting with a custom field a user created.
A few more questions about the URLs,
- I understand
__home__not playing well outside of Craft, that's probably worth adjusting - If you're in a
.twigtemplate and you call{{ entry.url }}does it suffer from the same issues you describe above? If so I'd rather push this upstream and deal with it in Craft, itself?
Regarding extending the schema, this is sort of possible today but I've been quiet about it because I'd rather get these features fixed in CraftQL core and not require uses to patch them in, themselves. Basically, this should all be resolved in core since it's a core bug so thanks for raising it!
Loves,
- I love the addition of
siteon theEntryInterface
thanks ❤️
supportedSitesmakes sense to me but I'm not sure why you need the custom resolver, won't the native code do the same thing?
I thought the same but for some reason $root['supportedSites'] contains an array containing assoc arrays of siteId and enabledByDefault:
Array
(
[0] => Array
(
[siteId] => 1
[enabledByDefault] => 1
)
[1] => Array
(
[siteId] => 2
[enabledByDefault] => 1
)
)
That seems to trip up the automatic resolver. I don't have enough experience to know why. :)
- Grabbing alternate entries is a neat idea. Does Craft support this natively through the
.twiginterfaces? If so then it's definitely worth bring in here. If it's not supported by.twigthen this may be better suited for theEntryConnectiontype.
I'm not aware of Craft exposing that in the twig api directly. How would you solve this with the EntryConnection type? I just added the Wrapper type because i wanted to carry the isSelf info somewhere.
Some critiques,
languageseems redundant if you can get the same info out ofEntryInterface.site.languageI'm also worried aboutlanguageconflicting with a custom field a user created.
Nevermind, let's drop it 😄
A few more questions about the URLs,
- I understand
__home__not playing well outside of Craft, that's probably worth adjusting- If you're in a
.twigtemplate and you call{{ entry.url }}does it suffer from the same issues you describe above? If so I'd rather push this upstream and deal with it in Craft, itself?
Mhh… if you deal with url in twig/craft itself then if your Craft runs on https://foobar.org/admin then url = 'https://foobar.org/my-cool-page' is correct as well because the hostname is the same.
That's not a given if you use craft as a headless solution. You could have https://foobar.org (running craft + craftql) and https://example.com (running some kind of app consuming the api). Still your url field contains "https://foobar.org"... which you're not interested in.
To achieve the desired result it might be better to remove the hostname from url field instead of rebuilding it from scratch with some replace magic.
Regarding extending the schema, this is sort of possible today but I've been quiet about it because I'd rather get these features fixed in CraftQL core and not require uses to patch them in, themselves. Basically, this should all be resolved in core since it's a core bug so thanks for raising it!
That makes sense. 😁
Thanks @djfarly!
- I see what's up with the default resolver now and, yea, we'll need the custom resolver there.
- I'll need to think on the URL bit a little. I really want to try to keep CraftQL 1:1 with
craft.entriesand if Craft returns the full URL inentry.urlthen I'd like to keep CraftQL doing the same. However, I get the struggle and it makes sense we'd need more flexibility in a headless approach. One question, does the nativeurifield not work for you in this case?
Nevermind, I see why .uri isn't working for you. I wonder if we could fix that with directives? Maybe something like this?
{
entries {
uri @withLocale @normalize
}
}
smiles, while deleting the explanation for the uri… 😄
That sounds like a super nice idea. I think it would need to be @withSitePrefix (or something) because you could use sites for something other than localization... (I guess).
What would @normalize do?
Oh, @normalize could convert __home__ to /. Or maybe if there's other "Craft-specific" things in the URI, @normalize could convert them…
Nice :)
Just trying to figure out what this would require:
- [ ] creating a Directive (
src/Directives/Uri.php) based onsrc/Directives/Date.php - [ ] creating a Builder (
src/Builders/Uri.php) based onsrc/Builders/Date.php
Do I need to wire it up somewhere else in the code?
@markhuot @djfarly is there any progress on this? or any way I can help to push this forward?
The addition of site on the EntryInterface and having a way to access alternate Entries (or even better: a way to query entries across sites) would be super helpful to us.
Edit: CraftCMS 3.2 now allows querying entries across sites: https://github.com/craftcms/cms/commit/d01702278bd84b84392e11da72aa4d0b6f4f0943