Skip to content

Clone field problems, fields return null #250

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
2 of 3 tasks
claus opened this issue Feb 23, 2025 · 9 comments · May be fixed by #254
Open
2 of 3 tasks

Clone field problems, fields return null #250

claus opened this issue Feb 23, 2025 · 9 comments · May be fixed by #254

Comments

@claus
Copy link

claus commented Feb 23, 2025

Description

I'm running into problems querying Clone fields in Groups.

Variations of this issue seem to come up a lot, the closest being #49 which is marked fixed and closed.

Here's my setup:

I have two ACF Field Groups:

  1. Hero - active, shows on Posts and Pages
  2. Media Component - inactive, cloned into Groups inside Hero. Has two fields, caption (Text field) and image (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:

Screenshot of the Hero Field Group with its first field expanded

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
Image Image Image Image

They are otherwise (except for Field Label and Field Name) identical.

Screenshot of the Hero Field Group with all its four fields collapsed and visible

I created a page and filled out all fields:

Screenshot of a Page titled About being edited. All groups have a caption and an image

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)

acf-export-2025-02-23.json

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.

  • Yes

Please confirm that you have disabled ALL plugins except for WPGraphQL, WPGraphQL For ACF, ACF, etc.

  • Yes
  • My issue is with compatibility with a specific WordPress plugin, and I have listed all my installed plugins (and version info) above.
@AlexandraKlein
Copy link

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!

@jasonbahl
Copy link
Contributor

@claus thanks for sharing your export. I'm taking a look now to see if I can reproduce and come up with solutions.

Thanks 🙏🏻

@jasonbahl
Copy link
Contributor

@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 🤞🏻

@claus
Copy link
Author

claus commented Feb 27, 2025

@jasonbahl Thanks Jason, much appreciated! Let me know if there's anything else you need, i'm happy to help in any way possible!

@jasonbahl
Copy link
Contributor

jasonbahl commented Feb 28, 2025

@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: string
  • image: 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_seamless
  • media_individual_fields_seamless
  • media_all_fields_group
  • media_individual_fields_group

These fields are mapped to the GraphQL Schema as fields on the Hero type:

  • mediaAllFieldsSeamless: HeroMediaAllFieldsSeamless
  • mediaAllFields: HeroMediaAllFieldsSeamless
  • mediaIndividualFieldsGroup: HeroMediaIndividualFieldsGroup
  • mediaIndividualFieldsSeamless: 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:

Image

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"

Image

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"."

Image

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. 😢

Image

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:

Image

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:

@AlexandraKlein
Copy link

@jasonbahl Thank you for digging into this! Any new updates?

@adamhake
Copy link

adamhake commented Mar 17, 2025

@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.

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';
}

@AlexandraKlein
Copy link

@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.

@jasonbahl jasonbahl linked a pull request Apr 7, 2025 that will close this issue
@jasonbahl
Copy link
Contributor

jasonbahl commented Apr 7, 2025

👋🏻 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants