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 +101 -3 2.7.1 → 2.12.8 View file →
@@ -10,9 +10,11 @@
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;
16 +use SRFM\Inc\Smart_Tags;
15 17
16 18 if ( ! defined( 'ABSPATH' ) ) {
17 19 exit; // Exit if accessed directly.
18 20 }
@@ -84,8 +86,9 @@
84 86 $this->set_error_msg( $attributes, 'srfm_dropdown_block_required_text' );
85 87 $this->multi_select_attr = ! empty( $attributes['multiSelect'] ) ? 'true' : 'false';
86 88 $this->search_attr = ! empty( $attributes['searchable'] ) ? 'true' : 'false';
87 89 $this->preselected_options = $attributes['preselectedOptions'] ?? [];
90 + $this->resolve_dynamic_default( $attributes );
88 91 $this->set_markup_properties();
89 92 $this->set_aria_described_by();
90 93
91 94 // Store the original placeholder before set_label_as_placeholder modifies placeholder_attr.
@@ -100,11 +103,14 @@
100 103 } elseif ( ! empty( $original_placeholder ) ) {
101 104 $this->placeholder = $original_placeholder;
102 105 }
103 106
104 - // 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.
105 111 if ( 'Select an option' === $this->placeholder ) {
106 - $this->placeholder = __( 'Select an option', 'sureforms' );
112 + $this->placeholder = String_Translator::get_instance()->translate_validation_message( 'srfm_dropdown_placeholder', __( 'Select an option', 'sureforms' ) );
107 113 }
108 114
109 115 $this->show_values = apply_filters( 'srfm_show_options_values', false, $attributes['showValues'] ?? false );
110 116
@@ -127,10 +133,10 @@
127 133 <fieldset>
128 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=""/>
129 135 <legend class="srfm-block-legend">
130 136 <?php echo wp_kses_post( $this->label_markup ); ?>
131 - <?php echo wp_kses_post( $this->help_markup ); ?>
132 137 </legend>
138 + <?php echo wp_kses_post( $this->help_markup ); ?>
133 139 <div class="srfm-block-wrap srfm-dropdown-common-wrap">
134 140 <?php
135 141 if ( is_array( $this->options ) ) {
136 142 ?>
@@ -183,8 +189,100 @@
183 189 'is_editing' => $this->is_editing,
184 190 'attributes' => $this->attributes,
185 191 ]
186 192 );
193 + }
194 +
195 + /**
196 + * Resolve dynamic default value from smart tags and override preselected options.
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 + *
213 + * @param array<mixed> $attributes Block attributes.
214 + * @since 2.8.1
215 + * @since 2.10.0 Added multi-select (pipe-delimited) value matching.
216 + * @return void
217 + */
218 + protected function resolve_dynamic_default( $attributes ) {
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 ) ) {
224 + return;
225 + }
226 +
227 + $smart_tags = new Smart_Tags();
228 + $resolved = $smart_tags->process_smart_tags( $dynamic_default );
229 +
230 + if ( empty( $resolved ) || ! is_string( $resolved ) || ! is_array( $this->options ) ) {
231 + return;
232 + }
233 +
234 + // START: multi-value dynamic default resolution.
235 + $is_multi_select = ! empty( $attributes['multiSelect'] );
236 +
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 ) {
259 + foreach ( $this->options as $i => $option ) {
260 + if ( ! is_array( $option ) || in_array( $i, $matching_indices, true ) ) {
261 + continue;
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 + }
278 + }
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.
187 285 }
188 286
189 287 /**
190 288 * Data attribute markup for min and max value