PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.26.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.26.1
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.26.1, at classes/models/fields/FrmFieldName.php

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