PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.4.4
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.4.4
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 / FrmForm.php

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

1,109 lines 31.1 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 FrmForm {
7
8 /**
9 * @param array $values
10 * @return int|boolean id on success or false on failure
11 */
12 public static function create( $values ) {
13 global $wpdb;
14
15 $values = FrmAppHelper::maybe_filter_array( $values, array( 'name', 'description' ) );
16
17 $new_values = array(
18 'form_key' => FrmAppHelper::get_unique_key( $values['form_key'], $wpdb->prefix . 'frm_forms', 'form_key' ),
19 'name' => $values['name'],
20 'description' => $values['description'],
21 'status' => isset( $values['status'] ) ? $values['status'] : 'published',
22 'logged_in' => isset( $values['logged_in'] ) ? $values['logged_in'] : 0,
23 'is_template' => isset( $values['is_template'] ) ? (int) $values['is_template'] : 0,
24 'parent_form_id' => isset( $values['parent_form_id'] ) ? absint( $values['parent_form_id'] ) : 0,
25 'editable' => isset( $values['editable'] ) ? (int) $values['editable'] : 0,
26 'created_at' => isset( $values['created_at'] ) ? $values['created_at'] : current_time( 'mysql', 1 ),
27 );
28
29 $options = isset( $values['options'] ) ? (array) $values['options'] : array();
30 FrmFormsHelper::fill_form_options( $options, $values );
31
32 $options['before_html'] = isset( $values['options']['before_html'] ) ? $values['options']['before_html'] : FrmFormsHelper::get_default_html( 'before' );
33 $options['after_html'] = isset( $values['options']['after_html'] ) ? $values['options']['after_html'] : FrmFormsHelper::get_default_html( 'after' );
34 $options['submit_html'] = isset( $values['options']['submit_html'] ) ? $values['options']['submit_html'] : FrmFormsHelper::get_default_html( 'submit' );
35
36 /**
37 * Allows modifying form options before updating or creating.
38 *
39 * @since 5.4 Add the third param.
40 *
41 * @param array $options Form options.
42 * @param array $values Form data.
43 * @param bool $update Is form updating or creating. It's `true` if is updating.
44 */
45 $options = apply_filters( 'frm_form_options_before_update', $options, $values, false );
46 $options = self::maybe_filter_form_options( $options );
47 $new_values['options'] = serialize( $options );
48
49 $wpdb->insert( $wpdb->prefix . 'frm_forms', $new_values );
50
51 $id = $wpdb->insert_id;
52
53 // Clear form caching
54 self::clear_form_cache();
55
56 return $id;
57 }
58
59 /**
60 * @since 5.0.08
61 *
62 * @param array $options
63 * @return array
64 */
65 private static function maybe_filter_form_options( $options ) {
66 if ( ! FrmAppHelper::allow_unfiltered_html() && ! empty( $options['submit_html'] ) ) {
67 $options['submit_html'] = FrmAppHelper::kses_submit_button( $options['submit_html'] );
68 }
69 return FrmAppHelper::maybe_filter_array( $options, array( 'submit_value', 'success_msg', 'before_html', 'after_html' ) );
70 }
71
72 /**
73 * @return int|boolean ID on success or false on failure
74 */
75 public static function duplicate( $id, $template = false, $copy_keys = false, $blog_id = false ) {
76 global $wpdb;
77
78 $values = self::getOne( $id, $blog_id );
79 if ( ! $values ) {
80 return false;
81 }
82
83 $new_key = $copy_keys ? $values->form_key : '';
84
85 $new_values = array(
86 'form_key' => FrmAppHelper::get_unique_key( $new_key, $wpdb->prefix . 'frm_forms', 'form_key' ),
87 'name' => $values->name,
88 'description' => $values->description,
89 'status' => $values->status ? $values->status : 'published',
90 'logged_in' => $values->logged_in ? $values->logged_in : 0,
91 'editable' => $values->editable ? $values->editable : 0,
92 'created_at' => current_time( 'mysql', 1 ),
93 'is_template' => $template ? 1 : 0,
94 );
95
96 if ( $blog_id ) {
97 $new_values['status'] = 'published';
98 $new_options = $values->options;
99 FrmAppHelper::unserialize_or_decode( $new_options );
100 $new_options['email_to'] = get_option( 'admin_email' );
101 $new_options['copy'] = false;
102 $new_values['options'] = $new_options;
103 } else {
104 $new_values['options'] = $values->options;
105 }
106
107 if ( is_array( $new_values['options'] ) ) {
108 $new_values['options'] = serialize( $new_values['options'] );
109 }
110
111 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_forms', $new_values );
112
113 if ( $query_results ) {
114 // Clear form caching
115 self::clear_form_cache();
116
117 $form_id = $wpdb->insert_id;
118 FrmField::duplicate( $id, $form_id, $copy_keys, $blog_id );
119
120 // update form settings after fields are created
121 do_action( 'frm_after_duplicate_form', $form_id, $new_values, array( 'old_id' => $id ) );
122
123 return $form_id;
124 }
125
126 return false;
127 }
128
129 public static function after_duplicate( $form_id, $values ) {
130 $new_opts = $values['options'];
131 FrmAppHelper::unserialize_or_decode( $new_opts );
132 $values['options'] = $new_opts;
133
134 if ( isset( $new_opts['success_msg'] ) ) {
135 $new_opts['success_msg'] = FrmFieldsHelper::switch_field_ids( $new_opts['success_msg'] );
136 }
137
138 $new_opts = apply_filters( 'frm_after_duplicate_form_values', $new_opts, $form_id );
139
140 if ( $new_opts != $values['options'] ) {
141 global $wpdb;
142 $wpdb->update( $wpdb->prefix . 'frm_forms', array( 'options' => maybe_serialize( $new_opts ) ), array( 'id' => $form_id ) );
143 }
144
145 self::switch_field_ids_in_fields( $form_id );
146 }
147
148 /**
149 * Switches field ID in fields.
150 *
151 * @since 5.3
152 *
153 * @param int $form_id Form ID.
154 */
155 private static function switch_field_ids_in_fields( $form_id ) {
156 global $wpdb;
157
158 // Keys of fields that you want to check to replace field ID.
159 $keys = array( 'default_value', 'field_options' );
160 $sql_cols = 'fi.id';
161 foreach ( $keys as $key ) {
162 $sql_cols .= ( ',fi.' . $key );
163 }
164
165 $fields = FrmDb::get_results(
166 "{$wpdb->prefix}frm_fields AS fi LEFT OUTER JOIN {$wpdb->prefix}frm_forms AS fr ON fi.form_id = fr.id",
167 array(
168 'or' => 1,
169 'fi.form_id' => $form_id,
170 'fr.parent_form_id' => $form_id,
171 ),
172 $sql_cols
173 );
174
175 if ( ! $fields || ! is_array( $fields ) ) {
176 return;
177 }
178
179 foreach ( $fields as $field ) {
180 self::switch_field_ids_in_field( (array) $field );
181 }
182 }
183
184 /**
185 * Switches field ID in a field.
186 *
187 * @since 5.3
188 *
189 * @param array $field Field array.
190 */
191 private static function switch_field_ids_in_field( $field ) {
192 $new_values = array();
193 foreach ( $field as $key => $value ) {
194 if ( 'id' === $key || ! $value ) {
195 continue;
196 }
197
198 if ( ! is_string( $value ) && ! is_array( $value ) ) {
199 continue;
200 }
201
202 if ( 'field_options' === $key ) {
203 // Need to loop through field_options to prevent breaking serialized string when length changed.
204 FrmAppHelper::unserialize_or_decode( $value );
205 $new_val = FrmFieldsHelper::switch_field_ids( $value );
206 $new_val = serialize( $new_val );
207 } else {
208 $new_val = FrmFieldsHelper::switch_field_ids( $value );
209 }
210
211 if ( $new_val !== $value ) {
212 $new_values[ $key ] = $new_val;
213 }
214 }
215
216 if ( ! empty( $new_values ) ) {
217 FrmField::update( $field['id'], $new_values );
218 }
219 }
220
221 /**
222 * @return int|boolean
223 */
224 public static function update( $id, $values, $create_link = false ) {
225 global $wpdb;
226
227 $values = FrmAppHelper::maybe_filter_array( $values, array( 'name', 'description' ) );
228
229 if ( ! isset( $values['status'] ) && ( $create_link || isset( $values['options'] ) || isset( $values['item_meta'] ) || isset( $values['field_options'] ) ) ) {
230 $values['status'] = 'published';
231 }
232
233 if ( isset( $values['form_key'] ) ) {
234 $values['form_key'] = FrmAppHelper::get_unique_key( $values['form_key'], $wpdb->prefix . 'frm_forms', 'form_key', $id );
235 }
236
237 $form_fields = array( 'form_key', 'name', 'description', 'status', 'parent_form_id' );
238
239 $new_values = self::set_update_options( array(), $values, array( 'form_id' => $id ) );
240
241 foreach ( $values as $value_key => $value ) {
242 if ( $value_key && in_array( $value_key, $form_fields ) ) {
243 $new_values[ $value_key ] = $value;
244 }
245 }
246
247 if ( isset( $values['new_status'] ) && ! empty( $values['new_status'] ) ) {
248 $new_values['status'] = $values['new_status'];
249 }
250
251 if ( ! empty( $new_values ) ) {
252 $query_results = $wpdb->update( $wpdb->prefix . 'frm_forms', $new_values, array( 'id' => $id ) );
253 if ( $query_results ) {
254 self::clear_form_cache();
255 }
256 } else {
257 $query_results = true;
258 }
259 unset( $new_values );
260
261 $values = self::update_fields( $id, $values );
262
263 do_action( 'frm_update_form', $id, $values );
264 do_action( 'frm_update_form_' . $id, $values );
265
266 return $query_results;
267 }
268
269 /**
270 * @param array $new_values
271 * @param array $values
272 * @param array $args
273 * @return array
274 */
275 public static function set_update_options( $new_values, $values, $args = array() ) {
276 if ( ! isset( $values['options'] ) ) {
277 return $new_values;
278 }
279
280 $options = isset( $values['options'] ) ? (array) $values['options'] : array();
281 FrmFormsHelper::fill_form_options( $options, $values );
282
283 $options['custom_style'] = isset( $values['options']['custom_style'] ) ? $values['options']['custom_style'] : 0;
284 $options['before_html'] = isset( $values['options']['before_html'] ) ? $values['options']['before_html'] : FrmFormsHelper::get_default_html( 'before' );
285 $options['after_html'] = isset( $values['options']['after_html'] ) ? $values['options']['after_html'] : FrmFormsHelper::get_default_html( 'after' );
286 $options['submit_html'] = ( isset( $values['options']['submit_html'] ) && '' !== $values['options']['submit_html'] ) ? $values['options']['submit_html'] : FrmFormsHelper::get_default_html( 'submit' );
287
288 if ( ! empty( $options['success_url'] ) && ! empty( $args['form_id'] ) ) {
289 $options['success_url'] = FrmFormsHelper::maybe_add_sanitize_url_attr( $options['success_url'], (int) $args['form_id'] );
290 $values['options']['success_url'] = $options['success_url'];
291 }
292
293 /**
294 * Allows modifying form options before updating or creating.
295 *
296 * @since 5.4 Added the third param.
297 *
298 * @param array $options Form options.
299 * @param array $values Form data.
300 * @param bool $update Is form updating or creating. It's `true` if is updating.
301 */
302 $options = apply_filters( 'frm_form_options_before_update', $options, $values, true );
303 $options = self::maybe_filter_form_options( $options );
304 $new_values['options'] = serialize( $options );
305
306 return $new_values;
307 }
308
309 /**
310 * @return array
311 */
312 public static function update_fields( $id, $values ) {
313
314 if ( ! isset( $values['item_meta'] ) && ! isset( $values['field_options'] ) ) {
315 return $values;
316 }
317
318 $all_fields = FrmField::get_all_for_form( $id );
319 if ( empty( $all_fields ) ) {
320 return $values;
321 }
322
323 if ( ! isset( $values['item_meta'] ) ) {
324 $values['item_meta'] = array();
325 }
326
327 $field_array = array();
328 $existing_keys = array_keys( $values['item_meta'] );
329 foreach ( $all_fields as $fid ) {
330 if ( ! in_array( $fid->id, $existing_keys ) && ( isset( $values['frm_fields_submitted'] ) && in_array( $fid->id, $values['frm_fields_submitted'] ) ) || isset( $values['options'] ) ) {
331 $values['item_meta'][ $fid->id ] = '';
332 }
333 $field_array[ $fid->id ] = $fid;
334 }
335 unset( $all_fields );
336
337 foreach ( $values['item_meta'] as $field_id => $default_value ) {
338 if ( isset( $field_array[ $field_id ] ) ) {
339 $field = $field_array[ $field_id ];
340 } else {
341 $field = FrmField::getOne( $field_id );
342 }
343
344 if ( ! $field ) {
345 continue;
346 }
347
348 $is_settings_page = ( isset( $values['options'] ) || isset( $values['field_options'][ 'custom_html_' . $field_id ] ) );
349 if ( $is_settings_page ) {
350 self::get_settings_page_html( $values, $field );
351
352 if ( ! defined( 'WP_IMPORTING' ) ) {
353 continue;
354 }
355 }
356
357 //updating the form
358 $update_options = FrmFieldsHelper::get_default_field_options_from_field( $field );
359 unset( $update_options['custom_html'] ); // don't check for POST html
360 $update_options = apply_filters( 'frm_field_options_to_update', $update_options );
361
362 foreach ( $update_options as $opt => $default ) {
363 $field->field_options[ $opt ] = isset( $values['field_options'][ $opt . '_' . $field_id ] ) ? $values['field_options'][ $opt . '_' . $field_id ] : $default;
364 self::sanitize_field_opt( $opt, $field->field_options[ $opt ] );
365 }
366
367 $field->field_options = apply_filters( 'frm_update_field_options', $field->field_options, $field, $values );
368
369 $new_field = array(
370 'field_options' => $field->field_options,
371 'default_value' => isset( $values[ 'default_value_' . $field_id ] ) ? FrmAppHelper::maybe_json_encode( $values[ 'default_value_' . $field_id ] ) : '',
372 );
373
374 self::prepare_field_update_values( $field, $values, $new_field );
375
376 FrmField::update( $field_id, $new_field );
377
378 FrmField::delete_form_transient( $field->form_id );
379 }
380 self::clear_form_cache();
381
382 return $values;
383 }
384
385 private static function sanitize_field_opt( $opt, &$value ) {
386 if ( is_string( $value ) ) {
387 if ( $opt === 'calc' ) {
388 $value = self::sanitize_calc( $value );
389 } else {
390 $value = FrmAppHelper::kses( $value, 'all' );
391 }
392 $value = trim( $value );
393 }
394 }
395
396 /**
397 * @param string $value
398 * @return string
399 */
400 private static function sanitize_calc( $value ) {
401 if ( false !== strpos( $value, '<' ) ) {
402 $value = self::normalize_calc_spaces( $value );
403 }
404 $allow = array( '<= ', ' >=' ); // Allow <= and >=
405 $temp = array( '< = ', ' > =' );
406 $value = str_replace( $allow, $temp, $value );
407 $value = strip_tags( $value );
408 $value = str_replace( $temp, $allow, $value );
409 return $value;
410 }
411
412 /**
413 * Format a comparison like 5<10 to 5 < 10. Also works on 5< 10, 5 <10, 5<=10 variations.
414 * This is to avoid an issue with unspaced calculations being recognized as HTML that gets removed when strip_tags is called.
415 *
416 * @param string $calc
417 * @return string
418 */
419 private static function normalize_calc_spaces( $calc ) {
420 // Check for a pattern with 5 parts
421 // $1 \d the first comparison digit.
422 // $2 a space (optional).
423 // $3 an equals sign (optional) that follows the < operator for <= comparisons.
424 // $4 another space (optional).
425 // $5 \d the second comparison digit.
426 return preg_replace( '/(\d)( ){0,1}<(=){0,1}( ){0,1}(\d)/', '$1 <$3 $5', $calc );
427 }
428
429 /**
430 * Updating the settings page
431 */
432 private static function get_settings_page_html( $values, &$field ) {
433 if ( isset( $values['field_options'][ 'custom_html_' . $field->id ] ) ) {
434 $prev_opts = array();
435 $fallback_html = isset( $field->field_options['custom_html'] ) ? $field->field_options['custom_html'] : FrmFieldsHelper::get_default_html( $field->type );
436
437 $field->field_options['custom_html'] = isset( $values['field_options'][ 'custom_html_' . $field->id ] ) ? $values['field_options'][ 'custom_html_' . $field->id ] : $fallback_html;
438 } elseif ( $field->type == 'hidden' || $field->type == 'user_id' ) {
439 $prev_opts = $field->field_options;
440 }
441
442 if ( isset( $prev_opts ) ) {
443 $field->field_options = apply_filters( 'frm_update_form_field_options', $field->field_options, $field, $values );
444 if ( $prev_opts != $field->field_options ) {
445 FrmField::update( $field->id, array( 'field_options' => $field->field_options ) );
446 }
447 }
448 }
449
450 private static function prepare_field_update_values( $field, $values, &$new_field ) {
451 $field_cols = array(
452 'field_order' => 0,
453 'field_key' => '',
454 'required' => false,
455 'type' => '',
456 'description' => '',
457 'options' => '',
458 'name' => '',
459 );
460 foreach ( $field_cols as $col => $default ) {
461 $default = ( $default === '' ) ? $field->{$col} : $default;
462
463 $new_field[ $col ] = isset( $values['field_options'][ $col . '_' . $field->id ] ) ? $values['field_options'][ $col . '_' . $field->id ] : $default;
464 }
465
466 // Don't save the template option.
467 if ( is_array( $new_field['options'] ) && isset( $new_field['options']['000'] ) ) {
468 unset( $new_field['options']['000'] );
469 }
470 }
471
472 /**
473 * Get a list of all form settings that should be translated
474 * on a multilingual site.
475 *
476 * @since 3.06.01
477 * @param object $form - The form object
478 */
479 public static function translatable_strings( $form ) {
480 $strings = array(
481 'name',
482 'description',
483 'submit_value',
484 'submit_msg',
485 'success_msg',
486 'invalid_msg',
487 'failed_msg',
488 'login_msg',
489 'admin_permission',
490 );
491
492 return apply_filters( 'frm_form_strings', $strings, $form );
493 }
494
495 /**
496 * @param string $status
497 *
498 * @return int|boolean
499 */
500 public static function set_status( $id, $status ) {
501 if ( 'trash' == $status ) {
502 return self::trash( $id );
503 }
504
505 $statuses = array( 'published', 'draft', 'trash' );
506 if ( ! in_array( $status, $statuses ) ) {
507 return false;
508 }
509
510 global $wpdb;
511
512 if ( is_array( $id ) ) {
513 $where = array(
514 'id' => $id,
515 'parent_form_id' => $id,
516 'or' => 1,
517 );
518 FrmDb::get_where_clause_and_values( $where );
519 array_unshift( $where['values'], $status );
520
521 $query_results = $wpdb->query( $wpdb->prepare( 'UPDATE ' . $wpdb->prefix . 'frm_forms SET status = %s ' . $where['where'], $where['values'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
522 } else {
523 $query_results = $wpdb->update( $wpdb->prefix . 'frm_forms', array( 'status' => $status ), array( 'id' => $id ) );
524 $wpdb->update( $wpdb->prefix . 'frm_forms', array( 'status' => $status ), array( 'parent_form_id' => $id ) );
525 }
526
527 if ( $query_results ) {
528 self::clear_form_cache();
529 }
530
531 return $query_results;
532 }
533
534 /**
535 * @return int|boolean
536 */
537 public static function trash( $id ) {
538 if ( ! EMPTY_TRASH_DAYS ) {
539 return self::destroy( $id );
540 }
541
542 $form = self::getOne( $id );
543 if ( ! $form ) {
544 return false;
545 }
546
547 $options = $form->options;
548 $options['trash_time'] = time();
549
550 global $wpdb;
551 $query_results = $wpdb->update(
552 $wpdb->prefix . 'frm_forms',
553 array(
554 'status' => 'trash',
555 'options' => serialize( $options ),
556 ),
557 array(
558 'id' => $id,
559 )
560 );
561
562 $wpdb->update(
563 $wpdb->prefix . 'frm_forms',
564 array(
565 'status' => 'trash',
566 'options' => serialize( $options ),
567 ),
568 array(
569 'parent_form_id' => $id,
570 )
571 );
572
573 if ( $query_results ) {
574 self::clear_form_cache();
575 }
576
577 return $query_results;
578 }
579
580 /**
581 * @return int|boolean
582 */
583 public static function destroy( $id ) {
584 global $wpdb;
585
586 $form = self::getOne( $id );
587 if ( ! $form ) {
588 return false;
589 }
590 $id = $form->id;
591
592 // Disconnect the entries from this form
593 $entries = FrmDb::get_col( $wpdb->prefix . 'frm_items', array( 'form_id' => $id ) );
594 foreach ( $entries as $entry_id ) {
595 FrmEntry::destroy( $entry_id );
596 unset( $entry_id );
597 }
598
599 // Disconnect the fields from this form
600 $wpdb->query( $wpdb->prepare( 'DELETE fi FROM ' . $wpdb->prefix . 'frm_fields AS fi LEFT JOIN ' . $wpdb->prefix . 'frm_forms fr ON (fi.form_id = fr.id) WHERE fi.form_id=%d OR parent_form_id=%d', $id, $id ) );
601
602 $query_results = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_forms WHERE id=%d OR parent_form_id=%d', $id, $id ) );
603 if ( $query_results ) {
604 // Delete all form actions linked to this form
605 $action_control = FrmFormActionsController::get_form_actions( 'email' );
606 $action_control->destroy( $id, 'all' );
607
608 // Clear form caching
609 self::clear_form_cache();
610
611 do_action( 'frm_destroy_form', $id );
612 do_action( 'frm_destroy_form_' . $id );
613 }
614
615 return $query_results;
616 }
617
618 /**
619 * Delete trashed forms based on how long they have been trashed
620 *
621 * @return int The number of forms deleted
622 */
623 public static function scheduled_delete( $delete_timestamp = '' ) {
624 global $wpdb;
625
626 $trash_forms = FrmDb::get_results( $wpdb->prefix . 'frm_forms', array( 'status' => 'trash' ), 'id, options' );
627
628 if ( ! $trash_forms ) {
629 return 0;
630 }
631
632 if ( empty( $delete_timestamp ) ) {
633 $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
634 }
635
636 $count = 0;
637 foreach ( $trash_forms as $form ) {
638 FrmAppHelper::unserialize_or_decode( $form->options );
639 if ( ! isset( $form->options['trash_time'] ) || $form->options['trash_time'] < $delete_timestamp ) {
640 self::destroy( $form->id );
641 $count ++;
642 }
643
644 unset( $form );
645 }
646
647 return $count;
648 }
649
650 /**
651 * @return string form name
652 */
653 public static function getName( $id ) {
654 $form = FrmDb::check_cache( $id, 'frm_form' );
655 if ( $form ) {
656 $r = stripslashes( $form->name );
657
658 return $r;
659 }
660
661 $query_key = is_numeric( $id ) ? 'id' : 'form_key';
662 $r = FrmDb::get_var( 'frm_forms', array( $query_key => $id ), 'name' );
663 $r = stripslashes( $r );
664
665 return $r;
666 }
667
668 /**
669 * @since 3.0
670 *
671 * @param string $key
672 *
673 * @return int form id
674 */
675 public static function get_id_by_key( $key ) {
676 return (int) FrmDb::get_var( 'frm_forms', array( 'form_key' => sanitize_title( $key ) ) );
677 }
678
679 /**
680 * @since 3.0
681 *
682 * @param int $id
683 *
684 * @return string form key
685 */
686 public static function get_key_by_id( $id ) {
687 $id = (int) $id;
688 $cache = FrmDb::check_cache( $id, 'frm_form' );
689 if ( $cache ) {
690 return $cache->form_key;
691 }
692
693 $key = FrmDb::get_var( 'frm_forms', array( 'id' => $id ), 'form_key' );
694
695 return $key;
696 }
697
698 /**
699 * If $form is numeric, get the form object
700 *
701 * @param object|int $form
702 *
703 * @since 2.0.9
704 */
705 public static function maybe_get_form( &$form ) {
706 if ( ! is_object( $form ) && ! is_array( $form ) && ! empty( $form ) ) {
707 $form = self::getOne( $form );
708 }
709 }
710
711 /**
712 * @return object form
713 */
714 public static function getOne( $id, $blog_id = false ) {
715 global $wpdb;
716
717 if ( $blog_id && is_multisite() ) {
718 global $wpmuBaseTablePrefix;
719 $prefix = $wpmuBaseTablePrefix ? $wpmuBaseTablePrefix . $blog_id . '_' : $wpdb->get_blog_prefix( $blog_id );
720
721 $table_name = $prefix . 'frm_forms';
722 } else {
723 $table_name = $wpdb->prefix . 'frm_forms';
724 $cache = wp_cache_get( $id, 'frm_form' );
725 if ( $cache ) {
726 if ( isset( $cache->options ) ) {
727 FrmAppHelper::unserialize_or_decode( $cache->options );
728 }
729
730 return wp_unslash( $cache );
731 }
732 }
733
734 if ( is_numeric( $id ) ) {
735 $where = array( 'id' => $id );
736 } else {
737 $where = array( 'form_key' => $id );
738 }
739
740 $results = FrmDb::get_row( $table_name, $where );
741
742 if ( isset( $results->options ) ) {
743 FrmDb::set_cache( $results->id, $results, 'frm_form' );
744 FrmAppHelper::unserialize_or_decode( $results->options );
745 }
746
747 return apply_filters( 'frm_form_object', wp_unslash( $results ) );
748 }
749
750 /**
751 * @return object|array of objects
752 */
753 public static function getAll( $where = array(), $order_by = '', $limit = '' ) {
754 if ( is_array( $where ) && ! empty( $where ) ) {
755 if ( isset( $where['is_template'] ) && $where['is_template'] && ! isset( $where['status'] ) && ! isset( $where['status !'] ) ) {
756 // don't get trashed templates
757 $where['status'] = array( null, '', 'published' );
758 }
759
760 $results = FrmDb::get_results( 'frm_forms', $where, '*', compact( 'order_by', 'limit' ) );
761 } else {
762 global $wpdb;
763
764 // the query has already been prepared if this is not an array
765 $query = 'SELECT * FROM ' . $wpdb->prefix . 'frm_forms' . FrmDb::prepend_and_or_where( ' WHERE ', $where ) . FrmDb::esc_order( $order_by ) . FrmDb::esc_limit( $limit );
766 $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
767 }
768
769 if ( $results ) {
770 foreach ( $results as $result ) {
771 FrmDb::set_cache( $result->id, $result, 'frm_form' );
772 FrmAppHelper::unserialize_or_decode( $result->options );
773 }
774 }
775
776 if ( $limit == ' LIMIT 1' || $limit == 1 ) {
777 // return the first form object if we are only getting one form
778 $results = reset( $results );
779 }
780
781 return wp_unslash( $results );
782 }
783
784 /**
785 * Get all published forms
786 *
787 * @since 2.0
788 * @return array of forms
789 */
790 public static function get_published_forms( $query = array(), $limit = 999, $inc_children = 'exclude' ) {
791 $query['is_template'] = 0;
792 $query['status'] = array( null, '', 'published' );
793 if ( $inc_children == 'exclude' ) {
794 $query['parent_form_id'] = array( null, 0 );
795 }
796
797 $forms = self::getAll( $query, 'name', $limit );
798
799 return $forms;
800 }
801
802 /**
803 * @return object count of forms
804 */
805 public static function get_count() {
806 global $wpdb;
807
808 $cache_key = 'frm_form_counts';
809
810 $counts = wp_cache_get( $cache_key, 'frm_form' );
811 if ( false !== $counts ) {
812 return $counts;
813 }
814
815 $results = (array) FrmDb::get_results(
816 'frm_forms',
817 array(
818 'or' => 1,
819 'parent_form_id' => null,
820 'parent_form_id <' => 0,
821 ),
822 'status, is_template'
823 );
824
825 $statuses = array( 'published', 'draft', 'template', 'trash' );
826 $counts = array_fill_keys( $statuses, 0 );
827
828 foreach ( $results as $row ) {
829 if ( 'trash' != $row->status ) {
830 if ( $row->is_template ) {
831 $counts['template'] ++;
832 } else {
833 $counts['published'] ++;
834 }
835 } else {
836 $counts['trash'] ++;
837 }
838
839 if ( 'draft' == $row->status ) {
840 $counts['draft'] ++;
841 }
842
843 unset( $row );
844 }
845
846 $counts = (object) $counts;
847 FrmDb::set_cache( $cache_key, $counts, 'frm_form' );
848
849 return $counts;
850 }
851
852 /**
853 * Clear form caching
854 * Called when a form is created, updated, duplicated, or deleted
855 * or when the form status is changed
856 *
857 * @since 2.0.4
858 */
859 public static function clear_form_cache() {
860 FrmDb::cache_delete_group( 'frm_form' );
861 }
862
863 /**
864 * @return array of errors
865 */
866 public static function validate( $values ) {
867 $errors = array();
868
869 return apply_filters( 'frm_validate_form', $errors, $values );
870 }
871
872 public static function get_params( $form = null ) {
873 global $frm_vars;
874
875 if ( ! $form ) {
876 $form = self::getAll( array(), 'name', 1 );
877 } else {
878 self::maybe_get_form( $form );
879 }
880
881 if ( isset( $frm_vars['form_params'] ) && is_array( $frm_vars['form_params'] ) && isset( $frm_vars['form_params'][ $form->id ] ) ) {
882 return $frm_vars['form_params'][ $form->id ];
883 }
884
885 $action_var = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action'; // phpcs:ignore WordPress.Security.NonceVerification.Missing
886 $action = apply_filters( 'frm_show_new_entry_page', FrmAppHelper::get_param( $action_var, 'new', 'get', 'sanitize_title' ), $form );
887
888 $default_values = array(
889 'id' => '',
890 'form_name' => '',
891 'paged' => 1,
892 'form' => $form->id,
893 'form_id' => $form->id,
894 'field_id' => '',
895 'search' => '',
896 'sort' => '',
897 'sdir' => '',
898 'action' => $action,
899 );
900
901 $values = array();
902 $values['posted_form_id'] = FrmAppHelper::get_param( 'form_id', '', 'get', 'absint' );
903 if ( ! $values['posted_form_id'] ) {
904 $values['posted_form_id'] = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
905 }
906
907 if ( $form->id == $values['posted_form_id'] ) {
908 //if there are two forms on the same page, make sure not to submit both
909 foreach ( $default_values as $var => $default ) {
910 if ( $var == 'action' ) {
911 $values[ $var ] = FrmAppHelper::get_param( $action_var, $default, 'get', 'sanitize_title' );
912 } else {
913 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
914 }
915 unset( $var, $default );
916 }
917 } else {
918 foreach ( $default_values as $var => $default ) {
919 $values[ $var ] = $default;
920 unset( $var, $default );
921 }
922 }
923
924 if ( in_array( $values['action'], array( 'create', 'update' ) ) &&
925 ( ! $_POST || ( ! isset( $_POST['action'] ) && ! isset( $_POST['frm_action'] ) ) ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
926 ) {
927 $values['action'] = 'new';
928 }
929
930 return $values;
931 }
932
933 public static function list_page_params() {
934 $values = array();
935 $defaults = array(
936 'template' => 0,
937 'id' => '',
938 'paged' => 1,
939 'form' => '',
940 'search' => '',
941 'sort' => '',
942 'sdir' => '',
943 );
944 foreach ( $defaults as $var => $default ) {
945 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
946 }
947
948 return $values;
949 }
950
951 public static function get_admin_params( $form = null ) {
952 $form_id = $form;
953 if ( $form === null ) {
954 $form_id = self::get_current_form_id();
955 } elseif ( $form && is_object( $form ) ) {
956 $form_id = $form->id;
957 }
958
959 $values = array();
960 $defaults = array(
961 'id' => '',
962 'form_name' => '',
963 'paged' => 1,
964 'form' => $form_id,
965 'field_id' => '',
966 'search' => '',
967 'sort' => '',
968 'sdir' => '',
969 'fid' => '',
970 'keep_post' => '',
971 );
972 foreach ( $defaults as $var => $default ) {
973 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
974 }
975
976 return $values;
977 }
978
979 public static function get_current_form_id( $default_form = 'none' ) {
980 if ( 'first' == $default_form ) {
981 $form = self::get_current_form();
982 } else {
983 $form = self::maybe_get_current_form();
984 }
985 $form_id = $form ? $form->id : 0;
986
987 return $form_id;
988 }
989
990 public static function maybe_get_current_form( $form_id = 0 ) {
991 global $frm_vars;
992
993 if ( isset( $frm_vars['current_form'] ) && $frm_vars['current_form'] && ( ! $form_id || $form_id == $frm_vars['current_form']->id ) ) {
994 return $frm_vars['current_form'];
995 }
996
997 $form_id = FrmAppHelper::get_param( 'form', $form_id, 'get', 'absint' );
998 if ( $form_id ) {
999 $form_id = self::set_current_form( $form_id );
1000 }
1001
1002 return $form_id;
1003 }
1004
1005 public static function get_current_form( $form_id = 0 ) {
1006 $form = self::maybe_get_current_form( $form_id );
1007 if ( is_numeric( $form ) ) {
1008 $form = self::set_current_form( $form );
1009 }
1010
1011 return $form;
1012 }
1013
1014 public static function set_current_form( $form_id ) {
1015 global $frm_vars;
1016
1017 $query = array();
1018 if ( $form_id ) {
1019 $query['id'] = $form_id;
1020 }
1021
1022 $frm_vars['current_form'] = self::get_published_forms( $query, 1 );
1023
1024 return $frm_vars['current_form'];
1025 }
1026
1027 public static function is_form_loaded( $form, $this_load, $global_load ) {
1028 global $frm_vars;
1029 $small_form = new stdClass();
1030 foreach ( array( 'id', 'form_key', 'name' ) as $var ) {
1031 $small_form->{$var} = $form->{$var};
1032 unset( $var );
1033 }
1034
1035 $frm_vars['forms_loaded'][] = $small_form;
1036
1037 if ( $this_load && empty( $global_load ) ) {
1038 $global_load = true;
1039 $frm_vars['load_css'] = true;
1040 }
1041
1042 return ( ( ! isset( $frm_vars['css_loaded'] ) || ! $frm_vars['css_loaded'] ) && $global_load );
1043 }
1044
1045 /**
1046 * @since 4.06.03
1047 *
1048 * @param object $form
1049 *
1050 * @return bool
1051 */
1052 public static function &is_visible_to_user( $form ) {
1053 if ( $form->logged_in && isset( $form->options['logged_in_role'] ) ) {
1054 $visible = FrmAppHelper::user_has_permission( $form->options['logged_in_role'] );
1055 } else {
1056 $visible = true;
1057 }
1058
1059 return $visible;
1060 }
1061
1062 public static function show_submit( $form ) {
1063 $show = ( ! $form->is_template && $form->status == 'published' && ! FrmAppHelper::is_admin() );
1064 $show = apply_filters( 'frm_show_submit_button', $show, $form );
1065
1066 return $show;
1067 }
1068
1069 /**
1070 * @since 2.3
1071 */
1072 public static function get_option( $atts ) {
1073 $form = $atts['form'];
1074 $default = isset( $atts['default'] ) ? $atts['default'] : '';
1075
1076 return isset( $form->options[ $atts['option'] ] ) ? $form->options[ $atts['option'] ] : $default;
1077 }
1078
1079 /**
1080 * Get the link to edit this form.
1081 *
1082 * @since 4.0
1083 * @param int $form_id The id of the form.
1084 */
1085 public static function get_edit_link( $form_id ) {
1086 return admin_url( 'admin.php?page=formidable&frm_action=edit&id=' . $form_id );
1087 }
1088
1089 /**
1090 * @deprecated 3.0
1091 * @codeCoverageIgnore
1092 *
1093 * @param string $key
1094 *
1095 * @return int form id
1096 */
1097 public static function getIdByKey( $key ) {
1098 return FrmFormDeprecated::getIdByKey( $key );
1099 }
1100
1101 /**
1102 * @deprecated 3.0
1103 * @codeCoverageIgnore
1104 */
1105 public static function getKeyById( $id ) {
1106 return FrmFormDeprecated::getKeyById( $id );
1107 }
1108 }
1109