PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.12.2
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.12.2
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 / admin / admin.php

admin.php in SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz 1.12.2, at admin/admin.php

1,582 lines 53.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Admin Class.
4 *
5 * @package sureforms.
6 */
7
8 namespace SRFM\Admin;
9
10 use SRFM\Admin\Views\Entries_List_Table;
11 use SRFM\Admin\Views\Single_Entry;
12 use SRFM\Inc\AI_Form_Builder\AI_Helper;
13 use SRFM\Inc\Database\Tables\Entries;
14 use SRFM\Inc\Helper;
15 use SRFM\Inc\Onboarding;
16 use SRFM\Inc\Post_Types;
17 use SRFM\Inc\Traits\Get_Instance;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit; // Exit if accessed directly.
21 }
22 /**
23 * Admin handler class.
24 *
25 * @since 0.0.1
26 */
27 class Admin {
28 use Get_Instance;
29
30 /**
31 * Dashboard widget entries data.
32 *
33 * @var array
34 * @since 1.9.1
35 */
36 private $dashboard_widget_data = [];
37
38 /**
39 * SureForms Page Default permission.
40 *
41 * @var string
42 * @since 1.12.2
43 */
44 private static $sureforms_page_default_capability = 'manage_options';
45
46 /**
47 * Class constructor.
48 *
49 * @return void
50 * @since 0.0.1
51 */
52 public function __construct() {
53 add_action( 'admin_menu', [ $this, 'add_menu_page' ], 9 );
54 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
55 add_action( 'admin_menu', [ $this, 'settings_page' ] );
56 add_action( 'admin_menu', [ $this, 'add_new_form' ] );
57 add_action( 'admin_menu', [ $this, 'add_suremail_page' ] );
58 if ( ! Helper::has_pro() && self::is_first_form_created() ) {
59 add_action( 'admin_menu', [ $this, 'add_upgrade_to_pro' ] );
60 add_action( 'admin_footer', [ $this, 'add_upgrade_to_pro_target_attr' ] );
61 }
62
63 add_filter( 'plugin_action_links', [ $this, 'add_settings_link' ], 10, 2 );
64 add_action( 'enqueue_block_assets', [ $this, 'enqueue_styles' ] );
65 add_action( 'admin_head', [ $this, 'enqueue_header_styles' ] );
66 add_filter( 'admin_body_class', [ $this, 'admin_template_picker_body_class' ] );
67
68 // this action is used to restrict Spectra's quick action bar on SureForms CPTS.
69 add_action( 'uag_enable_quick_action_sidebar', [ $this, 'restrict_spectra_quick_action_bar' ] );
70
71 add_action( 'current_screen', [ $this, 'enable_gutenberg_for_sureforms' ], 100 );
72 add_action( 'admin_notices', [ $this, 'srfm_pro_version_compatibility' ] );
73
74 // Handle entry actions.
75 add_action( 'admin_init', [ $this, 'handle_entry_actions' ] );
76 add_action( 'admin_notices', [ Entries_List_Table::class, 'display_bulk_action_notice' ] );
77
78 // This action enqueues translations for NPS Survey library.
79 // A better solution will be required from library to resolve plugin conflict.
80 add_action(
81 'admin_footer',
82 static function() {
83 Helper::register_script_translations( 'nps-survey-script' );
84 },
85 1000
86 );
87 // Enfold theme compatibility to enable block editor for SureForms post type.
88 add_filter( 'avf_use_block_editor_for_post', [ $this, 'enable_block_editor_in_enfold_theme' ] );
89
90 // Add action links to the plugin page.
91 add_filter( 'plugin_action_links_' . SRFM_BASENAME, [ $this, 'add_action_links' ] );
92 // Check if admin notification is enabled and add entries badge.
93 $general_options = get_option( 'srfm_general_settings_options', [] );
94 $admin_notification_on = isset( $general_options['srfm_admin_notification'] ) ? (bool) $general_options['srfm_admin_notification'] : true;
95
96 if ( $admin_notification_on ) {
97 add_action( 'admin_menu', [ $this, 'maybe_add_entries_badge' ], 99 );
98 }
99 add_filter( 'wpforms_current_user_can', [ $this, 'disable_wpforms_capabilities' ], 10, 3 );
100
101 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_pointer' ] );
102 // Ajax callbacks for wp-pointer functionality.
103 add_action( 'wp_ajax_should_show_pointer', [ $this, 'pointer_should_show' ] );
104 add_action( 'wp_ajax_sureforms_dismiss_pointer', [ $this, 'pointer_dismissed' ] );
105 add_action( 'wp_ajax_sureforms_accept_cta', [ $this, 'pointer_accepted_cta' ] );
106
107 // Register dashboard widget only if there are recent entries.
108 add_action( 'admin_init', [ $this, 'maybe_register_dashboard_widget' ] );
109
110 // Save first form creation time stamp.
111 add_action( 'admin_init', [ $this, 'save_first_form_creation_time_stamp' ] );
112 }
113
114 /**
115 * Get the first form creation time stamp.
116 *
117 * @since 1.10.1
118 * @return int|false
119 */
120 public static function get_first_form_creation_time_stamp() {
121 return Helper::get_srfm_option( 'first_form_created_at', false );
122 }
123
124 /**
125 * Check if the first form has been created.
126 *
127 * @since 1.10.1
128 * @return bool
129 */
130 public static function is_first_form_created() {
131 // Convert the first form creation time stamp to a boolean. If it exists, it will return true, otherwise false.
132 $first_form_creation_time_stamp = self::get_first_form_creation_time_stamp();
133
134 // If the first form creation time stamp is not set, return false.
135 if ( ! $first_form_creation_time_stamp ) {
136 return false; // No forms created yet.
137 }
138
139 // Check if the first form creation time stamp is a valid integer and greater than zero.
140 return is_int( $first_form_creation_time_stamp ) && $first_form_creation_time_stamp > 0;
141 }
142
143 /**
144 * Check and save the first form creation time stamp.
145 * If not already saved.
146 *
147 * @since 1.10.1
148 * @return void
149 */
150 public static function save_first_form_creation_time_stamp() {
151 if ( ! Helper::current_user_can() || self::is_first_form_created() || ! defined( 'SRFM_FORMS_POST_TYPE' ) || ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) {
152 return;
153 }
154
155 // Get the first form creation time from the database that is published.
156 $query = new \WP_Query(
157 [
158 'post_type' => SRFM_FORMS_POST_TYPE,
159 'posts_per_page' => 1,
160 'orderby' => 'date',
161 'order' => 'ASC',
162 'fields' => 'ids',
163 'post_status' => 'publish',
164 ]
165 );
166
167 if ( ! empty( $query->posts ) && isset( $query->posts[0] ) ) {
168 // Get the first post from the query result.
169 $post_id = $query->posts[0];
170 // Get the post creation time in GMT.
171 $creation_time = get_post_field( 'post_date_gmt', $post_id );
172 // Convert the creation time to a timestamp.
173 $timestamp = strtotime( $creation_time );
174
175 if ( ! $timestamp ) {
176 return;
177 }
178
179 Helper::update_srfm_option( 'first_form_created_at', $timestamp );
180 }
181 }
182
183 /**
184 * Check if n days have passed since the first form creation.
185 * This is used to determine if the dynamic nudges should be shown.
186 *
187 * @param int $days Number of days to check.
188 * @since 1.10.1
189 * @return bool
190 */
191 public static function check_first_form_creation_threshold( $days = 3 ) {
192 $first_form_creation_time_stamp = self::get_first_form_creation_time_stamp();
193
194 if ( ! $first_form_creation_time_stamp ) {
195 return false; // No forms created yet.
196 }
197
198 /**
199 * Calculate the number of days since the first form was created.
200 */
201 $days_from_creation = ( strtotime( current_time( 'mysql' ) ) - $first_form_creation_time_stamp ) / DAY_IN_SECONDS;
202
203 // Return a boolean indicating if the number of days since creation is greater than the specified days.
204 return $days_from_creation > $days;
205 }
206
207 /**
208 * Show action on plugin page.
209 *
210 * @param array $links links.
211 * @return array
212 * @since 1.4.2
213 */
214 public function add_action_links( $links ) {
215 if ( ! Helper::has_pro() ) {
216 // Display upsell link if SureForms Pro is not installed.
217 $upsell_link = add_query_arg(
218 [
219 'utm_medium' => 'plugin-list',
220 ],
221 Helper::get_sureforms_website_url( 'pricing' )
222 );
223
224 ob_start();
225 ?>
226 <a href="<?php echo esc_url( $upsell_link ); ?>" target="_blank" rel="noreferrer" class="sureforms-plugins-go-pro">
227 <?php echo esc_html__( 'Get SureForms Pro', 'sureforms' ); ?>
228 </a>
229 <?php
230 $links[] = trim( ob_get_clean() );
231 }
232
233 return $links;
234 }
235
236 /**
237 * Enable block editor in Enfold theme for SureForms post type.
238 *
239 * @param bool $use_block_editor Whether to use block editor.
240 * @since 1.3.1
241 */
242 public function enable_block_editor_in_enfold_theme( $use_block_editor ) {
243 // if SureForms form post type then return true.
244 if ( SRFM_FORMS_POST_TYPE === get_current_screen()->post_type ) {
245 return true;
246 }
247 return $use_block_editor;
248 }
249
250 /**
251 * Enable Gutenberg for SureForms associated post types.
252 *
253 * @since 0.0.10
254 */
255 public function enable_gutenberg_for_sureforms() {
256 /**
257 * Check if the classic editor is enabled from Classic Editor plugin settings or Divi settings.
258 */
259 if ( 'block' === get_option( 'classic-editor-replace' ) || 'on' === get_option( 'et_enable_classic_editor' ) ) {
260 return;
261 }
262
263 $srfm_post_types = apply_filters( 'srfm_enable_gutenberg_post_types', [ SRFM_FORMS_POST_TYPE ] );
264
265 if ( in_array( get_current_screen()->post_type, $srfm_post_types, true ) ) {
266 add_filter( 'use_block_editor_for_post_type', '__return_true', 110 );
267 add_filter( 'gutenberg_can_edit_post_type', '__return_true', 110 );
268 }
269 }
270
271 /**
272 * Sureforms editor header styles.
273 *
274 * @since 0.0.1
275 */
276 public function enqueue_header_styles() {
277 $current_screen = get_current_screen();
278 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
279 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
280
281 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
282
283 /* RTL */
284 if ( is_rtl() ) {
285 $file_prefix .= '-rtl';
286 }
287
288 if ( 'sureforms_form' === $current_screen->id ) {
289 wp_enqueue_style( SRFM_SLUG . '-editor-header-styles', $css_uri . 'header-styles' . $file_prefix . '.css', [], SRFM_VER );
290 }
291 }
292
293 /**
294 * Add menu page.
295 *
296 * @return void
297 * @since 0.0.1
298 */
299 public function add_menu_page() {
300 $menu_slug = 'sureforms_menu';
301
302 $logo = file_get_contents( plugin_dir_path( SRFM_FILE ) . 'images/icon.svg' );
303 add_menu_page(
304 __( 'SureForms', 'sureforms' ),
305 __( 'SureForms', 'sureforms' ),
306 self::$sureforms_page_default_capability,
307 $menu_slug,
308 static function () {
309 },
310 'data:image/svg+xml;base64,' . base64_encode( $logo ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
311 30
312 );
313
314 // Add the Dashboard Submenu.
315 add_submenu_page(
316 $menu_slug,
317 __( 'Dashboard', 'sureforms' ),
318 __( 'Dashboard', 'sureforms' ),
319 self::$sureforms_page_default_capability,
320 $menu_slug,
321 [ $this, 'render_dashboard' ]
322 );
323 }
324
325 /**
326 * Add Settings page.
327 *
328 * @return void
329 * @since 0.0.1
330 */
331 public function settings_page() {
332 $callback = [ $this, 'settings_page_callback' ];
333 add_submenu_page(
334 'sureforms_menu',
335 __( 'Settings', 'sureforms' ),
336 __( 'Settings', 'sureforms' ),
337 self::$sureforms_page_default_capability,
338 'sureforms_form_settings',
339 $callback
340 );
341
342 // Get the current submenu page.
343 $submenu_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
344
345 if ( ! isset( $_GET['tab'] ) && 'sureforms_form_settings' === $submenu_page ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
346 wp_safe_redirect( admin_url( 'admin.php?page=sureforms_form_settings&tab=general-settings' ) );
347 exit;
348 }
349 }
350
351 /**
352 * Open to Upgrade to Pro submenu link in new tab.
353 *
354 * @return void
355 * @since 1.6.1
356 */
357 public function add_upgrade_to_pro_target_attr() {
358
359 // only add if first form was created more than 8 days ago.
360 if ( ! self::check_first_form_creation_threshold( 8 ) ) {
361 return;
362 }
363
364 ?>
365 <script type="text/javascript">
366 document.addEventListener('DOMContentLoaded', function () {
367 // Upgrade link handler.
368 // IMPORTANT: If this URL changes, also update it in the `add_upgrade_to_pro` function.
369 const upgradeLink = document.querySelector('a[href*="https://sureforms.com/upgrade"]');
370 if (upgradeLink) {
371 upgradeLink.addEventListener('click', e => {
372 e.preventDefault();
373 window.open(upgradeLink.href, '_blank');
374 });
375 }
376 });
377 </script>
378 <?php
379 }
380
381 /**
382 * Add Upgrade to pro menu item.
383 *
384 * @return void
385 * @since 1.6.1
386 */
387 public function add_upgrade_to_pro() {
388
389 // only add if first form was created more than 8 days ago.
390 if ( ! self::check_first_form_creation_threshold( 8 ) ) {
391 return;
392 }
393
394 // The url used here is used as a selector for css to style the upgrade to pro submenu.
395 // If you are changing this url, please make sure to update the css as well.
396 $upgrade_url = add_query_arg(
397 [
398 'utm_medium' => 'submenu_link_upgrade',
399 ],
400 Helper::get_sureforms_website_url( 'upgrade' )
401 );
402
403 add_submenu_page(
404 'sureforms_menu',
405 __( 'Upgrade', 'sureforms' ),
406 __( 'Upgrade', 'sureforms' ),
407 self::$sureforms_page_default_capability,
408 $upgrade_url
409 );
410 }
411
412 /**
413 * Add SMTP promotional submenu page.
414 *
415 * @return void
416 * @since 1.7.1
417 */
418 public function add_suremail_page() {
419 add_submenu_page(
420 'sureforms_menu',
421 __( 'SMTP', 'sureforms' ),
422 __( 'SMTP', 'sureforms' ),
423 self::$sureforms_page_default_capability,
424 'sureforms_smtp',
425 [ $this, 'suremail_page_callback' ]
426 );
427
428 // Get the current submenu page.
429 $submenu_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
430
431 // Check if SureMail is installed and active.
432 if ( 'sureforms_smtp' === $submenu_page && file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' ) && is_plugin_active( 'suremails/suremails.php' ) ) {
433 // Plugin is installed and active - redirect to SureMail dashboard.
434 wp_safe_redirect( admin_url( 'options-general.php?page=suremail#/dashboard' ) );
435 exit;
436 }
437 }
438
439 /**
440 * SMTP promotional page callback.
441 *
442 * @return void
443 * @since 1.7.1
444 */
445 public function suremail_page_callback() {
446 ?>
447 <div id="srfm-suremail-container" class="srfm-admin-wrapper"></div>
448 <?php
449 }
450
451 /**
452 * Render Admin Dashboard.
453 *
454 * @return void
455 * @since 0.0.1
456 */
457 public function render_dashboard() {
458 ?>
459 <div id="srfm-dashboard-container" class="srfm-admin-wrapper"></div>
460 <?php
461 }
462
463 /**
464 * Settings page callback.
465 *
466 * @return void
467 * @since 0.0.1
468 */
469 public function settings_page_callback() {
470 ?>
471 <div id="srfm-settings-container" class="srfm-admin-wrapper"></div>
472 <?php
473 }
474
475 /**
476 * Add new form menu item.
477 *
478 * @return void
479 * @since 0.0.1
480 */
481 public function add_new_form() {
482 add_submenu_page(
483 'sureforms_menu',
484 __( 'New Form', 'sureforms' ),
485 __( 'New Form', 'sureforms' ),
486 self::$sureforms_page_default_capability,
487 'add-new-form',
488 [ $this, 'add_new_form_callback' ],
489 2
490 );
491 $entries_hook = add_submenu_page(
492 'sureforms_menu',
493 __( 'Entries', 'sureforms' ),
494 __( 'Entries', 'sureforms' ),
495 self::$sureforms_page_default_capability,
496 SRFM_ENTRIES,
497 [ $this, 'render_entries' ],
498 3
499 );
500
501 if ( $entries_hook ) {
502 add_action( 'load-' . $entries_hook, [ $this, 'mark_entries_page_visit' ] );
503 }
504 }
505
506 /**
507 * Add new form mentu item callback.
508 *
509 * @return void
510 * @since 0.0.1
511 */
512 public function add_new_form_callback() {
513 ?>
514 <div id="srfm-add-new-form-container" class="srfm-admin-wrapper"></div>
515 <?php
516 }
517
518 /**
519 * Entries page callback.
520 *
521 * @since 0.0.13
522 * @return void
523 */
524 public function render_entries() {
525 // Render single entry view.
526 // Adding the phpcs ignore nonce verification as no database operations are performed in this function, it is used to display the single entry view.
527 if ( isset( $_GET['entry_id'] ) && is_numeric( $_GET['entry_id'] ) && isset( $_GET['view'] ) && 'details' === $_GET['view'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not needed here and explained in the comments above as well.
528 $single_entry_view = new Single_Entry();
529 $single_entry_view->render();
530 return;
531 }
532
533 // Render all entries view.
534 $entries_table = new Entries_List_Table();
535 $entries_table->prepare_items();
536 ?>
537 <div class="wrap">
538 <h1 class="wp-heading-inline"><?php echo esc_html__( 'Entries', 'sureforms' ); ?></h1>
539 <?php
540 if ( empty( $entries_table->all_entries_count ) && empty( $entries_table->trash_entries_count ) ) {
541 $instance = Post_Types::get_instance();
542 $instance->sureforms_render_blank_state( SRFM_ENTRIES );
543 $instance->get_blank_state_styles();
544 return;
545 }
546 ?>
547 <form method="get">
548 <input type="hidden" name="page" value="sureforms_entries">
549 <?php $entries_table->display(); ?>
550 </form>
551 </div>
552 <?php
553 }
554
555 /**
556 * Add notification badge to SureForms menu when there are new entries.
557 *
558 * @since 1.7.3
559 * @return void
560 */
561 public function maybe_add_entries_badge() {
562 if ( ! Helper::current_user_can() ) {
563 return;
564 }
565
566 // If currently viewing the entries listing page, mark it as visited and skip the badge.
567 if ( isset( $_GET['page'] ) && SRFM_ENTRIES === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only checking the page slug.
568 $this->mark_entries_page_visit();
569 return;
570 }
571
572 $srfm_options = get_option( 'srfm_options', [] );
573 $last_visit = isset( $srfm_options['entries_last_visited'] ) ? absint( $srfm_options['entries_last_visited'] ) : 0;
574 $new_entries = Entries::get_entries_count_after( $last_visit );
575
576 if ( $new_entries <= 0 ) {
577 return;
578 }
579
580 global $menu;
581 foreach ( $menu as $index => $item ) {
582 if ( isset( $item[2] ) && 'sureforms_menu' === $item[2] ) {
583 ob_start();
584 ?>
585 <span class="srfm-update-dot"></span>
586 <?php
587 $dot_html = ob_get_clean();
588 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for menu item.
589 $menu[ $index ][0] .= $dot_html;
590 break;
591 }
592 }
593
594 global $submenu;
595 if ( isset( $submenu['sureforms_menu'] ) ) {
596 foreach ( $submenu['sureforms_menu'] as $index => $sub_item ) {
597 if ( isset( $sub_item[2] ) && SRFM_ENTRIES === $sub_item[2] ) {
598 ob_start();
599 ?>
600 <span class="update-plugins count-<?php echo absint( $new_entries ); ?>">
601 <span class="plugin-count"><?php echo absint( $new_entries ); ?></span>
602 </span>
603 <?php
604 $badge_html = ob_get_clean();
605 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for submenu item.
606 $submenu['sureforms_menu'][ $index ][0] .= $badge_html;
607 break;
608 }
609 }
610 }
611 }
612
613 /**
614 * Mark the user's visit to the entries page.
615 *
616 * @since 1.7.3
617 * @return void
618 */
619 public function mark_entries_page_visit() {
620 if ( Helper::current_user_can() ) {
621 $srfm_options = get_option( 'srfm_options', [] );
622 $srfm_options['entries_last_visited'] = time();
623 \SRFM\Inc\Helper::update_admin_settings_option( 'srfm_options', $srfm_options );
624 }
625 }
626
627 /**
628 * Adds a settings link to the plugin action links on the plugins page.
629 *
630 * @param array $links An array of plugin action links.
631 * @param string $file The plugin file path.
632 * @return array The updated array of plugin action links.
633 * @since 0.0.1
634 */
635 public function add_settings_link( $links, $file ) {
636 if ( 'sureforms/sureforms.php' === $file ) {
637 ob_start();
638 ?>
639 <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_form_settings&tab=general-settings' ) ); ?>">
640 <?php echo esc_html__( 'Settings', 'sureforms' ); ?>
641 </a>
642 <?php
643 $settings_link_html = ob_get_clean();
644 $plugin_links = apply_filters(
645 'sureforms_plugin_action_links',
646 [
647 'sureforms_settings' => $settings_link_html,
648 ]
649 );
650 $links = array_merge( $plugin_links, $links );
651 }
652 return $links;
653 }
654
655 /**
656 * Sureforms block editor styles.
657 *
658 * @since 0.0.1
659 */
660 public function enqueue_styles() {
661 $current_screen = get_current_screen();
662 global $wp_version;
663
664 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
665 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
666
667 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
668 $vendor_css_uri = SRFM_URL . 'assets/css/minified/deps/';
669
670 /* RTL */
671 if ( is_rtl() ) {
672 $file_prefix .= '-rtl';
673 }
674
675 // Enqueue editor styles for post and page.
676 if ( SRFM_FORMS_POST_TYPE === $current_screen->post_type ) {
677 wp_enqueue_style( SRFM_SLUG . '-editor', $css_uri . 'backend/editor' . $file_prefix . '.css', [], SRFM_VER );
678 wp_enqueue_style( SRFM_SLUG . '-backend-blocks', $css_uri . 'blocks/default/backend' . $file_prefix . '.css', [], SRFM_VER );
679 wp_enqueue_style( SRFM_SLUG . '-intl', $vendor_css_uri . 'intl/intlTelInput-backend.min.css', [], SRFM_VER );
680 wp_enqueue_style( SRFM_SLUG . '-common', $css_uri . 'common' . $file_prefix . '.css', [], SRFM_VER );
681 wp_enqueue_style( SRFM_SLUG . '-reactQuill', $vendor_css_uri . 'quill/quill.snow.css', [], SRFM_VER );
682 wp_enqueue_style( SRFM_SLUG . '-single-form-modal', $css_uri . 'single-form-setting' . $file_prefix . '.css', [], SRFM_VER );
683
684 // if version is equal to or lower than 6.6.2 then add compatibility css.
685 if ( version_compare( $wp_version, '6.6.2', '<=' ) ) {
686 $srfm_inline_css = '.srfm-settings-modal .srfm-setting-modal-container .components-toggle-control .components-base-control__help{
687 margin-left: 4em;
688 }';
689 wp_add_inline_style( SRFM_SLUG . '-single-form-modal', $srfm_inline_css );
690 }
691 }
692
693 wp_enqueue_style( SRFM_SLUG . '-form-selector', $css_uri . 'srfm-form-selector' . $file_prefix . '.css', [], SRFM_VER );
694 wp_enqueue_style( SRFM_SLUG . '-common-editor', SRFM_URL . 'assets/build/common-editor.css', [], SRFM_VER, 'all' );
695 }
696
697 /**
698 * Get Breadcrumbs for current page.
699 *
700 * @since 0.0.1
701 * @return array Breadcrumbs Array.
702 */
703 public function get_breadcrumbs_for_current_page() {
704 global $post, $pagenow;
705 $breadcrumbs = [];
706
707 if ( 'admin.php' === $pagenow && isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
708 $page_title = get_admin_page_title();
709 $breadcrumbs[] = [
710 'title' => $page_title,
711 'link' => '',
712 ];
713 } elseif ( $post && in_array( $pagenow, [ 'post.php', 'post-new.php', 'edit.php' ], true ) ) {
714 $post_type_obj = get_post_type_object( get_post_type() );
715 if ( $post_type_obj ) {
716 $post_type_plural = $post_type_obj->labels->name;
717 $breadcrumbs[] = [
718 'title' => $post_type_plural,
719 'link' => admin_url( 'edit.php?post_type=' . $post_type_obj->name ),
720 ];
721
722 if ( 'edit.php' === $pagenow && ! isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
723 $breadcrumbs[ count( $breadcrumbs ) - 1 ]['link'] = '';
724 } else {
725 $breadcrumbs[] = [
726 /* Translators: Post Title. */
727 'title' => sprintf( __( 'Edit %1$s', 'sureforms' ), get_the_title() ),
728 'link' => get_edit_post_link( $post->ID ),
729 ];
730 }
731 }
732 } else {
733 $current_screen = get_current_screen();
734 if ( $current_screen && 'sureforms_form' === $current_screen->post_type ) {
735 $breadcrumbs[] = [
736 'title' => 'Forms',
737 'link' => '',
738 ];
739 } else {
740 $breadcrumbs[] = [
741 'title' => '',
742 'link' => '',
743 ];
744 }
745 }
746
747 return $breadcrumbs;
748 }
749
750 /**
751 * Enqueue Admin Scripts.
752 *
753 * @return void
754 * @since 0.0.1
755 */
756 public function enqueue_scripts() {
757 $current_screen = get_current_screen();
758 global $wp_version;
759
760 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
761 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
762 $js_uri = SRFM_URL . 'assets/js/' . $dir_name . '/';
763 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
764 $is_rtl = is_rtl();
765 $rtl = $is_rtl ? '-rtl' : '';
766
767 /**
768 * List of the handles in which we need to add translation compatibility.
769 */
770 $script_translations_handlers = [];
771 $onboarding_instance = Onboarding::get_instance();
772
773 $localization_data = [
774 'site_url' => get_site_url(),
775 'breadcrumbs' => $this->get_breadcrumbs_for_current_page(),
776 'sureforms_dashboard_url' => admin_url( '/admin.php?page=sureforms_menu' ),
777 'plugin_version' => SRFM_VER,
778 'global_settings_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
779 'is_pro_active' => Helper::has_pro(),
780 'is_first_form_created' => self::is_first_form_created(),
781 'check_three_days_threshold' => self::check_first_form_creation_threshold(),
782 'check_eight_days_threshold' => self::check_first_form_creation_threshold( 8 ),
783 'pro_plugin_version' => Helper::has_pro() ? SRFM_PRO_VER : '',
784 'pro_plugin_name' => Helper::has_pro() && defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro',
785 'sureforms_pricing_page' => Helper::get_sureforms_website_url( 'pricing' ),
786 'field_spacing_vars' => Helper::get_css_vars(),
787 'is_ver_lower_than_6_7' => version_compare( $wp_version, '6.6.2', '<=' ),
788 'integrations' => Helper::sureforms_get_integration(),
789 'ajax_url' => admin_url( 'admin-ajax.php' ),
790 'sf_plugin_manager_nonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
791 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
792 'plugin_activating_text' => __( 'Activating...', 'sureforms' ),
793 'plugin_activated_text' => __( 'Activated', 'sureforms' ),
794 'plugin_activate_text' => __( 'Activate', 'sureforms' ),
795 'plugin_installing_text' => __( 'Installing...', 'sureforms' ),
796 'plugin_installed_text' => __( 'Installed', 'sureforms' ),
797 'is_rtl' => $is_rtl,
798 'onboarding_completed' => method_exists( $onboarding_instance, 'get_onboarding_status' ) ? $onboarding_instance->get_onboarding_status() : false,
799 'onboarding_redirect' => isset( $_GET['srfm-activation-redirect'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce is not required for the activation redirection.
800 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
801 'general_settings_url' => admin_url( '/options-general.php' ),
802 ];
803
804 $is_screen_sureforms_menu = Helper::validate_request_context( 'sureforms_menu', 'page' );
805 $is_screen_add_new_form = Helper::validate_request_context( 'add-new-form', 'page' );
806 $is_screen_sureforms_form_settings = Helper::validate_request_context( 'sureforms_form_settings', 'page' );
807 $is_screen_sureforms_entries = Helper::validate_request_context( SRFM_ENTRIES, 'page' );
808 $is_post_type_sureforms_form = SRFM_FORMS_POST_TYPE === $current_screen->post_type;
809
810 /**
811 * Check if the current screen is the SureForms Menu and AI Auth Email is present then we will add user type as registered.
812 * Compatibility with existing UI code that checks for this condition.
813 */
814 if ( $is_screen_sureforms_menu ) {
815 // If email is stored send the user type as registered else non-registered.
816 $localization_data['srfm_ai_details'] = [
817 'type' => ! empty( get_option( 'srfm_ai_auth_user_email' ) ) ? 'registered' : 'non-registered',
818 ];
819 }
820
821 if ( $is_screen_sureforms_menu || $is_post_type_sureforms_form || $is_screen_add_new_form || $is_screen_sureforms_form_settings || $is_screen_sureforms_entries ) {
822 $asset_handle = '-dashboard';
823
824 wp_enqueue_style( SRFM_SLUG . $asset_handle . '-font', 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap', [], SRFM_VER );
825
826 $script_asset_path = SRFM_DIR . 'assets/build/dashboard.asset.php';
827 $script_info = file_exists( $script_asset_path )
828 ? include $script_asset_path
829 : [
830 'dependencies' => [],
831 'version' => SRFM_VER,
832 ];
833 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/dashboard.js', $script_info['dependencies'], SRFM_VER, true );
834
835 wp_localize_script( SRFM_SLUG . $asset_handle, 'scIcons', [ 'path' => SRFM_URL . 'assets/build/icon-assets' ] );
836
837 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
838
839 if ( class_exists( 'SRFM_PRO\Admin\Licensing' ) ) {
840 $license_active = \SRFM_PRO\Admin\Licensing::is_license_active();
841 $localization_data['is_license_active'] = $license_active;
842
843 // Updating current licensing status.
844 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
845 $current_license_status = $license_active ? 'licensed' : 'unlicensed';
846 if ( $current_license_status !== $srfm_pro_license_status ) {
847 update_option( 'srfm_pro_license_status', $current_license_status );
848 }
849 }
850
851 $localization_data['security_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=security-settings' );
852 $localization_data['integration_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=integration-settings' );
853 wp_localize_script(
854 SRFM_SLUG . $asset_handle,
855 SRFM_SLUG . '_admin',
856 apply_filters(
857 SRFM_SLUG . '_admin_filter',
858 $localization_data
859 )
860 );
861 wp_enqueue_style( SRFM_SLUG . '-dashboard', SRFM_URL . 'assets/build/dashboard.css', [], SRFM_VER, 'all' );
862
863 }
864
865 if ( $is_screen_sureforms_form_settings ) {
866 wp_enqueue_style( SRFM_SLUG . '-settings', $css_uri . 'backend/settings' . $file_prefix . $rtl . '.css', [], SRFM_VER );
867 }
868
869 // Enqueue styles for the entries page.
870 if ( $is_screen_sureforms_entries ) {
871 $asset_handle = '-entries';
872 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/entries.js', $script_info['dependencies'], SRFM_VER, true );
873
874 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
875 }
876
877 // Enqueue scripts for the SureMail promotional page.
878 $is_screen_sureforms_smtp = Helper::validate_request_context( 'sureforms_smtp', 'page' );
879 if ( $is_screen_sureforms_smtp ) {
880 $asset_handle = 'suremail';
881
882 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
883 $script_info = file_exists( $script_asset_path )
884 ? include $script_asset_path
885 : [
886 'dependencies' => [],
887 'version' => SRFM_VER,
888 ];
889
890 wp_enqueue_script( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
891 wp_enqueue_style( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/suremail.css', [], SRFM_VER, 'all' );
892
893 // Localize script for SureMail page.
894 $suremail_localization_data = [
895 'ajax_url' => admin_url( 'admin-ajax.php' ),
896 'admin_url' => admin_url(),
897 'suremail_url' => 'https://sureforms.com/suremail/',
898 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
899 'sfPluginManagerNonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
900 'suremail_status' => file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' )
901 ? ( is_plugin_active( 'suremails/suremails.php' ) ? 'active' : 'installed' )
902 : 'not_installed',
903 ];
904
905 wp_localize_script(
906 SRFM_SLUG . '-suremail',
907 SRFM_SLUG . '_admin',
908 apply_filters(
909 SRFM_SLUG . '_suremail_admin_filter',
910 $suremail_localization_data
911 )
912 );
913
914 $script_translations_handlers[] = SRFM_SLUG . '-suremail';
915 }
916
917 // Admin Submenu Styles.
918 wp_enqueue_style( SRFM_SLUG . '-admin', $css_uri . 'backend/admin' . $file_prefix . $rtl . '.css', [], SRFM_VER );
919
920 if ( 'edit-' . SRFM_FORMS_POST_TYPE === $current_screen->id ) {
921 $asset_handle = 'page_header';
922
923 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
924 $script_info = file_exists( $script_asset_path )
925 ? include $script_asset_path
926 : [
927 'dependencies' => [],
928 'version' => SRFM_VER,
929 ];
930 wp_enqueue_script( SRFM_SLUG . '-form-page-header', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
931 wp_enqueue_style( SRFM_SLUG . '-form-archive-styles', $css_uri . 'form-archive-styles' . $file_prefix . $rtl . '.css', [], SRFM_VER );
932
933 $script_translations_handlers[] = SRFM_SLUG . '-form-page-header';
934 }
935
936 if ( $is_screen_sureforms_form_settings ) {
937 $asset_handle = 'settings';
938
939 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
940 $script_info = file_exists( $script_asset_path )
941 ? include $script_asset_path
942 : [
943 'dependencies' => [],
944 'version' => SRFM_VER,
945 ];
946
947 wp_enqueue_script( SRFM_SLUG . '-settings', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
948 wp_localize_script(
949 SRFM_SLUG . '-settings',
950 SRFM_SLUG . '_admin',
951 $localization_data
952 );
953
954 $script_translations_handlers[] = SRFM_SLUG . '-settings';
955 }
956 if ( 'edit-' . SRFM_FORMS_POST_TYPE === $current_screen->id ) {
957 wp_enqueue_script( SRFM_SLUG . '-form-archive', $js_uri . 'form-archive' . $file_prefix . '.js', [], SRFM_VER, true );
958 wp_enqueue_script( SRFM_SLUG . '-export', $js_uri . 'export' . $file_prefix . '.js', [ 'wp-i18n' ], SRFM_VER, true );
959 wp_localize_script(
960 SRFM_SLUG . '-export',
961 SRFM_SLUG . '_export',
962 [
963 'ajaxurl' => admin_url( 'admin-ajax.php' ),
964 'srfm_export_nonce' => wp_create_nonce( 'export_form_nonce' ),
965 'site_url' => get_site_url(),
966 'import_form_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
967 'import_btn_string' => __( 'Import Form', 'sureforms' ),
968 ]
969 );
970
971 wp_enqueue_script( SRFM_SLUG . '-backend', $js_uri . 'backend' . $file_prefix . '.js', [], SRFM_VER, true );
972 wp_localize_script(
973 SRFM_SLUG . '-backend',
974 SRFM_SLUG . '_backend',
975 [
976 'site_url' => get_site_url(),
977 ]
978 );
979
980 $script_translations_handlers[] = SRFM_SLUG . '-form-archive';
981 $script_translations_handlers[] = SRFM_SLUG . '-export';
982 $script_translations_handlers[] = SRFM_SLUG . '-backend';
983 }
984
985 if ( $is_screen_add_new_form ) {
986 wp_enqueue_style( SRFM_SLUG . '-template-picker', $css_uri . 'template-picker' . $file_prefix . $rtl . '.css', [], SRFM_VER );
987
988 $sureforms_admin = 'templatePicker';
989
990 $script_asset_path = SRFM_DIR . 'assets/build/' . $sureforms_admin . '.asset.php';
991 $script_info = file_exists( $script_asset_path )
992 ? include $script_asset_path
993 : [
994 'dependencies' => [],
995 'version' => SRFM_VER,
996 ];
997 wp_enqueue_script( SRFM_SLUG . '-template-picker', SRFM_URL . 'assets/build/' . $sureforms_admin . '.js', $script_info['dependencies'], SRFM_VER, true );
998
999 wp_localize_script(
1000 SRFM_SLUG . '-template-picker',
1001 SRFM_SLUG . '_admin',
1002 [
1003 'site_url' => get_site_url(),
1004 'plugin_url' => SRFM_URL,
1005 'admin_url' => admin_url( 'admin.php' ),
1006 'new_template_picker_base_url' => admin_url( 'post-new.php?post_type=sureforms_form' ),
1007 'capability' => Helper::current_user_can(),
1008 'template_picker_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
1009 'is_pro_active' => Helper::has_pro(),
1010 'srfm_ai_usage_details' => AI_Helper::get_current_usage_details(),
1011 'is_pro_license_active' => AI_Helper::is_pro_license_active(),
1012 'srfm_ai_auth_user_email' => get_option( 'srfm_ai_auth_user_email' ),
1013 'pricing_page_url' => Helper::get_sureforms_website_url( 'pricing' ),
1014 'licensing_nonce' => wp_create_nonce( 'srfm_pro_licensing_nonce' ),
1015 ]
1016 );
1017
1018 $script_translations_handlers[] = SRFM_SLUG . '-template-picker';
1019 }
1020 // Quick action sidebar.
1021 $default_allowed_quick_sidebar_blocks = apply_filters(
1022 'srfm_quick_sidebar_allowed_blocks',
1023 [
1024 'srfm/input',
1025 'srfm/email',
1026 'srfm/textarea',
1027 'srfm/checkbox',
1028 'srfm/number',
1029 'srfm/inline-button',
1030 'srfm/advanced-heading',
1031 ]
1032 );
1033 if ( ! is_array( $default_allowed_quick_sidebar_blocks ) ) {
1034 $default_allowed_quick_sidebar_blocks = [];
1035 }
1036
1037 $srfm_enable_quick_action_sidebar = get_option( 'srfm_enable_quick_action_sidebar' );
1038 if ( ! $srfm_enable_quick_action_sidebar ) {
1039 $srfm_enable_quick_action_sidebar = 'disabled';
1040 }
1041 $quick_sidebar_allowed_blocks = get_option( 'srfm_quick_sidebar_allowed_blocks' );
1042 $quick_sidebar_allowed_blocks = ! empty( $quick_sidebar_allowed_blocks ) && is_array( $quick_sidebar_allowed_blocks ) ? $quick_sidebar_allowed_blocks : $default_allowed_quick_sidebar_blocks;
1043 $srfm_ajax_nonce = wp_create_nonce( 'srfm_ajax_nonce' );
1044 wp_enqueue_script( SRFM_SLUG . '-quick-action-siderbar', SRFM_URL . 'assets/build/quickActionSidebar.js', [], SRFM_VER, true );
1045 wp_localize_script(
1046 SRFM_SLUG . '-quick-action-siderbar',
1047 SRFM_SLUG . '_quick_sidebar_blocks',
1048 [
1049 'allowed_blocks' => $quick_sidebar_allowed_blocks,
1050 'srfm_enable_quick_action_sidebar' => $srfm_enable_quick_action_sidebar,
1051 'srfm_ajax_nonce' => $srfm_ajax_nonce,
1052 'srfm_ajax_url' => admin_url( 'admin-ajax.php' ),
1053 ]
1054 );
1055
1056 $script_translations_handlers[] = SRFM_SLUG . '-quick-action-siderbar';
1057
1058 /**
1059 * Enqueuing SureTriggers Integration script.
1060 * This script loads suretriggers iframe in Intergations tab.
1061 */
1062 if ( $is_post_type_sureforms_form ) {
1063 wp_enqueue_script( SRFM_SLUG . '-suretriggers-integration', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL . 'js/v2/embed.js', [], SRFM_VER, true );
1064 }
1065
1066 // Check $script_translations_handlers is not empty before calling the function.
1067 if ( ! empty( $script_translations_handlers ) ) {
1068 // Remove duplicates values from the array.
1069 $script_translations_handlers = array_unique( $script_translations_handlers );
1070
1071 foreach ( $script_translations_handlers as $script_handle ) {
1072 Helper::register_script_translations( $script_handle );
1073 }
1074 }
1075 }
1076
1077 /**
1078 * Form Template Picker Admin Body Classes
1079 * WordPress sometimes translates class names in the admin body tag, which can result in
1080 * incorrect or missing class names when rendering the admin pages. This function ensures
1081 * that essential class names are manually added to the body tag to maintain proper functionality.
1082 *
1083 * @since 0.0.1
1084 * @param string $classes Space separated class string.
1085 */
1086 public function admin_template_picker_body_class( $classes = '' ) {
1087 // Define an associative array of class names and their corresponding conditions.
1088 // Each condition checks whether a specific request context matches.
1089 $srfm_classes = [
1090 'sureforms_page_sureforms_entries' => Helper::validate_request_context( SRFM_ENTRIES, 'page' ),
1091 'sureforms_page_sureforms_form_settings' => Helper::validate_request_context( 'sureforms_form_settings', 'page' ),
1092 'srfm-template-picker' => Helper::validate_request_context( 'add-new-form', 'page' ),
1093 ];
1094
1095 $add_srfm_classes = '';
1096
1097 // Loop through the defined classes and conditions.
1098 foreach ( $srfm_classes as $class => $condition ) {
1099 // Check if the condition evaluates to true.
1100 if ( $condition ) {
1101 // Append the class to the existing classes string, followed by a space.
1102 $add_srfm_classes .= empty( $add_srfm_classes ) ? $class : ' ' . $class;
1103 }
1104 }
1105
1106 // Append the new classes to the existing classes string.
1107 if ( ! empty( $add_srfm_classes ) ) {
1108 $classes .= ' ' . $add_srfm_classes;
1109 }
1110
1111 // Return the updated list of classes.
1112 return $classes;
1113 }
1114
1115 /**
1116 * Disable spectra's quick action bar in sureforms CPT.
1117 *
1118 * @param string $status current status of the quick action bar.
1119 * @since 0.0.2
1120 * @return string
1121 */
1122 public function restrict_spectra_quick_action_bar( $status ) {
1123 $screen = get_current_screen();
1124 if ( 'disabled' !== $status && isset( $screen->id ) && 'sureforms_form' === $screen->id ) {
1125 $status = 'disabled';
1126 }
1127
1128 return $status;
1129 }
1130
1131 // Entries methods.
1132
1133 /**
1134 * Handle entry actions.
1135 *
1136 * @since 0.0.13
1137 * @return void
1138 */
1139 public function handle_entry_actions() {
1140 Entries_List_Table::process_bulk_actions();
1141
1142 if ( ! isset( $_GET['page'] ) || SRFM_ENTRIES !== $_GET['page'] ) {
1143 return;
1144 }
1145 if ( ! isset( $_GET['entry_id'] ) || ! isset( $_GET['action'] ) ) {
1146 return;
1147 }
1148 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'srfm_entries_action' ) ) {
1149 wp_die( esc_html__( 'Nonce verification failed.', 'sureforms' ) );
1150 }
1151 $action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : '';
1152 $entry_id = Helper::get_integer_value( sanitize_text_field( wp_unslash( $_GET['entry_id'] ) ) );
1153 $view = isset( $_GET['view'] ) ? sanitize_text_field( wp_unslash( $_GET['view'] ) ) : '';
1154 if ( $entry_id > 0 ) {
1155 if ( 'read' === $action && 'details' === $view ) {
1156 $entry_status = Entries::get( $entry_id )['status'];
1157 if ( 'trash' === $entry_status ) {
1158 wp_die( esc_html__( 'You cannot view this entry because it is in trash.', 'sureforms' ) );
1159 }
1160 }
1161 Entries_List_Table::handle_entry_status( $entry_id, $action, $view );
1162 }
1163 }
1164
1165 /**
1166 * Admin Notice Callback if sureforms pro is out of date.
1167 *
1168 * Hooked - admin_notices
1169 *
1170 * @return void
1171 * @since 1.0.4
1172 */
1173 public function srfm_pro_version_compatibility() {
1174 if ( ! Helper::has_pro() ) {
1175 return;
1176 }
1177
1178 if ( empty( get_current_screen() ) ) {
1179 return;
1180 }
1181
1182 if ( ! Helper::current_user_can() ) {
1183 return;
1184 }
1185
1186 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
1187 /**
1188 * If the license status is not set then get the license status and update the option accordingly.
1189 * This will be executed only once. Subsequently, the option status is updated by the licensing class on license activation or deactivation.
1190 */
1191 if ( empty( $srfm_pro_license_status ) && class_exists( 'SRFM_PRO\Admin\Licensing' ) ) {
1192 $srfm_pro_license_status = \SRFM_PRO\Admin\Licensing::is_license_active() ? 'licensed' : 'unlicensed';
1193 update_option( 'srfm_pro_license_status', $srfm_pro_license_status );
1194 }
1195
1196 $pro_plugin_name = defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro';
1197 $message = '';
1198 $url = admin_url( 'admin.php?page=sureforms_form_settings&tab=account-settings' );
1199 if ( 'unlicensed' === $srfm_pro_license_status ) {
1200 ob_start();
1201 ?>
1202 <p>
1203 <?php
1204 printf(
1205 // translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name.
1206 esc_html__( 'Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more.', 'sureforms' ),
1207 '<a href="' . esc_url( $url ) . '">',
1208 '</a>',
1209 '<i>' . esc_html( $pro_plugin_name ) . '</i>'
1210 );
1211 ?>
1212 </p>
1213 <?php
1214 $message = ob_get_clean();
1215 }
1216
1217 if ( ! version_compare( SRFM_PRO_VER, SRFM_PRO_RECOMMENDED_VER, '>=' ) ) {
1218 ob_start();
1219 ?>
1220 <p>
1221 <?php
1222 printf(
1223 // translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version, %4$s: Anchor tag open, %5$s: Closing anchor tag.
1224 esc_html__( 'SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version from %4$shere%5$s.', 'sureforms' ),
1225 esc_html( SRFM_VER ),
1226 esc_html( $pro_plugin_name ),
1227 esc_html( SRFM_PRO_RECOMMENDED_VER ),
1228 '<a href="' . esc_url( admin_url( 'update-core.php' ) ) . '">',
1229 '</a>'
1230 );
1231 ?>
1232 </p>
1233 <?php
1234 $message .= ob_get_clean();
1235 }
1236
1237 if ( ! empty( $message ) ) {
1238 // Phpcs ignore comment is required as $message variable is already escaped.
1239 ?>
1240 <div class="notice notice-warning"><?php echo wp_kses_post( $message ); ?></div>
1241 <?php
1242 }
1243 }
1244
1245 /**
1246 * Disables the capabilities for WPForms to avoid conflicts when enqueueing
1247 * scripts and styles for WPForms.
1248 *
1249 * This function is intended to prevent any potential conflicts that may arise
1250 * when WPForms scripts and styles are enqueued. By disabling certain capabilities,
1251 * it ensures that WPForms does not interfere with other functionalities.
1252 *
1253 * @param bool $user_can A boolean indicating whether the user has the capability.
1254 * @return bool Returns true if the capabilities are successfully disabled, false otherwise.
1255 * @since 1.4.2
1256 */
1257 public function disable_wpforms_capabilities( $user_can ) {
1258 // Note: Nonce verification is intentionally omitted here as no database operations are performed.
1259 // The values of the $_REQUEST variables are strictly validated, ensuring security without the need for nonce verification.
1260
1261 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1262 $post_id = ! empty( $_REQUEST['post'] ) && ! empty( $_REQUEST['action'] ) ? absint( $_REQUEST['post'] ) : 0;
1263
1264 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1265 $post_type = $post_id ? get_post_type( $post_id ) : sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ?? '' ) );
1266 return SRFM_FORMS_POST_TYPE === $post_type ? false : $user_can;
1267 }
1268
1269 /**
1270 * Enqueueus the admin pointer script and styles.
1271 *
1272 * @return void
1273 * @since 1.8.0
1274 */
1275 public function enqueue_admin_pointer() {
1276 if ( ! $this->is_admin_pointer_visible() ) {
1277 return;
1278 }
1279 wp_enqueue_style( 'wp-pointer' );
1280 wp_enqueue_script( 'wp-pointer' );
1281 wp_enqueue_script(
1282 'sureforms-admin-pointer',
1283 plugins_url( 'admin/assets/js/sureforms-pointer.js', SRFM_FILE ),
1284 [ 'wp-pointer', 'jquery' ],
1285 SRFM_VER,
1286 true
1287 );
1288 wp_localize_script(
1289 'sureforms-admin-pointer',
1290 'sureformsPointerData',
1291 [
1292 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1293 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
1294 ]
1295 );
1296 }
1297
1298 /**
1299 * Ajax handler for pointer popup visibility.
1300 *
1301 * @return void
1302 * @since 1.8.0
1303 */
1304 public function pointer_should_show() {
1305 // Security: Check user capability.
1306 if ( ! Helper::current_user_can() ) {
1307 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1308 }
1309 // Security: Nonce check.
1310 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1311 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1312 }
1313
1314 $content_markup = sprintf(
1315 /* translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong */
1316 __( '%1$sGet started by %2$sbuilding your first form%3$s.%4$s%5$sExperience the power of our intuitive AI Form Builder%6$s', 'sureforms' ),
1317 '<span>',
1318 '<strong>',
1319 '</strong>',
1320 '</span><br/>',
1321 '<strong style="font-size:1.1em;">',
1322 '</strong>'
1323 );
1324 wp_send_json(
1325 [
1326 'show' => true,
1327 'title' => esc_html( __( 'SureForms is waiting for you!', 'sureforms' ) ),
1328 'content' => wp_kses_post( $content_markup ),
1329 'button_text' => esc_html( __( 'Build My First Form', 'sureforms' ) ),
1330 'dismiss' => esc_html( __( 'Dismiss', 'sureforms' ) ),
1331 'button_url' => admin_url( 'admin.php?page=add-new-form' ),
1332 ]
1333 );
1334 }
1335
1336 /**
1337 * Ajax callback for pointer popup dismissed action.
1338 *
1339 * @return void
1340 * @since 1.8.0
1341 */
1342 public function pointer_dismissed() {
1343 // Security: Check user capability.
1344 if ( ! Helper::current_user_can() ) {
1345 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1346 }
1347 // Security: Nonce check.
1348 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1349 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1350 }
1351 // Use Helper to update srfm_options key.
1352 Helper::update_srfm_option( 'pointer_popup_dismissed', time() );
1353
1354 wp_send_json_success();
1355 }
1356
1357 /**
1358 * Ajax pointer accepted CTA callback.
1359 *
1360 * @return void
1361 * @since 1.8.0
1362 */
1363 public function pointer_accepted_cta() {
1364 // Security: Check user capability.
1365 if ( ! Helper::current_user_can() ) {
1366 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1367 }
1368 // Security: Nonce check.
1369 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1370 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1371 }
1372 // Use Helper to update srfm_options key.
1373 Helper::update_srfm_option( 'pointer_popup_accepted', time() );
1374
1375 wp_send_json_success();
1376 }
1377
1378 /**
1379 * Maybe register the dashboard widget based on entries.
1380 *
1381 * @return void
1382 * @since 1.9.1
1383 */
1384 public function maybe_register_dashboard_widget() {
1385
1386 // Only for users with manage_options capability.
1387 if ( ! Helper::current_user_can() ) {
1388 return;
1389 }
1390
1391 // Quick check if there are any entries in the last 7 days.
1392 $seven_days_ago = strtotime( '-7 days' );
1393 $total_entries = Entries::get_entries_count_after( $seven_days_ago );
1394
1395 // Only add the dashboard setup hook if there are entries.
1396 if ( $total_entries > 0 ) {
1397 // Get forms with entries (limit 4 for dashboard widget).
1398 $this->dashboard_widget_data = Helper::get_forms_with_entry_counts( $seven_days_ago, 4 );
1399
1400 // Only show dashboard widget if there are forms with entries.
1401 if ( ! empty( $this->dashboard_widget_data ) ) {
1402 add_action( 'wp_dashboard_setup', [ $this, 'register_dashboard_widget' ] );
1403 }
1404 }
1405 }
1406
1407 /**
1408 * Register the dashboard widget.
1409 *
1410 * @return void
1411 * @since 1.9.1
1412 */
1413 public function register_dashboard_widget() {
1414 // Add the widget with high priority to position it at the top.
1415 wp_add_dashboard_widget(
1416 'sureforms_recent_entries',
1417 __( 'SureForms', 'sureforms' ),
1418 [ $this, 'render_dashboard_widget' ],
1419 null,
1420 null,
1421 'normal',
1422 'high'
1423 );
1424 }
1425
1426 /**
1427 * Render the dashboard widget content.
1428 *
1429 * @return void
1430 * @since 1.9.1
1431 */
1432 public function render_dashboard_widget() {
1433 // Use the pre-fetched data to avoid duplicate queries.
1434 $entries_data = $this->dashboard_widget_data;
1435
1436 // Display the widget content.
1437 ?>
1438 <div class="srfm-dashboard-widget">
1439 <div class="srfm-widget-header">
1440 <h3 class="srfm-widget-title">
1441 <?php esc_html_e( 'Recent Entries', 'sureforms' ); ?>
1442 <span class="srfm-widget-subtitle"><?php esc_html_e( '( Last 7 days )', 'sureforms' ); ?></span>
1443 </h3>
1444 <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_entries' ) ); ?>" class="srfm-widget-view-link">
1445 <?php esc_html_e( 'View', 'sureforms' ); ?>
1446 </a>
1447 </div>
1448
1449 <div class="srfm-table-wrapper">
1450 <table class="srfm-entries-table">
1451 <thead>
1452 <tr>
1453 <th><?php esc_html_e( 'Form Name', 'sureforms' ); ?></th>
1454 <th><?php esc_html_e( 'Entries', 'sureforms' ); ?></th>
1455 </tr>
1456 </thead>
1457 <tbody>
1458 <?php foreach ( $entries_data as $form_data ) { ?>
1459 <tr>
1460 <td class="form-name"><?php echo esc_html( $form_data['title'] ); ?></td>
1461 <td class="entry-count"><?php echo esc_html( $form_data['count'] ); ?></td>
1462 </tr>
1463 <?php } ?>
1464 </tbody>
1465 </table>
1466 </div>
1467
1468 <?php
1469 // Render footer if applicable.
1470 $this->render_dashboard_widget_footer( $entries_data );
1471 ?>
1472 </div>
1473 <?php
1474 }
1475
1476 /**
1477 * Get random premium feature text.
1478 *
1479 * @return string Random feature text.
1480 * @since 1.9.1
1481 */
1482 private function get_random_premium_feature_text() {
1483 $features = [
1484 __( 'Use Conditional Logic to show only what matters', 'sureforms' ),
1485 __( 'Split your form into steps to keep it easy', 'sureforms' ),
1486 __( 'Let people upload files directly to your form', 'sureforms' ),
1487 __( 'Turn responses into downloadable PDFs automatically', 'sureforms' ),
1488 __( 'Let users sign with a simple signature field', 'sureforms' ),
1489 __( 'Connect your form to other tools using webhooks', 'sureforms' ),
1490 __( 'Use Conversational Forms for a chat-like experience', 'sureforms' ),
1491 __( 'Let users register or log in through your form', 'sureforms' ),
1492 __( 'Build forms that create WordPress user accounts', 'sureforms' ),
1493 __( 'Add calculations to auto-total scores or prices', 'sureforms' ),
1494 ];
1495
1496 // Get a random feature.
1497 $random_key = array_rand( $features );
1498 return $features[ $random_key ];
1499 }
1500
1501 /**
1502 * Render the dashboard widget footer for upsell.
1503 *
1504 * @param array $entries_data The entries data array.
1505 * @return void
1506 * @since 1.9.1
1507 */
1508 private function render_dashboard_widget_footer( $entries_data ) {
1509 // Only show footer if Pro is not active.
1510 if ( Helper::has_pro() ) {
1511 return;
1512 }
1513
1514 // Count total entries in last 7 days.
1515 $total_entries = 0;
1516 foreach ( $entries_data as $form_data ) {
1517 $total_entries += $form_data['count'];
1518 }
1519
1520 // Count total published forms.
1521 $published_forms_count = wp_count_posts( SRFM_FORMS_POST_TYPE )->publish;
1522
1523 // Show footer only if 3+ entries received OR 3+ forms published.
1524 if ( $total_entries >= 3 || $published_forms_count >= 3 ) {
1525 ?>
1526 <div class="srfm-widget-footer">
1527 <div class="srfm-upgrade-content">
1528 <svg class="srfm-logo-icon" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
1529 <rect width="20" height="20" fill="#D54407"/>
1530 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1531 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1532 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1533 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1534 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1535 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1536 </svg>
1537 <span><?php echo esc_html( $this->get_random_premium_feature_text() ); ?></span>
1538 </div>
1539 <?php
1540 $upgrade_url = add_query_arg(
1541 [
1542 'utm_medium' => 'dashboard-widget',
1543 ],
1544 Helper::get_sureforms_website_url( 'pricing' )
1545 );
1546 ?>
1547 <a href="<?php echo esc_url( $upgrade_url ); ?>" class="srfm-upgrade-link" target="_blank">
1548 <?php esc_html_e( 'Upgrade', 'sureforms' ); ?>
1549 </a>
1550 </div>
1551 <?php
1552 }
1553 }
1554
1555 /**
1556 * Determine if the admin pointer should be visible on this page.
1557 *
1558 * @since 1.8.0
1559 * @return bool
1560 */
1561 private function is_admin_pointer_visible() {
1562 global $pagenow;
1563 $allowed_pages = [ 'index.php', 'options-general.php' ];
1564
1565 // Do not show if pointer dismissed, accepted, or more than 1 form exists.
1566 if (
1567 ! empty( Helper::get_srfm_option( 'pointer_popup_dismissed' ) )
1568 || ! empty( Helper::get_srfm_option( 'pointer_popup_accepted' ) )
1569 || (int) ( wp_count_posts( SRFM_FORMS_POST_TYPE )->publish ?? 0 ) > 1
1570 ) {
1571 return false;
1572 }
1573
1574 if ( in_array( $pagenow, $allowed_pages, true ) ) {
1575 return true;
1576 }
1577
1578 return false;
1579 }
1580
1581 }
1582