PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 4.01.02
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v4.01.02
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 / FrmField.php

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

1,008 lines 28.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmField {
7
8 public static $use_cache = true;
9 public static $transient_size = 200;
10
11 public static function field_selection() {
12 $fields = array(
13 'text' => array(
14 'name' => __( 'Text', 'formidable' ),
15 'icon' => 'frm_icon_font frm_text2_icon',
16 ),
17 'textarea' => array(
18 'name' => __( 'Paragraph', 'formidable' ),
19 'icon' => 'frm_icon_font frm_paragraph_icon',
20 ),
21 'checkbox' => array(
22 'name' => __( 'Checkboxes', 'formidable' ),
23 'icon' => 'frm_icon_font frm_check_square_icon',
24 ),
25 'radio' => array(
26 'name' => __( 'Radio Buttons', 'formidable' ),
27 'icon' => 'frm_icon_font frm_radio_checked_icon',
28 ),
29 'select' => array(
30 'name' => __( 'Dropdown', 'formidable' ),
31 'icon' => 'frm_icon_font frm_caret_square_down_icon',
32 ),
33 'email' => array(
34 'name' => __( 'Email', 'formidable' ),
35 'icon' => 'frm_icon_font frm_email_icon',
36 ),
37 'url' => array(
38 'name' => __( 'Website/URL', 'formidable' ),
39 'icon' => 'frm_icon_font frm_link_icon',
40 ),
41 'number' => array(
42 'name' => __( 'Number', 'formidable' ),
43 'icon' => 'frm_icon_font frm_hashtag_icon',
44 ),
45 'phone' => array(
46 'name' => __( 'Phone', 'formidable' ),
47 'icon' => 'frm_icon_font frm_phone_icon',
48 ),
49 'html' => array(
50 'name' => __( 'HTML', 'formidable' ),
51 'icon' => 'frm_icon_font frm_code_icon',
52 ),
53 'hidden' => array(
54 'name' => __( 'Hidden Field', 'formidable' ),
55 'icon' => 'frm_icon_font frm_eye_slash_icon',
56 ),
57 'user_id' => array(
58 'name' => __( 'User ID', 'formidable' ),
59 'icon' => 'frm_icon_font frm_user_icon',
60 ),
61 'captcha' => array(
62 'name' => __( 'reCAPTCHA', 'formidable' ),
63 'icon' => 'frm_icon_font frm_shield_check_icon',
64 ),
65 );
66
67 return apply_filters( 'frm_available_fields', $fields );
68 }
69
70 public static function pro_field_selection() {
71 $fields = array(
72 'file' => array(
73 'name' => __( 'File Upload', 'formidable' ),
74 'icon' => 'frm_icon_font frm_upload_icon',
75 ),
76 'rte' => array(
77 'name' => __( 'Rich Text', 'formidable' ),
78 'icon' => 'frm_icon_font frm_align_right_icon',
79 ),
80 'date' => array(
81 'name' => __( 'Date', 'formidable' ),
82 'icon' => 'frm_icon_font frm_calendar_icon',
83 ),
84 'time' => array(
85 'name' => __( 'Time', 'formidable' ),
86 'icon' => 'frm_icon_font frm_clock_icon',
87 ),
88 'scale' => array(
89 'name' => __( 'Scale', 'formidable' ),
90 'icon' => 'frm_icon_font frm_linear_scale_icon',
91 ),
92 'star' => array(
93 'name' => __( 'Star Rating', 'formidable' ),
94 'icon' => 'frm_icon_font frm_star_icon',
95 ),
96 'range' => array(
97 'name' => __( 'Slider', 'formidable' ),
98 'icon' => 'frm_icon_font frm_code_commit_icon',
99 ),
100 'toggle' => array(
101 'name' => __( 'Toggle', 'formidable' ),
102 'icon' => 'frm_icon_font frm_toggle_on_icon',
103 ),
104 'data' => array(
105 'name' => __( 'Dynamic', 'formidable' ),
106 'icon' => 'frm_icon_font frm_sitemap_icon',
107 ),
108 'lookup' => array(
109 'name' => __( 'Lookup', 'formidable' ),
110 'icon' => 'frm_icon_font frm_search_icon',
111 ),
112 'divider|repeat' => array(
113 'name' => __( 'Repeater', 'formidable' ),
114 'icon' => 'frm_icon_font frm_repeater_icon',
115 ),
116 'end_divider' => array(
117 'name' => __( 'Section Buttons', 'formidable' ),
118 'switch_from' => 'divider',
119 ),
120 'divider' => array(
121 'name' => __( 'Section', 'formidable' ),
122 'icon' => 'frm_icon_font frm_header_icon',
123 ),
124 'break' => array(
125 'name' => __( 'Page Break', 'formidable' ),
126 'icon' => 'frm_icon_font frm_page_break_icon',
127 ),
128 'form' => array(
129 'name' => __( 'Embed Form', 'formidable' ),
130 'icon' => 'frm_icon_font frm_file_text_icon',
131 ),
132 'password' => array(
133 'name' => __( 'Password', 'formidable' ),
134 'icon' => 'frm_icon_font frm_lock_open_icon',
135 ),
136 'tag' => array(
137 'name' => __( 'Tags', 'formidable' ),
138 'icon' => 'frm_icon_font frm_price_tags_icon',
139 ),
140 'credit_card' => array(
141 'name' => __( 'Credit Card', 'formidable' ),
142 'icon' => 'frm_icon_font frm_credit_card_icon frm_show_upgrade',
143 'addon' => 'stripe',
144 ),
145 'address' => array(
146 'name' => __( 'Address', 'formidable' ),
147 'icon' => 'frm_icon_font frm_location_icon',
148 ),
149 'signature' => array(
150 'name' => __( 'Signature', 'formidable' ),
151 'icon' => 'frm_icon_font frm_signature_icon frm_show_upgrade',
152 'addon' => 'signature',
153 ),
154 'quiz_score' => array(
155 'name' => __( 'Quiz Score', 'formidable' ),
156 'icon' => 'frm_icon_font frm_percent_icon frm_show_upgrade',
157 'addon' => 'quizzes',
158 ),
159 );
160
161 // Since the signature field may be in a different section, don't show it twice.
162 $lite_fields = self::field_selection();
163 if ( isset( $lite_fields['signature'] ) ) {
164 unset( $fields['signature'] );
165 }
166
167 return apply_filters( 'frm_pro_available_fields', $fields );
168 }
169
170 /**
171 * @since 4.0
172 */
173 public static function all_field_selection() {
174 $pro_field_selection = self::pro_field_selection();
175 return array_merge( $pro_field_selection, self::field_selection() );
176 }
177
178 public static function create( $values, $return = true ) {
179 global $wpdb, $frm_duplicate_ids;
180
181 $new_values = array();
182 $key = isset( $values['field_key'] ) ? $values['field_key'] : $values['name'];
183 $new_values['field_key'] = FrmAppHelper::get_unique_key( $key, $wpdb->prefix . 'frm_fields', 'field_key' );
184
185 foreach ( array( 'name', 'description', 'type', 'default_value' ) as $col ) {
186 $new_values[ $col ] = $values[ $col ];
187 }
188
189 $new_values['options'] = $values['options'];
190
191 $new_values['field_order'] = isset( $values['field_order'] ) ? (int) $values['field_order'] : null;
192 $new_values['required'] = isset( $values['required'] ) ? (int) $values['required'] : 0;
193 $new_values['form_id'] = isset( $values['form_id'] ) ? (int) $values['form_id'] : null;
194 $new_values['field_options'] = $values['field_options'];
195 $new_values['created_at'] = current_time( 'mysql', 1 );
196
197 if ( isset( $values['id'] ) ) {
198 $frm_duplicate_ids[ $values['field_key'] ] = $new_values['field_key'];
199 $new_values = apply_filters( 'frm_duplicated_field', $new_values );
200 }
201
202 self::preserve_format_option_backslashes( $new_values );
203
204 foreach ( $new_values as $k => $v ) {
205 if ( is_array( $v ) ) {
206 $new_values[ $k ] = serialize( $v );
207 }
208 unset( $k, $v );
209 }
210
211 //if(isset($values['id']) and is_numeric($values['id']))
212 // $new_values['id'] = $values['id'];
213
214 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_fields', $new_values );
215 $new_id = 0;
216 if ( $query_results ) {
217 self::delete_form_transient( $new_values['form_id'] );
218 $new_id = $wpdb->insert_id;
219 }
220
221 if ( ! $return ) {
222 return false;
223 }
224
225 if ( $query_results ) {
226 if ( isset( $values['id'] ) ) {
227 $frm_duplicate_ids[ $values['id'] ] = $new_id;
228 }
229
230 return $new_id;
231 } else {
232 return false;
233 }
234 }
235
236 public static function duplicate( $old_form_id, $form_id, $copy_keys = false, $blog_id = false ) {
237 global $frm_duplicate_ids;
238
239 $where = array(
240 array(
241 'or' => 1,
242 'fi.form_id' => $old_form_id,
243 'fr.parent_form_id' => $old_form_id,
244 ),
245 );
246 $fields = self::getAll( $where, 'field_order', '', $blog_id );
247
248 foreach ( (array) $fields as $field ) {
249 $new_key = $copy_keys ? $field->field_key : '';
250 if ( $copy_keys && substr( $field->field_key, - 1 ) == 2 ) {
251 $new_key = rtrim( $new_key, 2 );
252 }
253
254 $values = array();
255 FrmFieldsHelper::fill_field( $values, $field, $form_id, $new_key );
256
257 // If this is a repeating section, create new form
258 if ( self::is_repeating_field( $field ) ) {
259 // create the repeatable form
260 $new_repeat_form_id = apply_filters(
261 'frm_create_repeat_form',
262 0,
263 array(
264 'parent_form_id' => $form_id,
265 'field_name' => $field->name,
266 )
267 );
268
269 // Save old form_select
270 $old_repeat_form_id = $field->field_options['form_select'];
271
272 // Update form_select for repeating field
273 $values['field_options']['form_select'] = $new_repeat_form_id;
274 }
275
276 // If this is a field inside of a repeating section, associate it with the correct form
277 if ( $field->form_id != $old_form_id && isset( $old_repeat_form_id ) && isset( $new_repeat_form_id ) && $field->form_id == $old_repeat_form_id ) {
278 $values['form_id'] = $new_repeat_form_id;
279 }
280
281 $values['description'] = FrmFieldsHelper::switch_field_ids( $values['description'] );
282
283 $values = apply_filters( 'frm_duplicated_field', $values );
284 $new_id = self::create( $values );
285 $frm_duplicate_ids[ $field->id ] = $new_id;
286 $frm_duplicate_ids[ $field->field_key ] = $new_id;
287 unset( $field );
288 }
289 }
290
291 public static function update( $id, $values ) {
292 global $wpdb;
293
294 $id = absint( $id );
295
296 if ( isset( $values['field_key'] ) ) {
297 $values['field_key'] = FrmAppHelper::get_unique_key( $values['field_key'], $wpdb->prefix . 'frm_fields', 'field_key', $id );
298 }
299
300 if ( isset( $values['required'] ) ) {
301 $values['required'] = (int) $values['required'];
302 }
303
304 self::preserve_format_option_backslashes( $values );
305
306 if ( isset( $values['type'] ) ) {
307 $values = apply_filters( 'frm_clean_' . $values['type'] . '_field_options_before_update', $values );
308
309 if ( $values['type'] == 'hidden' && isset( $values['field_options'] ) && isset( $values['field_options']['clear_on_focus'] ) ) {
310 // don't keep the old placeholder setting for hidden fields
311 $values['field_options']['clear_on_focus'] = 0;
312 }
313 }
314
315 // serialize array values
316 foreach ( array( 'default_value', 'field_options', 'options' ) as $opt ) {
317 if ( isset( $values[ $opt ] ) && is_array( $values[ $opt ] ) ) {
318 $values[ $opt ] = serialize( $values[ $opt ] );
319 }
320 }
321
322 $query_results = $wpdb->update( $wpdb->prefix . 'frm_fields', $values, array( 'id' => $id ) );
323
324 $form_id = 0;
325 if ( isset( $values['form_id'] ) ) {
326 $form_id = absint( $values['form_id'] );
327 } else {
328 $field = self::getOne( $id );
329 if ( $field ) {
330 $form_id = $field->form_id;
331 }
332 unset( $field );
333 }
334 unset( $values );
335
336 if ( $query_results ) {
337 wp_cache_delete( $id, 'frm_field' );
338 if ( $form_id ) {
339 self::delete_form_transient( $form_id );
340 }
341 }
342
343 return $query_results;
344 }
345
346 /**
347 * Keep backslashes in the phone format option
348 *
349 * @since 2.0.8
350 *
351 * @param $values array - pass by reference
352 */
353 private static function preserve_format_option_backslashes( &$values ) {
354 if ( isset( $values['field_options']['format'] ) ) {
355 $values['field_options']['format'] = FrmAppHelper::preserve_backslashes( $values['field_options']['format'] );
356 }
357 }
358
359 public static function destroy( $id ) {
360 global $wpdb;
361
362 do_action( 'frm_before_destroy_field', $id );
363
364 wp_cache_delete( $id, 'frm_field' );
365 $field = self::getOne( $id );
366 if ( ! $field ) {
367 return false;
368 }
369
370 self::delete_form_transient( $field->form_id );
371
372 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_item_metas WHERE field_id=%d', $id ) );
373
374 return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_fields WHERE id=%d', $id ) );
375 }
376
377 public static function delete_form_transient( $form_id ) {
378 $form_id = absint( $form_id );
379 delete_transient( 'frm_form_fields_' . $form_id . 'excludeinclude' );
380 delete_transient( 'frm_form_fields_' . $form_id . 'includeinclude' );
381 delete_transient( 'frm_form_fields_' . $form_id . 'includeexclude' );
382 delete_transient( 'frm_form_fields_' . $form_id . 'excludeexclude' );
383
384 global $wpdb;
385 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s', '_transient_timeout_frm_form_fields_' . $form_id . 'ex%', '_transient_frm_form_fields_' . $form_id . 'ex%', '_transient_timeout_frm_form_fields_' . $form_id . 'in%', '_transient_frm_form_fields_' . $form_id . 'in%' ) );
386
387 FrmDb::cache_delete_group( 'frm_field' );
388
389 $form = FrmForm::getOne( $form_id );
390 if ( $form && $form->parent_form_id && $form->parent_form_id != $form_id ) {
391 self::delete_form_transient( $form->parent_form_id );
392 }
393 }
394
395 /**
396 * If $field is numeric, get the field object
397 */
398 public static function maybe_get_field( &$field ) {
399 if ( ! is_object( $field ) ) {
400 $field = self::getOne( $field );
401 }
402 }
403
404 /**
405 * @param string|int $id The field id or key.
406 * @param bool $filter When true, run the frm_field filter.
407 */
408 public static function getOne( $id, $filter = false ) {
409 if ( empty( $id ) ) {
410 return null;
411 }
412
413 global $wpdb;
414
415 $where = is_numeric( $id ) ? 'id=%d' : 'field_key=%s';
416 $query = $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'frm_fields WHERE ' . $where, $id ); // WPCS: unprepared SQL ok.
417
418 $results = FrmDb::check_cache( $id, 'frm_field', $query, 'get_row', 0 );
419
420 if ( empty( $results ) ) {
421 self::filter_field( $filter, $results );
422 return $results;
423 }
424
425 if ( is_numeric( $id ) ) {
426 FrmDb::set_cache( $results->field_key, $results, 'frm_field' );
427 } elseif ( $results ) {
428 FrmDb::set_cache( $results->id, $results, 'frm_field' );
429 }
430
431 self::prepare_options( $results );
432 self::filter_field( $filter, $results );
433
434 return wp_unslash( $results );
435 }
436
437 /**
438 * @since 3.06.01
439 * @param bool $filter When true, run the frm_field filter.
440 * @param object $results
441 */
442 private static function filter_field( $filter, &$results ) {
443 if ( $filter ) {
444 /**
445 * @since 3.06.01
446 */
447 $results = apply_filters( 'frm_field', $results );
448 }
449 }
450
451 /**
452 * Get the field type by key or id
453 *
454 * @param int|string The field id or key
455 * @param mixed $col The name of the column in the fields database table
456 */
457 public static function get_type( $id, $col = 'type' ) {
458 $field = FrmDb::check_cache( $id, 'frm_field' );
459 if ( $field ) {
460 $type = $field->{$col};
461 } else {
462 $where = array(
463 'or' => 1,
464 'id' => $id,
465 'field_key' => $id,
466 );
467 $type = FrmDb::get_var( 'frm_fields', $where, $col );
468 }
469
470 return $type;
471 }
472
473 public static function get_all_types_in_form( $form_id, $type, $limit = '', $inc_sub = 'exclude' ) {
474 if ( ! $form_id ) {
475 return array();
476 }
477
478 $results = self::get_fields_from_transients(
479 $form_id,
480 array(
481 'inc_embed' => $inc_sub,
482 'inc_repeat' => $inc_sub,
483 )
484 );
485 if ( ! empty( $results ) ) {
486 $fields = array();
487 $count = 0;
488 foreach ( $results as $result ) {
489 if ( $type != $result->type ) {
490 continue;
491 }
492
493 $fields[ $result->id ] = $result;
494 $count ++;
495 if ( $limit == 1 ) {
496 $fields = $result;
497 break;
498 }
499
500 if ( ! empty( $limit ) && $count >= $limit ) {
501 break;
502 }
503
504 unset( $result );
505 }
506
507 return wp_unslash( $fields );
508 }
509
510 self::$use_cache = false;
511
512 $where = array(
513 'fi.form_id' => (int) $form_id,
514 'fi.type' => $type,
515 );
516 self::maybe_include_repeating_fields( $inc_sub, $where );
517 $results = self::getAll( $where, 'field_order', $limit );
518 self::$use_cache = true;
519 self::include_sub_fields( $results, $inc_sub, $type, $form_id );
520
521 return $results;
522 }
523
524 public static function get_all_for_form( $form_id, $limit = '', $inc_embed = 'exclude', $inc_repeat = 'include' ) {
525 if ( ! (int) $form_id ) {
526 return array();
527 }
528
529 $results = self::get_fields_from_transients( $form_id, compact( 'inc_embed', 'inc_repeat' ) );
530 if ( ! empty( $results ) ) {
531 if ( empty( $limit ) ) {
532 return $results;
533 }
534
535 $fields = array();
536 $count = 0;
537 foreach ( $results as $result ) {
538 $count ++;
539 $fields[ $result->id ] = $result;
540 if ( ! empty( $limit ) && $count >= $limit ) {
541 break;
542 }
543 }
544
545 return $fields;
546 }
547
548 self::$use_cache = false;
549
550 $where = array( 'fi.form_id' => absint( $form_id ) );
551 self::maybe_include_repeating_fields( $inc_repeat, $where );
552 $results = self::getAll( $where, 'field_order', $limit );
553
554 self::$use_cache = true;
555
556 self::include_sub_fields( $results, $inc_embed, 'all', $form_id );
557
558 if ( empty( $limit ) ) {
559 self::set_field_transient( $results, $form_id, 0, compact( 'inc_embed', 'inc_repeat' ) );
560 }
561
562 return $results;
563 }
564
565 /**
566 * If repeating fields should be included, adjust $where accordingly
567 *
568 * @param string $inc_repeat
569 * @param array $where - pass by reference
570 */
571 private static function maybe_include_repeating_fields( $inc_repeat, &$where ) {
572 if ( $inc_repeat == 'include' ) {
573 $form_id = $where['fi.form_id'];
574 $where[] = array(
575 'or' => 1,
576 'fi.form_id' => $form_id,
577 'fr.parent_form_id' => $form_id,
578 );
579 unset( $where['fi.form_id'] );
580 }
581 }
582
583 public static function include_sub_fields( &$results, $inc_embed, $type = 'all', $form_id = '' ) {
584 $no_sub_forms = empty( $results ) && $type === 'all';
585 if ( 'include' != $inc_embed || $no_sub_forms ) {
586 return;
587 }
588
589 $form_fields = $results;
590 $should_get_subforms = ( $type !== 'all' && $type !== 'form' && ! empty( $form_id ) );
591 if ( $should_get_subforms ) {
592 $form_fields = self::get_all_types_in_form( $form_id, 'form' );
593 }
594
595 $index_offset = 1;
596 foreach ( $form_fields as $k => $field ) {
597 if ( 'form' != $field->type || ! isset( $field->field_options['form_select'] ) ) {
598 continue;
599 }
600
601 if ( $type == 'all' ) {
602 $sub_fields = self::get_all_for_form( $field->field_options['form_select'] );
603 } else {
604 $sub_fields = self::get_all_types_in_form( $field->field_options['form_select'], $type );
605 }
606
607 if ( ! empty( $sub_fields ) ) {
608 $index = $k + $index_offset;
609 $index_offset += count( $sub_fields );
610 array_splice( $results, $index, 0, $sub_fields );
611 }
612 unset( $field, $sub_fields );
613 }
614 }
615
616 public static function getAll( $where = array(), $order_by = '', $limit = '', $blog_id = false ) {
617 $cache_key = maybe_serialize( $where ) . $order_by . 'l' . $limit . 'b' . $blog_id;
618 if ( self::$use_cache ) {
619 // make sure old cache doesn't get saved as a transient
620 $results = wp_cache_get( $cache_key, 'frm_field' );
621 if ( false !== $results ) {
622 return wp_unslash( $results );
623 }
624 }
625
626 global $wpdb;
627
628 if ( $blog_id && is_multisite() ) {
629 global $wpmuBaseTablePrefix;
630 if ( $wpmuBaseTablePrefix ) {
631 $prefix = $wpmuBaseTablePrefix . $blog_id . '_';
632 } else {
633 $prefix = $wpdb->get_blog_prefix( $blog_id );
634 }
635
636 $table_name = $prefix . 'frm_fields';
637 $form_table_name = $prefix . 'frm_forms';
638 } else {
639 $table_name = $wpdb->prefix . 'frm_fields';
640 $form_table_name = $wpdb->prefix . 'frm_forms';
641 }
642
643 if ( ! empty( $order_by ) && strpos( $order_by, 'ORDER BY' ) === false ) {
644 $order_by = ' ORDER BY ' . $order_by;
645 }
646
647 $limit = FrmDb::esc_limit( $limit );
648
649 $query = "SELECT fi.*, fr.name as form_name FROM {$table_name} fi LEFT OUTER JOIN {$form_table_name} fr ON fi.form_id=fr.id";
650 $query_type = ( $limit == ' LIMIT 1' || $limit == 1 ) ? 'row' : 'results';
651
652 if ( is_array( $where ) ) {
653 $args = array(
654 'order_by' => $order_by,
655 'limit' => $limit,
656 );
657 $results = FrmDb::get_var( $table_name . ' fi LEFT OUTER JOIN ' . $form_table_name . ' fr ON fi.form_id=fr.id', $where, 'fi.*, fr.name as form_name', $args, '', $query_type );
658 } else {
659 // if the query is not an array, then it has already been prepared
660 $query .= FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
661
662 $function_name = ( $query_type == 'row' ) ? 'get_row' : 'get_results';
663 $results = $wpdb->$function_name( $query );
664 }
665 unset( $where );
666
667 self::format_field_results( $results );
668
669 FrmDb::set_cache( $cache_key, $results, 'frm_field' );
670
671 return wp_unslash( $results );
672 }
673
674 /**
675 * @since 2.0.8
676 */
677 private static function format_field_results( &$results ) {
678 if ( is_array( $results ) ) {
679 foreach ( $results as $r_key => $result ) {
680 FrmDb::set_cache( $result->id, $result, 'frm_field' );
681 FrmDb::set_cache( $result->field_key, $result, 'frm_field' );
682
683 $results[ $r_key ]->field_options = maybe_unserialize( $result->field_options );
684 $results[ $r_key ]->options = maybe_unserialize( $result->options );
685 $results[ $r_key ]->default_value = maybe_unserialize( $result->default_value );
686
687 unset( $r_key, $result );
688 }
689 } elseif ( $results ) {
690 FrmDb::set_cache( $results->id, $results, 'frm_field' );
691 FrmDb::set_cache( $results->field_key, $results, 'frm_field' );
692
693 self::prepare_options( $results );
694 }
695 }
696
697 /**
698 * Unserialize all the serialized field data
699 *
700 * @since 2.0
701 */
702 private static function prepare_options( &$results ) {
703 $results->field_options = maybe_unserialize( $results->field_options );
704
705 $results->options = maybe_unserialize( $results->options );
706 $results->default_value = maybe_unserialize( $results->default_value );
707 }
708
709 /**
710 * If a form has too many fields, thay won't all save into a single transient.
711 * We'll break them into groups of 200
712 *
713 * @since 2.0.1
714 */
715 private static function get_fields_from_transients( $form_id, $args ) {
716 $fields = array();
717 self::get_next_transient( $fields, 'frm_form_fields_' . $form_id . $args['inc_embed'] . $args['inc_repeat'] );
718
719 return $fields;
720 }
721
722 /**
723 * Called by get_fields_from_transients
724 *
725 * @since 2.0.1
726 */
727 private static function get_next_transient( &$fields, $base_name, $next = 0 ) {
728 $name = $next ? $base_name . $next : $base_name;
729 $next_fields = get_transient( $name );
730
731 if ( $next_fields ) {
732 $fields = array_merge( $fields, $next_fields );
733
734 if ( count( $next_fields ) >= self::$transient_size ) {
735 // if this transient is full, check for another
736 $next ++;
737 self::get_next_transient( $fields, $base_name, $next );
738 }
739 }
740 }
741
742 /**
743 * Save the transients in chunks for large forms
744 *
745 * @since 2.0.1
746 */
747 private static function set_field_transient( &$fields, $form_id, $next = 0, $args = array() ) {
748 $base_name = 'frm_form_fields_' . $form_id . $args['inc_embed'] . $args['inc_repeat'];
749 $field_chunks = array_chunk( $fields, self::$transient_size );
750
751 foreach ( $field_chunks as $field ) {
752 $name = $next ? $base_name . $next : $base_name;
753 $set = set_transient( $name, $field, 60 * 60 * 6 );
754 if ( ! $set ) {
755 // the transient didn't save
756 if ( $name != $base_name ) {
757 // if the first saved an others fail, this will show an incmoplete form
758 self::delete_form_transient( $form_id );
759 }
760
761 return;
762 }
763
764 $next ++;
765 }
766 }
767
768 public static function is_no_save_field( $type ) {
769 return in_array( $type, self::no_save_fields() );
770 }
771
772 public static function no_save_fields() {
773 return array( 'divider', 'end_divider', 'captcha', 'break', 'html', 'form' );
774 }
775
776 /**
777 * Check if this field can hold an array of values
778 *
779 * @since 2.0.9
780 *
781 * @param array|object $field
782 *
783 * @return boolean
784 */
785 public static function is_field_with_multiple_values( $field ) {
786 if ( ! $field ) {
787 return false;
788 }
789
790 $field_type = self::get_original_field_type( $field );
791
792 $is_multi_value_field = (
793 self::is_checkbox( $field ) ||
794 $field_type == 'address' ||
795 self::is_multiple_select( $field )
796 );
797
798 return $is_multi_value_field;
799 }
800
801 /**
802 * @since 3.0
803 * @return string
804 */
805 public static function get_field_type( $field ) {
806 return is_array( $field ) ? $field['type'] : $field->type;
807 }
808
809 /**
810 * @since 3.0
811 * @return string
812 */
813 public static function get_original_field_type( $field ) {
814 $field_type = self::get_field_type( $field );
815 $original_type = self::get_option( $field, 'original_type' );
816
817 if ( ! empty( $original_type ) && $original_type != $field_type ) {
818 $field_type = $original_type; // check the original type for arrays
819 }
820
821 return $field_type;
822 }
823
824 /**
825 * Check if this is a multiselect dropdown field
826 *
827 * @since 2.0.9
828 * @return boolean
829 */
830 public static function is_multiple_select( $field ) {
831 $field_type = self::get_field_type( $field );
832 $is_multiple = self::is_option_true( $field, 'multiple' ) && self::is_field_type( $field, 'select' ) && $field_type !== 'hidden';
833
834 return apply_filters( 'frm_is_multiple_select', $is_multiple, $field );
835 }
836
837 /**
838 * Check if a field is read only. Read only can be set in the field options,
839 * but disabled with the shortcode options
840 *
841 * @since 2.0.9
842 */
843 public static function is_read_only( $field ) {
844 global $frm_vars;
845
846 return ( self::is_option_true( $field, 'read_only' ) && ( ! isset( $frm_vars['readonly'] ) || $frm_vars['readonly'] != 'disabled' ) );
847 }
848
849 /**
850 * @since 2.0.9
851 */
852 public static function is_required( $field ) {
853 $required = ( $field['required'] != '0' );
854 $required = apply_filters( 'frm_is_field_required', $required, $field );
855
856 return $required;
857 }
858
859 /**
860 * @since 2.0.9
861 */
862 public static function is_option_true( $field, $option ) {
863 if ( is_array( $field ) ) {
864 return self::is_option_true_in_array( $field, $option );
865 } else {
866 return self::is_option_true_in_object( $field, $option );
867 }
868 }
869
870 /**
871 * @since 2.0.9
872 */
873 public static function is_option_empty( $field, $option ) {
874 if ( is_array( $field ) ) {
875 return self::is_option_empty_in_array( $field, $option );
876 } else {
877 return self::is_option_empty_in_object( $field, $option );
878 }
879 }
880
881 public static function is_option_true_in_array( $field, $option ) {
882 return isset( $field[ $option ] ) && $field[ $option ];
883 }
884
885 public static function is_option_true_in_object( $field, $option ) {
886 return isset( $field->field_options[ $option ] ) && $field->field_options[ $option ];
887 }
888
889 public static function is_option_empty_in_array( $field, $option ) {
890 return ! isset( $field[ $option ] ) || empty( $field[ $option ] );
891 }
892
893 public static function is_option_empty_in_object( $field, $option ) {
894 return ! isset( $field->field_options[ $option ] ) || empty( $field->field_options[ $option ] );
895 }
896
897 public static function is_option_value_in_object( $field, $option ) {
898 return isset( $field->field_options[ $option ] ) && $field->field_options[ $option ] != '';
899 }
900
901 /**
902 * @since 2.0.18
903 */
904 public static function get_option( $field, $option ) {
905 if ( is_array( $field ) ) {
906 $option = self::get_option_in_array( $field, $option );
907 } else {
908 $option = self::get_option_in_object( $field, $option );
909 }
910
911 return $option;
912 }
913
914 public static function get_option_in_array( $field, $option ) {
915 return isset( $field[ $option ] ) ? $field[ $option ] : '';
916 }
917
918 public static function get_option_in_object( $field, $option ) {
919 return isset( $field->field_options[ $option ] ) ? $field->field_options[ $option ] : '';
920 }
921
922 /**
923 * @since 2.0.09
924 */
925 public static function is_repeating_field( $field ) {
926 if ( is_array( $field ) ) {
927 $is_repeating_field = ( 'divider' == $field['type'] );
928 } else {
929 $is_repeating_field = ( 'divider' == $field->type );
930 }
931
932 return ( $is_repeating_field && self::is_option_true( $field, 'repeat' ) );
933 }
934
935 /**
936 * @param string $key
937 *
938 * @return int field id
939 */
940 public static function get_id_by_key( $key ) {
941 $id = FrmDb::get_var( 'frm_fields', array( 'field_key' => sanitize_title( $key ) ) );
942
943 return (int) $id;
944 }
945
946 /**
947 * @param string $id
948 *
949 * @return string
950 */
951 public static function get_key_by_id( $id ) {
952 return FrmDb::get_var( 'frm_fields', array( 'id' => $id ), 'field_key' );
953 }
954
955 public static function is_image( $field ) {
956 $type = self::get_field_type( $field );
957
958 return ( $type == 'url' && self::get_option( $field, 'show_image' ) );
959 }
960
961 /**
962 * Check if field is radio or Dynamic radio
963 *
964 * @since 3.0
965 *
966 * @param array|object $field
967 *
968 * @return boolean true if field type is radio or Dynamic radio
969 */
970 public static function is_radio( $field ) {
971 return self::is_field_type( $field, 'radio' );
972 }
973
974 /**
975 * Check if field is checkbox or Dynamic checkbox
976 *
977 * @since 3.0
978 *
979 * @param array|object $field
980 *
981 * @return boolean true if field type is checkbox or Dynamic checkbox
982 */
983 public static function is_checkbox( $field ) {
984 return self::is_field_type( $field, 'checkbox' );
985 }
986
987 /**
988 * Check if field is checkbox or radio
989 *
990 * @since 3.0
991 *
992 * @param array|object $field
993 * @param string $is_type Options include radio, checkbox, text
994 *
995 * @return boolean true if field type is checkbox or Dynamic checkbox
996 */
997 public static function is_field_type( $field, $is_type ) {
998 $field_type = self::get_original_field_type( $field );
999 $data_type = self::get_option( $field, 'data_type' );
1000
1001 return (
1002 $is_type === $field_type ||
1003 ( 'data' === $field_type && $is_type === $data_type ) ||
1004 ( 'lookup' === $field_type && $is_type === $data_type )
1005 );
1006 }
1007 }
1008