PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.12.8
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.12.8
2.12.8 2.12.7 2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 All 98 releases
← All changes | inc/fields/dropdown-markup.php +75 -12 2.8.2 → 2.12.8 View file →
@@ -10,8 +10,9 @@
10 10
11 11 require SRFM_DIR . 'modules/gutenberg/classes/class-spec-gb-helper.php';
12 12
13 13 use Spec_Gb_Helper;
14 +use SRFM\Inc\Compatibility\Multilingual\String_Translator;
14 15 use SRFM\Inc\Helper;
15 16 use SRFM\Inc\Smart_Tags;
16 17
17 18 if ( ! defined( 'ABSPATH' ) ) {
@@ -102,11 +103,14 @@
102 103 } elseif ( ! empty( $original_placeholder ) ) {
103 104 $this->placeholder = $original_placeholder;
104 105 }
105 106
106 - // Translate the default placeholder text for frontend display.
107 + // Translate the default placeholder text for frontend display. Routed through
108 + // the multilingual provider (not just the textdomain) so it is translated on
109 + // WPML/Polylang sites too — the default placeholder is not serialized into
110 + // block markup, so it never reaches the per-form string package.
107 111 if ( 'Select an option' === $this->placeholder ) {
108 - $this->placeholder = __( 'Select an option', 'sureforms' );
112 + $this->placeholder = String_Translator::get_instance()->translate_validation_message( 'srfm_dropdown_placeholder', __( 'Select an option', 'sureforms' ) );
109 113 }
110 114
111 115 $this->show_values = apply_filters( 'srfm_show_options_values', false, $attributes['showValues'] ?? false );
112 116
@@ -129,10 +133,10 @@
129 133 <fieldset>
130 134 <input class="srfm-input-<?php echo esc_attr( $this->slug ); ?>-hidden" data-required="<?php echo esc_attr( $this->data_require_attr ); ?>" aria-required="<?php echo esc_attr( $this->data_require_attr ); ?>" <?php echo wp_kses_post( $this->data_attribute_markup() ); ?> name="srfm-<?php echo esc_attr( $this->unique_slug ); ?>-<?php echo esc_attr( $this->block_id ); ?><?php echo esc_attr( $this->field_name ); ?>" type="hidden" value=""/>
131 135 <legend class="srfm-block-legend">
132 136 <?php echo wp_kses_post( $this->label_markup ); ?>
133 - <?php echo wp_kses_post( $this->help_markup ); ?>
134 137 </legend>
138 + <?php echo wp_kses_post( $this->help_markup ); ?>
135 139 <div class="srfm-block-wrap srfm-dropdown-common-wrap">
136 140 <?php
137 141 if ( is_array( $this->options ) ) {
138 142 ?>
@@ -190,15 +194,34 @@
190 194
191 195 /**
192 196 * Resolve dynamic default value from smart tags and override preselected options.
193 197 *
198 + * Single-select dropdowns match the resolved value as a single trimmed
199 + * string, so labels that legitimately contain delimiter characters
200 + * (commas, pipes, etc.) still match.
201 + *
202 + * Multi-select dropdowns split the resolved value on the pipe character
203 + * (`|`) and match every segment (for example "{get_input:a}|{get_input:b}"
204 + * resolving to "Red|Blue", or a single `{get_input:colors}` smart tag with
205 + * URL `?colors=Red|Blue`). The same pipe split applies to multi-character
206 + * resolved values from `{get_input:...}` and `{get_cookie:...}`, so cookie
207 + * payloads that contain pipes are treated as multi-value in multi-select
208 + * mode.
209 + *
210 + * When the `Add Numeric Values to Options` (showValues) setting is on,
211 + * each segment is also compared against the option's `value`.
212 + *
194 213 * @param array<mixed> $attributes Block attributes.
195 214 * @since 2.8.1
215 + * @since 2.10.0 Added multi-select (pipe-delimited) value matching.
196 216 * @return void
197 217 */
198 218 protected function resolve_dynamic_default( $attributes ) {
199 - $dynamic_default = is_string( $attributes['dynamicDefaultValue'] ?? '' ) ? $attributes['dynamicDefaultValue'] : '';
200 - if ( empty( $dynamic_default ) || ! empty( $attributes['multiSelect'] ) ) {
219 + // Coalesce first so blocks saved before this attribute existed (pre-2.10.0)
220 + // don't trigger an "Undefined array key" warning on every frontend render.
221 + $raw_default = $attributes['dynamicDefaultValue'] ?? '';
222 + $dynamic_default = is_string( $raw_default ) ? $raw_default : '';
223 + if ( empty( $dynamic_default ) ) {
201 224 return;
202 225 }
203 226
204 227 $smart_tags = new Smart_Tags();
@@ -203,23 +226,63 @@
203 226
204 227 $smart_tags = new Smart_Tags();
205 228 $resolved = $smart_tags->process_smart_tags( $dynamic_default );
206 229
207 - if ( empty( $resolved ) || ! is_string( $resolved ) ) {
230 + if ( empty( $resolved ) || ! is_string( $resolved ) || ! is_array( $this->options ) ) {
208 231 return;
209 232 }
210 233
211 - $resolved = trim( $resolved );
234 + // START: multi-value dynamic default resolution.
235 + $is_multi_select = ! empty( $attributes['multiSelect'] );
212 236
213 - if ( is_array( $this->options ) ) {
237 + if ( $is_multi_select ) {
238 + $segments = array_filter(
239 + array_map( 'trim', explode( '|', $resolved ) ),
240 + static function ( $segment ) {
241 + return '' !== $segment;
242 + }
243 + );
244 + // Cap segments to avoid pathological URLs (e.g. ?colors=|||||...) producing thousands of comparisons.
245 + $segments = array_slice( $segments, 0, 50 );
246 + } else {
247 + $trimmed = trim( $resolved );
248 + $segments = '' === $trimmed ? [] : [ $trimmed ];
249 + }
250 +
251 + if ( empty( $segments ) ) {
252 + return;
253 + }
254 +
255 + $match_value_too = ! empty( $attributes['showValues'] );
256 + $matching_indices = [];
257 +
258 + foreach ( $segments as $segment ) {
214 259 foreach ( $this->options as $i => $option ) {
215 - $option_label = is_array( $option ) ? ( $option['label'] ?? '' ) : '';
216 - if ( strcasecmp( $option_label, $resolved ) === 0 ) {
217 - $this->preselected_options = [ $i ];
218 - return;
260 + if ( ! is_array( $option ) || in_array( $i, $matching_indices, true ) ) {
261 + continue;
219 262 }
263 +
264 + $option_label = isset( $option['label'] ) && is_scalar( $option['label'] ) ? (string) $option['label'] : '';
265 + $raw_value = $option['value'] ?? '';
266 + $option_value = $match_value_too && is_scalar( $raw_value ) ? (string) $raw_value : '';
267 +
268 + $is_match = ( '' !== $option_label && strcasecmp( $option_label, $segment ) === 0 )
269 + || ( $match_value_too && '' !== $option_value && strcasecmp( $option_value, $segment ) === 0 );
270 +
271 + if ( $is_match ) {
272 + $matching_indices[] = $i;
273 + if ( ! $is_multi_select ) {
274 + break 2;
275 + }
276 + break;
277 + }
220 278 }
221 279 }
280 +
281 + if ( ! empty( $matching_indices ) ) {
282 + $this->preselected_options = $is_multi_select ? $matching_indices : [ $matching_indices[0] ];
283 + }
284 + // END: multi-value dynamic default resolution.
222 285 }
223 286
224 287 /**
225 288 * Data attribute markup for min and max value