diff --git a/projects/packages/forms/changelog/update-forms-image-select-no-options b/projects/packages/forms/changelog/update-forms-image-select-no-options
new file mode 100644
index 0000000000000..5d7467be66b2f
--- /dev/null
+++ b/projects/packages/forms/changelog/update-forms-image-select-no-options
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fixed
+
+Forms: Fix renderable status of image select field
diff --git a/projects/packages/forms/src/contact-form/class-contact-form-field.php b/projects/packages/forms/src/contact-form/class-contact-form-field.php
index 15c23facad5c4..7c52018e42459 100644
--- a/projects/packages/forms/src/contact-form/class-contact-form-field.php
+++ b/projects/packages/forms/src/contact-form/class-contact-form-field.php
@@ -2020,138 +2020,136 @@ public function render_image_select_field( $id, $label, $value, $class, $require
$used_html_ids = array();
- if ( ! empty( $options_data ) ) {
- // Create a separate array of original letters in sequence (A, B, C...)
- $perceived_letters = array();
+ // Create a separate array of original letters in sequence (A, B, C...)
+ $perceived_letters = array();
- foreach ( $options_data as $option ) {
- $perceived_letters[] = Contact_Form_Plugin::strip_tags( $option['letter'] );
- }
+ foreach ( $options_data as $option ) {
+ $perceived_letters[] = Contact_Form_Plugin::strip_tags( $option['letter'] );
+ }
- // Create a working copy of options for potential randomization
- $working_options = $options_data;
+ // Create a working copy of options for potential randomization
+ $working_options = $options_data;
- // Randomize options if requested, but preserve original letter values
- if ( $randomize_options ) {
- shuffle( $working_options );
+ // Randomize options if requested, but preserve original letter values
+ if ( $randomize_options ) {
+ shuffle( $working_options );
- // Trims options after randomization to ensure the last option has a label or image.
- $working_options = $this->trim_image_select_options( $working_options );
- }
+ // Trims options after randomization to ensure the last option has a label or image.
+ $working_options = $this->trim_image_select_options( $working_options );
+ }
- // Calculate row options count for CSS variable
- $total_options_count = count( $options_data );
- // Those values are halved on mobile via CSS media query
- $max_images_per_row = $is_supersized ? 2 : 4;
- $row_options_count = min( $total_options_count, $max_images_per_row );
+ // Calculate row options count for CSS variable
+ $total_options_count = count( $working_options );
+ // Those values are halved on mobile via CSS media query
+ $max_images_per_row = $is_supersized ? 2 : 4;
+ $row_options_count = min( $total_options_count, $max_images_per_row );
- foreach ( $working_options as $option_index => $option ) {
- $option_label = Contact_Form_Plugin::strip_tags( $option['label'] );
- $option_letter = Contact_Form_Plugin::strip_tags( $option['letter'] );
- $image_block = $option['image'];
+ foreach ( $working_options as $option_index => $option ) {
+ $option_label = Contact_Form_Plugin::strip_tags( $option['label'] );
+ $option_letter = Contact_Form_Plugin::strip_tags( $option['letter'] );
+ $image_block = $option['image'];
- // Extract image src from rendered block
- $rendered_image_block = render_block( $image_block );
- $image_src = '';
+ // Extract image src from rendered block
+ $rendered_image_block = render_block( $image_block );
+ $image_src = '';
- if ( ! empty( $rendered_image_block ) ) {
- if ( preg_match( '/
]+src=["\']([^"\']+)["\'][^>]*>/i', $rendered_image_block, $matches ) ) {
- $extracted_src = $matches[1];
+ if ( ! empty( $rendered_image_block ) ) {
+ if ( preg_match( '/
]+src=["\']([^"\']+)["\'][^>]*>/i', $rendered_image_block, $matches ) ) {
+ $extracted_src = $matches[1];
- if ( filter_var( $extracted_src, FILTER_VALIDATE_URL ) || str_starts_with( $extracted_src, 'data:' ) ) {
- $image_src = $extracted_src;
- }
+ if ( filter_var( $extracted_src, FILTER_VALIDATE_URL ) || str_starts_with( $extracted_src, 'data:' ) ) {
+ $image_src = $extracted_src;
}
- } else {
- $rendered_image_block = '
';
}
+ } else {
+ $rendered_image_block = '
';
+ }
- $option_value = wp_json_encode(
- array(
- 'perceived' => $perceived_letters[ $option_index ],
- 'selected' => $option_letter,
- 'label' => $option_label,
- 'showLabels' => $show_labels,
- 'image' => array(
- 'id' => $image_block['attrs']['id'] ?? null,
- 'src' => $image_src ?? null,
- ),
- )
- );
- $option_id = $id . '-' . $option_letter;
- $used_html_ids[ $option_id ] = true;
+ $option_value = wp_json_encode(
+ array(
+ 'perceived' => $perceived_letters[ $option_index ],
+ 'selected' => $option_letter,
+ 'label' => $option_label,
+ 'showLabels' => $show_labels,
+ 'image' => array(
+ 'id' => $image_block['attrs']['id'] ?? null,
+ 'src' => $image_src ?? null,
+ ),
+ )
+ );
+ $option_id = $id . '-' . $option_letter;
+ $used_html_ids[ $option_id ] = true;
- // To be able to apply the backdrop-filter for the hover effect, we need to separate the background into an outer div.
- // This outer div needs the color styles separately, and also the border radius to match the inner div without sticking out.
- $option_outer_classes = 'jetpack-input-image-option__outer ' . ( isset( $option['classcolor'] ) ? $option['classcolor'] : '' );
+ // To be able to apply the backdrop-filter for the hover effect, we need to separate the background into an outer div.
+ // This outer div needs the color styles separately, and also the border radius to match the inner div without sticking out.
+ $option_outer_classes = 'jetpack-input-image-option__outer ' . ( isset( $option['classcolor'] ) ? $option['classcolor'] : '' );
- if ( $is_supersized ) {
- $option_outer_classes .= ' is-supersized';
- }
+ if ( $is_supersized ) {
+ $option_outer_classes .= ' is-supersized';
+ }
- $border_styles = '';
- if ( ! empty( $option['style'] ) ) {
- preg_match( '/border-radius:([^;]+)/', $option['style'], $radius_match );
- preg_match( '/border-width:([^;]+)/', $option['style'], $width_match );
+ $border_styles = '';
+ if ( ! empty( $option['style'] ) ) {
+ preg_match( '/border-radius:([^;]+)/', $option['style'], $radius_match );
+ preg_match( '/border-width:([^;]+)/', $option['style'], $width_match );
- if ( ! empty( $radius_match[1] ) ) {
- $radius_value = trim( $radius_match[1] );
+ if ( ! empty( $radius_match[1] ) ) {
+ $radius_value = trim( $radius_match[1] );
- if ( ! empty( $width_match[1] ) ) {
- $width_value = trim( $width_match[1] );
- $border_styles = "border-radius:calc({$radius_value} + {$width_value});";
- } else {
- $border_styles = "border-radius:{$radius_value};";
- }
+ if ( ! empty( $width_match[1] ) ) {
+ $width_value = trim( $width_match[1] );
+ $border_styles = "border-radius:calc({$radius_value} + {$width_value});";
+ } else {
+ $border_styles = "border-radius:{$radius_value};";
}
}
+ }
- $option_outer_styles = ( empty( $option['stylecolor'] ) ? '' : $option['stylecolor'] ) . $border_styles;
- $option_outer_styles .= "--row-options-count: {$row_options_count};";
- $option_outer_styles = empty( $option_outer_styles ) ? '' : "style='" . esc_attr( $option_outer_styles ) . "'";
+ $option_outer_styles = ( empty( $option['stylecolor'] ) ? '' : $option['stylecolor'] ) . $border_styles;
+ $option_outer_styles .= "--row-options-count: {$row_options_count};";
+ $option_outer_styles = empty( $option_outer_styles ) ? '' : "style='" . esc_attr( $option_outer_styles ) . "'";
- $field .= "
";
+ $field .= "
";
- $default_classes = 'jetpack-field jetpack-input-image-option';
- $option_styles = empty( $option['style'] ) ? '' : "style='" . esc_attr( $option['style'] ) . "'";
- $option_classes = "class='" . ( empty( $option['class'] ) ? $default_classes : $default_classes . ' ' . $option['class'] ) . "'";
+ $default_classes = 'jetpack-field jetpack-input-image-option';
+ $option_styles = empty( $option['style'] ) ? '' : "style='" . esc_attr( $option['style'] ) . "'";
+ $option_classes = "class='" . ( empty( $option['class'] ) ? $default_classes : $default_classes . ' ' . $option['class'] ) . "'";
- $field .= "
";
+ $field .= "
";
- $input_id = esc_attr( $option_id );
+ $input_id = esc_attr( $option_id );
- $context = array(
- 'inputId' => $input_id,
- );
- $interactivity_attrs = ' data-wp-interactive="jetpack/form" ' . wp_interactivity_data_wp_context( $context ) . ' ';
-
- $field .= "
";
- $field .= " ';
-
- $field .= $rendered_image_block;
- $field .= '
';
-
- $field .= "
';
- }
+ $context = array(
+ 'inputId' => $input_id,
+ );
+ $interactivity_attrs = ' data-wp-interactive="jetpack/form" ' . wp_interactivity_data_wp_context( $context ) . ' ';
+
+ $field .= "
";
+ $field .= " ';
+
+ $field .= $rendered_image_block;
+ $field .= '
';
+
+ $field .= "
';
}
$field .= '';
@@ -2637,7 +2635,7 @@ private function maybe_override_type() {
public function is_field_renderable( $type ) {
// Check that radio, select, multiple choice, and image select
// fields have at least one valid option.
- if ( $type === 'radio' || $type === 'checkbox-multiple' || $type === 'select' || $type === 'image-select' ) {
+ if ( $type === 'radio' || $type === 'checkbox-multiple' || $type === 'select' ) {
$options = (array) $this->get_attribute( 'options' );
$non_empty_options = array_filter(
$options,
@@ -2648,16 +2646,11 @@ function ( $option ) {
return count( $non_empty_options ) > 0;
}
- // File field requires Jetpack to be active
- if ( $type === 'file' ) {
- /**
- * Check if Jetpack is active for file uploads.
- *
- * @since 5.3.0
- *
- * @return bool
- */
- return apply_filters( 'jetpack_forms_is_file_field_renderable', defined( 'JETPACK__PLUGIN_DIR' ) );
+ if ( $type === 'image-select' ) {
+ $options_data = (array) $this->get_attribute( 'optionsdata' );
+ $trimmed_options_data = $this->trim_image_select_options( $options_data );
+
+ return ! empty( $trimmed_options_data );
}
return true;
diff --git a/projects/packages/forms/tests/php/contact-form/Feedback_Test.php b/projects/packages/forms/tests/php/contact-form/Feedback_Test.php
index c99e04598ed08..ad35b29303a54 100644
--- a/projects/packages/forms/tests/php/contact-form/Feedback_Test.php
+++ b/projects/packages/forms/tests/php/contact-form/Feedback_Test.php
@@ -1189,19 +1189,58 @@ public function test_get_all_values_with_image_select() {
$_post_data = Utility::get_post_request(
array(
'images' => array(
- '{"perceived":"B","selected":"B","label":"Test choice","showLabels":true,"image":{"id":null,"src":"https://www.example.com/test-choice.png"}}',
- '{"perceived":"C","selected":"C","label":"Another test choice","showLabels":true,"image":{"id":12346,"src":"https://www.example.com/another-test-choice.png"}}',
+ '{"perceived":"B","selected":"B","label":"Choice B","showLabels":true,"image":{"id":null,"src":"https://www.example.com/choice-b.png"}}',
+ '{"perceived":"C","selected":"C","label":"Choice C","showLabels":true,"image":{"id":12346,"src":"https://www.example.com/choice-c.png"}}',
),
),
'g' . $form_id
);
+ // Helper function to create image block data for optionsdata
+ $create_image_block = function ( $url, $alt ) {
+ return array(
+ 'blockName' => 'core/image',
+ 'attrs' => array(
+ 'url' => $url,
+ 'alt' => $alt,
+ 'scale' => 'cover',
+ 'aspectRatio' => '1',
+ ),
+ 'innerHTML' => "
",
+ 'innerContent' => array( "
" ),
+ );
+ };
+
+ $optionsdata = Contact_Form::esc_shortcode_val(
+ wp_json_encode(
+ array(
+ array(
+ 'letter' => 'A',
+ 'label' => 'Choice A',
+ 'image' => $create_image_block( 'https://www.example.com/choice-a.png', 'Choice A' ),
+ ),
+ array(
+ 'letter' => 'B',
+ 'label' => 'Choice B',
+ 'image' => $create_image_block( 'https://www.example.com/choice-b.png', 'Choice B' ),
+ ),
+ array(
+ 'letter' => 'C',
+ 'label' => 'Choice C',
+ 'image' => $create_image_block( 'https://www.example.com/choice-c.png', 'Choice C' ),
+ ),
+ )
+ )
+ );
+
+ $shortcode = "[contact-field type=\"image-select\" label=\"Images\" isMultiple=\"1\" options=\"A,B,C\" showLabels=\"1\" optionsdata=\"{$optionsdata}\" /]";
+
$form = new Contact_Form(
array(
'title' => 'Test Form',
'description' => 'This is a test form.',
),
- "[contact-field type='image-select' label='Images' isMultiple='1' options='A,B,C' showLabels='1' /]"
+ $shortcode
);
$expected_images = array(
@@ -1210,21 +1249,21 @@ public function test_get_all_values_with_image_select() {
array(
'perceived' => 'B',
'selected' => 'B',
- 'label' => 'Test choice',
+ 'label' => 'Choice B',
'showLabels' => true,
'image' => array(
'id' => null,
- 'src' => 'https://www.example.com/test-choice.png',
+ 'src' => 'https://www.example.com/choice-b.png',
),
),
array(
'perceived' => 'C',
'selected' => 'C',
- 'label' => 'Another test choice',
+ 'label' => 'Choice C',
'showLabels' => true,
'image' => array(
'id' => 12346,
- 'src' => 'https://www.example.com/another-test-choice.png',
+ 'src' => 'https://www.example.com/choice-c.png',
),
),
),