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

1,152 lines 32.3 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|bool 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 *
812 * @param array $query
813 * @param int $limit
814 * @param string $inc_children
815 * @return array|object of forms A single form object would be passed if $limit was set to 1.
816 */
817 public static function get_published_forms( $query = array(), $limit = 999, $inc_children = 'exclude' ) {
818 $query['is_template'] = 0;
819 $query['status'] = array( null, '', 'published' );
820 if ( $inc_children == 'exclude' ) {
821 $query['parent_form_id'] = array( null, 0 );
822 }
823
824 $forms = self::getAll( $query, 'name', $limit );
825
826 return $forms;
827 }
828
829 /**
830 * @return object count of forms
831 */
832 public static function get_count() {
833 global $wpdb;
834
835 $cache_key = 'frm_form_counts';
836
837 $counts = wp_cache_get( $cache_key, 'frm_form' );
838 if ( false !== $counts ) {
839 return $counts;
840 }
841
842 $results = (array) FrmDb::get_results(
843 'frm_forms',
844 array(
845 'or' => 1,
846 'parent_form_id' => null,
847 'parent_form_id <' => 0,
848 ),
849 'status, is_template'
850 );
851
852 $statuses = array( 'published', 'draft', 'template', 'trash' );
853 $counts = array_fill_keys( $statuses, 0 );
854
855 foreach ( $results as $row ) {
856 if ( 'trash' != $row->status ) {
857 if ( $row->is_template ) {
858 $counts['template'] ++;
859 } else {
860 $counts['published'] ++;
861 }
862 } else {
863 $counts['trash'] ++;
864 }
865
866 if ( 'draft' == $row->status ) {
867 $counts['draft'] ++;
868 }
869
870 unset( $row );
871 }
872
873 $counts = (object) $counts;
874 FrmDb::set_cache( $cache_key, $counts, 'frm_form' );
875
876 return $counts;
877 }
878
879 /**
880 * Clear form caching
881 * Called when a form is created, updated, duplicated, or deleted
882 * or when the form status is changed
883 *
884 * @since 2.0.4
885 */
886 public static function clear_form_cache() {
887 FrmDb::cache_delete_group( 'frm_form' );
888 }
889
890 /**
891 * @return array of errors
892 */
893 public static function validate( $values ) {
894 $errors = array();
895
896 return apply_filters( 'frm_validate_form', $errors, $values );
897 }
898
899 public static function get_params( $form = null ) {
900 global $frm_vars;
901
902 if ( ! $form ) {
903 $form = self::getAll( array(), 'name', 1 );
904 } else {
905 self::maybe_get_form( $form );
906 }
907
908 if ( isset( $frm_vars['form_params'] ) && is_array( $frm_vars['form_params'] ) && isset( $frm_vars['form_params'][ $form->id ] ) ) {
909 return $frm_vars['form_params'][ $form->id ];
910 }
911
912 $action_var = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action'; // phpcs:ignore WordPress.Security.NonceVerification.Missing
913 $action = apply_filters( 'frm_show_new_entry_page', FrmAppHelper::get_param( $action_var, 'new', 'get', 'sanitize_title' ), $form );
914
915 $default_values = array(
916 'id' => '',
917 'form_name' => '',
918 'paged' => 1,
919 'form' => $form->id,
920 'form_id' => $form->id,
921 'field_id' => '',
922 'search' => '',
923 'sort' => '',
924 'sdir' => '',
925 'action' => $action,
926 );
927
928 $values = array();
929 $values['posted_form_id'] = FrmAppHelper::get_param( 'form_id', '', 'get', 'absint' );
930 if ( ! $values['posted_form_id'] ) {
931 $values['posted_form_id'] = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
932 }
933
934 if ( $form->id == $values['posted_form_id'] ) {
935 //if there are two forms on the same page, make sure not to submit both
936 foreach ( $default_values as $var => $default ) {
937 if ( $var == 'action' ) {
938 $values[ $var ] = FrmAppHelper::get_param( $action_var, $default, 'get', 'sanitize_title' );
939 } else {
940 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
941 }
942 unset( $var, $default );
943 }
944 } else {
945 foreach ( $default_values as $var => $default ) {
946 $values[ $var ] = $default;
947 unset( $var, $default );
948 }
949 }
950
951 if ( in_array( $values['action'], array( 'create', 'update' ) ) &&
952 ( ! $_POST || ( ! isset( $_POST['action'] ) && ! isset( $_POST['frm_action'] ) ) ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
953 ) {
954 $values['action'] = 'new';
955 }
956
957 return $values;
958 }
959
960 public static function list_page_params() {
961 $values = array();
962 $defaults = array(
963 'template' => 0,
964 'id' => '',
965 'paged' => 1,
966 'form' => '',
967 'search' => '',
968 'sort' => '',
969 'sdir' => '',
970 );
971 foreach ( $defaults as $var => $default ) {
972 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
973 }
974
975 return $values;
976 }
977
978 public static function get_admin_params( $form = null ) {
979 $form_id = $form;
980 if ( $form === null ) {
981 $form_id = self::get_current_form_id();
982 } elseif ( $form && is_object( $form ) ) {
983 $form_id = $form->id;
984 }
985
986 $values = array();
987 $defaults = array(
988 'id' => '',
989 'form_name' => '',
990 'paged' => 1,
991 'form' => $form_id,
992 'field_id' => '',
993 'search' => '',
994 'sort' => '',
995 'sdir' => '',
996 'fid' => '',
997 'keep_post' => '',
998 );
999 foreach ( $defaults as $var => $default ) {
1000 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
1001 }
1002
1003 return $values;
1004 }
1005
1006 public static function get_current_form_id( $default_form = 'none' ) {
1007 if ( 'first' == $default_form ) {
1008 $form = self::get_current_form();
1009 } else {
1010 $form = self::maybe_get_current_form();
1011 }
1012 $form_id = $form ? $form->id : 0;
1013
1014 return $form_id;
1015 }
1016
1017 public static function maybe_get_current_form( $form_id = 0 ) {
1018 global $frm_vars;
1019
1020 if ( isset( $frm_vars['current_form'] ) && $frm_vars['current_form'] && ( ! $form_id || $form_id == $frm_vars['current_form']->id ) ) {
1021 return $frm_vars['current_form'];
1022 }
1023
1024 $form_id = FrmAppHelper::get_param( 'form', $form_id, 'get', 'absint' );
1025 if ( $form_id ) {
1026 $form_id = self::set_current_form( $form_id );
1027 }
1028
1029 return $form_id;
1030 }
1031
1032 public static function get_current_form( $form_id = 0 ) {
1033 $form = self::maybe_get_current_form( $form_id );
1034 if ( is_numeric( $form ) ) {
1035 $form = self::set_current_form( $form );
1036 }
1037
1038 return $form;
1039 }
1040
1041 public static function set_current_form( $form_id ) {
1042 global $frm_vars;
1043
1044 $query = array();
1045 if ( $form_id ) {
1046 $query['id'] = $form_id;
1047 }
1048
1049 $frm_vars['current_form'] = self::get_published_forms( $query, 1 );
1050
1051 return $frm_vars['current_form'];
1052 }
1053
1054 public static function is_form_loaded( $form, $this_load, $global_load ) {
1055 global $frm_vars;
1056 $small_form = new stdClass();
1057 foreach ( array( 'id', 'form_key', 'name' ) as $var ) {
1058 $small_form->{$var} = $form->{$var};
1059 unset( $var );
1060 }
1061
1062 $frm_vars['forms_loaded'][] = $small_form;
1063
1064 if ( $this_load && empty( $global_load ) ) {
1065 $global_load = true;
1066 $frm_vars['load_css'] = true;
1067 }
1068
1069 return ( ( ! isset( $frm_vars['css_loaded'] ) || ! $frm_vars['css_loaded'] ) && $global_load );
1070 }
1071
1072 /**
1073 * @since 4.06.03
1074 *
1075 * @param object $form
1076 *
1077 * @return bool
1078 */
1079 public static function &is_visible_to_user( $form ) {
1080 if ( $form->logged_in && isset( $form->options['logged_in_role'] ) ) {
1081 $visible = FrmAppHelper::user_has_permission( $form->options['logged_in_role'] );
1082 } else {
1083 $visible = true;
1084 }
1085
1086 return $visible;
1087 }
1088
1089 public static function show_submit( $form ) {
1090 $show = ( ! $form->is_template && $form->status == 'published' && ! FrmAppHelper::is_admin() );
1091 $show = apply_filters( 'frm_show_submit_button', $show, $form );
1092
1093 return $show;
1094 }
1095
1096 /**
1097 * @since 2.3
1098 */
1099 public static function get_option( $atts ) {
1100 $form = $atts['form'];
1101 $default = isset( $atts['default'] ) ? $atts['default'] : '';
1102
1103 return isset( $form->options[ $atts['option'] ] ) ? $form->options[ $atts['option'] ] : $default;
1104 }
1105
1106 /**
1107 * Get the link to edit this form.
1108 *
1109 * @since 4.0
1110 * @param int $form_id The id of the form.
1111 */
1112 public static function get_edit_link( $form_id ) {
1113 return admin_url( 'admin.php?page=formidable&frm_action=edit&id=' . $form_id );
1114 }
1115
1116 /**
1117 * Check if the "Submit this form with AJAX" setting is toggled on.
1118 *
1119 * @since 6.2
1120 *
1121 * @param stdClass $form
1122 * @return bool
1123 */
1124 public static function is_ajax_on( $form ) {
1125 return ! empty( $form->options['ajax_submit'] );
1126 }
1127
1128 /**
1129 * @deprecated 2.03.05 This is still referenced in a few add ons (API, locations).
1130 * @codeCoverageIgnore
1131 *
1132 * @param string $key
1133 * @return int form id
1134 */
1135 public static function getIdByKey( $key ) {
1136 _deprecated_function( __FUNCTION__, '2.03.05', 'FrmForm::get_id_by_key' );
1137 return self::get_id_by_key( $key );
1138 }
1139
1140 /**
1141 * @deprecated 2.03.05 This is still referenced in the API add on as of v1.13.
1142 * @codeCoverageIgnore
1143 *
1144 * @param string|int $id
1145 * @return string
1146 */
1147 public static function getKeyById( $id ) {
1148 _deprecated_function( __FUNCTION__, '2.03.05', 'FrmForm::get_key_by_id' );
1149 return self::get_key_by_id( $id );
1150 }
1151 }
1152