Skip to content

Commit dd0292c

Browse files
authored
fix: resolve AddressField defaults by type (#483)
* fix: resolve AddressField defaults by type * fix: respect custom label
1 parent d6092ad commit dd0292c

File tree

6 files changed

+305
-5
lines changed

6 files changed

+305
-5
lines changed

.github/workflows/codeception.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
matrix:
6161
## GF 2.9.x only supports from WP 6.5, and we have no way to access earlier versions.
6262
php: ['8.4', '8.3', '8.2', '8.1']
63-
wordpress: ['6.9','6.8', '6.7', '6.6', '6.5']
63+
wordpress: ['6.9', '6.8', '6.7', '6.6', '6.5']
6464
coverage: [0]
6565
include:
6666
- php: '8.4'
@@ -146,7 +146,6 @@ jobs:
146146
command: |
147147
${{ matrix.coverage && 'PCOV_ENABLED=1 ' || '' }}npm run wp-env start -- ${{ secrets.ACTIONS_STEP_DEBUG && '--debug' || '' }}
148148
149-
150149
- name: Log versions
151150
run: |
152151
npm run wp-env -- run cli php -- -v

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## [Unreleased]
44

5+
- fix: Correctly resolve `AddressField.defaultState`, `AddressField.defaultProvince` based on the `addressType`. H/t @byanko-bot
6+
- fix: Set the default `AddressField.inputs.label` for the State/Province and Zip/Postal inputs based on the `addressType`. H/t @byanko-bot
57
- chore: Update Composer and NPM deps.
68

79
## [v0.13.3]

src/Model/FormField.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,19 @@ static function ( $choice ) use ( $data ) {
240240

241241
$inputs[ $input_index ]['key'] = $input_keys[ $input_index ];
242242
}
243+
244+
// Apply dynamic labels for address fields based on addressType.
245+
if ( 'address' === $data->type ) {
246+
$address_labels = self::get_address_input_type_labels( $data->formId, $data->addressType ?? '' );
247+
248+
// Only override label if no customLabel is set.
249+
if ( empty( $inputs[3]['customLabel'] ) ) {
250+
$inputs[3]['label'] = $address_labels['state_label'] ?? $inputs[3]['label'];
251+
}
252+
if ( empty( $inputs[4]['customLabel'] ) ) {
253+
$inputs[4]['label'] = $address_labels['zip_label'] ?? $inputs[4]['label'];
254+
}
255+
}
243256
} elseif ( 'email' === $data->type && empty( $data->emailConfirmEnabled ) ) {
244257
// Prime inputs for email fields without confirmation.
245258
$inputs = [
@@ -287,6 +300,25 @@ private static function get_address_input_keys(): array {
287300
];
288301
}
289302

303+
/**
304+
* Returns dynamic labels for Address field based on addressType.
305+
*
306+
* Mirrors the logic from GF_Field_Address::get_address_types().
307+
*
308+
* @param int $form_id The form ID to get the address type for.
309+
* @param string $address_type The address type (international, us, canadian).
310+
*
311+
* @return array{state_label:string, zip_label:string}
312+
*/
313+
private static function get_address_input_type_labels( int $form_id, string $address_type ): array {
314+
/** @var \GF_Field_Address $field */
315+
$field = \GF_Fields::get( 'address' );
316+
$address_types = $field->get_address_types( $form_id );
317+
$address_type = $address_type ?: $field->get_default_address_type( $form_id );
318+
319+
return $address_types[ $address_type ] ?? $address_types['international'];
320+
}
321+
290322
/**
291323
* Returns input keys for Name field.
292324
*

src/Type/WPInterface/FieldSetting/FieldWithAddress.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use WPGraphQL\GF\Interfaces\TypeWithInterfaces;
1414
use WPGraphQL\GF\Type\Enum\AddressFieldCountryEnum;
1515
use WPGraphQL\GF\Type\Enum\AddressFieldProvinceEnum;
16+
use WPGraphQL\GF\Type\Enum\AddressFieldStateEnum;
1617
use WPGraphQL\GF\Type\Enum\AddressFieldTypeEnum;
1718
use WPGraphQL\GF\Type\WPInterface\FieldWithInputs;
1819
use WPGraphQL\Registry\TypeRegistry;
@@ -62,10 +63,19 @@ public static function get_fields(): array {
6263
'defaultProvince' => [
6364
'type' => AddressFieldProvinceEnum::$type,
6465
'description' => static fn () => __( 'Contains the province that will be selected by default. Only applicable when "addressType" is set to "CANADA".', 'wp-graphql-gravity-forms' ),
66+
'resolve' => static function ( $source ): ?string {
67+
if ( 'canadian' !== ( $source->addressType ?? '' ) ) {
68+
return null;
69+
}
70+
71+
// Older versions of GF use defaultProvince.
72+
return ! empty( $source->defaultProvince ) ? $source->defaultProvince : ( $source->defaultState ?? null );
73+
},
6574
],
6675
'defaultState' => [
67-
'type' => AddressFieldProvinceEnum::$type,
76+
'type' => AddressFieldStateEnum::$type,
6877
'description' => static fn () => __( 'Contains the state that will be selected by default. Only applicable when "addressType" is set to "US".', 'wp-graphql-gravity-forms' ),
78+
'resolve' => static fn ( $source ): ?string => 'us' === ( $source->addressType ?? '' ) ? ( $source->defaultState ?? null ) : null,
6979
],
7080
];
7181
}

tests/_support/Helper/GFHelpers/ExpectedFormFields.php

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,17 @@ public function address_setting( GF_Field $field, array &$properties ): void {
2323
$properties[] = $this->expectedField( 'addressType', ! empty( $field->addressType ) ? GFHelpers::get_enum_for_value( Enum\AddressFieldTypeEnum::$type, $field->addressType ) : self::IS_NULL );
2424

2525
$properties[] = $this->expectedField( 'defaultCountry', ! empty( $field->defaultCountry ) ? GFHelpers::get_enum_for_value( Enum\AddressFieldCountryEnum::$type, $field->defaultCountry ) : self::IS_NULL );
26-
$properties[] = $this->expectedField( 'defaultProvince', ! empty( $field->defaultProvince ) ? GFHelpers::get_enum_for_value( Enum\AddressFieldProvinceEnum::$type, $field->defaultProvince ) : self::IS_NULL );
27-
$properties[] = $this->expectedField( 'defaultState', ! empty( $field->defaultState ) ? GFHelpers::get_enum_for_value( Enum\AddressFieldStateEnum::$type, $field->defaultState ) : self::IS_NULL );
26+
27+
// For Canadian addresses, defaultProvince should return defaultProvince or fallback to defaultState.
28+
$default_province = null;
29+
if ( 'canadian' === $field->addressType ) {
30+
$default_province = ! empty( $field->defaultProvince ) ? $field->defaultProvince : ( $field->defaultState ?? null );
31+
}
32+
$properties[] = $this->expectedField( 'defaultProvince', ! empty( $default_province ) ? GFHelpers::get_enum_for_value( Enum\AddressFieldProvinceEnum::$type, $default_province ) : self::IS_NULL );
33+
34+
// For US addresses, defaultState returns the value; for others it's null.
35+
$default_state = 'us' === $field->addressType && ! empty( $field->defaultState ) ? $field->defaultState : null;
36+
$properties[] = $this->expectedField( 'defaultState', ! empty( $default_state ) ? GFHelpers::get_enum_for_value( Enum\AddressFieldStateEnum::$type, $default_state ) : self::IS_NULL );
2837

2938
$input_keys = [
3039
'autocompleteAttribute' => 'autocompleteAttribute',
@@ -38,6 +47,19 @@ public function address_setting( GF_Field $field, array &$properties ): void {
3847
];
3948

4049
$properties[] = $this->expected_inputs( $input_keys, ! empty( $field->inputs ) ? $field->inputs : [] );
50+
51+
// Override labels for state (input 3) and zip (input 4) with dynamic values based on addressType.
52+
$dynamic_labels = $this->get_address_type_labels( $field->addressType ?? '' );
53+
$inputs = ! empty( $field->inputs ) ? $field->inputs : [];
54+
55+
// Only override if no customLabel is set.
56+
if ( isset( $inputs[3] ) && empty( $inputs[3]['customLabel'] ) ) {
57+
$properties[] = $this->expectedField( 'inputs.3.label', $dynamic_labels['state_label'] );
58+
}
59+
if ( isset( $inputs[4] ) && empty( $inputs[4]['customLabel'] ) ) {
60+
$properties[] = $this->expectedField( 'inputs.4.label', $dynamic_labels['zip_label'] );
61+
}
62+
4163
$properties[] = $this->expectedField( 'inputs.0.key', 'street' );
4264
$properties[] = $this->expectedField( 'inputs.1.key', 'lineTwo' );
4365
$properties[] = $this->expectedField( 'inputs.2.key', 'city' );
@@ -46,6 +68,31 @@ public function address_setting( GF_Field $field, array &$properties ): void {
4668
$properties[] = $this->expectedField( 'inputs.5.key', 'country' );
4769
}
4870

71+
/**
72+
* Get dynamic labels for address fields based on addressType.
73+
*
74+
* @param string $address_type The address type.
75+
* @return array{state_label:string, zip_label:string}
76+
*/
77+
private function get_address_type_labels( string $address_type ): array {
78+
$labels = [
79+
'international' => [
80+
'state_label' => 'State / Province / Region',
81+
'zip_label' => 'ZIP / Postal Code',
82+
],
83+
'us' => [
84+
'state_label' => 'State',
85+
'zip_label' => 'ZIP Code',
86+
],
87+
'canadian' => [
88+
'state_label' => 'Province',
89+
'zip_label' => 'Postal Code',
90+
],
91+
];
92+
93+
return $labels[ $address_type ] ?? $labels['international'];
94+
}
95+
4996
public function admin_label_setting( GF_Field $field, array &$properties ): void {
5097
$properties[] = $this->expectedField( 'adminLabel', ! empty( $field->adminLabel ) ? $field->adminLabel : self::IS_NULL );
5198
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
<?php
2+
/**
3+
* Tests for Address field type issues.
4+
*
5+
* @package WPGraphQL\GF\Tests\WPUnit
6+
*/
7+
8+
use Tests\WPGraphQL\GF\TestCase\GFGraphQLTestCase;
9+
10+
/**
11+
* Class AddressFieldTypesTest
12+
*/
13+
class AddressFieldTypesTest extends GFGraphQLTestCase {
14+
/**
15+
* The ID of the form created for testing.
16+
*
17+
* @var int
18+
*/
19+
private $form_id;
20+
21+
/**
22+
* {@inheritDoc}
23+
*/
24+
public function setUp(): void {
25+
parent::setUp();
26+
27+
wp_set_current_user( $this->admin->ID );
28+
$this->clearSchema();
29+
}
30+
31+
/**
32+
* {@inheritDoc}
33+
*/
34+
public function tearDown(): void {
35+
$this->factory->form->delete( $this->form_id );
36+
37+
parent::tearDown();
38+
}
39+
40+
/**
41+
* Helper method to create a form with an address field with the given properties.
42+
*
43+
* @param array $props The properties for the address field.
44+
*
45+
* @return int The ID of the created form.
46+
*/
47+
private function create_address_form( array $props ): int {
48+
$field_helper = $this->tester->getPropertyHelper( 'AddressField', $props );
49+
$field = $this->factory->field->create( $field_helper->values );
50+
51+
return $this->factory->form->create(
52+
array_merge(
53+
[ 'fields' => [ $field ] ],
54+
$this->tester->getFormDefaultArgs()
55+
)
56+
);
57+
}
58+
59+
/**
60+
* Test that the US address type returns the correct address type and default state, and that default province is null.
61+
*/
62+
public function testUsAddressType(): void {
63+
$this->form_id = $this->create_address_form(
64+
[
65+
'addressType' => 'us',
66+
'defaultState' => 'Michigan',
67+
'defaultProvince' => 'Ontario',
68+
]
69+
);
70+
71+
$query = '
72+
query ($id: ID!) {
73+
gfForm(id: $id, idType: DATABASE_ID) {
74+
formFields {
75+
nodes {
76+
... on AddressField {
77+
addressType
78+
defaultState
79+
defaultProvince
80+
}
81+
}
82+
}
83+
}
84+
}
85+
';
86+
87+
$variables = [ 'id' => $this->form_id ];
88+
$response = $this->graphql( compact( 'query', 'variables' ) );
89+
90+
$this->assertArrayNotHasKey( 'errors', $response );
91+
$this->assertEquals( 'US', $response['data']['gfForm']['formFields']['nodes'][0]['addressType'] );
92+
$this->assertNotNull( $response['data']['gfForm']['formFields']['nodes'][0]['defaultState'] );
93+
$this->assertEquals( 'MICHIGAN', $response['data']['gfForm']['formFields']['nodes'][0]['defaultState'] );
94+
$this->assertNull( $response['data']['gfForm']['formFields']['nodes'][0]['defaultProvince'] );
95+
}
96+
97+
/**
98+
* Test that the Canadian address type returns the correct address type and default province, and that default state is null.
99+
*/
100+
public function testCanadianAddressTypeWithProvince(): void {
101+
$this->form_id = $this->create_address_form(
102+
[
103+
'addressType' => 'canadian',
104+
'defaultProvince' => 'Ontario',
105+
'defaultState' => 'Michigan',
106+
]
107+
);
108+
109+
$query = '
110+
query ($id: ID!) {
111+
gfForm(id: $id, idType: DATABASE_ID) {
112+
formFields {
113+
nodes {
114+
... on AddressField {
115+
addressType
116+
defaultState
117+
defaultProvince
118+
}
119+
}
120+
}
121+
}
122+
}
123+
';
124+
125+
$variables = [ 'id' => $this->form_id ];
126+
$response = $this->graphql( compact( 'query', 'variables' ) );
127+
128+
$this->assertArrayNotHasKey( 'errors', $response );
129+
$this->assertEquals( 'CANADA', $response['data']['gfForm']['formFields']['nodes'][0]['addressType'] );
130+
$this->assertNotNull( $response['data']['gfForm']['formFields']['nodes'][0]['defaultProvince'] );
131+
$this->assertEquals( 'ONTARIO', $response['data']['gfForm']['formFields']['nodes'][0]['defaultProvince'] );
132+
$this->assertNull( $response['data']['gfForm']['formFields']['nodes'][0]['defaultState'] );
133+
}
134+
135+
/**
136+
* Test that the Canadian address type returns the correct address type and default province,
137+
* and that default state is null, when default province is set but default state is not set.
138+
*/
139+
public function testCanadianAddressTypeWithState(): void {
140+
$this->form_id = $this->create_address_form(
141+
[
142+
'addressType' => 'canadian',
143+
'defaultProvince' => null,
144+
'defaultState' => 'Ontario',
145+
]
146+
);
147+
148+
$query = '
149+
query ($id: ID!) {
150+
gfForm(id: $id, idType: DATABASE_ID) {
151+
formFields {
152+
nodes {
153+
... on AddressField {
154+
addressType
155+
defaultState
156+
defaultProvince
157+
}
158+
}
159+
}
160+
}
161+
}
162+
';
163+
164+
$variables = [ 'id' => $this->form_id ];
165+
$response = $this->graphql( compact( 'query', 'variables' ) );
166+
167+
$this->assertArrayNotHasKey( 'errors', $response );
168+
$this->assertEquals( 'CANADA', $response['data']['gfForm']['formFields']['nodes'][0]['addressType'] );
169+
$this->assertNotNull( $response['data']['gfForm']['formFields']['nodes'][0]['defaultProvince'] );
170+
$this->assertEquals( 'ONTARIO', $response['data']['gfForm']['formFields']['nodes'][0]['defaultProvince'] );
171+
$this->assertNull( $response['data']['gfForm']['formFields']['nodes'][0]['defaultState'] );
172+
}
173+
174+
/**
175+
* Test that the international address type returns the correct address type and that default state and default province are null.
176+
*/
177+
public function testInternationalAddressType(): void {
178+
$this->form_id = $this->create_address_form(
179+
[
180+
'addressType' => 'international',
181+
'defaultState' => 'Michigan',
182+
'defaultProvince' => 'Ontario',
183+
]
184+
);
185+
186+
$query = '
187+
query ($id: ID!) {
188+
gfForm(id: $id, idType: DATABASE_ID) {
189+
formFields {
190+
nodes {
191+
... on AddressField {
192+
addressType
193+
defaultState
194+
defaultProvince
195+
}
196+
}
197+
}
198+
}
199+
}
200+
';
201+
202+
$variables = [ 'id' => $this->form_id ];
203+
$response = $this->graphql( compact( 'query', 'variables' ) );
204+
205+
$this->assertArrayNotHasKey( 'errors', $response );
206+
$this->assertEquals( 'INTERNATIONAL', $response['data']['gfForm']['formFields']['nodes'][0]['addressType'] );
207+
$this->assertNull( $response['data']['gfForm']['formFields']['nodes'][0]['defaultState'] );
208+
$this->assertNull( $response['data']['gfForm']['formFields']['nodes'][0]['defaultProvince'] );
209+
}
210+
}

0 commit comments

Comments
 (0)