From 74384e8f885ddee0e028dd4673e977005f820c7d Mon Sep 17 00:00:00 2001 From: Douglas Date: Fri, 17 Oct 2025 20:51:07 -0300 Subject: [PATCH 1/3] fix field renderable status --- .../contact-form/class-contact-form-field.php | 229 +++++++++--------- 1 file changed, 111 insertions(+), 118 deletions(-) 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 .= "
"; - $field .= "
" . esc_html( $perceived_letters[ $option_index ] ) . '
'; - - $label_classes = 'jetpack-input-image-option__label'; - $label_classes .= $show_labels ? '' : ' visually-hidden'; - $field .= "" . esc_html( $option_label ) . ''; - $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 .= "
" . esc_html( $perceived_letters[ $option_index ] ) . '
'; + + $label_classes = 'jetpack-input-image-option__label'; + $label_classes .= $show_labels ? '' : ' visually-hidden'; + $field .= "" . esc_html( $option_label ) . ''; + $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; From a1e1a65e606c6b695df00d67fe691148577153f1 Mon Sep 17 00:00:00 2001 From: Douglas Date: Fri, 17 Oct 2025 20:52:16 -0300 Subject: [PATCH 2/3] changelog --- .../forms/changelog/update-forms-image-select-no-options | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 projects/packages/forms/changelog/update-forms-image-select-no-options 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 From a0efa6a670f358592eb42824991b99f318427f65 Mon Sep 17 00:00:00 2001 From: Douglas Date: Fri, 17 Oct 2025 22:17:08 -0300 Subject: [PATCH 3/3] fix test --- .../tests/php/contact-form/Feedback_Test.php | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) 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' => "\"{$alt}\"", + 'innerContent' => array( "\"{$alt}\"" ), + ); + }; + + $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', ), ), ),