Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Forms: Update data processing and UI for image select field
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import './editor.scss';
*/
import type { Block, BlockEditorStoreSelect } from '../../types';

const showOtherOption = false;

export default function ImageSelectFieldEdit( props ) {
const { attributes, clientId, isSelected, setAttributes, name } = props;
const { id, required, width } = attributes;
Expand Down Expand Up @@ -151,7 +153,7 @@ export default function ImageSelectFieldEdit( props ) {
/>
),
},
{
showOtherOption && {
index: 5,
element: (
<ToggleControl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@
width: calc(( 1 / 2 ) * 100% - var(--jetpack-field-image-options-gap) * ( 1 / 2 ));
}
}

div.wp-block.jetpack-input-image-option.jetpack-field {
margin: 0;
}
13 changes: 8 additions & 5 deletions projects/packages/forms/src/blocks/field-image-select/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
figure.wp-block-image {
margin: 0 !important;
padding: 0 !important;
position: relative;

img {
max-width: 100% !important;
width: 100% !important;
margin: 0 !important;
}
}

Expand All @@ -32,6 +35,10 @@ figure.wp-block-image {
&.is-supersized {
width: calc(( 1 / 2 ) * 100% - var(--jetpack-field-image-options-gap) * ( 1 / 2 ));
}

.jetpack-input-image-option {
width: 100%;
}
}

.jetpack-input-image-option {
Expand All @@ -47,7 +54,6 @@ figure.wp-block-image {
}

.jetpack-input-image-option__wrapper {
width: 100%;
overflow: hidden;
position: relative;

Expand All @@ -60,6 +66,7 @@ figure.wp-block-image {
color: currentColor;
outline-offset: 1px;
border-radius: 4px;
z-index: 1;

&:checked {
background-color: currentColor;
Expand Down Expand Up @@ -91,10 +98,6 @@ figure.wp-block-image {
}
}

figure {
margin: 0;
}

figcaption {

@extend %visually-hidden;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,16 +433,24 @@ function ( $option ) {
}
);

// For single selection (radio), check if the value is in the options
// For single selection (radio), check if the selected value is in the options
if ( ! $this->get_attribute( 'ismultiple' ) ) {
if ( ! in_array( $field_value, $non_empty_options, true ) ) {
// Decode the JSON response to get the selected value
$decoded_value = json_decode( $field_value, true );
$selected_value = $decoded_value['selected'] ?? '';

if ( ! in_array( $selected_value, $non_empty_options, true ) ) {
/* translators: %s is the name of a form field */
$this->add_error( sprintf( __( '%s requires a valid selection.', 'jetpack-forms' ), $field_label ) );
}
} else {
// For multiple selection (checkbox), check each selected value
foreach ( $field_value as $field_value_item ) {
if ( ! in_array( $field_value_item, $non_empty_options, true ) ) {
// Decode the JSON response to get the selected value
$decoded_item = json_decode( $field_value_item, true );
$selected_value = $decoded_item['selected'] ?? '';

if ( ! in_array( $selected_value, $non_empty_options, true ) ) {
/* translators: %s is the name of a form field */
$this->add_error( sprintf( __( '%s requires valid selections.', 'jetpack-forms' ), $field_label ) );
break;
Expand Down Expand Up @@ -1931,10 +1939,10 @@ public function render_image_select_field( $id, $label, $value, $class, $require

if ( ! empty( $options_data ) ) {
// Create a separate array of original letters in sequence (A, B, C...)
$original_letters = array();
$perceived_letters = array();

foreach ( $options_data as $option ) {
$original_letters[] = Contact_Form_Plugin::strip_tags( $option['letter'] );
$perceived_letters[] = Contact_Form_Plugin::strip_tags( $option['letter'] );
}

// Create a working copy of options for potential randomization
Expand All @@ -1946,11 +1954,37 @@ public function render_image_select_field( $id, $label, $value, $class, $require
}

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'] );
$option_value = $this->get_option_value( $this->get_attribute( 'values' ), $option_index, $option_letter );
$image_block = $option['image'];
$option_id = $id . '-' . sanitize_html_class( $option_value );
$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 = '';

if ( ! empty( $rendered_image_block ) ) {
if ( preg_match( '/<img[^>]+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;
}
}
} else {
$rendered_image_block = '<figure class="wp-block-image"><img src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" alt="" style="aspect-ratio:1;object-fit:cover"/></figure>';
}

$option_value = wp_json_encode(
array(
'perceived' => $perceived_letters[ $option_index ],
'selected' => $option_letter,
'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.
Expand Down Expand Up @@ -2002,11 +2036,11 @@ class='jetpack-input-image-option__input'
. ( $required ? "required aria-required='true'" : '' )
. '/> ';

$field .= render_block( $image_block );
$field .= $rendered_image_block;
$field .= '</div>';

$field .= "<div class='jetpack-input-image-option__label-wrapper'>";
$field .= "<div class='jetpack-input-image-option__label-code'>" . esc_html( $original_letters[ $option_index ] ) . '</div>';
$field .= "<div class='jetpack-input-image-option__label-code'>" . esc_html( $perceived_letters[ $option_index ] ) . '</div>';

$label_classes = 'jetpack-input-image-option__label';
$label_classes .= $show_labels ? '' : ' visually-hidden';
Expand Down
58 changes: 55 additions & 3 deletions projects/packages/forms/src/contact-form/class-contact-form.php
Original file line number Diff line number Diff line change
Expand Up @@ -896,8 +896,9 @@ private static function format_submission_data( $data ) {

foreach ( $data as $field_data ) {
$formatted_submission_data[] = array(
'label' => self::maybe_add_colon_to_label( $field_data['label'] ),
'value' => self::maybe_transform_value( $field_data['value'] ),
'label' => self::maybe_add_colon_to_label( $field_data['label'] ),
'value' => self::maybe_transform_value( $field_data['value'] ),
'images' => self::get_images( $field_data['value'] ),
);
}

Expand Down Expand Up @@ -969,6 +970,11 @@ private static function render_ajax_success_wrapper( $form, $submission_success
<div>
<div class="field-name" data-wp-text="context.submission.label" data-wp-bind--hidden="!context.submission.label"></div>
<div class="field-value" data-wp-text="context.submission.value"></div>
<div class="field-images" data-wp-bind--hidden="!context.submission.images">
<template data-wp-each--image="context.submission.images">
<img class="field-image" data-wp-bind--src="context.image" />
</template>
</div>
</div>
</template>';

Expand All @@ -977,7 +983,17 @@ private static function render_ajax_success_wrapper( $form, $submission_success
$html .= '<div data-wp-each-child>
<div class="field-name" data-wp-text="context.submission.label" data-wp-bind--hidden="!context.submission.label">' . $submission['label'] . '</div>
<div class="field-value" data-wp-text="context.submission.value">' . $submission['value'] . '</div>
</div>';
<div class="field-images" data-wp-bind--hidden="!context.submission.images">';

if ( $submission['images'] ) {
foreach ( $submission['images'] ?? array() as $image ) {
$html .= '<img data-wp-each-child class="field-image" data-wp-bind--src="context.image" src="' . $image . '" />';
}
} else {
$html .= '<template data-wp-each--image="context.submission.images"></template>';
}

$html .= '</div></div>';
}
}

Expand Down Expand Up @@ -1467,6 +1483,9 @@ public static function get_default_label_from_type( $type ) {
case 'time':
$str = __( 'Time', 'jetpack-forms' );
break;
case 'image-select':
$str = __( 'Select an image', 'jetpack-forms' );
break;
default:
$str = null;
}
Expand Down Expand Up @@ -2454,6 +2473,18 @@ private static function maybe_add_colon_to_label( $label ) {
* @return mixed The transformed value.
*/
private static function maybe_transform_value( $value ) {
if ( is_array( $value ) && isset( $value['type'] ) && $value['type'] === 'image-select' ) {
return implode(
', ',
array_map(
function ( $choice ) {
return $choice['perceived'];
},
$value['choices']
)
);
}

// For file upload fields, we want to show the file name and size
if ( is_array( $value ) && isset( $value['name'] ) && isset( $value['size'] ) ) {
$file_name = $value['name'];
Expand All @@ -2464,6 +2495,27 @@ private static function maybe_transform_value( $value ) {
return $value;
}

/**
* Helper method to get the images from an image select field.
*
* @param array $value The value to get the images from.
* @return array The images.
*/
private static function get_images( $value ) {
if ( is_array( $value ) && isset( $value['type'] ) && $value['type'] === 'image-select' ) {
return array_map(
function ( $choice ) {
$src = $choice['image']['src'] ?? '';

return empty( $src ) ? 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' : $src;
},
$value['choices']
);
}

return null;
}

/**
* Helper method to format a raw label string for display, including kses sanitization.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,74 @@ public function get_render_value( $context = 'default' ) {
return $this->get_render_submit_value();
case 'api':
return $this->get_render_api_value();
case 'web': // For the post-submission page screen.
return $this->get_render_web_value();
case 'email':
return $this->get_render_email_value();
case 'ajax':
return $this->get_render_web_value(); // For now, we use the same value for ajax and web.
case 'csv':
return $this->get_render_csv_value();
case 'default':
default:
return $this->get_render_default_value();
}
}

/**
* Get the value of the field for rendering the CSV.
*
* @return string
*/
private function get_render_csv_value() {
if ( $this->is_of_type( 'image-select' ) ) {
return implode(
', ',
array_map(
function ( $choice ) {
return $choice['selected'];
},
$this->value['choices']
)
);
}

return $this->get_render_default_value();
}

/**
* Get the value of the field for rendering the post-submission page.
*
* @return string
*/
private function get_render_web_value() {
if ( $this->is_of_type( 'image-select' ) ) {
return $this->value;
}

return $this->get_render_default_value();
}

/**
* Get the value of the field for rendering the email.
*
* @return string
*/
private function get_render_email_value() {
if ( $this->is_of_type( 'image-select' ) ) {
$choices = array();

foreach ( $this->value['choices'] as $choice ) {
// On the email, we want to show the actual selected value, not the perceived value, as the options can be shuffled.
$choices[] = $choice['selected'];
}

return implode( ', ', $choices );
}

return $this->get_render_default_value();
}

/**
* Get the default value of the field for rendering.
*
Expand All @@ -168,6 +230,11 @@ private function get_render_default_value() {
return implode( ', ', $files );
}

if ( $this->is_of_type( 'image-select' ) ) {
// Return the array as is.
return $this->value;
}

if ( is_array( $this->value ) ) {
return implode( ', ', $this->value );
}
Expand All @@ -181,7 +248,6 @@ private function get_render_default_value() {
* @return string
*/
private function get_render_api_value() {

if ( $this->is_of_type( 'file' ) ) {
$files = array();
foreach ( $this->value['files'] as &$file ) {
Expand All @@ -200,6 +266,11 @@ private function get_render_api_value() {
return $this->value;
}

if ( $this->is_of_type( 'image-select' ) ) {
// Return the array as is.
return $this->value;
}

if ( is_array( $this->value ) ) {
// If the value is an array, we can return it as a JSON string.
return implode( ', ', $this->value );
Expand Down
Loading
Loading