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

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