Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## [Unreleased]

### Added
- feat: Add `phoneFormatProperties` field to Phone fields returning detailed format information (label, mask, regex, instruction, type). Resolves #441.

## [v0.13.3]

This _minor_ release improves compatibility with WPGraphQL v2.6.0, Gravity Forms v2.9.x, WordPress 6.9, and PHP 8.4. Additionally, we've migrated our development and testing environment to use `@wordpress/env` (`wp-env`), integrated Prettier and `@wordpress/scripts` for codebase management, and made some bug fixes and performance improvements.
Expand Down
2 changes: 2 additions & 0 deletions src/Registry/TypeRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ public static function objects(): array {
WPObject\FormField\FormFields::class,
// Field Error.
WPObject\FieldError::class,
// Phone Format Properties.
WPObject\PhoneFormatProperties::class,
// Submission Confirmation.
WPObject\SubmissionConfirmation::class,
// GF Settings.
Expand Down
60 changes: 59 additions & 1 deletion src/Type/WPInterface/FieldSetting/FieldWithPhoneFormat.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace WPGraphQL\GF\Type\WPInterface\FieldSetting;

use WPGraphQL\GF\Type\Enum\PhoneFieldFormatEnum;
use WPGraphQL\GF\Type\WPObject\PhoneFormatProperties;

/**
* Class - FieldWithPhoneFormat
Expand All @@ -35,10 +36,67 @@ class FieldWithPhoneFormat extends AbstractFieldSetting {
*/
public static function get_fields(): array {
return [
'phoneFormat' => [
'phoneFormat' => [
'type' => PhoneFieldFormatEnum::$type,
'description' => static fn () => __( 'Determines the allowed format for phones. If the phone value does not conform with the specified format, the field will fail validation.', 'wp-graphql-gravity-forms' ),
],
'phoneFormatProperties' => [
'type' => PhoneFormatProperties::$type,
'description' => static fn () => __( 'The properties of the selected phone format, including label, mask, regex, instruction and type.', 'wp-graphql-gravity-forms' ),
'resolve' => static function ( $field ) {
if ( empty( $field->phoneFormat ) ) {
return null;
}

// Get all available phone formats, including custom ones from gform_phone_formats filter.
$phone_formats = apply_filters(
'gform_phone_formats', // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
[
'standard' => [
'label' => '(###) ###-####',
'mask' => '(999) 999-9999',
'regex' => '/^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$/',
'instruction' => '(###) ###-####',
'type' => 'standard',
],
'international' => [
'label' => 'International',
'mask' => false,
'regex' => false,
'instruction' => __( 'International phone numbers must start with a + followed by the country code and phone number.', 'wp-graphql-gravity-forms' ),
'type' => 'international',
],
Comment on lines +62 to +68
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'international' format has 'mask' and 'regex' set to boolean false, but the PhoneFormatProperties type defines these fields as String (non-nullable). This creates a type mismatch that will cause GraphQL validation errors when international format is used. Consider converting false values to null in the resolver or updating the PhoneFormatProperties type to make these fields nullable (String instead of String!).

Copilot uses AI. Check for mistakes.
]
);

$format = $phone_formats[ $field->phoneFormat ] ?? null;
if ( ! is_array( $format ) ) {
return null;
}

$required_keys = [
'label' => null,
'mask' => null,
'regex' => null,
'instruction' => null,
'type' => null,
];

$normalized = [];
foreach ( $required_keys as $key => $default ) {
$value = $format[ $key ] ?? $default;
if ( false === $value ) {
$value = null;
}
if ( null !== $value && ! is_scalar( $value ) ) {
$value = $default;
}
$normalized[ $key ] = $value;
}

return $normalized;
},
],
];
}
}
58 changes: 58 additions & 0 deletions src/Type/WPObject/PhoneFormatProperties.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
/**
* Object Type - PhoneFormatProperties
*
* @package WPGraphQL\GF\Type\WPObject
* @since @todo
*/

declare( strict_types = 1 );

namespace WPGraphQL\GF\Type\WPObject;

/**
* Class - PhoneFormatProperties
*/
class PhoneFormatProperties extends AbstractObject {
/**
* Type registered in WPGraphQL.
*
* @var string
*/
public static string $type = 'PhoneFormatProperties';

/**
* {@inheritDoc}
*/
public static function get_description(): string {
return __( 'Properties of a phone number format, including label, mask, regex, instruction and type.', 'wp-graphql-gravity-forms' );
}

/**
* {@inheritDoc}
*/
public static function get_fields(): array {
return [
'label' => [
'type' => 'String',
'description' => static fn () => __( 'The display label for the phone format.', 'wp-graphql-gravity-forms' ),
],
'mask' => [
'type' => 'String',
'description' => static fn () => __( 'The input mask for the phone format (e.g., "(999) 999-9999").', 'wp-graphql-gravity-forms' ),
],
'regex' => [
'type' => 'String',
'description' => static fn () => __( 'The regex pattern for validating the phone format.', 'wp-graphql-gravity-forms' ),
],
'instruction' => [
'type' => 'String',
'description' => static fn () => __( 'The instruction text displayed to users for this phone format.', 'wp-graphql-gravity-forms' ),
],
'type' => [
'type' => 'String',
'description' => static fn () => __( 'The internal type identifier for the phone format.', 'wp-graphql-gravity-forms' ),
],
];
}
}
16 changes: 16 additions & 0 deletions tests/_support/Helper/GFHelpers/ExpectedFormFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,22 @@ public function pen_size_setting( GF_Field $field, array &$properties ): void {

public function phone_format_setting( GF_Field $field, array &$properties ): void {
$properties[] = $this->expectedField( 'phoneFormat', ! empty( $field->phoneFormat ) ? GFHelpers::get_enum_for_value( Enum\PhoneFieldFormatEnum::$type, $field->phoneFormat ) : self::IS_NULL );

// Add phoneFormatProperties field.
if ( ! empty( $field->phoneFormat ) ) {
$properties[] = $this->expectedField( 'phoneFormatProperties.label', self::NOT_NULL );
$properties[] = $this->expectedField( 'phoneFormatProperties.instruction', self::NOT_NULL );
$properties[] = $this->expectedField( 'phoneFormatProperties.type', self::NOT_NULL );
if ( 'international' === $field->phoneFormat ) {
$properties[] = $this->expectedField( 'phoneFormatProperties.mask', self::IS_NULL );
$properties[] = $this->expectedField( 'phoneFormatProperties.regex', self::IS_NULL );
} else {
$properties[] = $this->expectedField( 'phoneFormatProperties.mask', self::NOT_NULL );
$properties[] = $this->expectedField( 'phoneFormatProperties.regex', self::NOT_NULL );
}
} else {
$properties[] = $this->expectedField( 'phoneFormatProperties', self::IS_NULL );
}
}

public function placeholder_setting( GF_Field $field, array &$properties ): void {
Expand Down
Loading