PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 4.02.04
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v4.02.04
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.02.04, at classes/models/FrmField.php

1,015 lines 28.6 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 if ( $k === 'default_value' ) {
207 $new_values[ $k ] = FrmAppHelper::maybe_json_encode( $v );
208 } else {
209 $new_values[ $k ] = serialize( $v );
210 }
211 }
212 unset( $k, $v );
213 }
214
215 //if(isset($values['id']) and is_numeric($values['id']))
216 // $new_values['id'] = $values['id'];
217
218 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_fields', $new_values );
219 $new_id = 0;
220 if ( $query_results ) {
221 self::delete_form_transient( $new_values['form_id'] );
222 $new_id = $wpdb->insert_id;
223 }
224
225 if ( ! $return ) {
226 return false;
227 }
228
229 if ( $query_results ) {
230 if ( isset( $values['id'] ) ) {
231 $frm_duplicate_ids[ $values['id'] ] = $new_id;
232 }
233
234 return $new_id;
235 } else {
236 return false;
237 }
238 }
239
240 public static function duplicate( $old_form_id, $form_id, $copy_keys = false, $blog_id = false ) {
241 global $frm_duplicate_ids;
242
243 $where = array(
244 array(
245 'or' => 1,
246 'fi.form_id' => $old_form_id,
247 'fr.parent_form_id' => $old_form_id,
248 ),
249 );
250 $fields = self::getAll( $where, 'field_order', '', $blog_id );
251
252 foreach ( (array) $fields as $field ) {
253 $new_key = $copy_keys ? $field->field_key : '';
254 if ( $copy_keys && substr( $field->field_key, - 1 ) == 2 ) {
255 $new_key = rtrim( $new_key, 2 );
256 }
257
258 $values = array();
259 FrmFieldsHelper::fill_field( $values, $field, $form_id, $new_key );
260
261 // If this is a repeating section, create new form
262 if ( self::is_repeating_field( $field ) ) {
263 // create the repeatable form
264 $new_repeat_form_id = apply_filters(
265 'frm_create_repeat_form',
266 0,
267 array(
268 'parent_form_id' => $form_id,
269 'field_name' => $field->name,
270 )
271 );
272
273 // Save old form_select
274 $old_repeat_form_id = $field->field_options['form_select'];
275
276 // Update form_select for repeating field
277 $values['field_options']['form_select'] = $new_repeat_form_id;
278 }
279
280 // If this is a field inside of a repeating section, associate it with the correct form
281 if ( $field->form_id != $old_form_id && isset( $old_repeat_form_id ) && isset( $new_repeat_form_id ) && $field->form_id == $old_repeat_form_id ) {
282 $values['form_id'] = $new_repeat_form_id;
283 }
284
285 $values['description'] = FrmFieldsHelper::switch_field_ids( $values['description'] );
286
287 $values = apply_filters( 'frm_duplicated_field', $values );
288 $new_id = self::create( $values );
289 $frm_duplicate_ids[ $field->id ] = $new_id;
290 $frm_duplicate_ids[ $field->field_key ] = $new_id;
291 unset( $field );
292 }
293 }
294
295 public static function update( $id, $values ) {
296 global $wpdb;
297
298 $id = absint( $id );
299
300 if ( isset( $values['field_key'] ) ) {
301 $values['field_key'] = FrmAppHelper::get_unique_key( $values['field_key'], $wpdb->prefix . 'frm_fields', 'field_key', $id );
302 }
303
304 if ( isset( $values['required'] ) ) {
305 $values['required'] = (int) $values['required'];
306 }
307
308 self::preserve_format_option_backslashes( $values );
309
310 if ( isset( $values['type'] ) ) {
311 $values = apply_filters( 'frm_clean_' . $values['type'] . '_field_options_before_update', $values );
312
313 if ( $values['type'] == 'hidden' && isset( $values['field_options'] ) && isset( $values['field_options']['clear_on_focus'] ) ) {
314 // don't keep the old placeholder setting for hidden fields
315 $values['field_options']['clear_on_focus'] = 0;
316 }
317 }
318
319 // serialize array values
320 foreach ( array( 'field_options', 'options' ) as $opt ) {
321 if ( isset( $values[ $opt ] ) && is_array( $values[ $opt ] ) ) {
322 $values[ $opt ] = serialize( $values[ $opt ] );
323 }
324 }
325 if ( isset( $values['default_value'] ) && is_array( $values['default_value'] ) ) {
326 $values['default_value'] = json_encode( $values['default_value'] );
327 }
328
329 $query_results = $wpdb->update( $wpdb->prefix . 'frm_fields', $values, array( 'id' => $id ) );
330
331 $form_id = 0;
332 if ( isset( $values['form_id'] ) ) {
333 $form_id = absint( $values['form_id'] );
334 } else {
335 $field = self::getOne( $id );
336 if ( $field ) {
337 $form_id = $field->form_id;
338 }
339 unset( $field );
340 }
341 unset( $values );
342
343 if ( $query_results ) {
344 wp_cache_delete( $id, 'frm_field' );
345 if ( $form_id ) {
346 self::delete_form_transient( $form_id );
347 }
348 }
349
350 return $query_results;
351 }
352
353 /**
354 * Keep backslashes in the phone format option
355 *
356 * @since 2.0.8
357 *
358 * @param $values array - pass by reference
359 */
360 private static function preserve_format_option_backslashes( &$values ) {
361 if ( isset( $values['field_options']['format'] ) ) {
362 $values['field_options']['format'] = FrmAppHelper::preserve_backslashes( $values['field_options']['format'] );
363 }
364 }
365
366 public static function destroy( $id ) {
367 global $wpdb;
368
369 do_action( 'frm_before_destroy_field', $id );
370
371 wp_cache_delete( $id, 'frm_field' );
372 $field = self::getOne( $id );
373 if ( ! $field ) {
374 return false;
375 }
376
377 self::delete_form_transient( $field->form_id );
378
379 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_item_metas WHERE field_id=%d', $id ) );
380
381 return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_fields WHERE id=%d', $id ) );
382 }
383
384 public static function delete_form_transient( $form_id ) {
385 $form_id = absint( $form_id );
386 delete_transient( 'frm_form_fields_' . $form_id . 'excludeinclude' );
387 delete_transient( 'frm_form_fields_' . $form_id . 'includeinclude' );
388 delete_transient( 'frm_form_fields_' . $form_id . 'includeexclude' );
389 delete_transient( 'frm_form_fields_' . $form_id . 'excludeexclude' );
390
391 global $wpdb;
392 $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%' ) );
393
394 FrmDb::cache_delete_group( 'frm_field' );
395
396 $form = FrmForm::getOne( $form_id );
397 if ( $form && $form->parent_form_id && $form->parent_form_id != $form_id ) {
398 self::delete_form_transient( $form->parent_form_id );
399 }
400 }
401
402 /**
403 * If $field is numeric, get the field object
404 */
405 public static function maybe_get_field( &$field ) {
406 if ( ! is_object( $field ) ) {
407 $field = self::getOne( $field );
408 }
409 }
410
411 /**
412 * @param string|int $id The field id or key.
413 * @param bool $filter When true, run the frm_field filter.
414 */
415 public static function getOne( $id, $filter = false ) {
416 if ( empty( $id ) ) {
417 return null;
418 }
419
420 global $wpdb;
421
422 $where = is_numeric( $id ) ? 'id=%d' : 'field_key=%s';
423 $query = $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'frm_fields WHERE ' . $where, $id ); // WPCS: unprepared SQL ok.
424
425 $results = FrmDb::check_cache( $id, 'frm_field', $query, 'get_row', 0 );
426
427 if ( empty( $results ) ) {
428 self::filter_field( $filter, $results );
429 return $results;
430 }
431
432 if ( is_numeric( $id ) ) {
433 FrmDb::set_cache( $results->field_key, $results, 'frm_field' );
434 } elseif ( $results ) {
435 FrmDb::set_cache( $results->id, $results, 'frm_field' );
436 }
437
438 self::prepare_options( $results );
439 self::filter_field( $filter, $results );
440
441 return wp_unslash( $results );
442 }
443
444 /**
445 * @since 3.06.01
446 * @param bool $filter When true, run the frm_field filter.
447 * @param object $results
448 */
449 private static function filter_field( $filter, &$results ) {
450 if ( $filter ) {
451 /**
452 * @since 3.06.01
453 */
454 $results = apply_filters( 'frm_field', $results );
455 }
456 }
457
458 /**
459 * Get the field type by key or id
460 *
461 * @param int|string The field id or key
462 * @param mixed $col The name of the column in the fields database table
463 */
464 public static function get_type( $id, $col = 'type' ) {
465 $field = FrmDb::check_cache( $id, 'frm_field' );
466 if ( $field ) {
467 $type = $field->{$col};
468 } else {
469 $where = array(
470 'or' => 1,
471 'id' => $id,
472 'field_key' => $id,
473 );
474 $type = FrmDb::get_var( 'frm_fields', $where, $col );
475 }
476
477 return $type;
478 }
479
480 public static function get_all_types_in_form( $form_id, $type, $limit = '', $inc_sub = 'exclude' ) {
481 if ( ! $form_id ) {
482 return array();
483 }
484
485 $results = self::get_fields_from_transients(
486 $form_id,
487 array(
488 'inc_embed' => $inc_sub,
489 'inc_repeat' => $inc_sub,
490 )
491 );
492 if ( ! empty( $results ) ) {
493 $fields = array();
494 $count = 0;
495 foreach ( $results as $result ) {
496 if ( $type != $result->type ) {
497 continue;
498 }
499
500 $fields[ $result->id ] = $result;
501 $count ++;
502 if ( $limit == 1 ) {
503 $fields = $result;
504 break;
505 }
506
507 if ( ! empty( $limit ) && $count >= $limit ) {
508 break;
509 }
510
511 unset( $result );
512 }
513
514 return wp_unslash( $fields );
515 }
516
517 self::$use_cache = false;
518
519 $where = array(
520 'fi.form_id' => (int) $form_id,
521 'fi.type' => $type,
522 );
523 self::maybe_include_repeating_fields( $inc_sub, $where );
524 $results = self::getAll( $where, 'field_order', $limit );
525 self::$use_cache = true;
526 self::include_sub_fields( $results, $inc_sub, $type, $form_id );
527
528 return $results;
529 }
530
531 public static function get_all_for_form( $form_id, $limit = '', $inc_embed = 'exclude', $inc_repeat = 'include' ) {
532 if ( ! (int) $form_id ) {
533 return array();
534 }
535
536 $results = self::get_fields_from_transients( $form_id, compact( 'inc_embed', 'inc_repeat' ) );
537 if ( ! empty( $results ) ) {
538 if ( empty( $limit ) ) {
539 return $results;
540 }
541
542 $fields = array();
543 $count = 0;
544 foreach ( $results as $result ) {
545 $count ++;
546 $fields[ $result->id ] = $result;
547 if ( ! empty( $limit ) && $count >= $limit ) {
548 break;
549 }
550 }
551
552 return $fields;
553 }
554
555 self::$use_cache = false;
556
557 $where = array( 'fi.form_id' => absint( $form_id ) );
558 self::maybe_include_repeating_fields( $inc_repeat, $where );
559 $results = self::getAll( $where, 'field_order', $limit );
560
561 self::$use_cache = true;
562
563 self::include_sub_fields( $results, $inc_embed, 'all', $form_id );
564
565 if ( empty( $limit ) ) {
566 self::set_field_transient( $results, $form_id, 0, compact( 'inc_embed', 'inc_repeat' ) );
567 }
568
569 return $results;
570 }
571
572 /**
573 * If repeating fields should be included, adjust $where accordingly
574 *
575 * @param string $inc_repeat
576 * @param array $where - pass by reference
577 */
578 private static function maybe_include_repeating_fields( $inc_repeat, &$where ) {
579 if ( $inc_repeat == 'include' ) {
580 $form_id = $where['fi.form_id'];
581 $where[] = array(
582 'or' => 1,
583 'fi.form_id' => $form_id,
584 'fr.parent_form_id' => $form_id,
585 );
586 unset( $where['fi.form_id'] );
587 }
588 }
589
590 public static function include_sub_fields( &$results, $inc_embed, $type = 'all', $form_id = '' ) {
591 $no_sub_forms = empty( $results ) && $type === 'all';
592 if ( 'include' != $inc_embed || $no_sub_forms ) {
593 return;
594 }
595
596 $form_fields = $results;
597 $should_get_subforms = ( $type !== 'all' && $type !== 'form' && ! empty( $form_id ) );
598 if ( $should_get_subforms ) {
599 $form_fields = self::get_all_types_in_form( $form_id, 'form' );
600 }
601
602 $index_offset = 1;
603 foreach ( $form_fields as $k => $field ) {
604 if ( 'form' != $field->type || ! isset( $field->field_options['form_select'] ) ) {
605 continue;
606 }
607
608 if ( $type == 'all' ) {
609 $sub_fields = self::get_all_for_form( $field->field_options['form_select'] );
610 } else {
611 $sub_fields = self::get_all_types_in_form( $field->field_options['form_select'], $type );
612 }
613
614 if ( ! empty( $sub_fields ) ) {
615 $index = $k + $index_offset;
616 $index_offset += count( $sub_fields );
617 array_splice( $results, $index, 0, $sub_fields );
618 }
619 unset( $field, $sub_fields );
620 }
621 }
622
623 public static function getAll( $where = array(), $order_by = '', $limit = '', $blog_id = false ) {
624 $cache_key = FrmAppHelper::maybe_json_encode( $where ) . $order_by . 'l' . $limit . 'b' . $blog_id;
625 if ( self::$use_cache ) {
626 // make sure old cache doesn't get saved as a transient
627 $results = wp_cache_get( $cache_key, 'frm_field' );
628 if ( false !== $results ) {
629 return wp_unslash( $results );
630 }
631 }
632
633 global $wpdb;
634
635 if ( $blog_id && is_multisite() ) {
636 global $wpmuBaseTablePrefix;
637 if ( $wpmuBaseTablePrefix ) {
638 $prefix = $wpmuBaseTablePrefix . $blog_id . '_';
639 } else {
640 $prefix = $wpdb->get_blog_prefix( $blog_id );
641 }
642
643 $table_name = $prefix . 'frm_fields';
644 $form_table_name = $prefix . 'frm_forms';
645 } else {
646 $table_name = $wpdb->prefix . 'frm_fields';
647 $form_table_name = $wpdb->prefix . 'frm_forms';
648 }
649
650 if ( ! empty( $order_by ) && strpos( $order_by, 'ORDER BY' ) === false ) {
651 $order_by = ' ORDER BY ' . $order_by;
652 }
653
654 $limit = FrmDb::esc_limit( $limit );
655
656 $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";
657 $query_type = ( $limit == ' LIMIT 1' || $limit == 1 ) ? 'row' : 'results';
658
659 if ( is_array( $where ) ) {
660 $args = array(
661 'order_by' => $order_by,
662 'limit' => $limit,
663 );
664 $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 );
665 } else {
666 // if the query is not an array, then it has already been prepared
667 $query .= FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
668
669 $function_name = ( $query_type == 'row' ) ? 'get_row' : 'get_results';
670 $results = $wpdb->$function_name( $query );
671 }
672 unset( $where );
673
674 self::format_field_results( $results );
675
676 FrmDb::set_cache( $cache_key, $results, 'frm_field' );
677
678 return wp_unslash( $results );
679 }
680
681 /**
682 * @since 2.0.8
683 */
684 private static function format_field_results( &$results ) {
685 if ( is_array( $results ) ) {
686 foreach ( $results as $r_key => $result ) {
687 FrmDb::set_cache( $result->id, $result, 'frm_field' );
688 FrmDb::set_cache( $result->field_key, $result, 'frm_field' );
689
690 self::prepare_options( $result );
691 $results[ $r_key ]->field_options = $result->field_options;
692 $results[ $r_key ]->options = $result->options;
693 $results[ $r_key ]->default_value = $result->default_value;
694
695 unset( $r_key, $result );
696 }
697 } elseif ( $results ) {
698 FrmDb::set_cache( $results->id, $results, 'frm_field' );
699 FrmDb::set_cache( $results->field_key, $results, 'frm_field' );
700
701 self::prepare_options( $results );
702 }
703 }
704
705 /**
706 * Unserialize all the serialized field data
707 *
708 * @since 2.0
709 */
710 private static function prepare_options( &$results ) {
711 FrmAppHelper::unserialize_or_decode( $results->field_options );
712 FrmAppHelper::unserialize_or_decode( $results->options );
713 FrmAppHelper::unserialize_or_decode( $results->default_value );
714 }
715
716 /**
717 * If a form has too many fields, thay won't all save into a single transient.
718 * We'll break them into groups of 200
719 *
720 * @since 2.0.1
721 */
722 private static function get_fields_from_transients( $form_id, $args ) {
723 $fields = array();
724 self::get_next_transient( $fields, 'frm_form_fields_' . $form_id . $args['inc_embed'] . $args['inc_repeat'] );
725
726 return $fields;
727 }
728
729 /**
730 * Called by get_fields_from_transients
731 *
732 * @since 2.0.1
733 */
734 private static function get_next_transient( &$fields, $base_name, $next = 0 ) {
735 $name = $next ? $base_name . $next : $base_name;
736 $next_fields = get_transient( $name );
737
738 if ( $next_fields ) {
739 $fields = array_merge( $fields, $next_fields );
740
741 if ( count( $next_fields ) >= self::$transient_size ) {
742 // if this transient is full, check for another
743 $next ++;
744 self::get_next_transient( $fields, $base_name, $next );
745 }
746 }
747 }
748
749 /**
750 * Save the transients in chunks for large forms
751 *
752 * @since 2.0.1
753 */
754 private static function set_field_transient( &$fields, $form_id, $next = 0, $args = array() ) {
755 $base_name = 'frm_form_fields_' . $form_id . $args['inc_embed'] . $args['inc_repeat'];
756 $field_chunks = array_chunk( $fields, self::$transient_size );
757
758 foreach ( $field_chunks as $field ) {
759 $name = $next ? $base_name . $next : $base_name;
760 $set = set_transient( $name, $field, 60 * 60 * 6 );
761 if ( ! $set ) {
762 // the transient didn't save
763 if ( $name != $base_name ) {
764 // if the first saved an others fail, this will show an incmoplete form
765 self::delete_form_transient( $form_id );
766 }
767
768 return;
769 }
770
771 $next ++;
772 }
773 }
774
775 public static function is_no_save_field( $type ) {
776 return in_array( $type, self::no_save_fields() );
777 }
778
779 public static function no_save_fields() {
780 return array( 'divider', 'end_divider', 'captcha', 'break', 'html', 'form' );
781 }
782
783 /**
784 * Check if this field can hold an array of values
785 *
786 * @since 2.0.9
787 *
788 * @param array|object $field
789 *
790 * @return boolean
791 */
792 public static function is_field_with_multiple_values( $field ) {
793 if ( ! $field ) {
794 return false;
795 }
796
797 $field_type = self::get_original_field_type( $field );
798
799 $is_multi_value_field = (
800 self::is_checkbox( $field ) ||
801 $field_type == 'address' ||
802 self::is_multiple_select( $field )
803 );
804
805 return $is_multi_value_field;
806 }
807
808 /**
809 * @since 3.0
810 * @return string
811 */
812 public static function get_field_type( $field ) {
813 return is_array( $field ) ? $field['type'] : $field->type;
814 }
815
816 /**
817 * @since 3.0
818 * @return string
819 */
820 public static function get_original_field_type( $field ) {
821 $field_type = self::get_field_type( $field );
822 $original_type = self::get_option( $field, 'original_type' );
823
824 if ( ! empty( $original_type ) && $original_type != $field_type ) {
825 $field_type = $original_type; // check the original type for arrays
826 }
827
828 return $field_type;
829 }
830
831 /**
832 * Check if this is a multiselect dropdown field
833 *
834 * @since 2.0.9
835 * @return boolean
836 */
837 public static function is_multiple_select( $field ) {
838 $field_type = self::get_field_type( $field );
839 $is_multiple = self::is_option_true( $field, 'multiple' ) && self::is_field_type( $field, 'select' ) && $field_type !== 'hidden';
840
841 return apply_filters( 'frm_is_multiple_select', $is_multiple, $field );
842 }
843
844 /**
845 * Check if a field is read only. Read only can be set in the field options,
846 * but disabled with the shortcode options
847 *
848 * @since 2.0.9
849 */
850 public static function is_read_only( $field ) {
851 global $frm_vars;
852
853 return ( self::is_option_true( $field, 'read_only' ) && ( ! isset( $frm_vars['readonly'] ) || $frm_vars['readonly'] != 'disabled' ) );
854 }
855
856 /**
857 * @since 2.0.9
858 */
859 public static function is_required( $field ) {
860 $required = ( $field['required'] != '0' );
861 $required = apply_filters( 'frm_is_field_required', $required, $field );
862
863 return $required;
864 }
865
866 /**
867 * @since 2.0.9
868 */
869 public static function is_option_true( $field, $option ) {
870 if ( is_array( $field ) ) {
871 return self::is_option_true_in_array( $field, $option );
872 } else {
873 return self::is_option_true_in_object( $field, $option );
874 }
875 }
876
877 /**
878 * @since 2.0.9
879 */
880 public static function is_option_empty( $field, $option ) {
881 if ( is_array( $field ) ) {
882 return self::is_option_empty_in_array( $field, $option );
883 } else {
884 return self::is_option_empty_in_object( $field, $option );
885 }
886 }
887
888 public static function is_option_true_in_array( $field, $option ) {
889 return isset( $field[ $option ] ) && $field[ $option ];
890 }
891
892 public static function is_option_true_in_object( $field, $option ) {
893 return isset( $field->field_options[ $option ] ) && $field->field_options[ $option ];
894 }
895
896 public static function is_option_empty_in_array( $field, $option ) {
897 return ! isset( $field[ $option ] ) || empty( $field[ $option ] );
898 }
899
900 public static function is_option_empty_in_object( $field, $option ) {
901 return ! isset( $field->field_options[ $option ] ) || empty( $field->field_options[ $option ] );
902 }
903
904 public static function is_option_value_in_object( $field, $option ) {
905 return isset( $field->field_options[ $option ] ) && $field->field_options[ $option ] != '';
906 }
907
908 /**
909 * @since 2.0.18
910 */
911 public static function get_option( $field, $option ) {
912 if ( is_array( $field ) ) {
913 $option = self::get_option_in_array( $field, $option );
914 } else {
915 $option = self::get_option_in_object( $field, $option );
916 }
917
918 return $option;
919 }
920
921 public static function get_option_in_array( $field, $option ) {
922 return isset( $field[ $option ] ) ? $field[ $option ] : '';
923 }
924
925 public static function get_option_in_object( $field, $option ) {
926 return isset( $field->field_options[ $option ] ) ? $field->field_options[ $option ] : '';
927 }
928
929 /**
930 * @since 2.0.09
931 */
932 public static function is_repeating_field( $field ) {
933 if ( is_array( $field ) ) {
934 $is_repeating_field = ( 'divider' == $field['type'] );
935 } else {
936 $is_repeating_field = ( 'divider' == $field->type );
937 }
938
939 return ( $is_repeating_field && self::is_option_true( $field, 'repeat' ) );
940 }
941
942 /**
943 * @param string $key
944 *
945 * @return int field id
946 */
947 public static function get_id_by_key( $key ) {
948 $id = FrmDb::get_var( 'frm_fields', array( 'field_key' => sanitize_title( $key ) ) );
949
950 return (int) $id;
951 }
952
953 /**
954 * @param string $id
955 *
956 * @return string
957 */
958 public static function get_key_by_id( $id ) {
959 return FrmDb::get_var( 'frm_fields', array( 'id' => $id ), 'field_key' );
960 }
961
962 public static function is_image( $field ) {
963 $type = self::get_field_type( $field );
964
965 return ( $type == 'url' && self::get_option( $field, 'show_image' ) );
966 }
967
968 /**
969 * Check if field is radio or Dynamic radio
970 *
971 * @since 3.0
972 *
973 * @param array|object $field
974 *
975 * @return boolean true if field type is radio or Dynamic radio
976 */
977 public static function is_radio( $field ) {
978 return self::is_field_type( $field, 'radio' );
979 }
980
981 /**
982 * Check if field is checkbox or Dynamic checkbox
983 *
984 * @since 3.0
985 *
986 * @param array|object $field
987 *
988 * @return boolean true if field type is checkbox or Dynamic checkbox
989 */
990 public static function is_checkbox( $field ) {
991 return self::is_field_type( $field, 'checkbox' );
992 }
993
994 /**
995 * Check if field is checkbox or radio
996 *
997 * @since 3.0
998 *
999 * @param array|object $field
1000 * @param string $is_type Options include radio, checkbox, text
1001 *
1002 * @return boolean true if field type is checkbox or Dynamic checkbox
1003 */
1004 public static function is_field_type( $field, $is_type ) {
1005 $field_type = self::get_original_field_type( $field );
1006 $data_type = self::get_option( $field, 'data_type' );
1007
1008 return (
1009 $is_type === $field_type ||
1010 ( 'data' === $field_type && $is_type === $data_type ) ||
1011 ( 'lookup' === $field_type && $is_type === $data_type )
1012 );
1013 }
1014 }
1015