PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.8.0
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.8.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
1,455 lines 47.2 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 'sanitize_callback' => static function( $meta_value ) {
470 if ( ! is_array( $meta_value ) ) {
471 return [];
472 }
473 return [
474 'site_logo' => isset( $meta_value['site_logo'] ) ? esc_url_raw( $meta_value['site_logo'] ) : '',
475 'site_logo_id' => isset( $meta_value['site_logo_id'] ) ? absint( $meta_value['site_logo_id'] ) : 0,
476 'cover_type' => isset( $meta_value['cover_type'] ) ? sanitize_text_field( $meta_value['cover_type'] ) : '',
477 'cover_color' => isset( $meta_value['cover_color'] ) ? sanitize_text_field( $meta_value['cover_color'] ) : '',
478 'cover_image' => isset( $meta_value['cover_image'] ) ? esc_url_raw( $meta_value['cover_image'] ) : '',
479 'cover_image_id' => isset( $meta_value['cover_image_id'] ) ? absint( $meta_value['cover_image_id'] ) : 0,
480 'bg_type' => isset( $meta_value['bg_type'] ) ? sanitize_text_field( $meta_value['bg_type'] ) : '',
481 'bg_color' => isset( $meta_value['bg_color'] ) ? sanitize_text_field( $meta_value['bg_color'] ) : '',
482 'bg_image' => isset( $meta_value['bg_image'] ) ? esc_url_raw( $meta_value['bg_image'] ) : '',
483 'bg_image_id' => isset( $meta_value['bg_image_id'] ) ? absint( $meta_value['bg_image_id'] ) : 0,
484 'enable_instant_form' => isset( $meta_value['enable_instant_form'] ) ? filter_var( $meta_value['enable_instant_form'], FILTER_VALIDATE_BOOLEAN ) : false,
485 'form_container_width' => isset( $meta_value['form_container_width'] ) ? absint( $meta_value['form_container_width'] ) : 620,
486 'single_page_form_title' => isset( $meta_value['single_page_form_title'] ) ? filter_var( $meta_value['single_page_form_title'], FILTER_VALIDATE_BOOLEAN ) : true,
487 'use_banner_as_page_background' => isset( $meta_value['use_banner_as_page_background'] ) ? filter_var( $meta_value['use_banner_as_page_background'], FILTER_VALIDATE_BOOLEAN ) : false,
488 ];
489 },
490 'show_in_rest' => [
491 'schema' => [
492 'type' => 'object',
493 'context' => [ 'edit' ],
494 'properties' => [
495 'site_logo' => [
496 'type' => 'string',
497 ],
498 'site_logo_id' => [
499 'type' => 'integer',
500 ],
501 // Form page banner settings.
502 'cover_type' => [
503 'type' => 'string',
504 ],
505 'cover_color' => [
506 'type' => 'string',
507 ],
508 'cover_image' => [
509 'type' => 'string',
510 ],
511 'cover_image_id' => [
512 'type' => 'integer',
513 ],
514 // Form page background settings.
515 'bg_type' => [
516 'type' => 'string',
517 ],
518 'bg_color' => [
519 'type' => 'string',
520 ],
521 'bg_image' => [
522 'type' => 'string',
523 ],
524 'bg_image_id' => [
525 'type' => 'integer',
526 ],
527 'enable_instant_form' => [
528 'type' => 'boolean',
529 ],
530 'form_container_width' => [
531 'type' => 'integer',
532 ],
533 'single_page_form_title' => [
534 'type' => 'boolean',
535 ],
536 'use_banner_as_page_background' => [
537 'type' => 'boolean',
538 ],
539 ],
540 ],
541 ],
542 'default' => [
543 'bg_type' => 'color',
544 'bg_color' => '#ffffff',
545 'bg_image' => '',
546 'site_logo' => '',
547 'cover_type' => 'color',
548 'cover_color' => '#111C44',
549 'cover_image' => '',
550 'enable_instant_form' => false,
551 'form_container_width' => 620,
552 'single_page_form_title' => true,
553 'use_banner_as_page_background' => false,
554 ],
555 ]
556 );
557
558 register_post_meta(
559 SRFM_FORMS_POST_TYPE,
560 '_srfm_forms_styling',
561 [
562 'single' => true,
563 'type' => 'object',
564 'auth_callback' => static function() {
565 return Helper::current_user_can();
566 },
567 'sanitize_callback' => static function( $meta_value ) {
568 return Helper::sanitize_by_type( $meta_value );
569 },
570 'show_in_rest' => [
571 'schema' => [
572 'type' => 'object',
573 'context' => [ 'edit' ],
574 'properties' => [
575 'primary_color' => [
576 'type' => 'string',
577 ],
578 'text_color' => [
579 'type' => 'string',
580 ],
581 'text_color_on_primary' => [
582 'type' => 'string',
583 ],
584 'field_spacing' => [
585 'type' => 'string',
586 ],
587 'submit_button_alignment' => [
588 'type' => 'string',
589 ],
590 'bg_type' => [
591 'type' => 'string',
592 ],
593 'bg_color' => [
594 'type' => 'string',
595 ],
596 'bg_image' => [
597 'type' => 'string',
598 ],
599 'bg_image_id' => [
600 'type' => 'integer',
601 ],
602 // Image Properties.
603 'bg_image_position' => [
604 'type' => 'object',
605 'properties' => [
606 'x' => [
607 'type' => 'number',
608 'format' => 'float',
609 ],
610 'y' => [
611 'type' => 'number',
612 'format' => 'float',
613 ],
614 ],
615 ],
616 'bg_image_attachment' => [
617 'type' => 'string',
618 ],
619 'bg_image_repeat' => [
620 'type' => 'string',
621 ],
622 'bg_image_size' => [
623 'type' => 'string',
624 ],
625 'bg_image_size_custom' => [
626 'type' => 'integer',
627 ],
628 'bg_image_size_custom_unit' => [
629 'type' => 'string',
630 ],
631 // Gradient Properties.
632 'bg_gradient' => [
633 'type' => 'string',
634 ],
635 'gradient_type' => [
636 'type' => 'string',
637 ],
638 'bg_gradient_type' => [
639 'type' => 'string',
640 ],
641 'bg_gradient_color_1' => [
642 'type' => 'string',
643 ],
644 'bg_gradient_color_2' => [
645 'type' => 'string',
646 ],
647 'bg_gradient_angle' => [
648 'type' => 'integer',
649 ],
650 'bg_gradient_location_1' => [
651 'type' => 'integer',
652 ],
653 'bg_gradient_location_2' => [
654 'type' => 'integer',
655 ],
656 // Overlay Properties.
657 'bg_overlay_size' => [
658 'type' => 'string',
659 ],
660 'bg_gradient_overlay_type' => [
661 'type' => 'string',
662 ],
663 'bg_overlay_opacity' => [
664 'type' => 'number',
665 ],
666 'bg_overlay_image' => [
667 'type' => 'string',
668 ],
669 'bg_overlay_image_id' => [
670 'type' => 'integer',
671 ],
672 'bg_image_overlay_color' => [
673 'type' => 'string',
674 ],
675 'bg_overlay_custom_size_unit' => [
676 'type' => 'string',
677 ],
678 'bg_overlay_custom_size' => [
679 'type' => 'integer',
680 ],
681 'bg_overlay_blend_mode' => [
682 'type' => 'string',
683 ],
684 'bg_overlay_position' => [
685 'type' => 'object',
686 'properties' => [
687 'x' => [
688 'type' => 'number',
689 'format' => 'float',
690 ],
691 'y' => [
692 'type' => 'number',
693 'format' => 'float',
694 ],
695 ],
696 ],
697 'bg_overlay_attachment' => [
698 'type' => 'string',
699 ],
700 'bg_overlay_repeat' => [
701 'type' => 'string',
702 ],
703 // Gradient Overlay Properties.
704 'bg_overlay_gradient' => [
705 'type' => 'string',
706 ],
707 'overlay_gradient_type' => [
708 'type' => 'string',
709 ],
710 'bg_overlay_gradient_type' => [
711 'type' => 'string',
712 ],
713 'bg_overlay_gradient_color_1' => [
714 'type' => 'string',
715 ],
716 'bg_overlay_gradient_color_2' => [
717 'type' => 'string',
718 ],
719 'bg_overlay_gradient_angle' => [
720 'type' => 'integer',
721 ],
722 'bg_overlay_gradient_location_1' => [
723 'type' => 'integer',
724 ],
725 'bg_overlay_gradient_location_2' => [
726 'type' => 'integer',
727 ],
728 // Form Padding.
729 'form_padding_top' => [
730 'type' => 'number',
731 ],
732 'form_padding_right' => [
733 'type' => 'number',
734 ],
735 'form_padding_bottom' => [
736 'type' => 'number',
737 ],
738 'form_padding_left' => [
739 'type' => 'number',
740 ],
741 'form_padding_unit' => [
742 'type' => 'string',
743 ],
744 'form_padding_link' => [
745 'type' => 'boolean',
746 ],
747 // Border Radius.
748 'form_border_radius_top' => [
749 'type' => 'number',
750 ],
751 'form_border_radius_right' => [
752 'type' => 'number',
753 ],
754 'form_border_radius_bottom' => [
755 'type' => 'number',
756 ],
757 'form_border_radius_left' => [
758 'type' => 'number',
759 ],
760 'form_border_radius_unit' => [
761 'type' => 'string',
762 ],
763 'form_border_radius_link' => [
764 'type' => 'boolean',
765 ],
766 // Form Padding and Border Radius.
767 // Form Padding.
768 'instant_form_padding_top' => [
769 'type' => 'number',
770 ],
771 'instant_form_padding_right' => [
772 'type' => 'number',
773 ],
774 'instant_form_padding_bottom' => [
775 'type' => 'number',
776 ],
777 'instant_form_padding_left' => [
778 'type' => 'number',
779 ],
780 'instant_form_padding_unit' => [
781 'type' => 'string',
782 ],
783 'instant_form_padding_link' => [
784 'type' => 'boolean',
785 ],
786 // Border Radius.
787 'instant_form_border_radius_top' => [
788 'type' => 'number',
789 ],
790 'instant_form_border_radius_right' => [
791 'type' => 'number',
792 ],
793 'instant_form_border_radius_bottom' => [
794 'type' => 'number',
795 ],
796 'instant_form_border_radius_left' => [
797 'type' => 'number',
798 ],
799 'instant_form_border_radius_unit' => [
800 'type' => 'string',
801 ],
802 'instant_form_border_radius_link' => [
803 'type' => 'boolean',
804 ],
805 ],
806 ],
807 ],
808 'default' => [
809 'primary_color' => '#111C44',
810 'text_color' => '#1E1E1E',
811 'text_color_on_primary' => '#FFFFFF',
812 'field_spacing' => 'medium',
813 'submit_button_alignment' => 'left',
814 'bg_type' => 'color',
815 'bg_color' => '#ffffff',
816 'bg_image' => '',
817 'bg_image_position' => [
818 'x' => 0.5,
819 'y' => 0.5,
820 ],
821 'bg_image_attachment' => 'scroll',
822 'bg_image_repeat' => 'no-repeat',
823 'bg_image_size' => 'cover',
824 'bg_image_size_custom' => 100, // Image width when set to custom.
825 'bg_image_size_custom_unit' => '%',
826 'gradient_type' => 'basic',
827 'bg_gradient_type' => 'linear',
828 'bg_gradient_color_1' => '#FFC9B2',
829 'bg_gradient_color_2' => '#C7CBFF',
830 'bg_gradient_angle' => 90,
831 'bg_gradient_location_1' => 0,
832 'bg_gradient_location_2' => 100,
833 'bg_overlay_size' => 'cover',
834 'bg_gradient_overlay_type' => '',
835 'bg_overlay_opacity' => 1,
836 'bg_overlay_image' => '',
837 'bg_image_overlay_color' => '#FFFFFF75',
838 'bg_overlay_custom_size_unit' => '%',
839 'bg_overlay_custom_size' => 100,
840 'bg_overlay_position' => [
841 'x' => 0.5,
842 'y' => 0.5,
843 ],
844 'bg_overlay_attachment' => 'scroll',
845 'bg_overlay_repeat' => 'no-repeat',
846 'bg_overlay_blend_mode' => 'normal',
847 // Gradient Overlay Properties.
848 'overlay_gradient_type' => 'basic',
849 'bg_overlay_gradient_type' => 'linear',
850 'bg_overlay_gradient_color_1' => '#FFC9B2',
851 'bg_overlay_gradient_color_2' => '#C7CBFF',
852 'bg_overlay_gradient_angle' => 90,
853 'bg_overlay_gradient_location_1' => 0,
854 'bg_overlay_gradient_location_2' => 100,
855 // Form Properties.
856 // Padding.
857 'form_padding_top' => 0,
858 'form_padding_right' => 0,
859 'form_padding_bottom' => 0,
860 'form_padding_left' => 0,
861 'form_padding_unit' => 'px',
862 'form_padding_link' => true,
863 // Border Radius.
864 'form_border_radius_top' => 0,
865 'form_border_radius_right' => 0,
866 'form_border_radius_bottom' => 0,
867 'form_border_radius_left' => 0,
868 'form_border_radius_unit' => 'px',
869 'form_border_radius_link' => true,
870 // Form Properties.
871 // Padding.
872 'instant_form_padding_top' => 32,
873 'instant_form_padding_right' => 32,
874 'instant_form_padding_bottom' => 32,
875 'instant_form_padding_left' => 32,
876 'instant_form_padding_unit' => 'px',
877 'instant_form_padding_link' => true,
878 // Border Radius.
879 'instant_form_border_radius_top' => 12,
880 'instant_form_border_radius_right' => 12,
881 'instant_form_border_radius_bottom' => 12,
882 'instant_form_border_radius_left' => 12,
883 'instant_form_border_radius_unit' => 'px',
884 'instant_form_border_radius_link' => true,
885 ],
886 ]
887 );
888
889 // Email notification Metas.
890 register_post_meta(
891 'sureforms_form',
892 '_srfm_email_notification',
893 [
894 'single' => true,
895 'type' => 'array',
896 'auth_callback' => static function() {
897 return Helper::current_user_can();
898 },
899 'sanitize_callback' => static function( $meta_value ) {
900 if ( ! is_array( $meta_value ) ) {
901 return [];
902 }
903 $sanitized = [];
904 foreach ( $meta_value as $item ) {
905 if ( ! is_array( $item ) ) {
906 continue;
907 }
908 $sanitized[] = [
909 'id' => isset( $item['id'] ) ? intval( $item['id'] ) : 0,
910 'status' => isset( $item['status'] ) ? filter_var( $item['status'], FILTER_VALIDATE_BOOLEAN ) : false,
911 'is_raw_format' => isset( $item['is_raw_format'] ) ? filter_var( $item['is_raw_format'], FILTER_VALIDATE_BOOLEAN ) : false,
912 'name' => isset( $item['name'] ) ? sanitize_text_field( $item['name'] ) : '',
913 'email_to' => isset( $item['email_to'] ) ? sanitize_text_field( $item['email_to'] ) : '',
914 'email_reply_to' => isset( $item['email_reply_to'] ) ? sanitize_text_field( $item['email_reply_to'] ) : '',
915 'from_name' => isset( $item['from_name'] ) ? sanitize_text_field( $item['from_name'] ) : '',
916 'from_email' => isset( $item['from_email'] ) ? sanitize_text_field( $item['from_email'] ) : '',
917 'email_cc' => isset( $item['email_cc'] ) ? sanitize_text_field( $item['email_cc'] ) : '',
918 'email_bcc' => isset( $item['email_bcc'] ) ? sanitize_text_field( $item['email_bcc'] ) : '',
919 'subject' => isset( $item['subject'] ) ? sanitize_text_field( $item['subject'] ) : '',
920 'email_body' => isset( $item['email_body'] ) ? wp_kses_post( $item['email_body'] ) : '',
921 ];
922 }
923 return $sanitized;
924 },
925 'show_in_rest' => [
926 'schema' => [
927 'type' => 'array',
928 'context' => [ 'edit' ],
929 'items' => [
930 'type' => 'object',
931 'properties' => [
932 'id' => [
933 'type' => 'integer',
934 ],
935 'status' => [
936 'type' => 'boolean',
937 ],
938 'is_raw_format' => [
939 'type' => 'boolean',
940 ],
941 'name' => [
942 'type' => 'string',
943 ],
944 'email_to' => [
945 'type' => 'string',
946 ],
947 'email_reply_to' => [
948 'type' => 'string',
949 ],
950 'from_name' => [
951 'type' => 'string',
952 ],
953 'from_email' => [
954 'type' => 'string',
955 ],
956 'email_cc' => [
957 'type' => 'string',
958 ],
959 'email_bcc' => [
960 'type' => 'string',
961 ],
962 'subject' => [
963 'type' => 'string',
964 ],
965 'email_body' => [
966 'type' => 'string',
967 ],
968 ],
969 ],
970 ],
971 ],
972 'default' => [
973 [
974 'id' => 1,
975 'status' => true,
976 'is_raw_format' => false,
977 'name' => __( 'Admin Notification Email', 'sureforms' ),
978 'email_to' => '{admin_email}',
979 'email_reply_to' => '{admin_email}',
980 'from_name' => '{site_title}',
981 'from_email' => '{admin_email}',
982 'email_cc' => '{admin_email}',
983 'email_bcc' => '{admin_email}',
984 'subject' => sprintf( /* translators: %s: Form title smart tag */ __( 'New Form Submission - %s', 'sureforms' ), '{form_title}' ),
985 'email_body' => '{all_data}',
986 ],
987 ],
988 ]
989 );
990
991 // Compliance Settings metas.
992 register_post_meta(
993 'sureforms_form',
994 '_srfm_compliance',
995 [
996 'single' => true,
997 'type' => 'array',
998 'auth_callback' => static function() {
999 return Helper::current_user_can();
1000 },
1001 'sanitize_callback' => static function( $meta_value ) {
1002 if ( ! is_array( $meta_value ) ) {
1003 return [];
1004 }
1005 $sanitized = [];
1006 foreach ( $meta_value as $item ) {
1007 if ( ! is_array( $item ) ) {
1008 continue;
1009 }
1010 $sanitized[] = [
1011 'id' => isset( $item['id'] ) ? sanitize_text_field( $item['id'] ) : '',
1012 'gdpr' => isset( $item['gdpr'] ) ? filter_var( $item['gdpr'], FILTER_VALIDATE_BOOLEAN ) : false,
1013 'do_not_store_entries' => isset( $item['do_not_store_entries'] ) ? filter_var( $item['do_not_store_entries'], FILTER_VALIDATE_BOOLEAN ) : false,
1014 'auto_delete_entries' => isset( $item['auto_delete_entries'] ) ? filter_var( $item['auto_delete_entries'], FILTER_VALIDATE_BOOLEAN ) : false,
1015 'auto_delete_days' => isset( $item['auto_delete_days'] ) ? sanitize_text_field( $item['auto_delete_days'] ) : '',
1016 ];
1017 }
1018 return $sanitized;
1019 },
1020 'show_in_rest' => [
1021 'schema' => [
1022 'type' => 'array',
1023 'context' => [ 'edit' ],
1024 'items' => [
1025 'type' => 'object',
1026 'properties' => [
1027 'id' => [
1028 'type' => 'string',
1029 ],
1030 'gdpr' => [
1031 'type' => 'boolean',
1032 ],
1033 'do_not_store_entries' => [
1034 'type' => 'boolean',
1035 ],
1036 'auto_delete_entries' => [
1037 'type' => 'boolean',
1038 ],
1039 'auto_delete_days' => [
1040 'type' => 'string',
1041 ],
1042 ],
1043 ],
1044 ],
1045 ],
1046 'default' => [
1047 [
1048 'id' => 'gdpr',
1049 'gdpr' => false,
1050 'do_not_store_entries' => false,
1051 'auto_delete_entries' => false,
1052 'auto_delete_days' => '',
1053 ],
1054 ],
1055 ]
1056 );
1057
1058 ob_start();
1059 ?>
1060 <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>
1061 <?php
1062 $default_confirmation_message = ob_get_clean();
1063
1064 // form confirmation.
1065 register_post_meta(
1066 'sureforms_form',
1067 '_srfm_form_confirmation',
1068 [
1069 'single' => true,
1070 'type' => 'array',
1071 'auth_callback' => static function() {
1072 return Helper::current_user_can();
1073 },
1074 'sanitize_callback' => static function( $meta_value ) {
1075 if ( ! is_array( $meta_value ) ) {
1076 return [];
1077 }
1078 $sanitized = [];
1079 foreach ( $meta_value as $item ) {
1080 if ( ! is_array( $item ) ) {
1081 continue;
1082 }
1083 $sanitized_item = [
1084 'id' => isset( $item['id'] ) ? intval( $item['id'] ) : 0,
1085 'confirmation_type' => isset( $item['confirmation_type'] ) ? sanitize_text_field( $item['confirmation_type'] ) : '',
1086 'page_url' => isset( $item['page_url'] ) ? esc_url_raw( $item['page_url'] ) : '',
1087 'custom_url' => isset( $item['custom_url'] ) ? esc_url_raw( $item['custom_url'] ) : '',
1088 'message' => isset( $item['message'] ) ? Helper::strip_js_attributes( $item['message'] ) : '',
1089 'submission_action' => isset( $item['submission_action'] ) ? sanitize_text_field( $item['submission_action'] ) : '',
1090 'enable_query_params' => isset( $item['enable_query_params'] ) ? filter_var( $item['enable_query_params'], FILTER_VALIDATE_BOOLEAN ) : false,
1091 'query_params' => isset( $item['query_params'] ) && is_array( $item['query_params'] )
1092 ? array_map(
1093 static function ( $pair ) {
1094 if ( ! is_array( $pair ) ) {
1095 return [];
1096 }
1097 $key = key( $pair );
1098 $value = current( $pair );
1099
1100 return [
1101 sanitize_text_field( Helper::get_string_value( $key ) ) => sanitize_text_field( Helper::get_string_value( $value ) ),
1102 ];
1103 },
1104 $item['query_params']
1105 )
1106 : [],
1107 ];
1108
1109 $sanitized_item = apply_filters( 'srfm_form_confirmation_params', $sanitized_item, $item );
1110
1111 $sanitized[] = $sanitized_item;
1112 }
1113 return $sanitized;
1114 },
1115 'show_in_rest' => [
1116 'schema' => [
1117 'type' => 'array',
1118 'context' => [ 'edit' ],
1119 'items' => [
1120 'type' => 'object',
1121 'properties' => [
1122 'id' => [
1123 'type' => 'integer',
1124 ],
1125 'confirmation_type' => [
1126 'type' => 'string',
1127 ],
1128 'page_url' => [
1129 'type' => 'string',
1130 ],
1131 'custom_url' => [
1132 'type' => 'string',
1133 ],
1134 'message' => [
1135 'type' => 'string',
1136 ],
1137 'submission_action' => [
1138 'type' => 'string',
1139 ],
1140 'enable_query_params' => [
1141 'type' => 'boolean',
1142 ],
1143 'query_params' => [
1144 'type' => 'array',
1145 ],
1146 ],
1147 ],
1148 ],
1149 ],
1150 'default' => [
1151 [
1152 'id' => 1,
1153 'confirmation_type' => 'same page',
1154 'page_url' => '',
1155 'custom_url' => '',
1156 'message' => $default_confirmation_message,
1157 'submission_action' => 'hide form',
1158 ],
1159 ],
1160 ]
1161 );
1162
1163 // conditional logic.
1164 do_action( 'srfm_register_conditional_logic_post_meta' );
1165 /**
1166 * Hook for registering additional Post Meta
1167 */
1168 do_action( 'srfm_register_additional_post_meta' );
1169
1170 register_meta(
1171 'post',
1172 '_srfm_form_restriction',
1173 [
1174 'type' => 'string', // Will store as JSON string.
1175 'single' => true, // Store as single value.
1176 'show_in_rest' => [
1177 'schema' => [
1178 'type' => 'string',
1179 'context' => [ 'edit' ],
1180 ],
1181 ],
1182 // Custom callback to sanitize the data.
1183 'sanitize_callback' => [ $this, 'sanitize_form_restriction_data' ],
1184 'object_subtype' => SRFM_FORMS_POST_TYPE,
1185 'auth_callback' => static function () {
1186 return Helper::current_user_can();
1187 },
1188 'default' => wp_json_encode(
1189 [
1190 'status' => false,
1191 'maxEntries' => 0,
1192 'date' => '',
1193 'hours' => '12',
1194 'minutes' => '00',
1195 'meridiem' => 'AM',
1196 'message' => Translatable::get_default_form_restriction_message(),
1197 // Form Scheduling meta.
1198 'schedulingStatus' => false,
1199 'startDate' => '',
1200 'startHours' => '12',
1201 'startMinutes' => '00',
1202 'startMeridiem' => 'AM',
1203 'schedulingNotStartedMessage' => __( 'This form is not yet available. Check back after the scheduled start time.', 'sureforms' ),
1204 'schedulingEndedMessage' => __( 'This form is closed. The submission period has ended.', 'sureforms' ),
1205 ]
1206 ),
1207 ]
1208 );
1209 }
1210
1211 /**
1212 * Sanitizes the form restriction data.
1213 *
1214 * @param mixed $meta_value The meta value to sanitize.
1215 * @return string|false Sanitized JSON string.
1216 */
1217 public function sanitize_form_restriction_data( $meta_value ) {
1218 if ( empty( $meta_value ) || ! is_string( $meta_value ) ) {
1219 return wp_json_encode( [] );
1220 }
1221
1222 $meta_value = json_decode( $meta_value, true );
1223
1224 if ( ! is_array( $meta_value ) || json_last_error() !== JSON_ERROR_NONE ) {
1225 // If the JSON is invalid, return an empty array as JSON.
1226 return wp_json_encode( [] );
1227 }
1228
1229 $sanitized = [
1230 'status' => isset( $meta_value['status'] ) ? wp_validate_boolean( $meta_value['status'] ) : false,
1231 'maxEntries' => isset( $meta_value['maxEntries'] ) ? absint( $meta_value['maxEntries'] ) : 0,
1232 'date' => isset( $meta_value['date'] ) ? sanitize_text_field( $meta_value['date'] ) : '',
1233 'hours' => isset( $meta_value['hours'] ) ? sanitize_text_field( $meta_value['hours'] ) : '12',
1234 'minutes' => isset( $meta_value['minutes'] ) ? sanitize_text_field( $meta_value['minutes'] ) : '00',
1235 'meridiem' => isset( $meta_value['meridiem'] ) ? sanitize_text_field( $meta_value['meridiem'] ) : 'AM',
1236 'message' => isset( $meta_value['message'] ) ? sanitize_textarea_field( $meta_value['message'] ) : Translatable::get_default_form_restriction_message(),
1237 // Form Scheduling meta.
1238 'schedulingStatus' => isset( $meta_value['schedulingStatus'] ) ? wp_validate_boolean( $meta_value['schedulingStatus'] ) : false,
1239 'startDate' => isset( $meta_value['startDate'] ) ? sanitize_text_field( $meta_value['startDate'] ) : '',
1240 'startHours' => isset( $meta_value['startHours'] ) ? sanitize_text_field( $meta_value['startHours'] ) : '12',
1241 'startMinutes' => isset( $meta_value['startMinutes'] ) ? sanitize_text_field( $meta_value['startMinutes'] ) : '00',
1242 'startMeridiem' => isset( $meta_value['startMeridiem'] ) ? sanitize_text_field( $meta_value['startMeridiem'] ) : 'AM',
1243 'schedulingNotStartedMessage' => isset( $meta_value['schedulingNotStartedMessage'] ) ? sanitize_textarea_field( $meta_value['schedulingNotStartedMessage'] ) : __( 'This form is not yet available. Check back after the scheduled start time.', 'sureforms' ),
1244 'schedulingEndedMessage' => isset( $meta_value['schedulingEndedMessage'] ) ? sanitize_textarea_field( $meta_value['schedulingEndedMessage'] ) : __( 'This form is closed. The submission period has ended.', 'sureforms' ),
1245 ];
1246
1247 // Validate scheduling: start date/time must be before end date/time.
1248 if ( $sanitized['schedulingStatus'] && ! empty( $sanitized['startDate'] ) && ! empty( $sanitized['date'] ) ) {
1249 $start_datetime = $this->create_datetime_object(
1250 $sanitized['startDate'],
1251 $sanitized['startHours'],
1252 $sanitized['startMinutes'],
1253 $sanitized['startMeridiem']
1254 );
1255
1256 $end_datetime = $this->create_datetime_object(
1257 $sanitized['date'],
1258 $sanitized['hours'],
1259 $sanitized['minutes'],
1260 $sanitized['meridiem']
1261 );
1262
1263 // If start date/time is not before end date/time, disable scheduling.
1264 if ( $start_datetime && $end_datetime && $start_datetime >= $end_datetime ) {
1265 // Disable scheduling status due to invalid date range.
1266 $sanitized['schedulingStatus'] = false;
1267 }
1268 }
1269
1270 // Return the sanitized data as a JSON string.
1271 return wp_json_encode( $sanitized );
1272 }
1273
1274 /**
1275 * Custom Shortcode.
1276 *
1277 * @param array<mixed> $atts Attributes.
1278 * @return string|false. $content Post Content.
1279 * @since 0.0.1
1280 */
1281 public function forms_shortcode( $atts ) {
1282 $atts = shortcode_atts(
1283 [
1284 'id' => '',
1285 'show_title' => true,
1286 ],
1287 $atts
1288 );
1289
1290 $id = intval( $atts['id'] );
1291 $post = get_post( $id );
1292
1293 if ( ! empty( $id ) && $post && ( 'publish' === $post->post_status || 'protected' === $post->post_status ) ) {
1294 return Generate_Form_Markup::get_form_markup( $id, ! filter_var( $atts['show_title'], FILTER_VALIDATE_BOOLEAN ), '', 'post', true );
1295 }
1296
1297 return esc_html__( 'This form has been deleted or is unavailable.', 'sureforms' );
1298 }
1299
1300 /**
1301 * Redirect to home page if instant form is not enabled.
1302 *
1303 * @since 0.0.1
1304 * @return void
1305 */
1306 public function srfm_instant_form_redirect() {
1307
1308 $form_id = Helper::get_integer_value( get_the_ID() );
1309
1310 $instant_form_settings = Helper::get_array_value( Helper::get_post_meta( $form_id, '_srfm_instant_form_settings' ) );
1311 $enable_instant_form = ! empty( $instant_form_settings['enable_instant_form'] ) ? boolval( $instant_form_settings['enable_instant_form'] ) : false;
1312
1313 if ( $enable_instant_form ) {
1314 return;
1315 }
1316
1317 $form_preview = '';
1318
1319 $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.
1320
1321 if ( $form_preview_attr ) {
1322 $form_preview = filter_var( $form_preview_attr, FILTER_VALIDATE_BOOLEAN );
1323 }
1324
1325 if ( is_singular( 'sureforms_form' ) && ! $form_preview && ! Helper::current_user_can() ) {
1326 wp_safe_redirect( home_url() );
1327 return;
1328 }
1329 }
1330
1331 /**
1332 * Restrict RankMath meta boxes in edit page.
1333 *
1334 * @since 0.0.5
1335 * @return void
1336 */
1337 public function restrict_data() {
1338 add_filter( 'rank_math/excluded_post_types', [ $this, 'unset_sureforms_post_type' ] );
1339 }
1340
1341 /**
1342 * Remove SureForms post type from RankMath and Yoast.
1343 *
1344 * @param array<mixed> $post_types Post types.
1345 * @since 0.0.5
1346 * @return array<mixed> $post_types Modified post types.
1347 */
1348 public function unset_sureforms_post_type( $post_types ) {
1349 return array_filter(
1350 $post_types,
1351 static function( $post_type ) {
1352 if ( is_array( $post_type ) && isset( $post_type['name'] ) ) {
1353 return SRFM_FORMS_POST_TYPE !== $post_type['name'];
1354 }
1355 return SRFM_FORMS_POST_TYPE !== $post_type;
1356 }
1357 );
1358 }
1359
1360 /**
1361 * Restrict unwanted insertions from the AIOSEO plugin.
1362 *
1363 * This method ensures that the SureForms post type is excluded from AIOSEO's
1364 * public post types unless the current page is related to AIOSEO settings.
1365 *
1366 * @return void
1367 * @since 1.6.0
1368 */
1369 public function restrict_in_aioseo_plugin() {
1370 /**
1371 * Checks if the AIOSEO plugin is installed and excludes the SureForms post type from AIOSEO's public post types.
1372 *
1373 * - Verifies the presence of the AIOSEO_DIR constant to ensure AIOSEO is installed.
1374 * - Allows AIOSEO functionality on its own settings pages by checking the `REQUEST_URI` and `page` query parameter.
1375 * - Excludes the SureForms post type from AIOSEO's public post types using the `aioseo_public_post_types` filter.
1376 *
1377 * Security Note:
1378 * - Nonce verification is intentionally skipped (`phpcs:ignore WordPress.Security.NonceVerification.Recommended`)
1379 * because this code is only performing a read operation to check the current request URI and query parameters.
1380 * It does not modify or process sensitive data, making nonce verification unnecessary in this context.
1381 */
1382 // Check if AIOSEO is installed by verifying the AIOSEO_DIR constant.
1383 if ( ! defined( 'AIOSEO_DIR' ) ) {
1384 return;
1385 }
1386
1387 // Allow AIOSEO functionality on its own settings pages.
1388 if ( isset( $_SERVER['REQUEST_URI'] ) ) {
1389 $request_uri = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) );
1390 if ( strpos( $request_uri, 'admin.php' ) !== false ) {
1391 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.
1392 $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.
1393 if ( strpos( $page, 'aioseo' ) !== false ) {
1394 return;
1395 }
1396 }
1397 }
1398 }
1399
1400 // Exclude the SureForms post type from AIOSEO's public post types.
1401 add_filter( 'aioseo_public_post_types', [ $this, 'unset_sureforms_post_type' ] );
1402 }
1403
1404 /**
1405 * Creates a DateTime object from date string and time components.
1406 *
1407 * @param string $date_str Date string.
1408 * @param string $hours Hours in 12-hour format.
1409 * @param string $minutes Minutes.
1410 * @param string $meridiem AM or PM.
1411 * @since 2.4.0
1412 * @return \DateTime|null DateTime object or null if invalid.
1413 */
1414 private function create_datetime_object( $date_str, $hours, $minutes, $meridiem ) {
1415 if ( empty( $date_str ) ) {
1416 return null;
1417 }
1418
1419 try {
1420 $date = new \DateTime( $date_str );
1421
1422 // Convert 12-hour format to 24-hour format.
1423 $hour_24 = intval( $hours );
1424 if ( 'PM' === $meridiem && 12 !== $hour_24 ) {
1425 $hour_24 += 12;
1426 } elseif ( 'AM' === $meridiem && 12 === $hour_24 ) {
1427 $hour_24 = 0;
1428 }
1429
1430 $date->setTime( $hour_24, intval( $minutes ), 0 );
1431 return $date;
1432 } catch ( \Exception $e ) {
1433 return null;
1434 }
1435 }
1436
1437 /**
1438 * Restrict interference of other plugins with SureForms.
1439 *
1440 * @since 0.0.5
1441 * @return void
1442 */
1443 private function restrict_unwanted_insertions() {
1444 // Restrict RankMath metaboxes in edit page.
1445 add_action( 'cmb2_admin_init', [ $this, 'restrict_data' ] );
1446
1447 // Restrict Yoast columns.
1448 add_filter( 'wpseo_accessible_post_types', [ $this, 'unset_sureforms_post_type' ] );
1449 add_filter( 'wpseo_metabox_prio', '__return_false' );
1450
1451 // Restrict AIOSEO columns.
1452 $this->restrict_in_aioseo_plugin();
1453 }
1454 }
1455