Clone field problems, fields return null
Description
I'm running into problems querying Clone fields in Groups.
Variations of this issue seem to come up a lot, the closest being https://github.com/wp-graphql/wpgraphql-acf/issues/49 which is marked fixed and closed.
Here's my setup:
I have two ACF Field Groups:
Hero- active, shows on Posts and PagesMedia Component- inactive, cloned into Groups inside Hero. Has two fields,caption(Text field) andimage(Image field).
Hero has four fields that are all set up the same and only differ in the way Media Component fields are cloned into them. Each field is a Group that has one Clone sub-field:
The four Group fields inside Hero have their Clone sub-field set up like this:
| Name | "Fields" option | "Display" option |
|---|---|---|
| media_all_fields_seamless_clone | "All fields from Media Component field group" | Seamless |
| media_individual_fields_seamless_clone | "Caption (text)", "Image (image)" | Seamless |
| media_all_fields_group_clone | "All fields from Media Component field group" | Group |
| media_individual_fields_group_clone | "Caption (text)", "Image (image)" | Group |
They are otherwise (except for Field Label and Field Name) identical.
I created a page and filled out all fields:
I query that page like this:
query GetAboutPage {
page(id: "/about", idType: URI) {
title
hero {
mediaAllFieldsSeamless {
__typename
caption
image {
node {
mediaItemUrl
}
}
}
mediaIndividualFieldsSeamless {
__typename
caption
image {
node {
mediaItemUrl
}
}
}
mediaAllFieldsGroup {
__typename
caption
image {
node {
mediaItemUrl
}
}
}
mediaIndividualFieldsGroup {
__typename
# caption
# Cannot query field "caption" on type "HeroMediaIndividualFieldsGroups"
# image { ... }
# Cannot query field "image" on type "HeroMediaIndividualFieldsGroups"
}
}
}
}
The result i get is this:
{
"data": {
"page": {
"title": "About",
"hero": {
"mediaAllFieldsSeamless": {
"__typename": "HeroMediaAllFieldsSeamless",
"caption": "Media All Fields Seamless Caption Value",
"image": null
},
"mediaIndividualFieldsSeamless": {
"__typename": "HeroMediaIndividualFieldsSeamless",
"caption": "Media Individual Fields Seamless Caption Value",
"image": {
"node": {
"mediaItemUrl": "https://dentistsguild.wpenginepowered.com/wp-content/uploads/2025/02/charly.jpg"
}
}
},
"mediaAllFieldsGroup": {
"__typename": "HeroMediaAllFieldsGroup",
"caption": null,
"image": null
},
"mediaIndividualFieldsGroup": {
"__typename": "HeroMediaIndividualFieldsGroup"
}
}
}
}
}
Summary:
| "All fields from Media Component" | "caption" and "image" individually | |
|---|---|---|
| Seamless | caption ✅, image ⛔ (null) | caption ✅, image ✅ |
| Group | caption ⛔, image ⛔ (both null) | caption ⛔, image ⛔ (missing in schema) |
NB: I should mention that i can swap the image field with a file field and get the same behavior, if that helps.
Steps to reproduce
I can provide access to the live WordPress installation if needed
PHP or JSON export of the ACF Field Group(s)
Additional context
No response
WPGraphQL Version
2.0.0
WPGraphQL For ACF Version
2.4.1
ACF (Advanced Custom Fields) Version. Free or Pro?
6.3.11 (Pro)
WordPress Version
6.7.2
PHP Version
8.2
Additional enviornment details
WordPress is hosted on WP Engine (Headless Platform)
Please confirm that you have searched existing issues in the repo.
- [x] Yes
Please confirm that you have disabled ALL plugins except for WPGraphQL, WPGraphQL For ACF, ACF, etc.
- [x] Yes
- [ ] My issue is with compatibility with a specific WordPress plugin, and I have listed all my installed plugins (and version info) above.
Hi @jasonbahl, would you be able to provide an estimate on when you might have a chance to review this? It’s a key part of our project, and your input would be greatly appreciated. Thanks!
@claus thanks for sharing your export. I'm taking a look now to see if I can reproduce and come up with solutions.
Thanks 🙏🏻
@claus ok, I'm able to reproduce and indeed do not see the fields applied to the HeroMediaIndividualFieldsGroup type in the Schema.
I don't yet know the cause of the issue, but being able to reproduce is a good first step in debugging. I hope to make progress on this today 🤞🏻
@jasonbahl Thanks Jason, much appreciated! Let me know if there's anything else you need, i'm happy to help in any way possible!
@claus ok, I still don't have a solution quite yet (clone fields are a delicate thing!)
But I am getting a better understanding of where some of the bugs are coming from.
[!NOTE] Below is a brain-dump, mostly for my future self to have full context on this issue, how things should work and how things currently are working (i.e. the bugs)
WPGraphQL for ACF produces an ObjectType and an InterfaceType for each field group.
So, in the case of the exported groups .json file in this issue, we should have:
Hero(ObjectType)Hero_Fields(Interface)MediaComponent(ObjectType)MediaComponent_Fields(Interface)
The MediaComponent_Fields Interface has 2 fields:
caption: stringimage: AcfMediaItemConnectionEdge
This allows us to use a GraphQL fragment for the MediaComponent field group, like so:
fragment MediaComponent on MediaComponent_Fields {
caption
image {
node {
mediaItemUrl
}
}
}
[!NOTE] I will reference this fragment below without explicitly writing it out again
And then we can use that on any Type that implements the MediaComponent_Fields Interface.
Neat!
Now, if we look at the Hero field group, we we have the following fields, all of the "Group" type:
media_all_fields_seamlessmedia_individual_fields_seamlessmedia_all_fields_groupmedia_individual_fields_group
These fields are mapped to the GraphQL Schema as fields on the Hero type:
mediaAllFieldsSeamless: HeroMediaAllFieldsSeamlessmediaAllFields: HeroMediaAllFieldsSeamlessmediaIndividualFieldsGroup: HeroMediaIndividualFieldsGroupmediaIndividualFieldsSeamless: HeroMediaIndividualFieldsSeamless
Now, each of these nested groups have fields of the "clone" field type.
Let's take a look at each of these fields and how they should behave vs how they are behaving:
Hero.mediaAllFieldsSeamless
ACF Field Config:
- field: media_all_fields_seamless_clone
- field type: clone
- fields to clone: "All fields from Media Component field group"
- display: seamless
- prefix field labels: false
- prefix field names: false
Because the selection was to "Clone all fields from the media component field group", WPGraphQL for ACF should apply the MediaComponent_Fields Interface to the HeroMediaAllFieldsSeamless ObjectType, and thus, if things are working properly, we should be able to query like so:
query GetAboutPage {
page(id: "/about", idType: URI) {
title
hero {
mediaAllFieldsSeamless {
__typename
...MediaComponent
}
}
}
}
And, success! I can query:
There are no GraphQL Errors. The query is valid and we get results.
However the image field returns a null value, even though I have an image uploaded to that field.
[!CAUTION] BUG 1: The resolver on the mediaAllFieldsSeamless.image field is broken. I believe this has to do with the data passed to the resolver and being able to identify that the field was cloned vs a native field. Point is, The bug is in the resolver, not the schema. Also worth noting, the caption field works but not the image field. The caption field is a string while the image is a one-to-one connection, so likely there's an issue with cloned fields that map to connections in the schema.
Hero.mediaIndividualFieldsSeamless
ACF Field Config:
- field: media_individual_fields_seamless_clone
- field type: clone
- fields to clone: "MediaComponent.caption", "MediaComponent.image"
- display: seamless
- prefix field labels: false
- prefix field names: false
By cloning individual fields from the MediaComponent group, I DO NOT expect the MediaComponent_Fields interface to apply to the HeroMediaIndividualFieldsSeamless type.
So, I should not expect to be able to use the fragment like we did in the previous query, but I should be able to query like so:
query GetAboutPage {
page(id: "/about", idType: URI) {
title
hero {
mediaIndividualFieldsGroup {
__typename
caption
image {
node {
mediaItemUrl
}
}
}
}
}
}
However (as reported in the OP), this causes errors:
- Error: Cannot query field "caption" on type "HeroMediaIndividualFieldsGroup"
- Error: Cannot query field "image" on type "HeroMediaIndividualFieldsGroup"
[!CAUTION] BUG 2: The individually cloned fields are not appropriately added to the Group field that cloned them.
Hero.mediaAllFieldsGroup
ACF Field Config:
- field: media_all_fields_group_clone
- field type: clone
- fields to clone: "All Fields from Media Component field group"
- display: group
- prefix field labels: false
- prefix field names: false
Because this clone field is set to display as a group instead of seamless, I would expect there to be a nested field.
My expectation would be to query like so:
query GetAboutPage {
page(id: "/about", idType: URI) {
title
hero {
mediaAllFieldsGroup {
# this field represents the clone field that was cloned with "display group"
# i.e. nested under mediaAllFieldsGroup
mediaAllFieldsGroupClone {
...MediaComponent # I should be able to use the fragment as the entire MediaComponent group was cloned
}
}
}
}
}
However, this would be an invalid query:
- Error: "Cannot query field "mediaAllFieldsGroupClone" on type "HeroMediaAllFieldsGroup"."
I CAN, however, query like so:
query GetAboutPage {
page(id: "/about", idType: URI) {
title
hero {
mediaAllFieldsGroup {
...MediaComponent # The fragment is applied to the `HeroMediaAllFieldsGroup` directly and not nested.
}
}
}
}
BUT, both the caption and image fields return null values. 😢
[!CAUTION] BUG 3: Clone Fields that clone an entire group and are set to "display: group" are not being nested under a field, but rather are applying their cloned group's interface (i.e. MediaComponent_Fields) directly to the group (i.e. HeroMediaAllFieldsGroup) they were cloned onto. And the resolvers are returning null.
Hero.mediaIndividualFieldsGroup
ACF Field Config:
- field: media_individual_fields_group_clone
- field type: clone
- fields to clone: "MediaComponent.caption", "MediaComponent.image"
- display: group
- prefix field labels: false
- prefix field names: false
Because we cloned individual fields, I do NOT expect to be able to use the ...MediaComponent fragment. But, because the clone field is set to display: group I do expect the cloned image and caption fields to be nested.
My expectation would be to query like so:
query GetAboutPage {
page(id: "/about", idType: URI) {
title
hero {
mediaIndividualFieldsGroup {
# this field represents the clone field that was cloned with "display group"
# i.e. nested under mediaIndividualFieldsGroup
mediaIndividualFieldsGroupClone {
caption
image {
node {
mediaItemUrl
}
}
}
}
}
}
}
However, this is invalid:
- Error: "Cannot query field "mediaIndividualFieldsGroupClone" on type "HeroMediaIndividualFieldsGroup"
Possibly the display: group isn't working as expected and the image and caption fields are available directly under mediaIndividualFieldsGroup?
If I adjust my query:
query GetAboutPage {
page(id: "/about", idType: URI) {
title
hero {
mediaIndividualFieldsGroup {
caption
image {
node {
mediaItemUrl
}
}
}
}
}
}
We still have an invalid query:
- error: Cannot query field "caption" on type "HeroMediaIndividualFieldsGroup"
- error: Cannot query field "image" on type "HeroMediaIndividualFieldsGroup"
And we can check the Schema and see that indeed HeroMediaIndividualFieldsGroup has no fields other than the fieldGroupName field:
[!CAUTION] BUG 4: Clone fields set to "display: group" and cloning individual fields aren't being added to the schema (at all, it seems)
With all this info in mind, I believe we're discovering some issues related to:
- the "display" and "prefix" options on a clone field
- cloning fields that return Connections vs Scalars
- resolvers understanding how to resolve data for cloned fields
Files that are most likely involved in producing the bugs:
- src/WPGraphQLAcf.php
- src/Registry.php
- src/FieldTypeRegistry.php
- src/FieldConfig.php
- src/AcfGraphQLFieldType.php
- src/AcfGraphQLFieldResolver.php
- src/FieldType/Clone.php
- src/FieldType/Group.php
- src/FieldType/Image.php
Some other notes:
In the past we had clone field bugs reported and thought that we had fixed them.
see:
- https://github.com/wp-graphql/wpgraphql-acf/pull/185/files
- https://github.com/wp-graphql/wpgraphql-acf/pull/193/files
@jasonbahl Thank you for digging into this! Any new updates?
@AlexandraKlein For what it's worth, our workaround for now is to enable the "Prefix Field Names" option and then run a SQL script to update the field names in the DB (for content that already exists). Using this option adds the cloned fields to the Schema.
@jasonbahl, thanks for the in-depth investigation. Hoping the fix isn't too onerous!
Update: this workaround seems to work because using prefixes seems to be the only way to register a clone field according to the clone field definition, but this was a very cursory peek into the code.
https://github.com/wp-graphql/wpgraphql-acf/blob/c589bfac44890fb0deb509fbc9841814002a935a/src/FieldType/CloneField.php#L13-L30
@AlexandraKlein For what it's worth, our workaround for now is to enable the "Prefix Field Names" option and then run a SQL script to update the field names in the DB (for content that already exists). Using this option adds the cloned fields to the Schema.
@jasonbahl, thanks for the in-depth investigation. Hoping the fix isn't too onerous!
Update: this workaround seems to work because using prefixes seems to be the only way to register a clone field according to the clone field definition, but this was a very cursory peek into the code.
wpgraphql-acf/src/FieldType/CloneField.php
Lines 13 to 30 in c589bfa
public static function register_field_type(): void { register_graphql_acf_field_type( 'clone', [ 'graphql_type' => static function ( FieldConfig $field_config, AcfGraphQLFieldType $acf_field_type ) {
$sub_field_group = $field_config->get_raw_acf_field(); $parent_type = $field_config->get_parent_graphql_type_name( $sub_field_group ); $field_name = $field_config->get_graphql_field_name(); $type_name = Utils::format_type_name( $parent_type . ' ' . $field_name ); $prefix_name = $sub_field_group['prefix_name'] ?? false; // If the "Clone" field has not set a "prefix_name", // return NULL to prevent registering a new type // The cloned if ( ! $prefix_name ) { return 'NULL'; }
Thanks for this! But enabling the "Prefix Field Names" option doesn't for for us. The fields in question are still null.
👋🏻 I made some progress on this issue.
I need to test with this scenario again, but I tested with another user's ACF Field Group export and was able to get things to work as expected.
I will test with this scenario and the changes in the PR and report back.
EDIT: I may have spoken too soon. I might have resolved an issue for another specific scenario, but not quite fixed this issue still.
Still looking into it