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

1,132 lines 31.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 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 /**
386 * @param string $opt
387 * @param mixed $value
388 * @return void
389 */
390 private static function sanitize_field_opt( $opt, &$value ) {
391 if ( ! is_string( $value ) ) {
392 return;
393 }
394
395 /**
396 * Allow the option to turn off sanitization for a field. This way a custom rule can be used instead.
397 * Make sure to add custom sanitization using the frm_update_field_options filter as the data will no longer be sanitized.
398 *
399 * @since 6.0
400 *
401 * @param bool $should_sanitize
402 * @param string $opt
403 */
404 $should_sanitize = apply_filters( 'frm_should_sanitize_field_opt_string', true, $opt );
405
406 if ( ! $should_sanitize ) {
407 return;
408 }
409
410 if ( $opt === 'calc' ) {
411 $value = self::sanitize_calc( $value );
412 } else {
413 $value = FrmAppHelper::kses( $value, 'all' );
414 }
415
416 $value = trim( $value );
417 }
418
419 /**
420 * @param string $value
421 * @return string
422 */
423 private static function sanitize_calc( $value ) {
424 if ( false !== strpos( $value, '<' ) ) {
425 $value = self::normalize_calc_spaces( $value );
426 }
427 $allow = array( '<= ', ' >=' ); // Allow <= and >=
428 $temp = array( '< = ', ' > =' );
429 $value = str_replace( $allow, $temp, $value );
430 $value = strip_tags( $value );
431 $value = str_replace( $temp, $allow, $value );
432 return $value;
433 }
434
435 /**
436 * Format a comparison like 5<10 to 5 < 10. Also works on 5< 10, 5 <10, 5<=10 variations.
437 * This is to avoid an issue with unspaced calculations being recognized as HTML that gets removed when strip_tags is called.
438 *
439 * @param string $calc
440 * @return string
441 */
442 private static function normalize_calc_spaces( $calc ) {
443 // Check for a pattern with 5 parts
444 // $1 \d the first comparison digit.
445 // $2 a space (optional).
446 // $3 an equals sign (optional) that follows the < operator for <= comparisons.
447 // $4 another space (optional).
448 // $5 \d the second comparison digit.
449 return preg_replace( '/(\d)( ){0,1}<(=){0,1}( ){0,1}(\d)/', '$1 <$3 $5', $calc );
450 }
451
452 /**
453 * Updating the settings page
454 */
455 private static function get_settings_page_html( $values, &$field ) {
456 if ( isset( $values['field_options'][ 'custom_html_' . $field->id ] ) ) {
457 $prev_opts = array();
458 $fallback_html = isset( $field->field_options['custom_html'] ) ? $field->field_options['custom_html'] : FrmFieldsHelper::get_default_html( $field->type );
459
460 $field->field_options['custom_html'] = isset( $values['field_options'][ 'custom_html_' . $field->id ] ) ? $values['field_options'][ 'custom_html_' . $field->id ] : $fallback_html;
461 } elseif ( $field->type == 'hidden' || $field->type == 'user_id' ) {
462 $prev_opts = $field->field_options;
463 }
464
465 if ( isset( $prev_opts ) ) {
466 $field->field_options = apply_filters( 'frm_update_form_field_options', $field->field_options, $field, $values );
467 if ( $prev_opts != $field->field_options ) {
468 FrmField::update( $field->id, array( 'field_options' => $field->field_options ) );
469 }
470 }
471 }
472
473 private static function prepare_field_update_values( $field, $values, &$new_field ) {
474 $field_cols = array(
475 'field_order' => 0,
476 'field_key' => '',
477 'required' => false,
478 'type' => '',
479 'description' => '',
480 'options' => '',
481 'name' => '',
482 );
483 foreach ( $field_cols as $col => $default ) {
484 $default = ( $default === '' ) ? $field->{$col} : $default;
485
486 $new_field[ $col ] = isset( $values['field_options'][ $col . '_' . $field->id ] ) ? $values['field_options'][ $col . '_' . $field->id ] : $default;
487 }
488
489 // Don't save the template option.
490 if ( is_array( $new_field['options'] ) && isset( $new_field['options']['000'] ) ) {
491 unset( $new_field['options']['000'] );
492 }
493 }
494
495 /**
496 * Get a list of all form settings that should be translated
497 * on a multilingual site.
498 *
499 * @since 3.06.01
500 * @param object $form - The form object
501 */
502 public static function translatable_strings( $form ) {
503 $strings = array(
504 'name',
505 'description',
506 'submit_value',
507 'submit_msg',
508 'success_msg',
509 'invalid_msg',
510 'failed_msg',
511 'login_msg',
512 'admin_permission',
513 );
514
515 return apply_filters( 'frm_form_strings', $strings, $form );
516 }
517
518 /**
519 * @param string $status
520 *
521 * @return int|boolean
522 */
523 public static function set_status( $id, $status ) {
524 if ( 'trash' == $status ) {
525 return self::trash( $id );
526 }
527
528 $statuses = array( 'published', 'draft', 'trash' );
529 if ( ! in_array( $status, $statuses ) ) {
530 return false;
531 }
532
533 global $wpdb;
534
535 if ( is_array( $id ) ) {
536 $where = array(
537 'id' => $id,
538 'parent_form_id' => $id,
539 'or' => 1,
540 );
541 FrmDb::get_where_clause_and_values( $where );
542 array_unshift( $where['values'], $status );
543
544 $query_results = $wpdb->query( $wpdb->prepare( 'UPDATE ' . $wpdb->prefix . 'frm_forms SET status = %s ' . $where['where'], $where['values'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
545 } else {
546 $query_results = $wpdb->update( $wpdb->prefix . 'frm_forms', array( 'status' => $status ), array( 'id' => $id ) );
547 $wpdb->update( $wpdb->prefix . 'frm_forms', array( 'status' => $status ), array( 'parent_form_id' => $id ) );
548 }
549
550 if ( $query_results ) {
551 self::clear_form_cache();
552 }
553
554 return $query_results;
555 }
556
557 /**
558 * @return int|boolean
559 */
560 public static function trash( $id ) {
561 if ( ! EMPTY_TRASH_DAYS ) {
562 return self::destroy( $id );
563 }
564
565 $form = self::getOne( $id );
566 if ( ! $form ) {
567 return false;
568 }
569
570 $options = $form->options;
571 $options['trash_time'] = time();
572
573 global $wpdb;
574 $query_results = $wpdb->update(
575 $wpdb->prefix . 'frm_forms',
576 array(
577 'status' => 'trash',
578 'options' => serialize( $options ),
579 ),
580 array(
581 'id' => $id,
582 )
583 );
584
585 $wpdb->update(
586 $wpdb->prefix . 'frm_forms',
587 array(
588 'status' => 'trash',
589 'options' => serialize( $options ),
590 ),
591 array(
592 'parent_form_id' => $id,
593 )
594 );
595
596 if ( $query_results ) {
597 self::clear_form_cache();
598 }
599
600 return $query_results;
601 }
602
603 /**
604 * @return int|boolean
605 */
606 public static function destroy( $id ) {
607 global $wpdb;
608
609 $form = self::getOne( $id );
610 if ( ! $form ) {
611 return false;
612 }
613 $id = $form->id;
614
615 // Disconnect the entries from this form
616 $entries = FrmDb::get_col( $wpdb->prefix . 'frm_items', array( 'form_id' => $id ) );
617 foreach ( $entries as $entry_id ) {
618 FrmEntry::destroy( $entry_id );
619 unset( $entry_id );
620 }
621
622 // Disconnect the fields from this form
623 $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 ) );
624
625 $query_results = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_forms WHERE id=%d OR parent_form_id=%d', $id, $id ) );
626 if ( $query_results ) {
627 // Delete all form actions linked to this form
628 $action_control = FrmFormActionsController::get_form_actions( 'email' );
629 $action_control->destroy( $id, 'all' );
630
631 // Clear form caching
632 self::clear_form_cache();
633
634 do_action( 'frm_destroy_form', $id );
635 do_action( 'frm_destroy_form_' . $id );
636 }
637
638 return $query_results;
639 }
640
641 /**
642 * Delete trashed forms based on how long they have been trashed
643 *
644 * @return int The number of forms deleted
645 */
646 public static function scheduled_delete( $delete_timestamp = '' ) {
647 global $wpdb;
648
649 $trash_forms = FrmDb::get_results( $wpdb->prefix . 'frm_forms', array( 'status' => 'trash' ), 'id, options' );
650
651 if ( ! $trash_forms ) {
652 return 0;
653 }
654
655 if ( empty( $delete_timestamp ) ) {
656 $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
657 }
658
659 $count = 0;
660 foreach ( $trash_forms as $form ) {
661 FrmAppHelper::unserialize_or_decode( $form->options );
662 if ( ! isset( $form->options['trash_time'] ) || $form->options['trash_time'] < $delete_timestamp ) {
663 self::destroy( $form->id );
664 $count ++;
665 }
666
667 unset( $form );
668 }
669
670 return $count;
671 }
672
673 /**
674 * @return string form name
675 */
676 public static function getName( $id ) {
677 $form = FrmDb::check_cache( $id, 'frm_form' );
678 if ( $form ) {
679 $r = stripslashes( $form->name );
680
681 return $r;
682 }
683
684 $query_key = is_numeric( $id ) ? 'id' : 'form_key';
685 $r = FrmDb::get_var( 'frm_forms', array( $query_key => $id ), 'name' );
686 $r = stripslashes( $r );
687
688 return $r;
689 }
690
691 /**
692 * @since 3.0
693 *
694 * @param string $key
695 *
696 * @return int form id
697 */
698 public static function get_id_by_key( $key ) {
699 return (int) FrmDb::get_var( 'frm_forms', array( 'form_key' => sanitize_title( $key ) ) );
700 }
701
702 /**
703 * @since 3.0
704 *
705 * @param int $id
706 *
707 * @return string form key
708 */
709 public static function get_key_by_id( $id ) {
710 $id = (int) $id;
711 $cache = FrmDb::check_cache( $id, 'frm_form' );
712 if ( $cache ) {
713 return $cache->form_key;
714 }
715
716 $key = FrmDb::get_var( 'frm_forms', array( 'id' => $id ), 'form_key' );
717
718 return $key;
719 }
720
721 /**
722 * If $form is numeric, get the form object
723 *
724 * @param object|int $form
725 *
726 * @since 2.0.9
727 */
728 public static function maybe_get_form( &$form ) {
729 if ( ! is_object( $form ) && ! is_array( $form ) && ! empty( $form ) ) {
730 $form = self::getOne( $form );
731 }
732 }
733
734 /**
735 * @return object form
736 */
737 public static function getOne( $id, $blog_id = false ) {
738 global $wpdb;
739
740 if ( $blog_id && is_multisite() ) {
741 global $wpmuBaseTablePrefix;
742 $prefix = $wpmuBaseTablePrefix ? $wpmuBaseTablePrefix . $blog_id . '_' : $wpdb->get_blog_prefix( $blog_id );
743
744 $table_name = $prefix . 'frm_forms';
745 } else {
746 $table_name = $wpdb->prefix . 'frm_forms';
747 $cache = wp_cache_get( $id, 'frm_form' );
748 if ( $cache ) {
749 if ( isset( $cache->options ) ) {
750 FrmAppHelper::unserialize_or_decode( $cache->options );
751 }
752
753 return apply_filters( 'frm_form_object', wp_unslash( $cache ) );
754 }
755 }
756
757 if ( is_numeric( $id ) ) {
758 $where = array( 'id' => $id );
759 } else {
760 $where = array( 'form_key' => $id );
761 }
762
763 $results = FrmDb::get_row( $table_name, $where );
764
765 if ( isset( $results->options ) ) {
766 FrmDb::set_cache( $results->id, $results, 'frm_form' );
767 FrmAppHelper::unserialize_or_decode( $results->options );
768 }
769
770 return apply_filters( 'frm_form_object', wp_unslash( $results ) );
771 }
772
773 /**
774 * @return object|array of objects
775 */
776 public static function getAll( $where = array(), $order_by = '', $limit = '' ) {
777 if ( is_array( $where ) && ! empty( $where ) ) {
778 if ( isset( $where['is_template'] ) && $where['is_template'] && ! isset( $where['status'] ) && ! isset( $where['status !'] ) ) {
779 // don't get trashed templates
780 $where['status'] = array( null, '', 'published' );
781 }
782
783 $results = FrmDb::get_results( 'frm_forms', $where, '*', compact( 'order_by', 'limit' ) );
784 } else {
785 global $wpdb;
786
787 // the query has already been prepared if this is not an array
788 $query = 'SELECT * FROM ' . $wpdb->prefix . 'frm_forms' . FrmDb::prepend_and_or_where( ' WHERE ', $where ) . FrmDb::esc_order( $order_by ) . FrmDb::esc_limit( $limit );
789 $results = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
790 }
791
792 if ( $results ) {
793 foreach ( $results as $result ) {
794 FrmDb::set_cache( $result->id, $result, 'frm_form' );
795 FrmAppHelper::unserialize_or_decode( $result->options );
796 }
797 }
798
799 if ( $limit == ' LIMIT 1' || $limit == 1 ) {
800 // return the first form object if we are only getting one form
801 $results = reset( $results );
802 }
803
804 return wp_unslash( $results );
805 }
806
807 /**
808 * Get all published forms
809 *
810 * @since 2.0
811 * @return array of forms
812 */
813 public static function get_published_forms( $query = array(), $limit = 999, $inc_children = 'exclude' ) {
814 $query['is_template'] = 0;
815 $query['status'] = array( null, '', 'published' );
816 if ( $inc_children == 'exclude' ) {
817 $query['parent_form_id'] = array( null, 0 );
818 }
819
820 $forms = self::getAll( $query, 'name', $limit );
821
822 return $forms;
823 }
824
825 /**
826 * @return object count of forms
827 */
828 public static function get_count() {
829 global $wpdb;
830
831 $cache_key = 'frm_form_counts';
832
833 $counts = wp_cache_get( $cache_key, 'frm_form' );
834 if ( false !== $counts ) {
835 return $counts;
836 }
837
838 $results = (array) FrmDb::get_results(
839 'frm_forms',
840 array(
841 'or' => 1,
842 'parent_form_id' => null,
843 'parent_form_id <' => 0,
844 ),
845 'status, is_template'
846 );
847
848 $statuses = array( 'published', 'draft', 'template', 'trash' );
849 $counts = array_fill_keys( $statuses, 0 );
850
851 foreach ( $results as $row ) {
852 if ( 'trash' != $row->status ) {
853 if ( $row->is_template ) {
854 $counts['template'] ++;
855 } else {
856 $counts['published'] ++;
857 }
858 } else {
859 $counts['trash'] ++;
860 }
861
862 if ( 'draft' == $row->status ) {
863 $counts['draft'] ++;
864 }
865
866 unset( $row );
867 }
868
869 $counts = (object) $counts;
870 FrmDb::set_cache( $cache_key, $counts, 'frm_form' );
871
872 return $counts;
873 }
874
875 /**
876 * Clear form caching
877 * Called when a form is created, updated, duplicated, or deleted
878 * or when the form status is changed
879 *
880 * @since 2.0.4
881 */
882 public static function clear_form_cache() {
883 FrmDb::cache_delete_group( 'frm_form' );
884 }
885
886 /**
887 * @return array of errors
888 */
889 public static function validate( $values ) {
890 $errors = array();
891
892 return apply_filters( 'frm_validate_form', $errors, $values );
893 }
894
895 public static function get_params( $form = null ) {
896 global $frm_vars;
897
898 if ( ! $form ) {
899 $form = self::getAll( array(), 'name', 1 );
900 } else {
901 self::maybe_get_form( $form );
902 }
903
904 if ( isset( $frm_vars['form_params'] ) && is_array( $frm_vars['form_params'] ) && isset( $frm_vars['form_params'][ $form->id ] ) ) {
905 return $frm_vars['form_params'][ $form->id ];
906 }
907
908 $action_var = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action'; // phpcs:ignore WordPress.Security.NonceVerification.Missing
909 $action = apply_filters( 'frm_show_new_entry_page', FrmAppHelper::get_param( $action_var, 'new', 'get', 'sanitize_title' ), $form );
910
911 $default_values = array(
912 'id' => '',
913 'form_name' => '',
914 'paged' => 1,
915 'form' => $form->id,
916 'form_id' => $form->id,
917 'field_id' => '',
918 'search' => '',
919 'sort' => '',
920 'sdir' => '',
921 'action' => $action,
922 );
923
924 $values = array();
925 $values['posted_form_id'] = FrmAppHelper::get_param( 'form_id', '', 'get', 'absint' );
926 if ( ! $values['posted_form_id'] ) {
927 $values['posted_form_id'] = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
928 }
929
930 if ( $form->id == $values['posted_form_id'] ) {
931 //if there are two forms on the same page, make sure not to submit both
932 foreach ( $default_values as $var => $default ) {
933 if ( $var == 'action' ) {
934 $values[ $var ] = FrmAppHelper::get_param( $action_var, $default, 'get', 'sanitize_title' );
935 } else {
936 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
937 }
938 unset( $var, $default );
939 }
940 } else {
941 foreach ( $default_values as $var => $default ) {
942 $values[ $var ] = $default;
943 unset( $var, $default );
944 }
945 }
946
947 if ( in_array( $values['action'], array( 'create', 'update' ) ) &&
948 ( ! $_POST || ( ! isset( $_POST['action'] ) && ! isset( $_POST['frm_action'] ) ) ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
949 ) {
950 $values['action'] = 'new';
951 }
952
953 return $values;
954 }
955
956 public static function list_page_params() {
957 $values = array();
958 $defaults = array(
959 'template' => 0,
960 'id' => '',
961 'paged' => 1,
962 'form' => '',
963 'search' => '',
964 'sort' => '',
965 'sdir' => '',
966 );
967 foreach ( $defaults as $var => $default ) {
968 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
969 }
970
971 return $values;
972 }
973
974 public static function get_admin_params( $form = null ) {
975 $form_id = $form;
976 if ( $form === null ) {
977 $form_id = self::get_current_form_id();
978 } elseif ( $form && is_object( $form ) ) {
979 $form_id = $form->id;
980 }
981
982 $values = array();
983 $defaults = array(
984 'id' => '',
985 'form_name' => '',
986 'paged' => 1,
987 'form' => $form_id,
988 'field_id' => '',
989 'search' => '',
990 'sort' => '',
991 'sdir' => '',
992 'fid' => '',
993 'keep_post' => '',
994 );
995 foreach ( $defaults as $var => $default ) {
996 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
997 }
998
999 return $values;
1000 }
1001
1002 public static function get_current_form_id( $default_form = 'none' ) {
1003 if ( 'first' == $default_form ) {
1004 $form = self::get_current_form();
1005 } else {
1006 $form = self::maybe_get_current_form();
1007 }
1008 $form_id = $form ? $form->id : 0;
1009
1010 return $form_id;
1011 }
1012
1013 public static function maybe_get_current_form( $form_id = 0 ) {
1014 global $frm_vars;
1015
1016 if ( isset( $frm_vars['current_form'] ) && $frm_vars['current_form'] && ( ! $form_id || $form_id == $frm_vars['current_form']->id ) ) {
1017 return $frm_vars['current_form'];
1018 }
1019
1020 $form_id = FrmAppHelper::get_param( 'form', $form_id, 'get', 'absint' );
1021 if ( $form_id ) {
1022 $form_id = self::set_current_form( $form_id );
1023 }
1024
1025 return $form_id;
1026 }
1027
1028 public static function get_current_form( $form_id = 0 ) {
1029 $form = self::maybe_get_current_form( $form_id );
1030 if ( is_numeric( $form ) ) {
1031 $form = self::set_current_form( $form );
1032 }
1033
1034 return $form;
1035 }
1036
1037 public static function set_current_form( $form_id ) {
1038 global $frm_vars;
1039
1040 $query = array();
1041 if ( $form_id ) {
1042 $query['id'] = $form_id;
1043 }
1044
1045 $frm_vars['current_form'] = self::get_published_forms( $query, 1 );
1046
1047 return $frm_vars['current_form'];
1048 }
1049
1050 public static function is_form_loaded( $form, $this_load, $global_load ) {
1051 global $frm_vars;
1052 $small_form = new stdClass();
1053 foreach ( array( 'id', 'form_key', 'name' ) as $var ) {
1054 $small_form->{$var} = $form->{$var};
1055 unset( $var );
1056 }
1057
1058 $frm_vars['forms_loaded'][] = $small_form;
1059
1060 if ( $this_load && empty( $global_load ) ) {
1061 $global_load = true;
1062 $frm_vars['load_css'] = true;
1063 }
1064
1065 return ( ( ! isset( $frm_vars['css_loaded'] ) || ! $frm_vars['css_loaded'] ) && $global_load );
1066 }
1067
1068 /**
1069 * @since 4.06.03
1070 *
1071 * @param object $form
1072 *
1073 * @return bool
1074 */
1075 public static function &is_visible_to_user( $form ) {
1076 if ( $form->logged_in && isset( $form->options['logged_in_role'] ) ) {
1077 $visible = FrmAppHelper::user_has_permission( $form->options['logged_in_role'] );
1078 } else {
1079 $visible = true;
1080 }
1081
1082 return $visible;
1083 }
1084
1085 public static function show_submit( $form ) {
1086 $show = ( ! $form->is_template && $form->status == 'published' && ! FrmAppHelper::is_admin() );
1087 $show = apply_filters( 'frm_show_submit_button', $show, $form );
1088
1089 return $show;
1090 }
1091
1092 /**
1093 * @since 2.3
1094 */
1095 public static function get_option( $atts ) {
1096 $form = $atts['form'];
1097 $default = isset( $atts['default'] ) ? $atts['default'] : '';
1098
1099 return isset( $form->options[ $atts['option'] ] ) ? $form->options[ $atts['option'] ] : $default;
1100 }
1101
1102 /**
1103 * Get the link to edit this form.
1104 *
1105 * @since 4.0
1106 * @param int $form_id The id of the form.
1107 */
1108 public static function get_edit_link( $form_id ) {
1109 return admin_url( 'admin.php?page=formidable&frm_action=edit&id=' . $form_id );
1110 }
1111
1112 /**
1113 * @deprecated 3.0
1114 * @codeCoverageIgnore
1115 *
1116 * @param string $key
1117 *
1118 * @return int form id
1119 */
1120 public static function getIdByKey( $key ) {
1121 return FrmFormDeprecated::getIdByKey( $key );
1122 }
1123
1124 /**
1125 * @deprecated 3.0
1126 * @codeCoverageIgnore
1127 */
1128 public static function getKeyById( $id ) {
1129 return FrmFormDeprecated::getKeyById( $id );
1130 }
1131 }
1132