PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.2.0
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.2.0
2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 All 96 releases
sureforms / inc / post-types.php

post-types.php in SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz 2.2.0, at inc/post-types.php

1,314 lines 39.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Post Types Class file.
4 *
5 * @package sureforms.
6 * @since 0.0.1
7 */
8
9 namespace SRFM\Inc;
10
11 use SRFM\Inc\Traits\Get_Instance;
12 use WP_Admin_Bar;
13 use WP_Post;
14 use WP_REST_Response;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit; // Exit if accessed directly.
18 }
19
20 /**
21 * Post Types Main Class.
22 *
23 * @since 0.0.1
24 */
25 class Post_Types {
26 use Get_Instance;
27
28 /**
29 * Constructor
30 *
31 * @since 0.0.1
32 */
33 public function __construct() {
34 $this->restrict_unwanted_insertions();
35 add_action( 'init', [ $this, 'register_post_types' ] );
36 add_action( 'init', [ $this, 'register_post_metas' ] );
37 add_shortcode( 'sureforms', [ $this, 'forms_shortcode' ] );
38 add_action( 'manage_posts_extra_tablenav', [ $this, 'maybe_render_blank_form_state' ] );
39 add_action( 'admin_bar_menu', [ $this, 'remove_admin_bar_menu_item' ], 80, 1 );
40 add_action( 'template_redirect', [ $this, 'srfm_instant_form_redirect' ] );
41 add_action( 'template_redirect', [ $this, 'disable_sureforms_archive_page' ], 9 );
42 add_action( 'load-edit.php', [ $this, 'redirect_forms_listing_page' ] );
43
44 add_filter( 'rest_prepare_sureforms_form', [ $this, 'sureforms_normalize_meta_for_rest' ], 10, 2 );
45 add_action( 'admin_bar_menu', [ $this, 'add_edit_form_to_admin_bar_menu' ], 100 );
46 }
47
48 /**
49 * Redirect the forms listing page to the updated forms page.
50 *
51 * @return void
52 * @since 2.0.0
53 */
54 public function redirect_forms_listing_page() {
55 global $pagenow;
56
57 if ( 'edit.php' === $pagenow && isset( $_GET['post_type'] ) && SRFM_FORMS_POST_TYPE === $_GET['post_type'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce is not required for the redirection.
58 wp_safe_redirect( admin_url( 'admin.php?page=sureforms_forms' ) );
59 exit;
60 }
61 }
62
63 /**
64 * Add "Edit Form" link to the admin bar menu.
65 *
66 * @param WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance.
67 * @since 2.0.0
68 * @return void
69 */
70 public function add_edit_form_to_admin_bar_menu( $wp_admin_bar ) {
71
72 // Bail early if admin bar or user isn’t available.
73 if ( ! is_user_logged_in() || ! is_admin_bar_showing() || ! $wp_admin_bar instanceof WP_Admin_Bar ) {
74 return;
75 }
76
77 global $post;
78
79 // Bail if no valid post or wrong post type.
80 if ( empty( $post ) || SRFM_FORMS_POST_TYPE !== $post->post_type ) {
81 return;
82 }
83
84 $edit_link = get_edit_post_link( $post->ID );
85 if ( ! $edit_link ) {
86 return;
87 }
88
89 $wp_admin_bar->add_node(
90 [
91 'id' => 'edit-form',
92 'title' => sprintf(
93 '<span class="ab-icon dashicons dashicons-edit" style="line-height:1.2;margin-right:4px;"></span>
94 <span class="ab-label" style="position:relative;top:-1px;">%s</span>',
95 esc_html__( 'Edit Form', 'sureforms' )
96 ),
97 'href' => esc_url( $edit_link ),
98 'meta' => [
99 'title' => esc_attr__( 'Edit this form', 'sureforms' ),
100 ],
101 'html' => true,
102 ]
103 );
104 }
105
106 /**
107 * Remove this method in the future once _srfm_form_confirmation meta is updated.
108 * Normalize the _srfm_form_confirmation meta before it's sent to the REST API.
109 * Ensures the meta data is type-safe and includes necessary defaults like `hide_copy`.
110 *
111 * @param WP_REST_Response $response The REST response object.
112 * @param WP_Post $post The post object.
113 *
114 * @return WP_REST_Response Modified REST response with normalized meta.
115 * @since 1.7.3
116 */
117 public function sureforms_normalize_meta_for_rest( $response, $post ) {
118 $meta_raw = get_post_meta( $post->ID, '_srfm_form_confirmation', true );
119 $form_confirmation = maybe_unserialize( is_string( $meta_raw ) ? $meta_raw : '' );
120
121 if ( ! is_array( $form_confirmation ) ) {
122 return $response;
123 }
124
125 foreach ( $form_confirmation as $index => $item ) {
126 if ( ! is_array( $item ) ) {
127 continue;
128 }
129
130 $form_confirmation[ $index ]['hide_copy'] = ! empty( $item['hide_copy'] );
131 $form_confirmation[ $index ]['hide_download_all'] = ! empty( $item['hide_download_all'] );
132 }
133
134 $response_data = $response->get_data();
135 if ( is_array( $response_data ) ) {
136 if ( ! isset( $response_data['meta'] ) || ! is_array( $response_data['meta'] ) ) {
137 $response_data['meta'] = [];
138 }
139
140 $response_data['meta']['_srfm_form_confirmation'] = $form_confirmation;
141 $response->set_data( $response_data );
142 }
143 return $response;
144 }
145
146 /**
147 * Add SureForms menu.
148 *
149 * @param string $title Parent slug.
150 * @param string $subtitle Parent slug.
151 * @param string $image Parent slug.
152 * @param string $button_text Parent slug.
153 * @param string $button_url Parent slug.
154 * @param string $after_button After button content.
155 * @return void
156 * @since 0.0.1
157 */
158 public function get_blank_page_markup( $title, $subtitle, $image, $button_text = '', $button_url = '', $after_button = '' ) {
159 ?>
160 <div class="sureform-add-new-form">
161 <p class="sureform-blank-page-title"><?php echo esc_html( $title ); ?></p>
162 <p class="sureform-blank-page-subtitle"><?php echo esc_html( $subtitle ); ?></p>
163 <img src="<?php echo esc_url( SRFM_URL . '/images/' . $image . '.svg' ); ?>" alt=""/>
164 <?php if ( ! empty( $button_text ) && ! empty( $button_url ) ) { ?>
165 <div class="sureforms-add-new-form-container">
166 <a class="sf-add-new-form-button" href="<?php echo esc_url( $button_url ); ?>">
167 <div class="button-secondary"><?php echo esc_html( $button_text ); ?></div>
168 </a>
169 <?php echo wp_kses_post( $after_button ); ?>
170 </div>
171 <?php } ?>
172 </div>
173 <?php
174 }
175
176 /**
177 * Render blank state for add new form screen.
178 *
179 * @param string $post_type Post type.
180 * @return void
181 * @since 0.0.1
182 */
183 public function sureforms_render_blank_state( $post_type ) {
184 if ( SRFM_ENTRIES === $post_type ) {
185
186 $this->get_blank_page_markup(
187 esc_html__( 'No records found', 'sureforms' ),
188 esc_html__(
189 'This is where your form entries will appear',
190 'sureforms'
191 ),
192 'blank-entries'
193 );
194 }
195 }
196
197 /**
198 * Registers the forms and submissions post types.
199 *
200 * @return void
201 * @since 0.0.1
202 */
203 public function register_post_types() {
204 $form_labels = [
205 'name' => _x( 'Forms', 'post type general name', 'sureforms' ),
206 'singular_name' => _x( 'Form', 'post type singular name', 'sureforms' ),
207 'menu_name' => _x( 'Forms', 'admin menu', 'sureforms' ),
208 'add_new' => _x( 'Add New', 'form', 'sureforms' ),
209 'add_new_item' => __( 'Add New Form', 'sureforms' ),
210 'new_item' => __( 'New Form', 'sureforms' ),
211 'edit_item' => __( 'Edit Form', 'sureforms' ),
212 'view_item' => __( 'View Form', 'sureforms' ),
213 'view_items' => __( 'View Forms', 'sureforms' ),
214 'all_items' => __( 'Forms', 'sureforms' ),
215 'search_items' => __( 'Search Forms', 'sureforms' ),
216 'parent_item_colon' => __( 'Parent Forms:', 'sureforms' ),
217 'not_found' => __( 'No forms found.', 'sureforms' ),
218 'not_found_in_trash' => __( 'No forms found in Trash.', 'sureforms' ),
219 'item_published' => __( 'Form published.', 'sureforms' ),
220 'item_updated' => __( 'Form updated.', 'sureforms' ),
221 ];
222 register_post_type(
223 SRFM_FORMS_POST_TYPE,
224 [
225 'labels' => $form_labels,
226 'rewrite' => [ 'slug' => 'form' ],
227 'public' => true,
228 'show_in_rest' => true,
229 'has_archive' => true,
230 'show_ui' => true,
231 'supports' => [ 'title', 'author', 'editor', 'custom-fields' ],
232 'show_in_menu' => false,
233 'show_in_nav_menus' => true,
234 'capabilities' => [
235 'edit_post' => 'manage_options',
236 'read_post' => 'manage_options',
237 'delete_post' => 'manage_options',
238 'edit_posts' => 'manage_options',
239 'edit_others_posts' => 'manage_options',
240 'publish_posts' => 'manage_options',
241 'read_private_posts' => 'manage_options',
242 'create_posts' => 'manage_options',
243 ],
244 ]
245 );
246 // will be used later.
247 // register_post_status(
248 // 'unread',
249 // array(
250 // 'label' => _x( 'Unread', 'sureforms', 'sureforms' ),
251 // 'public' => true,
252 // 'exclude_from_search' => false,
253 // 'show_in_admin_all_list' => true,
254 // 'show_in_admin_status_list' => true,
255 // Translators: %s is the number of unread items.
256 // 'label_count' => _n_noop( 'Unread (%s)', 'Unread (%s)', 'sureforms' ),
257 // )
258 // );.
259 }
260
261 /**
262 * Redirects requests for SureForms archieve page to homeurl
263 *
264 * @since 1.4.0
265 * @return void
266 */
267 public function disable_sureforms_archive_page() {
268 if ( is_post_type_archive( SRFM_FORMS_POST_TYPE ) ) {
269 wp_safe_redirect( home_url(), 301 );
270 exit;
271 }
272 }
273
274 /**
275 * Remove add new form menu item.
276 *
277 * @param WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance.
278 *
279 * @return void
280 * @since 0.0.1
281 */
282 public function remove_admin_bar_menu_item( $wp_admin_bar ) {
283 $wp_admin_bar->remove_node( 'new-sureforms_form' );
284 }
285
286 /**
287 * Show blank slate styles.
288 *
289 * @return void
290 * @since 0.0.1
291 */
292 public function get_blank_state_styles() {
293 ?>
294 <style type="text/css">
295 .sf-add-new-form-button:focus {
296 box-shadow: none !important;
297 outline: none !important;
298 }
299 #posts-filter .wp-list-table,
300 #posts-filter .tablenav.top,
301 .tablenav.bottom .actions,
302 .wrap .subsubsub {
303 display: none;
304 }
305 #posts-filter .tablenav.bottom {
306 height: auto;
307 }
308 .sureform-add-new-form {
309 display: flex;
310 flex-direction: column;
311 gap: 8px;
312 justify-content: center;
313 align-items: center;
314 padding: 24px 0 24px 0;
315 }
316 .sureform-blank-page-title {
317 color: var(--dashboard-heading);
318 font-family: Inter;
319 font-size: 22px;
320 font-style: normal;
321 font-weight: 600;
322 line-height: 28px;
323 margin: 0;
324 }
325 .sureform-blank-page-subtitle {
326 color: var(--dashboard-text);
327 margin: 0;
328 font-family: Inter;
329 font-size: 14px;
330 font-style: normal;
331 font-weight: 400;
332 line-height: 16px;
333 }
334 </style>
335 <?php
336 }
337
338 /**
339 * Show blank slate.
340 *
341 * @param string $which String which tablenav is being shown.
342 * @return void
343 * @since 0.0.1
344 */
345 public function maybe_render_blank_form_state( $which ) {
346 $screen = get_current_screen();
347 $post_type = $screen ? $screen->post_type : '';
348
349 if ( SRFM_FORMS_POST_TYPE === $post_type && 'bottom' === $which ) {
350
351 $counts = (array) wp_count_posts( SRFM_FORMS_POST_TYPE );
352 unset( $counts['auto-draft'] );
353 $count = array_sum( $counts );
354
355 if ( 0 < $count ) {
356 return;
357 }
358
359 $this->sureforms_render_blank_state( $post_type );
360
361 $this->get_blank_state_styles();
362
363 }
364 }
365
366 /**
367 * Registers the sureforms metas.
368 *
369 * @return void
370 * @since 0.0.1
371 */
372 public function register_post_metas() {
373 $check_icon = 'data:image/svg+xml;base64,' . base64_encode( strval( file_get_contents( plugin_dir_path( SRFM_FILE ) . 'images/check-icon.svg' ) ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
374
375 $metas = apply_filters(
376 'srfm_register_post_meta',
377 [
378 // General tab metas.
379 '_srfm_use_label_as_placeholder' => 'boolean',
380 '_srfm_submit_button_text' => 'string',
381 '_srfm_is_inline_button' => 'boolean',
382 // Submit Button.
383 '_srfm_submit_width_backend' => 'string',
384 '_srfm_button_border_radius' => 'integer',
385 '_srfm_submit_alignment' => 'string',
386 '_srfm_submit_alignment_backend' => 'string',
387 '_srfm_submit_width' => 'string',
388 '_srfm_inherit_theme_button' => 'boolean',
389 // Additional Classes.
390 '_srfm_additional_classes' => 'string',
391
392 // Advanced tab metas.
393 // Success Message.
394 '_srfm_submit_type' => 'string',
395 // Security.
396 '_srfm_captcha_security_type' => 'string',
397 '_srfm_form_recaptcha' => 'string',
398 // post meta to store if the form is AI generated.
399 '_srfm_is_ai_generated' => 'boolean',
400 ]
401 );
402
403 // Form Custom CSS meta.
404 register_post_meta(
405 'sureforms_form',
406 '_srfm_form_custom_css',
407 [
408 'show_in_rest' => [
409 'schema' => [
410 'type' => 'string',
411 'context' => [ 'edit' ],
412 ],
413 ],
414 'type' => 'string',
415 'single' => true,
416 'auth_callback' => static function() {
417 return Helper::current_user_can();
418 },
419 'sanitize_callback' => static function( $meta_value ) {
420 return wp_kses_post( $meta_value );
421 },
422 ]
423 );
424
425 // Get default values for meta keys.
426 $default_meta_keys = Create_New_Form::get_default_meta_keys();
427
428 foreach ( $metas as $meta => $type ) {
429 // Get default value if exists.
430 $default_value = $default_meta_keys[ $meta ] ?? null;
431
432 $meta_args = [
433 'show_in_rest' => [
434 'schema' => [
435 'type' => $type,
436 'context' => [ 'edit' ],
437 ],
438 ],
439 'single' => true,
440 'type' => $type,
441 'sanitize_callback' => 'sanitize_text_field',
442 'auth_callback' => static function() {
443 return Helper::current_user_can();
444 },
445 ];
446
447 // Add default value if it exists.
448 if ( null !== $default_value ) {
449 $meta_args['default'] = $default_value;
450 }
451
452 register_post_meta(
453 SRFM_FORMS_POST_TYPE,
454 $meta,
455 $meta_args
456 );
457 }
458
459 // Registers meta to handle values associated with form styling.
460 register_post_meta(
461 SRFM_FORMS_POST_TYPE,
462 '_srfm_instant_form_settings',
463 [
464 'single' => true,
465 'type' => 'object',
466 'auth_callback' => static function() {
467 return Helper::current_user_can();
468 },
469 'show_in_rest' => [
470 'schema' => [
471 'type' => 'object',
472 'context' => [ 'edit' ],
473 'properties' => [
474 'site_logo' => [
475 'type' => 'string',
476 ],
477 'site_logo_id' => [
478 'type' => 'integer',
479 ],
480 // Form page banner settings.
481 'cover_type' => [
482 'type' => 'string',
483 ],
484 'cover_color' => [
485 'type' => 'string',
486 ],
487 'cover_image' => [
488 'type' => 'string',
489 ],
490 'cover_image_id' => [
491 'type' => 'integer',
492 ],
493 // Form page background settings.
494 'bg_type' => [
495 'type' => 'string',
496 ],
497 'bg_color' => [
498 'type' => 'string',
499 ],
500 'bg_image' => [
501 'type' => 'string',
502 ],
503 'bg_image_id' => [
504 'type' => 'integer',
505 ],
506 'enable_instant_form' => [
507 'type' => 'boolean',
508 ],
509 'form_container_width' => [
510 'type' => 'integer',
511 ],
512 'single_page_form_title' => [
513 'type' => 'boolean',
514 ],
515 'use_banner_as_page_background' => [
516 'type' => 'boolean',
517 ],
518 ],
519 ],
520 ],
521 'default' => [
522 'bg_type' => 'color',
523 'bg_color' => '#ffffff',
524 'bg_image' => '',
525 'site_logo' => '',
526 'cover_type' => 'color',
527 'cover_color' => '#111C44',
528 'cover_image' => '',
529 'enable_instant_form' => false,
530 'form_container_width' => 620,
531 'single_page_form_title' => true,
532 'use_banner_as_page_background' => false,
533 ],
534 ]
535 );
536
537 register_post_meta(
538 SRFM_FORMS_POST_TYPE,
539 '_srfm_forms_styling',
540 [
541 'single' => true,
542 'type' => 'object',
543 'auth_callback' => static function() {
544 return Helper::current_user_can();
545 },
546 'show_in_rest' => [
547 'schema' => [
548 'type' => 'object',
549 'context' => [ 'edit' ],
550 'properties' => [
551 'primary_color' => [
552 'type' => 'string',
553 ],
554 'text_color' => [
555 'type' => 'string',
556 ],
557 'text_color_on_primary' => [
558 'type' => 'string',
559 ],
560 'field_spacing' => [
561 'type' => 'string',
562 ],
563 'submit_button_alignment' => [
564 'type' => 'string',
565 ],
566 'bg_type' => [
567 'type' => 'string',
568 ],
569 'bg_color' => [
570 'type' => 'string',
571 ],
572 'bg_image' => [
573 'type' => 'string',
574 ],
575 'bg_image_id' => [
576 'type' => 'integer',
577 ],
578 // Image Properties.
579 'bg_image_position' => [
580 'type' => 'object',
581 'properties' => [
582 'x' => [
583 'type' => 'number',
584 'format' => 'float',
585 ],
586 'y' => [
587 'type' => 'number',
588 'format' => 'float',
589 ],
590 ],
591 ],
592 'bg_image_attachment' => [
593 'type' => 'string',
594 ],
595 'bg_image_repeat' => [
596 'type' => 'string',
597 ],
598 'bg_image_size' => [
599 'type' => 'string',
600 ],
601 'bg_image_size_custom' => [
602 'type' => 'integer',
603 ],
604 'bg_image_size_custom_unit' => [
605 'type' => 'string',
606 ],
607 // Gradient Properties.
608 'bg_gradient' => [
609 'type' => 'string',
610 ],
611 'gradient_type' => [
612 'type' => 'string',
613 ],
614 'bg_gradient_type' => [
615 'type' => 'string',
616 ],
617 'bg_gradient_color_1' => [
618 'type' => 'string',
619 ],
620 'bg_gradient_color_2' => [
621 'type' => 'string',
622 ],
623 'bg_gradient_angle' => [
624 'type' => 'integer',
625 ],
626 'bg_gradient_location_1' => [
627 'type' => 'integer',
628 ],
629 'bg_gradient_location_2' => [
630 'type' => 'integer',
631 ],
632 // Overlay Properties.
633 'bg_overlay_size' => [
634 'type' => 'string',
635 ],
636 'bg_gradient_overlay_type' => [
637 'type' => 'string',
638 ],
639 'bg_overlay_opacity' => [
640 'type' => 'number',
641 ],
642 'bg_overlay_image' => [
643 'type' => 'string',
644 ],
645 'bg_overlay_image_id' => [
646 'type' => 'integer',
647 ],
648 'bg_image_overlay_color' => [
649 'type' => 'string',
650 ],
651 'bg_overlay_custom_size_unit' => [
652 'type' => 'string',
653 ],
654 'bg_overlay_custom_size' => [
655 'type' => 'integer',
656 ],
657 'bg_overlay_blend_mode' => [
658 'type' => 'string',
659 ],
660 'bg_overlay_position' => [
661 'type' => 'object',
662 'properties' => [
663 'x' => [
664 'type' => 'number',
665 'format' => 'float',
666 ],
667 'y' => [
668 'type' => 'number',
669 'format' => 'float',
670 ],
671 ],
672 ],
673 'bg_overlay_attachment' => [
674 'type' => 'string',
675 ],
676 'bg_overlay_repeat' => [
677 'type' => 'string',
678 ],
679 // Gradient Overlay Properties.
680 'bg_overlay_gradient' => [
681 'type' => 'string',
682 ],
683 'overlay_gradient_type' => [
684 'type' => 'string',
685 ],
686 'bg_overlay_gradient_type' => [
687 'type' => 'string',
688 ],
689 'bg_overlay_gradient_color_1' => [
690 'type' => 'string',
691 ],
692 'bg_overlay_gradient_color_2' => [
693 'type' => 'string',
694 ],
695 'bg_overlay_gradient_angle' => [
696 'type' => 'integer',
697 ],
698 'bg_overlay_gradient_location_1' => [
699 'type' => 'integer',
700 ],
701 'bg_overlay_gradient_location_2' => [
702 'type' => 'integer',
703 ],
704 // Form Padding.
705 'form_padding_top' => [
706 'type' => 'number',
707 ],
708 'form_padding_right' => [
709 'type' => 'number',
710 ],
711 'form_padding_bottom' => [
712 'type' => 'number',
713 ],
714 'form_padding_left' => [
715 'type' => 'number',
716 ],
717 'form_padding_unit' => [
718 'type' => 'string',
719 ],
720 'form_padding_link' => [
721 'type' => 'boolean',
722 ],
723 // Border Radius.
724 'form_border_radius_top' => [
725 'type' => 'number',
726 ],
727 'form_border_radius_right' => [
728 'type' => 'number',
729 ],
730 'form_border_radius_bottom' => [
731 'type' => 'number',
732 ],
733 'form_border_radius_left' => [
734 'type' => 'number',
735 ],
736 'form_border_radius_unit' => [
737 'type' => 'string',
738 ],
739 'form_border_radius_link' => [
740 'type' => 'boolean',
741 ],
742 // Form Padding and Border Radius.
743 // Form Padding.
744 'instant_form_padding_top' => [
745 'type' => 'number',
746 ],
747 'instant_form_padding_right' => [
748 'type' => 'number',
749 ],
750 'instant_form_padding_bottom' => [
751 'type' => 'number',
752 ],
753 'instant_form_padding_left' => [
754 'type' => 'number',
755 ],
756 'instant_form_padding_unit' => [
757 'type' => 'string',
758 ],
759 'instant_form_padding_link' => [
760 'type' => 'boolean',
761 ],
762 // Border Radius.
763 'instant_form_border_radius_top' => [
764 'type' => 'number',
765 ],
766 'instant_form_border_radius_right' => [
767 'type' => 'number',
768 ],
769 'instant_form_border_radius_bottom' => [
770 'type' => 'number',
771 ],
772 'instant_form_border_radius_left' => [
773 'type' => 'number',
774 ],
775 'instant_form_border_radius_unit' => [
776 'type' => 'string',
777 ],
778 'instant_form_border_radius_link' => [
779 'type' => 'boolean',
780 ],
781 ],
782 ],
783 ],
784 'default' => [
785 'primary_color' => '#111C44',
786 'text_color' => '#1E1E1E',
787 'text_color_on_primary' => '#FFFFFF',
788 'field_spacing' => 'medium',
789 'submit_button_alignment' => 'left',
790 'bg_type' => 'color',
791 'bg_color' => '#ffffff',
792 'bg_image' => '',
793 'bg_image_position' => [
794 'x' => 0.5,
795 'y' => 0.5,
796 ],
797 'bg_image_attachment' => 'scroll',
798 'bg_image_repeat' => 'no-repeat',
799 'bg_image_size' => 'cover',
800 'bg_image_size_custom' => 100, // Image width when set to custom.
801 'bg_image_size_custom_unit' => '%',
802 'gradient_type' => 'basic',
803 'bg_gradient_type' => 'linear',
804 'bg_gradient_color_1' => '#FFC9B2',
805 'bg_gradient_color_2' => '#C7CBFF',
806 'bg_gradient_angle' => 90,
807 'bg_gradient_location_1' => 0,
808 'bg_gradient_location_2' => 100,
809 'bg_overlay_size' => 'cover',
810 'bg_gradient_overlay_type' => '',
811 'bg_overlay_opacity' => 1,
812 'bg_overlay_image' => '',
813 'bg_image_overlay_color' => '#FFFFFF75',
814 'bg_overlay_custom_size_unit' => '%',
815 'bg_overlay_custom_size' => 100,
816 'bg_overlay_position' => [
817 'x' => 0.5,
818 'y' => 0.5,
819 ],
820 'bg_overlay_attachment' => 'scroll',
821 'bg_overlay_repeat' => 'no-repeat',
822 'bg_overlay_blend_mode' => 'normal',
823 // Gradient Overlay Properties.
824 'overlay_gradient_type' => 'basic',
825 'bg_overlay_gradient_type' => 'linear',
826 'bg_overlay_gradient_color_1' => '#FFC9B2',
827 'bg_overlay_gradient_color_2' => '#C7CBFF',
828 'bg_overlay_gradient_angle' => 90,
829 'bg_overlay_gradient_location_1' => 0,
830 'bg_overlay_gradient_location_2' => 100,
831 // Form Properties.
832 // Padding.
833 'form_padding_top' => 0,
834 'form_padding_right' => 0,
835 'form_padding_bottom' => 0,
836 'form_padding_left' => 0,
837 'form_padding_unit' => 'px',
838 'form_padding_link' => true,
839 // Border Radius.
840 'form_border_radius_top' => 0,
841 'form_border_radius_right' => 0,
842 'form_border_radius_bottom' => 0,
843 'form_border_radius_left' => 0,
844 'form_border_radius_unit' => 'px',
845 'form_border_radius_link' => true,
846 // Form Properties.
847 // Padding.
848 'instant_form_padding_top' => 32,
849 'instant_form_padding_right' => 32,
850 'instant_form_padding_bottom' => 32,
851 'instant_form_padding_left' => 32,
852 'instant_form_padding_unit' => 'px',
853 'instant_form_padding_link' => true,
854 // Border Radius.
855 'instant_form_border_radius_top' => 12,
856 'instant_form_border_radius_right' => 12,
857 'instant_form_border_radius_bottom' => 12,
858 'instant_form_border_radius_left' => 12,
859 'instant_form_border_radius_unit' => 'px',
860 'instant_form_border_radius_link' => true,
861 ],
862 ]
863 );
864
865 // Email notification Metas.
866 register_post_meta(
867 'sureforms_form',
868 '_srfm_email_notification',
869 [
870 'single' => true,
871 'type' => 'array',
872 'auth_callback' => static function() {
873 return Helper::current_user_can();
874 },
875 'show_in_rest' => [
876 'schema' => [
877 'type' => 'array',
878 'context' => [ 'edit' ],
879 'items' => [
880 'type' => 'object',
881 'properties' => [
882 'id' => [
883 'type' => 'integer',
884 ],
885 'status' => [
886 'type' => 'boolean',
887 ],
888 'is_raw_format' => [
889 'type' => 'boolean',
890 ],
891 'name' => [
892 'type' => 'string',
893 ],
894 'email_to' => [
895 'type' => 'string',
896 ],
897 'email_reply_to' => [
898 'type' => 'string',
899 ],
900 'from_name' => [
901 'type' => 'string',
902 ],
903 'from_email' => [
904 'type' => 'string',
905 ],
906 'email_cc' => [
907 'type' => 'string',
908 ],
909 'email_bcc' => [
910 'type' => 'string',
911 ],
912 'subject' => [
913 'type' => 'string',
914 ],
915 'email_body' => [
916 'type' => 'string',
917 ],
918 ],
919 ],
920 ],
921 ],
922 'default' => [
923 [
924 'id' => 1,
925 'status' => true,
926 'is_raw_format' => false,
927 'name' => __( 'Admin Notification Email', 'sureforms' ),
928 'email_to' => '{admin_email}',
929 'email_reply_to' => '{admin_email}',
930 'from_name' => '{site_title}',
931 'from_email' => '{admin_email}',
932 'email_cc' => '{admin_email}',
933 'email_bcc' => '{admin_email}',
934 'subject' => sprintf( /* translators: %s: Form title smart tag */ __( 'New Form Submission - %s', 'sureforms' ), '{form_title}' ),
935 'email_body' => '{all_data}',
936 ],
937 ],
938 ]
939 );
940
941 // Compliance Settings metas.
942 register_post_meta(
943 'sureforms_form',
944 '_srfm_compliance',
945 [
946 'single' => true,
947 'type' => 'array',
948 'auth_callback' => static function() {
949 return Helper::current_user_can();
950 },
951 'show_in_rest' => [
952 'schema' => [
953 'type' => 'array',
954 'context' => [ 'edit' ],
955 'items' => [
956 'type' => 'object',
957 'properties' => [
958 'id' => [
959 'type' => 'string',
960 ],
961 'gdpr' => [
962 'type' => 'boolean',
963 ],
964 'do_not_store_entries' => [
965 'type' => 'boolean',
966 ],
967 'auto_delete_entries' => [
968 'type' => 'boolean',
969 ],
970 'auto_delete_days' => [
971 'type' => 'string',
972 ],
973 ],
974 ],
975 ],
976 ],
977 'default' => [
978 [
979 'id' => 'gdpr',
980 'gdpr' => false,
981 'do_not_store_entries' => false,
982 'auto_delete_entries' => false,
983 'auto_delete_days' => '',
984 ],
985 ],
986 ]
987 );
988
989 ob_start();
990 ?>
991 <p style="text-align: center;"><img src="<?php echo esc_attr( $check_icon ); ?>" alt="" aria-hidden="true" /></p><h2 style="text-align: center;"><?php echo esc_html__( 'Thank you', 'sureforms' ); ?></h2><p style="text-align: center;"><?php echo esc_html__( 'Your form has been submitted successfully. We\'ll review your details and get back to you soon.', 'sureforms' ); ?></p>
992 <?php
993 $default_confirmation_message = ob_get_clean();
994
995 // form confirmation.
996 register_post_meta(
997 'sureforms_form',
998 '_srfm_form_confirmation',
999 [
1000 'single' => true,
1001 'type' => 'array',
1002 'auth_callback' => static function() {
1003 return Helper::current_user_can();
1004 },
1005 'sanitize_callback' => static function( $meta_value ) {
1006 if ( ! is_array( $meta_value ) ) {
1007 return [];
1008 }
1009 $sanitized = [];
1010 foreach ( $meta_value as $item ) {
1011 if ( ! is_array( $item ) ) {
1012 continue;
1013 }
1014 $sanitized_item = [
1015 'id' => isset( $item['id'] ) ? intval( $item['id'] ) : 0,
1016 'confirmation_type' => isset( $item['confirmation_type'] ) ? sanitize_text_field( $item['confirmation_type'] ) : '',
1017 'page_url' => isset( $item['page_url'] ) ? esc_url_raw( $item['page_url'] ) : '',
1018 'custom_url' => isset( $item['custom_url'] ) ? esc_url_raw( $item['custom_url'] ) : '',
1019 'message' => isset( $item['message'] ) ? Helper::strip_js_attributes( $item['message'] ) : '',
1020 'submission_action' => isset( $item['submission_action'] ) ? sanitize_text_field( $item['submission_action'] ) : '',
1021 'enable_query_params' => isset( $item['enable_query_params'] ) ? filter_var( $item['enable_query_params'], FILTER_VALIDATE_BOOLEAN ) : false,
1022 'query_params' => isset( $item['query_params'] ) && is_array( $item['query_params'] )
1023 ? array_map(
1024 static function ( $pair ) {
1025 if ( ! is_array( $pair ) ) {
1026 return [];
1027 }
1028 $key = key( $pair );
1029 $value = current( $pair );
1030
1031 return [
1032 sanitize_text_field( Helper::get_string_value( $key ) ) => sanitize_text_field( Helper::get_string_value( $value ) ),
1033 ];
1034 },
1035 $item['query_params']
1036 )
1037 : [],
1038 ];
1039
1040 $sanitized_item = apply_filters( 'srfm_form_confirmation_params', $sanitized_item, $item );
1041
1042 $sanitized[] = $sanitized_item;
1043 }
1044 return $sanitized;
1045 },
1046 'show_in_rest' => [
1047 'schema' => [
1048 'type' => 'array',
1049 'context' => [ 'edit' ],
1050 'items' => [
1051 'type' => 'object',
1052 'properties' => [
1053 'id' => [
1054 'type' => 'integer',
1055 ],
1056 'confirmation_type' => [
1057 'type' => 'string',
1058 ],
1059 'page_url' => [
1060 'type' => 'string',
1061 ],
1062 'custom_url' => [
1063 'type' => 'string',
1064 ],
1065 'message' => [
1066 'type' => 'string',
1067 ],
1068 'submission_action' => [
1069 'type' => 'string',
1070 ],
1071 'enable_query_params' => [
1072 'type' => 'boolean',
1073 ],
1074 'query_params' => [
1075 'type' => 'array',
1076 ],
1077 ],
1078 ],
1079 ],
1080 ],
1081 'default' => [
1082 [
1083 'id' => 1,
1084 'confirmation_type' => 'same page',
1085 'page_url' => '',
1086 'custom_url' => '',
1087 'message' => $default_confirmation_message,
1088 'submission_action' => 'hide form',
1089 ],
1090 ],
1091 ]
1092 );
1093
1094 // conditional logic.
1095 do_action( 'srfm_register_conditional_logic_post_meta' );
1096 /**
1097 * Hook for registering additional Post Meta
1098 */
1099 do_action( 'srfm_register_additional_post_meta' );
1100
1101 register_meta(
1102 'post',
1103 '_srfm_form_restriction',
1104 [
1105 'type' => 'string', // Will store as JSON string.
1106 'single' => true, // Store as single value.
1107 'show_in_rest' => [
1108 'schema' => [
1109 'type' => 'string',
1110 'context' => [ 'edit' ],
1111 ],
1112 ],
1113 // Custom callback to sanitize the data.
1114 'sanitize_callback' => [ $this, 'sanitize_form_restriction_data' ],
1115 'object_subtype' => SRFM_FORMS_POST_TYPE,
1116 'auth_callback' => static function () {
1117 return Helper::current_user_can();
1118 },
1119 'default' => wp_json_encode(
1120 [
1121 'status' => false,
1122 'maxEntries' => 0,
1123 'date' => '',
1124 'hours' => '12',
1125 'minutes' => '00',
1126 'meridiem' => 'AM',
1127 'message' => Translatable::get_default_form_restriction_message(),
1128 ]
1129 ),
1130 ]
1131 );
1132 }
1133
1134 /**
1135 * Sanitizes the form restriction data.
1136 *
1137 * @param mixed $meta_value The meta value to sanitize.
1138 * @return string|false Sanitized JSON string.
1139 */
1140 public function sanitize_form_restriction_data( $meta_value ) {
1141 if ( empty( $meta_value ) || ! is_string( $meta_value ) ) {
1142 return wp_json_encode( [] );
1143 }
1144
1145 $meta_value = json_decode( $meta_value, true );
1146
1147 if ( ! is_array( $meta_value ) || json_last_error() !== JSON_ERROR_NONE ) {
1148 // If the JSON is invalid, return an empty array as JSON.
1149 return wp_json_encode( [] );
1150 }
1151
1152 $sanitized = [
1153 'status' => isset( $meta_value['status'] ) ? wp_validate_boolean( $meta_value['status'] ) : false,
1154 'maxEntries' => isset( $meta_value['maxEntries'] ) ? absint( $meta_value['maxEntries'] ) : 0,
1155 'date' => isset( $meta_value['date'] ) ? sanitize_text_field( $meta_value['date'] ) : '',
1156 'hours' => isset( $meta_value['hours'] ) ? sanitize_text_field( $meta_value['hours'] ) : '12',
1157 'minutes' => isset( $meta_value['minutes'] ) ? sanitize_text_field( $meta_value['minutes'] ) : '00',
1158 'meridiem' => isset( $meta_value['meridiem'] ) ? sanitize_text_field( $meta_value['meridiem'] ) : 'AM',
1159 'message' => isset( $meta_value['message'] ) ? sanitize_textarea_field( $meta_value['message'] ) : Translatable::get_default_form_restriction_message(),
1160 ];
1161
1162 // Return the sanitized data as a JSON string.
1163 return wp_json_encode( $sanitized );
1164 }
1165
1166 /**
1167 * Custom Shortcode.
1168 *
1169 * @param array<mixed> $atts Attributes.
1170 * @return string|false. $content Post Content.
1171 * @since 0.0.1
1172 */
1173 public function forms_shortcode( $atts ) {
1174 $atts = shortcode_atts(
1175 [
1176 'id' => '',
1177 'show_title' => true,
1178 ],
1179 $atts
1180 );
1181
1182 $id = intval( $atts['id'] );
1183 $post = get_post( $id );
1184
1185 if ( ! empty( $id ) && $post && 'publish' === $post->post_status ) {
1186 return Generate_Form_Markup::get_form_markup( $id, ! filter_var( $atts['show_title'], FILTER_VALIDATE_BOOLEAN ), '', 'post', true );
1187 }
1188
1189 return esc_html__( 'This form has been deleted or is unavailable.', 'sureforms' );
1190 }
1191
1192 /**
1193 * Redirect to home page if instant form is not enabled.
1194 *
1195 * @since 0.0.1
1196 * @return void
1197 */
1198 public function srfm_instant_form_redirect() {
1199
1200 $form_id = Helper::get_integer_value( get_the_ID() );
1201
1202 $instant_form_settings = Helper::get_array_value( Helper::get_post_meta( $form_id, '_srfm_instant_form_settings' ) );
1203 $enable_instant_form = ! empty( $instant_form_settings['enable_instant_form'] ) ? boolval( $instant_form_settings['enable_instant_form'] ) : false;
1204
1205 if ( $enable_instant_form ) {
1206 return;
1207 }
1208
1209 $form_preview = '';
1210
1211 $form_preview_attr = isset( $_GET['preview'] ) ? sanitize_text_field( wp_unslash( $_GET['preview'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not needed here.
1212
1213 if ( $form_preview_attr ) {
1214 $form_preview = filter_var( $form_preview_attr, FILTER_VALIDATE_BOOLEAN );
1215 }
1216
1217 if ( is_singular( 'sureforms_form' ) && ! $form_preview && ! Helper::current_user_can() ) {
1218 wp_safe_redirect( home_url() );
1219 return;
1220 }
1221 }
1222
1223 /**
1224 * Restrict RankMath meta boxes in edit page.
1225 *
1226 * @since 0.0.5
1227 * @return void
1228 */
1229 public function restrict_data() {
1230 add_filter( 'rank_math/excluded_post_types', [ $this, 'unset_sureforms_post_type' ] );
1231 }
1232
1233 /**
1234 * Remove SureForms post type from RankMath and Yoast.
1235 *
1236 * @param array<mixed> $post_types Post types.
1237 * @since 0.0.5
1238 * @return array<mixed> $post_types Modified post types.
1239 */
1240 public function unset_sureforms_post_type( $post_types ) {
1241 return array_filter(
1242 $post_types,
1243 static function( $post_type ) {
1244 if ( is_array( $post_type ) && isset( $post_type['name'] ) ) {
1245 return SRFM_FORMS_POST_TYPE !== $post_type['name'];
1246 }
1247 return SRFM_FORMS_POST_TYPE !== $post_type;
1248 }
1249 );
1250 }
1251
1252 /**
1253 * Restrict unwanted insertions from the AIOSEO plugin.
1254 *
1255 * This method ensures that the SureForms post type is excluded from AIOSEO's
1256 * public post types unless the current page is related to AIOSEO settings.
1257 *
1258 * @return void
1259 * @since 1.6.0
1260 */
1261 public function restrict_in_aioseo_plugin() {
1262 /**
1263 * Checks if the AIOSEO plugin is installed and excludes the SureForms post type from AIOSEO's public post types.
1264 *
1265 * - Verifies the presence of the AIOSEO_DIR constant to ensure AIOSEO is installed.
1266 * - Allows AIOSEO functionality on its own settings pages by checking the `REQUEST_URI` and `page` query parameter.
1267 * - Excludes the SureForms post type from AIOSEO's public post types using the `aioseo_public_post_types` filter.
1268 *
1269 * Security Note:
1270 * - Nonce verification is intentionally skipped (`phpcs:ignore WordPress.Security.NonceVerification.Recommended`)
1271 * because this code is only performing a read operation to check the current request URI and query parameters.
1272 * It does not modify or process sensitive data, making nonce verification unnecessary in this context.
1273 */
1274 // Check if AIOSEO is installed by verifying the AIOSEO_DIR constant.
1275 if ( ! defined( 'AIOSEO_DIR' ) ) {
1276 return;
1277 }
1278
1279 // Allow AIOSEO functionality on its own settings pages.
1280 if ( isset( $_SERVER['REQUEST_URI'] ) ) {
1281 $request_uri = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) );
1282 if ( strpos( $request_uri, 'admin.php' ) !== false ) {
1283 if ( isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here because Safe here as we're only reading the `page` parameter.
1284 $page = sanitize_text_field( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here because only we are reading the `page` parameter.
1285 if ( strpos( $page, 'aioseo' ) !== false ) {
1286 return;
1287 }
1288 }
1289 }
1290 }
1291
1292 // Exclude the SureForms post type from AIOSEO's public post types.
1293 add_filter( 'aioseo_public_post_types', [ $this, 'unset_sureforms_post_type' ] );
1294 }
1295
1296 /**
1297 * Restrict interference of other plugins with SureForms.
1298 *
1299 * @since 0.0.5
1300 * @return void
1301 */
1302 private function restrict_unwanted_insertions() {
1303 // Restrict RankMath metaboxes in edit page.
1304 add_action( 'cmb2_admin_init', [ $this, 'restrict_data' ] );
1305
1306 // Restrict Yoast columns.
1307 add_filter( 'wpseo_accessible_post_types', [ $this, 'unset_sureforms_post_type' ] );
1308 add_filter( 'wpseo_metabox_prio', '__return_false' );
1309
1310 // Restrict AIOSEO columns.
1311 $this->restrict_in_aioseo_plugin();
1312 }
1313 }
1314