PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.29
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.29
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / models / fields / FrmFieldName.php

FrmFieldName.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.29, at classes/models/fields/FrmFieldName.php

362 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Name field
4 *
5 * @package Formidable
6 *
7 * @since 4.11
8 */
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 die( 'You are not allowed to call this page directly.' );
12 }
13
14 class FrmFieldName extends FrmFieldCombo {
15
16 /**
17 * Track the first name field ID in forms.
18 *
19 * @var array Array with keys are form ID and values are name field IDs.
20 */
21 private static $first_name_field_ids = array();
22
23 /**
24 * Field name.
25 *
26 * @var string
27 *
28 * @since 3.0
29 */
30 protected $type = 'name';
31
32 /**
33 * Could this field hold email values?
34 *
35 * @var bool
36 *
37 * @since 3.0
38 */
39 protected $holds_email_values = true;
40
41 /**
42 * @param array|int|object $field
43 * @param string $type
44 */
45 public function __construct( $field = 0, $type = '' ) {
46 parent::__construct( $field, $type );
47
48 $this->register_sub_fields(
49 array(
50 'first' => __( 'First Name', 'formidable' ),
51 'middle' => __( 'Middle Name', 'formidable' ),
52 'last' => __( 'Last Name', 'formidable' ),
53 )
54 );
55 }
56
57 /**
58 * Gets processed sub fields.
59 * This should return the list of sub fields after sorting or show/hide based of some options.
60 *
61 * @return array
62 */
63 protected function get_processed_sub_fields() {
64 $name_layout = $this->get_name_layout();
65 $names = explode( '_', $name_layout );
66 $col_class = 'frm' . intval( 12 / count( $names ) );
67 $result = array();
68
69 foreach ( $names as $name ) {
70 if ( empty( $this->sub_fields[ $name ] ) ) {
71 continue;
72 }
73
74 if ( ! isset( $this->sub_fields[ $name ]['wrapper_classes'] ) ) {
75 $this->sub_fields[ $name ]['wrapper_classes'] = $col_class;
76 } elseif ( is_array( $this->sub_fields[ $name ]['wrapper_classes'] ) ) {
77 $this->sub_fields[ $name ]['wrapper_classes'] = implode( ' ', $this->sub_fields[ $name ]['wrapper_classes'] ) . ' ' . $col_class;
78 } else {
79 $this->sub_fields[ $name ]['wrapper_classes'] .= ' ' . $col_class;
80 }
81
82 $result[ $name ] = $this->sub_fields[ $name ];
83 }
84
85 return $result;
86 }
87
88 /**
89 * Gets name layout option value.
90 *
91 * @return string
92 */
93 protected function get_name_layout() {
94 $name_layout = FrmField::get_option( $this->field, 'name_layout' );
95 return $name_layout ? $name_layout : 'first_last';
96 }
97
98 /**
99 * Gets extra field options.
100 *
101 * @return string[]
102 */
103 protected function extra_field_opts() {
104 $extra_options = parent::extra_field_opts();
105
106 $extra_options['name_layout'] = 'first_last';
107
108 // Default desc.
109 foreach ( $this->sub_fields as $name => $sub_field ) {
110 $extra_options[ $name . '_desc' ] = $sub_field['label'];
111 }
112
113 return $extra_options;
114 }
115
116 /**
117 * Shows primary options.
118 *
119 * @since 4.0
120 *
121 * @param array $args Includes 'field', 'display', and 'values'.
122 *
123 * @return void
124 */
125 public function show_primary_options( $args ) {
126 $field = (array) $args['field'];
127 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/name/primary-options.php';
128
129 parent::show_primary_options( $args );
130 }
131
132 /**
133 * Prepares the display value.
134 * This also handles the shortcode output. Support [id], [id show=first], [id show=last], [id show=middle].
135 *
136 * @param mixed $value Field value before processing.
137 * @param array $atts Shortcode attributes.
138 *
139 * @return string Most of cases, this will return string.
140 */
141 protected function prepare_display_value( $value, $atts ) {
142 if ( ! is_array( $value ) ) {
143 return $value;
144 }
145
146 if ( ! empty( $atts['show'] ) ) {
147 return $value[ $atts['show'] ] ?? '';
148 }
149
150 $name_layout = $this->get_name_layout();
151
152 $value = wp_parse_args(
153 $value,
154 array(
155 'first' => '',
156 'middle' => '',
157 'last' => '',
158 )
159 );
160
161 switch ( $name_layout ) {
162 case 'last_first':
163 $value = $value['last'] . ' ' . $value['first'];
164 break;
165
166 case 'first_middle_last':
167 $value = $value['first'] . ' ' . $value['middle'] . ' ' . $value['last'];
168 break;
169
170 default:
171 $value = $value['first'] . ' ' . $value['last'];
172 }
173
174 return trim( $value );
175 }
176
177 /**
178 * @since 4.0.04
179 *
180 * @param array|string $value
181 *
182 * @return void
183 */
184 public function sanitize_value( &$value ) {
185 FrmAppHelper::sanitize_value( 'sanitize_text_field', $value );
186 }
187
188 /**
189 * Validate field.
190 *
191 * @param array $args Arguments. Includes `errors`, `value`.
192 *
193 * @return array Errors array.
194 */
195 public function validate( $args ) {
196 /**
197 * If users fill just HTML tag, it passes the validation but value is empty in the database because of the
198 * sanitization. So we need to sanitize the value before validating.
199 */
200 $this->sanitize_value( $args['value'] );
201 return parent::validate( $args );
202 }
203
204 /**
205 * Loads processed args for field output.
206 *
207 * @param array $args {
208 * Arguments.
209 *
210 * @type array $field Field array.
211 * @type string $html_id HTML ID.
212 * @type string $field_name Field name attribute.
213 * @type array $shortcode_atts Shortcode attributes.
214 * @type array $errors Field errors.
215 * @type bool $remove_names Remove name attribute or not.
216 * }
217 *
218 * @return void
219 */
220 protected function process_args_for_field_output( &$args ) {
221 parent::process_args_for_field_output( $args );
222
223 // Show all subfields in form builder then use JS to show or hide them.
224 if ( ! $this->should_print_hidden_sub_fields() || count( $args['sub_fields'] ) === count( $this->sub_fields ) ) {
225 return;
226 }
227
228 $hidden_fields = array_diff_key( $this->sub_fields, $args['sub_fields'] );
229 $args['sub_fields'] = $this->sub_fields;
230
231 foreach ( $hidden_fields as $name => $hidden_field ) {
232 $args['sub_fields'][ $name ]['wrapper_classes'] .= ' frm_hidden';
233 }
234 }
235
236 /**
237 * Checks if should print hidden subfields and hide them. This is useful to use js to show or hide sub fields.
238 *
239 * @return bool
240 */
241 protected function should_print_hidden_sub_fields() {
242 // phpcs:ignore WordPress.Security.NonceVerification.Missing
243 return FrmAppHelper::is_form_builder_page() || FrmAppHelper::doing_ajax() && isset( $_POST['action'] ) && 'frm_insert_field' === $_POST['action'];
244 }
245
246 /**
247 * Gets inputs container attributes.
248 *
249 * @return array
250 */
251 protected function get_inputs_container_attrs() {
252 $attrs = parent::get_inputs_container_attrs();
253
254 $attrs['data-name-layout'] = $this->get_name_layout();
255 return $attrs;
256 }
257
258 /**
259 * Maybe show a warning if a name field is using a description that is not descriptive enough.
260 * Prior to version 6.16, First and Last were the default values, but this has been updated to
261 * improve accessibility.
262 *
263 * @since 6.16
264 *
265 * @param array $args
266 *
267 * @return void
268 */
269 public function show_after_default( $args ) {
270 echo '<div class="frm-mt-xs">';
271 parent::show_after_default( $args );
272 echo '</div>';
273
274 /**
275 * @var array $field
276 */
277 $field = $args['field'];
278
279 $show_warning = false;
280
281 foreach ( $this->sub_fields as $sub_field ) {
282 $description = FrmField::get_option( $field, $sub_field['name'] . '_desc' );
283
284 if ( in_array( $description, array( 'First', 'Last' ), true ) ) {
285 $show_warning = true;
286 break;
287 }
288 }
289
290 if ( ! $show_warning ) {
291 return;
292 }
293 // phpcs:disable Generic.WhiteSpace.ScopeIndent
294 ?>
295 <div class="frm_warning_style">
296 <?php
297 FrmAppHelper::icon_by_class( 'frmfont frm_alert_icon', array( 'style' => 'width:24px' ) );
298 echo ' ';
299 esc_html_e( 'Subfield descriptions are read by screen readers. Enhance accessibility by using complete labels, like "First Name" instead of "First".', 'formidable' );
300 ?>
301 </div>
302 <?php
303 // phpcs:enable Generic.WhiteSpace.ScopeIndent
304 }
305
306 /**
307 * Tracks the first name field ID in a form.
308 *
309 * @since 6.26
310 *
311 * @param object[] $fields Array of fields in a form.
312 *
313 * @return void
314 */
315 public static function track_first_name_field( $fields ) {
316 foreach ( $fields as $field ) {
317 if ( 'name' === $field->type ) {
318 self::$first_name_field_ids[ $field->form_id ] = $field->id;
319 return;
320 }
321 }
322 }
323
324 /**
325 * Gets subfield input attributes.
326 *
327 * @since 6.26
328 *
329 * @param array $sub_field Subfield data.
330 * @param array $args Field output args. See {@see FrmFieldCombo::load_field_output()}.
331 *
332 * @return array
333 */
334 protected function get_sub_field_input_attrs( $sub_field, $args ) {
335 $attrs = parent::get_sub_field_input_attrs( $sub_field, $args );
336 $form_id = (int) ( is_array( $args['field'] ) ? $args['field']['form_id'] : $args['field']->form_id );
337
338 if ( ! self::$first_name_field_ids || empty( self::$first_name_field_ids[ $form_id ] ) ) {
339 return $attrs;
340 }
341
342 $parent_form_id = (int) FrmField::get_option( $args['field'], 'parent_form_id' );
343
344 if ( $form_id !== $parent_form_id ) {
345 // Do not add autocomplete attribute to a name field inside repeater.
346 return $attrs;
347 }
348
349 $field_id = (int) ( is_array( $args['field'] ) ? $args['field']['id'] : $args['field']->id );
350
351 if ( intval( self::$first_name_field_ids[ $form_id ] ) === $field_id ) {
352 if ( 'first' === $sub_field['name'] ) {
353 $attrs['autocomplete'] = 'given-name';
354 } elseif ( 'last' === $sub_field['name'] ) {
355 $attrs['autocomplete'] = 'family-name';
356 }
357 }
358
359 return $attrs;
360 }
361 }
362