Skip to content

Commit 777d53a

Browse files
authored
Merge pull request #136 from wp-graphql/fix/125-clone-fields-not-respecting-prefix
fix: clone fields not respecting prefix
2 parents b56bef5 + 633b4a4 commit 777d53a

File tree

11 files changed

+1368
-331
lines changed

11 files changed

+1368
-331
lines changed

composer.lock

Lines changed: 292 additions & 197 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/FieldConfig.php

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ class FieldConfig {
1212
*/
1313
protected $acf_field;
1414

15+
/**
16+
* @var array
17+
*/
18+
protected $raw_field;
19+
1520
/**
1621
* @var array
1722
*/
@@ -46,12 +51,13 @@ class FieldConfig {
4651
* @throws \GraphQL\Error\Error
4752
*/
4853
public function __construct( array $acf_field, array $acf_field_group, Registry $registry ) {
49-
$this->acf_field = $acf_field;
54+
$this->raw_field = $acf_field;
55+
$this->acf_field = ! empty( $acf_field['key'] ) && acf_get_field( $acf_field['key'] ) ? acf_get_field( $acf_field['key'] ) : $acf_field;
5056
$this->acf_field_group = $acf_field_group;
5157
$this->registry = $registry;
5258
$this->graphql_field_group_type_name = $this->registry->get_field_group_graphql_type_name( $this->acf_field_group );
5359
$this->graphql_field_name = $this->registry->get_graphql_field_name( $this->acf_field );
54-
$this->graphql_field_type = Utils::get_graphql_field_type( $this->acf_field['type'] );
60+
$this->graphql_field_type = Utils::get_graphql_field_type( $this->raw_field['type'] );
5561
}
5662

5763
/**
@@ -85,7 +91,9 @@ public function get_graphql_field_type(): ?AcfGraphQLFieldType {
8591
public function get_parent_graphql_type_name( array $acf_field, ?string $prepend = '' ): string {
8692
$type_name = '';
8793

88-
if ( ! empty( $acf_field['parent'] ) ) {
94+
if ( ! empty( $acf_field['parent_layout_group'] ) ) {
95+
$type_name = $this->registry->get_field_group_graphql_type_name( $acf_field['parent_layout_group'] );
96+
} elseif ( ! empty( $acf_field['parent'] ) ) {
8997
$parent_field = acf_get_field( $acf_field['parent'] );
9098
$parent_group = acf_get_field_group( $acf_field['parent'] );
9199
if ( ! empty( $parent_field ) ) {
@@ -137,7 +145,12 @@ public function get_field_description(): string {
137145
} else {
138146
// Fallback description
139147
// translators: %s is the name of the ACF Field Group
140-
$description = sprintf( __( 'Field added to the schema as part of the "%s" Field Group', 'wp-graphql-acf' ), $this->registry->get_field_group_graphql_type_name( $this->acf_field_group ) );
148+
$description = sprintf(
149+
// translators: %1$s is the ACF Field Type and %2$s is the name of the ACF Field Group
150+
__( 'Field of the "%1$s" Field Type added to the schema as part of the "%2$s" Field Group', 'wp-graphql-acf' ),
151+
$this->acf_field['type'] ?? '',
152+
$this->registry->get_field_group_graphql_type_name( $this->acf_field_group )
153+
);
141154
}
142155

143156
return $description;
@@ -150,6 +163,13 @@ public function get_acf_field(): array {
150163
return $this->acf_field;
151164
}
152165

166+
/**
167+
* @return array
168+
*/
169+
public function get_raw_acf_field(): array {
170+
return $this->raw_field;
171+
}
172+
153173
/**
154174
* @return array
155175
*/
@@ -217,6 +237,12 @@ public function get_graphql_field_config():?array {
217237
return null;
218238
}
219239

240+
// if the field type returns a NULL type,
241+
// bail and prevent the field from being directly mapped to the Schema
242+
if ( 'NULL' === $field_type ) {
243+
return null;
244+
}
245+
220246
switch ( $this->acf_field['type'] ) {
221247
case 'color_picker':
222248
case 'number':
@@ -288,6 +314,7 @@ public function should_format_field_value( string $field_type ): bool {
288314
'repeater',
289315
'flexible_content',
290316
'oembed',
317+
'clone',
291318
];
292319

293320
return in_array( $field_type, $types_to_format, true );
@@ -347,10 +374,9 @@ public function resolve_field( $root, array $args, AppContext $context, ResolveI
347374
} elseif ( ! empty( $field_config['__key'] ) ) {
348375
$field_key = $field_config['__key'];
349376
}
350-
$cloned_field_config = acf_get_field( $field_key );
351-
$field_config = ! empty( $cloned_field_config ) ? $cloned_field_config : $field_config;
352377
}
353378

379+
354380
$should_format_value = false;
355381

356382
if ( ! empty( $field_config['type'] ) && $this->should_format_field_value( $field_config['type'] ) ) {
@@ -362,7 +388,7 @@ public function resolve_field( $root, array $args, AppContext $context, ResolveI
362388
}
363389

364390
// if the field_config is empty or not an array, set it as an empty array as a fallback
365-
$field_config = ! empty( $field_config ) && is_array( $field_config ) ? $field_config : [];
391+
$field_config = ! empty( $field_config ) ? $field_config : [];
366392

367393
// If the root being passed down already has a value
368394
// for the field key, let's use it to resolve
@@ -391,6 +417,7 @@ public function resolve_field( $root, array $args, AppContext $context, ResolveI
391417
return $pre_value;
392418
}
393419

420+
$parent_field = null;
394421
$parent_field_name = null;
395422
if ( ! empty( $field_config['parent'] ) ) {
396423
$parent_field = acf_get_field( $field_config['parent'] );
@@ -419,6 +446,8 @@ public function resolve_field( $root, array $args, AppContext $context, ResolveI
419446
}
420447
}
421448

449+
450+
422451
// If there's no node_id at this point, we can return null
423452
if ( empty( $return_value ) && empty( $node_id ) ) {
424453
return null;
@@ -429,7 +458,6 @@ public function resolve_field( $root, array $args, AppContext $context, ResolveI
429458
$return_value = $this->get_field( $field_key, $parent_field_name, $node_id, $should_format_value );
430459
}
431460

432-
433461
// Prepare the value for response
434462
$prepared_value = $this->prepare_acf_field_value( $return_value, $root, $node_id, $field_config );
435463
// Empty values are set to null

src/FieldType/CloneField.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<?php
22
namespace WPGraphQL\Acf\FieldType;
33

4+
use WPGraphQL\Acf\AcfGraphQLFieldType;
5+
use WPGraphQL\Acf\FieldConfig;
6+
use WPGraphQL\Utils\Utils;
7+
48
class CloneField {
59

610
/**
@@ -10,7 +14,71 @@ public static function register_field_type():void {
1014
register_graphql_acf_field_type(
1115
'clone',
1216
[
17+
'graphql_type' => static function ( FieldConfig $field_config, AcfGraphQLFieldType $acf_field_type ) {
18+
$sub_field_group = $field_config->get_raw_acf_field();
19+
$parent_type = $field_config->get_parent_graphql_type_name( $sub_field_group );
20+
$field_name = $field_config->get_graphql_field_name();
21+
$registry = $field_config->get_registry();
22+
$type_name = Utils::format_type_name( $parent_type . ' ' . $field_name );
23+
$prefix_name = $sub_field_group['prefix_name'] ?? false;
24+
25+
$cloned_fields = array_filter(
26+
array_map(
27+
static function ( $cloned ) {
28+
return acf_get_field( $cloned );
29+
},
30+
$sub_field_group['clone']
31+
)
32+
);
33+
34+
$cloned_group_interfaces = array_filter(
35+
array_map(
36+
static function ( $cloned ) use ( $field_config ) {
37+
$cloned_group = acf_get_field_group( $cloned );
38+
if ( empty( $cloned_group ) ) {
39+
return null;
40+
}
41+
return $field_config->get_registry()->get_field_group_graphql_type_name( $cloned_group ) . '_Fields';
42+
},
43+
$sub_field_group['clone']
44+
)
45+
);
46+
47+
if ( ! empty( $cloned_group_interfaces ) ) {
48+
if ( ! $prefix_name ) {
49+
register_graphql_interfaces_to_types( $cloned_group_interfaces, [ $parent_type ] );
50+
} else {
51+
$type_name = self::register_prefixed_clone_field_type( $type_name, $sub_field_group, $cloned_fields, $field_config );
52+
register_graphql_interfaces_to_types( $cloned_group_interfaces, [ $type_name ] );
53+
return $type_name;
54+
}
55+
}
56+
1357

58+
// If the "Clone" field has cloned individual fields
59+
if ( ! empty( $cloned_fields ) ) {
60+
61+
// If the clone field is NOT set to use "prefix_name"
62+
if ( ! $prefix_name ) {
63+
64+
// Map over the cloned fields and register them to the parent type
65+
foreach ( $cloned_fields as $cloned_field ) {
66+
$field_config = $registry->map_acf_field_to_graphql( $cloned_field, $sub_field_group );
67+
if ( ! empty( $field_config['name'] ) ) {
68+
register_graphql_field( $parent_type, $field_config['name'], $field_config );
69+
}
70+
}
71+
72+
// If the Clone field is set to use "prefix_name"
73+
// Register a new Object Type with the cloned fields, and return
74+
// the new type.
75+
} else {
76+
return self::register_prefixed_clone_field_type( $type_name, $sub_field_group, $cloned_fields, $field_config );
77+
}
78+
}
79+
// Bail by returning a NULL type
80+
return 'NULL';
81+
},
1482
// The clone field adds its own settings field to display
1583
'admin_fields' => static function ( $default_admin_settings, $field, $config, \WPGraphQL\Acf\Admin\Settings $settings ) {
1684

@@ -27,4 +95,27 @@ public static function register_field_type():void {
2795
]
2896
);
2997
}
98+
99+
/**
100+
* @param string $type_name The name of the GraphQL Type representing the prefixed clone field
101+
* @param array $sub_field_group The Field Group representing the cloned field
102+
* @param array $cloned_fields The cloned fields to be registered to the Cloned Field Type
103+
* @param \WPGraphQL\Acf\FieldConfig $field_config The ACF Field Config
104+
*
105+
* @return string
106+
* @throws \Exception
107+
*/
108+
public static function register_prefixed_clone_field_type( string $type_name, array $sub_field_group, array $cloned_fields, FieldConfig $field_config ): string {
109+
$sub_field_group['graphql_type_name'] = $type_name;
110+
$sub_field_group['graphql_field_name'] = $type_name;
111+
$sub_field_group['parent'] = $sub_field_group['key'];
112+
$sub_field_group['sub_fields'] = $cloned_fields;
113+
114+
$field_config->get_registry()->register_acf_field_groups_to_graphql(
115+
[
116+
$sub_field_group,
117+
]
118+
);
119+
return $type_name;
120+
}
30121
}

src/FieldType/FlexibleContent.php

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ public static function register_field_type(): void {
2121
$layout_interface_prefix = Utils::format_type_name( $parent_type . ' ' . $field_name );
2222
$layout_interface_name = $layout_interface_prefix . '_Layout';
2323

24-
$flex_field_raw_sub_fields = acf_get_raw_fields( $acf_field['key'] );
25-
2624
if ( ! $field_config->get_registry()->has_registered_field_group( $layout_interface_name ) ) {
2725
register_graphql_interface_type(
2826
$layout_interface_name,
@@ -33,13 +31,16 @@ public static function register_field_type(): void {
3331
'fields' => [
3432
'fieldGroupName' => [
3533
'type' => 'String',
34+
'resolve' => static function ( $object ) use ( $layout_interface_prefix ) {
35+
$layout = $object['acf_fc_layout'] ?? null;
36+
return Utils::format_type_name( $layout_interface_prefix . ' ' . $layout ) . 'Layout';
37+
},
3638
'description' => __( 'The name of the ACF Flex Field Layout', 'wp-graphql-acf' ),
37-
'deprecationReason' => __( 'Use __typename instead', 'wp-graphql-acf' ),
3839
],
3940
],
4041
'resolveType' => static function ( $object ) use ( $layout_interface_prefix ) {
4142
$layout = $object['acf_fc_layout'] ?? null;
42-
return Utils::format_type_name( $layout_interface_prefix . ' ' . $layout );
43+
return Utils::format_type_name( $layout_interface_prefix . ' ' . $layout ) . 'Layout';
4344
},
4445
]
4546
);
@@ -48,42 +49,33 @@ public static function register_field_type(): void {
4849
}
4950

5051
$layouts = [];
52+
53+
// If there are no layouts, return a NULL type
5154
if ( ! empty( $acf_field['layouts'] ) ) {
5255
foreach ( $acf_field['layouts'] as $layout ) {
53-
54-
// Format the name of the group using the layout prefix + the layout name
55-
$layout_name = Utils::format_type_name( $layout_interface_prefix . ' ' . $field_config->get_registry()->get_field_group_graphql_type_name( $layout ) );
56-
57-
// set the graphql_field_name using the $layout_name
58-
$layout['graphql_field_name'] = $layout_name;
59-
60-
// Pass that the layout is a flexLayout (compared to a standard field group)
61-
$layout['isFlexLayout'] = true;
62-
63-
$layout['parent'] = $acf_field['key'];
64-
$layout['raw_fields'] = array_filter(
65-
$flex_field_raw_sub_fields,
66-
static function ( $field ) use ( $layout ) {
67-
return isset( $field['parent_layout'] ) && $field['parent_layout'] === $layout['key'] ? $layout : null;
68-
}
56+
$layout_type_name = Utils::format_type_name( $layout_interface_prefix . ' ' . $field_config->get_registry()->get_field_group_graphql_type_name( $layout ) ) . 'Layout';
57+
$layout['interfaces'] = [ $layout_interface_name ];
58+
$layout['eagerlyLoadType'] = true;
59+
$layout['isFlexLayout'] = true;
60+
$layout['parent_layout_group'] = $layout;
61+
$layout['graphql_type_name'] = $layout_type_name;
62+
63+
$sub_fields = array_filter(
64+
array_map(
65+
static function ( $field ) use ( $layout ) {
66+
$field['graphql_types'] = [];
67+
$field['parent_layout_group'] = $layout;
68+
$field['isFlexLayoutField'] = true;
69+
70+
return isset( $field['parent_layout'] ) && $layout['key'] === $field['parent_layout'] ? $field : null;
71+
},
72+
acf_get_raw_fields( $layout['key'] )
73+
)
6974
);
7075

71-
// Get interfaces, including cloned field groups, for the layout
72-
$interfaces = $field_config->get_registry()->get_field_group_interfaces( $layout );
76+
$layout['sub_fields'] = array_merge( $sub_fields, $layout['sub_fields'] );
7377

74-
// Add the layout interface name as an interface. This is the type that is returned as a list of for accessing all layouts of the flex field
75-
$interfaces[] = $layout_interface_name;
76-
$layout['eagerlyLoadType'] = true;
77-
$layout['graphql_field_name'] = $layout_name;
78-
$layout['fields'] = [
79-
'fieldGroupName' => [
80-
'type' => 'String',
81-
'description' => __( 'The name of the ACF Flex Field Layout', 'wp-graphql-acf' ),
82-
'deprecationReason' => __( 'Use __typename instead', 'wp-graphql-acf' ),
83-
],
84-
];
85-
$layout['interfaces'] = $interfaces;
86-
$layouts[ $layout_name ] = $layout;
78+
$layouts[] = $layout;
8779
}
8880
}
8981

src/FieldType/Repeater.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ public static function register_field_type(): void {
2222

2323
$sub_field_group['graphql_type_name'] = $type_name;
2424
$sub_field_group['graphql_field_name'] = $type_name;
25+
$sub_field_group['locations'] = null;
26+
27+
if ( ! empty( $sub_field_group['__key'] ) ) {
28+
$cloned_from = acf_get_field( $sub_field_group['__key'] );
29+
$cloned_parent = ! empty( $cloned_from ) ? $field_config->get_parent_graphql_type_name( $cloned_from ) : null;
30+
if ( ! empty( $cloned_parent ) ) {
31+
$type_name = Utils::format_type_name( $cloned_parent . ' ' . $field_name );
32+
return [ 'list_of' => $type_name ];
33+
}
34+
}
35+
2536

2637
$field_config->get_registry()->register_acf_field_groups_to_graphql(
2738
[

0 commit comments

Comments
 (0)