PluginProbe
weForms – Easy Drag & Drop Contact Form Builder For WordPress / 1.6.26
weForms – Easy Drag & Drop Contact Form Builder For WordPress v1.6.26
1.6.7 1.6.8 1.6.9 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.18 1.6.19 1.6.2 1.6.20 1.6.21 1.6.22 1.6.23 1.6.24 1.6.25 1.6.26 1.6.27 1.6.28 1.6.3 1.6.4 1.6.5 1.6.6 All 74 releases
weforms / includes / class-form.php

class-form.php in weForms – Easy Drag & Drop Contact Form Builder For WordPress 1.6.26, at includes/class-form.php

663 lines 21.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The Form Class
5 *
6 * @since 1.1.0
7 */
8 class WeForms_Form {
9
10 /**
11 * The form id
12 *
13 * @var int
14 */
15 public $id = 0;
16
17 /**
18 * The form title
19 *
20 * @var string
21 */
22 public $name = '';
23
24 /**
25 * Holds the post data object
26 *
27 * @var WP_post|null
28 */
29 public $data = null;
30
31 /**
32 * Derived/formatted stats & metadata used by admin/AJAX/API responses.
33 * Declared explicitly to avoid PHP 8.2 "dynamic property" deprecations.
34 *
35 * @var int
36 */
37 public $entries = 0;
38
39 /**
40 * @var array
41 */
42 public $settings = [];
43
44 /**
45 * @var int
46 */
47 public $views = 0;
48
49 /**
50 * @var int
51 */
52 public $payments = 0;
53
54 /**
55 * @var array
56 */
57 public $author = [];
58
59 /**
60 * Form fields
61 *
62 * @var array
63 */
64 public $form_fields = [];
65
66 /**
67 * The Constructor
68 *
69 * @param int|WP_Post $form
70 */
71 public function __construct( $form = null ) {
72 if ( is_numeric( $form ) ) {
73 $the_post = get_post( $form );
74
75 if ( $the_post ) {
76 $this->id = $the_post->ID;
77 $this->name = $the_post->post_title;
78 $this->data = $the_post;
79 }
80 } elseif ( is_a( $form, 'WP_Post' ) ) {
81 $this->id = $form->ID;
82 $this->name = $form->post_title;
83 $this->data = $form;
84 }
85 }
86
87 /**
88 * Get the form ID
89 *
90 * @return int
91 */
92 public function get_id() {
93 return $this->id;
94 }
95
96 /**
97 * Get the form name
98 *
99 * @return string
100 */
101 public function get_name() {
102 return $this->name;
103 }
104
105 /**
106 * Get all form fields of this form
107 *
108 * @return array
109 */
110 public function get_fields() {
111
112 // return if already fetched
113 if ( $this->form_fields ) {
114 return $this->form_fields;
115 }
116
117 $fields = get_children( [
118 'post_parent' => $this->id,
119 'post_status' => 'publish',
120 'post_type' => 'wpuf_input',
121 'numberposts' => '-1',
122 'orderby' => 'menu_order',
123 'order' => 'ASC',
124 ] );
125
126 $form_fields = [];
127
128 foreach ( $fields as $key => $content ) {
129 $field = maybe_unserialize( $content->post_content );
130
131 if ( empty( $field['template'] ) ) {
132 continue;
133 }
134
135 $field['id'] = $content->ID;
136
137 // Add inline property for radio and checkbox fields
138 $inline_supported_fields = apply_filters( 'inline_supported_fields_list', [ 'radio_field', 'checkbox_field' ] );
139
140 if ( in_array( $field['template'], $inline_supported_fields ) ) {
141 if ( !isset( $field['inline'] ) ) {
142 $field['inline'] = 'no';
143 }
144 }
145
146 // Add 'selected' property
147 $option_based_fields = apply_filters( 'option_based_fields_list', [ 'dropdown_field', 'multiple_select', 'radio_field', 'checkbox_field' ] );
148
149 if ( in_array( $field['template'], $option_based_fields ) ) {
150 if ( !isset( $field['selected'] ) ) {
151 if ( 'dropdown_field' === $field['template'] || 'radio_field' === $field['template'] ) {
152 $field['selected'] = '';
153 } else {
154 $field['selected'] = [];
155 }
156 }
157 }
158
159 // Add 'multiple' key for template:repeat
160 if ( 'repeat_field' === $field['template'] && !isset( $field['multiple'] ) ) {
161 $field['multiple'] = '';
162 }
163
164 if ( 'recaptcha' === $field['template'] ) {
165 $field['name'] = 'recaptcha';
166 $field['enable_no_captcha'] = isset( $field['enable_no_captcha'] ) ? $field['enable_no_captcha'] : '';
167 $field['recaptcha_theme'] = isset( $field['recaptcha_theme'] ) ? $field['recaptcha_theme'] : 'light';
168 }
169
170 // Check if meta_key has changed when saving form compared current entries
171 if ( isset( $field['name'] ) ) {
172 $field['original_name'] = $field['name'];
173 }
174 $form_fields[] = apply_filters( 'weforms-get-form-field', $field, $this->id );
175 }
176
177 $this->form_fields = apply_filters( 'weforms-get-form-fields', $form_fields, $this->id );
178
179 return $this->form_fields;
180 }
181
182 /**
183 * Check if any perticular field template is used in a form
184 *
185 * @return array
186 */
187 public function has_field( $field_template ) {
188 foreach ( $this->get_fields() as $key => $field ) {
189 if ( isset( $field['template'] ) && $field['template'] == $field_template ) {
190 return true;
191 }
192 }
193 }
194
195 /**
196 * Get all fields by a template
197 *
198 * @return array
199 */
200 public function search_fields( $field_template ) {
201 $fields = [];
202
203 foreach ( $this->get_fields() as $key => $field ) {
204 if ( isset( $field['template'] ) && $field['template'] == $field_template ) {
205 $fields[] = $field;
206 }
207 }
208
209 return $fields;
210 }
211
212 /**
213 * Search fileds and get the first one
214 *
215 * @return array
216 */
217 public function search_field( $field_template ) {
218 $fields = $this->search_fields( $field_template );
219
220 return isset( $fields[0] ) ? $fields[0] : [];
221 }
222
223 /**
224 * Get formatted field name/values
225 *
226 * @return array
227 */
228 public function get_field_values() {
229 $values = [];
230 $fields = $this->get_fields();
231
232 if ( !$fields ) {
233 return $values;
234 }
235
236 $ignore_fields = apply_filters( 'ignore_fields_list', [ 'recaptcha', 'section_break' ] );
237 $options_fields = apply_filters( 'option_fields_list', [ 'dropdown_field', 'radio_field', 'multiple_select', 'checkbox_field' ] );
238
239 foreach ( $fields as $field ) {
240 if ( in_array( $field['template'], $ignore_fields ) ) {
241 continue;
242 }
243
244 // Prepare column field data
245 if ( $field['template'] == 'column_field' ) {
246 $inner_columns = $field['inner_fields'];
247
248 if ( !empty( $inner_columns ) ) {
249 foreach ( $inner_columns as $column => $column_fields ) {
250 if ( !empty( $column_fields ) ) {
251 foreach ( $column_fields as $field_obj ) {
252 if ( in_array( $field_obj['template'], $ignore_fields ) ) {
253 continue;
254 }
255
256 if ( !isset( $field_obj['name'] ) ) {
257 continue;
258 }
259
260 $field_value = [
261 'label' => isset( $field_obj['label'] ) ? $field_obj['label'] : '',
262 'type' => $field_obj['template'],
263 ];
264
265 // put options if this is an option field
266 if ( in_array( $field_obj['template'], $options_fields ) ) {
267 $field_value['options'] = $field_obj['options'];
268 }
269
270 $values[ $field_obj['name'] ] = array_merge( $field_obj, $field_value );
271 }
272 }
273 }
274 }
275 }
276
277 if ( !isset( $field['name'] ) ) {
278 continue;
279 }
280
281 $value = [
282 'label' => isset( $field['label'] ) ? $field['label'] : '',
283 'type' => $field['template'],
284 ];
285
286 // put options if this is an option field
287 if ( in_array( $field['template'], $options_fields ) ) {
288 $value['options'] = $field['options'];
289 }
290
291 $values[ $field['name'] ] = array_merge( $field, $value );
292 }
293
294 return apply_filters( 'weforms_get_field_values', $values );
295 }
296
297 /**
298 * Get form settings
299 *
300 * @return array
301 */
302 public function get_settings() {
303 $settings = get_post_meta( $this->id, 'wpuf_form_settings', true );
304 $default = weforms_get_default_form_settings();
305
306 return apply_filters( 'weforms-get-form-settings', array_merge( $default, $settings ), $this->id );
307 }
308
309 /**
310 * Check if the form submission is open
311 *
312 * @return bool|WP_Error
313 */
314 public function is_submission_open() {
315 $settings = $this->get_settings();
316
317 $needs_login = ( isset( $settings['require_login'] ) && $settings['require_login'] == 'true' ) ? true : false;
318 $has_limit = ( isset( $settings['limit_entries'] ) && $settings['limit_entries'] == 'true' ) ? true : false;
319 $is_scheduled = ( isset( $settings['schedule_form'] ) && $settings['schedule_form'] == 'true' ) ? true : false;
320
321 if ( $this->data->post_status != 'publish' ) {
322 return new WP_Error( 'needs-publish', __( 'The form is not published yet.', 'weforms' ) );
323 }
324
325 if ( $needs_login && !is_user_logged_in() ) {
326 return new WP_Error( 'needs-login', $settings['req_login_message'] );
327 }
328
329 if ( $has_limit ) {
330 $limit = (int) $settings['limit_number'];
331 $form_entries = $this->num_form_entries();
332
333 if ( $limit <= $form_entries ) {
334 return new WP_Error( 'entry-limit', $settings['limit_message'] );
335 }
336 }
337
338 if ( $is_scheduled ) {
339 $start_time = strtotime( $settings['schedule_start'] );
340 $end_time = strtotime( $settings['schedule_end'] );
341 $current_time = current_time( 'timestamp' );
342
343 // too early?
344 if ( $current_time < $start_time ) {
345 return new WP_Error( 'form-pending', $settings['sc_pending_message'] );
346 } elseif ( $current_time > $end_time ) {
347 return new WP_Error( 'form-expired', $settings['sc_expired_message'] );
348 }
349 }
350
351 return apply_filters( 'weforms_is_submission_open', true, $settings, $this );
352 }
353
354 /**
355 * Get form notifications
356 *
357 * @return array
358 */
359 public function get_notifications() {
360 $notifications = get_post_meta( $this->id, 'notifications', true );
361 $defualt = weforms_get_default_form_notification();
362
363 if ( !$notifications ) {
364 $notifications = [];
365 }
366
367 $notifications = array_map( function ( $notification ) use ( $defualt ) {
368 if ( empty( $notification ) ) {
369 $notification = [];
370 }
371
372 return array_merge( $defualt, $notification );
373 }, $notifications );
374
375 return $notifications;
376 }
377
378 /**
379 * Get all the integrations
380 *
381 * @return array
382 */
383 public function get_integrations() {
384 $integrations = get_post_meta( $this->id, 'integrations', true );
385
386 if ( !$integrations ) {
387 return [];
388 }
389
390 return $integrations;
391 }
392
393 /**
394 * Get entries of this form
395 *
396 * @return \WeForms_Form_Entry_Manager
397 */
398 public function entries() {
399 return new WeForms_Form_Entry_Manager( $this->id, $this );
400 }
401
402 /**
403 * When a user is editing their form they may change a fields name.
404 * This method will loop through existing entries to match the new field names.
405 *
406 * @since 1.6.9
407 *
408 * @param int $form_id
409 * @param array $form_fields
410 */
411 public function maybe_update_entries( $form_fields ) {
412 $changed_fields = $this->get_changed_fields( $form_fields );
413 // Loop through changed fields and update entries
414 foreach ( $changed_fields as $old => $new) {
415 $updated_fields = $this->rename_field( $old, $new );
416 }
417 }
418
419 /**
420 * When a user is editing their form they may change a fields name.
421 * This method will loop through all fields that have changed.
422 *
423 * @since 1.6.9
424 *
425 * @param int $form_id
426 * @param array $form_fields
427 *
428 * @return array
429 */
430 public function get_changed_fields( $form_fields ) {
431 $changed_fields = array();
432 foreach ( $form_fields as $field ) {
433 $org_field = $field['original_name'];
434 // All form fields should have an original name.
435 if ( empty( $field['original_name'] ) ) {
436 continue;
437 }
438 if ( $field['name'] !== $field['original_name'] ) {
439 $changed_fields[$field['original_name']] = $field['name'];
440 } else {
441 continue;
442 }
443 }
444 return $changed_fields;
445
446 }
447
448 /**
449 * When a user changes the field names of a form, the existing entries will need updated.
450 * This method will loop through the existing entries and update them will the new names.
451 *
452 * @since 1.6.9
453 *
454 * @param int $form_id
455 * @param array $form_fields
456 *
457 * @return array
458 */
459 public function rename_field ( $old, $new ) {
460 global $wpdb;
461
462 $entries = weforms_get_form_entries( $this->id );
463
464 foreach ( $entries as $entry ) {
465 $entry_id = $entry->id;
466 $values = weforms_get_entry_meta( $entry_id );
467 $update_keys = $wpdb->update( $wpdb->weforms_entrymeta, array( 'meta_key' => $new ), array( 'meta_key' => $old, 'weforms_entry_id' => $entry_id ) );
468 }
469 }
470
471 /**
472 * Get number of form entries
473 *
474 * @return int
475 */
476 public function num_form_entries() {
477 return weforms_count_form_entries( $this->id );
478 }
479
480 /**
481 * Get number of form payments
482 *
483 * @return int
484 */
485 public function num_form_payments() {
486 return weforms_count_form_payments( $this->id );
487 }
488
489 /**
490 * Get form author details
491 *
492 * @return array
493 */
494 public function get_form_author_details() {
495 return weforms_get_form_author_details( $this->id );
496 }
497
498 /**
499 * Get the number of form views
500 *
501 * @return int
502 */
503 public function num_form_views() {
504 return weforms_get_form_views( $this->id );
505 }
506
507 /**
508 * prepare_entries
509 *
510 * @return array
511 */
512 public function prepare_entries( $args = [] ) {
513 $fields = weforms()->fields->get_fields();
514 $form_fields = $this->get_fields();
515
516 $entry_fields = [];
517
518 $ignore_list = apply_filters( 'wefroms_entry_ignore_list', [
519 'recaptcha', 'section_break', 'step_start',
520 ] );
521
522 foreach ( $form_fields as $field ) {
523 if ( in_array( $field['template'], $ignore_list ) ) {
524 continue;
525 }
526
527 if ( !array_key_exists( $field['template'], $fields ) ) {
528 continue;
529 }
530
531 // Prepare column field data
532 if ( $field['template'] == 'column_field' ) {
533 $inner_columns = $field['inner_fields'];
534
535 if ( !empty( $inner_columns ) ) {
536 foreach ( $inner_columns as $column => $column_fields ) {
537 if ( !empty( $column_fields ) ) {
538 foreach ( $column_fields as $field_obj ) {
539 if ( in_array( $field_obj['template'], $ignore_list ) ) {
540 continue;
541 }
542
543 $fieldClass = $fields[ $field_obj['template'] ];
544 $entry_fields[ $field_obj['name'] ] = $fieldClass->prepare_entry( $field_obj );
545 }
546 }
547 }
548 }
549 }
550
551 $field_class = $fields[ $field['template'] ];
552
553 $entry_fields[ $field['name'] ] = $field_class->prepare_entry( $field, $args );
554 }
555
556 return apply_filters( 'weforms_prepare_entries', $entry_fields );
557 }
558
559 /**
560 * Check if the form submission is open On API
561 *
562 * @return bool|WP_Error
563 */
564 public function is_api_form_submission_open() {
565 $response = [];
566 $settings = $this->get_settings();
567 $form_entries = $this->num_form_entries();
568 $needs_login = isset( $settings['require_login'] ) ? $settings['require_login'] : 'false';
569 $limit_entries = isset( $settings['limit_entries'] ) ? $settings['limit_entries'] : 'false';
570 $schedule_form = isset( $settings['schedule_form'] ) ? $settings['schedule_form'] : 'false';
571 $limit_number = isset( $settings['limit_number'] ) ? $settings['limit_number'] : '';
572 $schedule_start = isset( $settings['schedule_start'] ) ? $settings['schedule_start'] : '';
573 $schedule_end = isset( $settings['schedule_end'] ) ? $settings['schedule_end'] : '';
574 $schedule_start_date = date_i18n( 'M d, Y', strtotime( $schedule_start ) );
575 $schedule_end_date = date_i18n( 'M d, Y', strtotime( $schedule_end ) );
576
577 if ( $this->data->post_status != 'publish' ) {
578 $response['type'] = __( 'Closed', 'weforms' );
579 }
580
581 if ( $this->isFormStatusClosed( $settings, $form_entries ) ) {
582 $response['type'] = __( 'Closed', 'weforms' );
583 } else {
584 $response['type'] = __( 'Open', 'weforms' );
585 }
586
587 if ( $limit_entries === 'true' ) {
588 if ( $schedule_form === 'true' && $this->isExpiredForm( $schedule_end ) ) {
589 $response['message'] = __( "Expired at {$schedule_end_date}", 'weforms' );
590 } elseif ( $schedule_form === 'true' && $this->isPendingForm( $schedule_start ) ) {
591 $response['message'] = __( "Starts at {$schedule_start_date}", 'weforms' );
592 } elseif ( $form_entries >= $limit_number ) {
593 $response['message'] = __( 'Reached maximum entry limit', 'weforms' );
594 } else {
595 $remaining_entries = $limit_number - $form_entries;
596 $response['message'] = __( "{$remaining_entries} entries remaining ", 'weforms' );
597 }
598 } elseif ( $schedule_form === 'true' ) {
599 if ( $this->isPendingForm( $schedule_start ) ) {
600 $response['message'] = __( "Starts at {$schedule_start_date}", 'weforms' );
601 } elseif ( $this->isExpiredForm( $schedule_end ) ) {
602 $response['message'] = __( "Expired at {$schedule_end_date}", 'weforms' );
603 } elseif ( $this->isOpenForm( $schedule_start, $schedule_end ) ) {
604 $response['message'] = __( "Expires at {$schedule_end_date}", 'weforms' );
605 }
606 } elseif ( $needs_login === 'true' ) {
607 $response['message'] =__( 'Requires login', 'weforms' );
608 }
609
610 return apply_filters( 'weforms_is_submission_open', $response, $settings, $this );
611 }
612
613 public function isPendingForm( $scheduleStart ) {
614 $currentTime = current_time( 'timestamp' );
615 $startTime = strtotime( $scheduleStart );
616
617 if ( $currentTime < $startTime ) {
618 return true;
619 }
620
621 return false;
622 }
623
624 public function isExpiredForm( $scheduleEnd ) {
625 $currentTime = current_time( 'timestamp' );
626 $endTime = strtotime( $scheduleEnd );
627
628 if ( $currentTime > $endTime ) {
629 return true;
630 }
631
632 return false;
633 }
634
635 public function isOpenForm( $scheduleStart, $scheduleEnd ) {
636 $currentTime = current_time( 'timestamp' );
637 $startTime = strtotime( $scheduleStart );
638 $endTime = strtotime( $scheduleEnd );
639
640 if ( $currentTime > $startTime && $currentTime < $endTime ) {
641 return true;
642 }
643
644 return false;
645 }
646
647 public function isFormStatusClosed( $formSettings, $entries ) {
648 if ( $formSettings['schedule_form'] === 'true' && $this->isPendingForm( $formSettings['schedule_start'] ) ) {
649 return true;
650 }
651
652 if ( $formSettings['schedule_form'] === 'true' && $this->isExpiredForm( $formSettings['schedule_end'] ) ) {
653 return true;
654 }
655
656 if ( $formSettings['limit_entries'] === 'true' && $entries >= $formSettings['limit_number'] ) {
657 return true;
658 }
659
660 return false;
661 }
662 }
663