PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.13.0
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.13.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 / admin / admin.php
admin.php
1,585 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
1045 if ( Helper::is_sureforms_admin_page() ) {
1046 wp_enqueue_script( SRFM_SLUG . '-quick-action-siderbar', SRFM_URL . 'assets/build/quickActionSidebar.js', [], SRFM_VER, true );
1047 wp_localize_script(
1048 SRFM_SLUG . '-quick-action-siderbar',
1049 SRFM_SLUG . '_quick_sidebar_blocks',
1050 [
1051 'allowed_blocks' => $quick_sidebar_allowed_blocks,
1052 'srfm_enable_quick_action_sidebar' => $srfm_enable_quick_action_sidebar,
1053 'srfm_ajax_nonce' => $srfm_ajax_nonce,
1054 'srfm_ajax_url' => admin_url( 'admin-ajax.php' ),
1055 ]
1056 );
1057
1058 $script_translations_handlers[] = SRFM_SLUG . '-quick-action-siderbar';
1059 }
1060
1061 /**
1062 * Enqueuing SureTriggers Integration script.
1063 * This script loads suretriggers iframe in Intergations tab.
1064 */
1065 if ( $is_post_type_sureforms_form ) {
1066 wp_enqueue_script( SRFM_SLUG . '-suretriggers-integration', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL . 'js/v2/embed.js', [], SRFM_VER, true );
1067 }
1068
1069 // Check $script_translations_handlers is not empty before calling the function.
1070 if ( ! empty( $script_translations_handlers ) ) {
1071 // Remove duplicates values from the array.
1072 $script_translations_handlers = array_unique( $script_translations_handlers );
1073
1074 foreach ( $script_translations_handlers as $script_handle ) {
1075 Helper::register_script_translations( $script_handle );
1076 }
1077 }
1078 }
1079
1080 /**
1081 * Form Template Picker Admin Body Classes
1082 * WordPress sometimes translates class names in the admin body tag, which can result in
1083 * incorrect or missing class names when rendering the admin pages. This function ensures
1084 * that essential class names are manually added to the body tag to maintain proper functionality.
1085 *
1086 * @since 0.0.1
1087 * @param string $classes Space separated class string.
1088 */
1089 public function admin_template_picker_body_class( $classes = '' ) {
1090 // Define an associative array of class names and their corresponding conditions.
1091 // Each condition checks whether a specific request context matches.
1092 $srfm_classes = [
1093 'sureforms_page_sureforms_entries' => Helper::validate_request_context( SRFM_ENTRIES, 'page' ),
1094 'sureforms_page_sureforms_form_settings' => Helper::validate_request_context( 'sureforms_form_settings', 'page' ),
1095 'srfm-template-picker' => Helper::validate_request_context( 'add-new-form', 'page' ),
1096 ];
1097
1098 $add_srfm_classes = '';
1099
1100 // Loop through the defined classes and conditions.
1101 foreach ( $srfm_classes as $class => $condition ) {
1102 // Check if the condition evaluates to true.
1103 if ( $condition ) {
1104 // Append the class to the existing classes string, followed by a space.
1105 $add_srfm_classes .= empty( $add_srfm_classes ) ? $class : ' ' . $class;
1106 }
1107 }
1108
1109 // Append the new classes to the existing classes string.
1110 if ( ! empty( $add_srfm_classes ) ) {
1111 $classes .= ' ' . $add_srfm_classes;
1112 }
1113
1114 // Return the updated list of classes.
1115 return $classes;
1116 }
1117
1118 /**
1119 * Disable spectra's quick action bar in sureforms CPT.
1120 *
1121 * @param string $status current status of the quick action bar.
1122 * @since 0.0.2
1123 * @return string
1124 */
1125 public function restrict_spectra_quick_action_bar( $status ) {
1126 $screen = get_current_screen();
1127 if ( 'disabled' !== $status && isset( $screen->id ) && 'sureforms_form' === $screen->id ) {
1128 $status = 'disabled';
1129 }
1130
1131 return $status;
1132 }
1133
1134 // Entries methods.
1135
1136 /**
1137 * Handle entry actions.
1138 *
1139 * @since 0.0.13
1140 * @return void
1141 */
1142 public function handle_entry_actions() {
1143 Entries_List_Table::process_bulk_actions();
1144
1145 if ( ! isset( $_GET['page'] ) || SRFM_ENTRIES !== $_GET['page'] ) {
1146 return;
1147 }
1148 if ( ! isset( $_GET['entry_id'] ) || ! isset( $_GET['action'] ) ) {
1149 return;
1150 }
1151 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'srfm_entries_action' ) ) {
1152 wp_die( esc_html__( 'Nonce verification failed.', 'sureforms' ) );
1153 }
1154 $action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : '';
1155 $entry_id = Helper::get_integer_value( sanitize_text_field( wp_unslash( $_GET['entry_id'] ) ) );
1156 $view = isset( $_GET['view'] ) ? sanitize_text_field( wp_unslash( $_GET['view'] ) ) : '';
1157 if ( $entry_id > 0 ) {
1158 if ( 'read' === $action && 'details' === $view ) {
1159 $entry_status = Entries::get( $entry_id )['status'];
1160 if ( 'trash' === $entry_status ) {
1161 wp_die( esc_html__( 'You cannot view this entry because it is in trash.', 'sureforms' ) );
1162 }
1163 }
1164 Entries_List_Table::handle_entry_status( $entry_id, $action, $view );
1165 }
1166 }
1167
1168 /**
1169 * Admin Notice Callback if sureforms pro is out of date.
1170 *
1171 * Hooked - admin_notices
1172 *
1173 * @return void
1174 * @since 1.0.4
1175 */
1176 public function srfm_pro_version_compatibility() {
1177 if ( ! Helper::has_pro() ) {
1178 return;
1179 }
1180
1181 if ( empty( get_current_screen() ) ) {
1182 return;
1183 }
1184
1185 if ( ! Helper::current_user_can() ) {
1186 return;
1187 }
1188
1189 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
1190 /**
1191 * If the license status is not set then get the license status and update the option accordingly.
1192 * This will be executed only once. Subsequently, the option status is updated by the licensing class on license activation or deactivation.
1193 */
1194 if ( empty( $srfm_pro_license_status ) && class_exists( 'SRFM_PRO\Admin\Licensing' ) ) {
1195 $srfm_pro_license_status = \SRFM_PRO\Admin\Licensing::is_license_active() ? 'licensed' : 'unlicensed';
1196 update_option( 'srfm_pro_license_status', $srfm_pro_license_status );
1197 }
1198
1199 $pro_plugin_name = defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro';
1200 $message = '';
1201 $url = admin_url( 'admin.php?page=sureforms_form_settings&tab=account-settings' );
1202 if ( 'unlicensed' === $srfm_pro_license_status ) {
1203 ob_start();
1204 ?>
1205 <p>
1206 <?php
1207 printf(
1208 // translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name.
1209 esc_html__( 'Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more.', 'sureforms' ),
1210 '<a href="' . esc_url( $url ) . '">',
1211 '</a>',
1212 '<i>' . esc_html( $pro_plugin_name ) . '</i>'
1213 );
1214 ?>
1215 </p>
1216 <?php
1217 $message = ob_get_clean();
1218 }
1219
1220 if ( ! version_compare( SRFM_PRO_VER, SRFM_PRO_RECOMMENDED_VER, '>=' ) ) {
1221 ob_start();
1222 ?>
1223 <p>
1224 <?php
1225 printf(
1226 // 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.
1227 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' ),
1228 esc_html( SRFM_VER ),
1229 esc_html( $pro_plugin_name ),
1230 esc_html( SRFM_PRO_RECOMMENDED_VER ),
1231 '<a href="' . esc_url( admin_url( 'update-core.php' ) ) . '">',
1232 '</a>'
1233 );
1234 ?>
1235 </p>
1236 <?php
1237 $message .= ob_get_clean();
1238 }
1239
1240 if ( ! empty( $message ) ) {
1241 // Phpcs ignore comment is required as $message variable is already escaped.
1242 ?>
1243 <div class="notice notice-warning"><?php echo wp_kses_post( $message ); ?></div>
1244 <?php
1245 }
1246 }
1247
1248 /**
1249 * Disables the capabilities for WPForms to avoid conflicts when enqueueing
1250 * scripts and styles for WPForms.
1251 *
1252 * This function is intended to prevent any potential conflicts that may arise
1253 * when WPForms scripts and styles are enqueued. By disabling certain capabilities,
1254 * it ensures that WPForms does not interfere with other functionalities.
1255 *
1256 * @param bool $user_can A boolean indicating whether the user has the capability.
1257 * @return bool Returns true if the capabilities are successfully disabled, false otherwise.
1258 * @since 1.4.2
1259 */
1260 public function disable_wpforms_capabilities( $user_can ) {
1261 // Note: Nonce verification is intentionally omitted here as no database operations are performed.
1262 // The values of the $_REQUEST variables are strictly validated, ensuring security without the need for nonce verification.
1263
1264 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1265 $post_id = ! empty( $_REQUEST['post'] ) && ! empty( $_REQUEST['action'] ) ? absint( $_REQUEST['post'] ) : 0;
1266
1267 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1268 $post_type = $post_id ? get_post_type( $post_id ) : sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ?? '' ) );
1269 return SRFM_FORMS_POST_TYPE === $post_type ? false : $user_can;
1270 }
1271
1272 /**
1273 * Enqueueus the admin pointer script and styles.
1274 *
1275 * @return void
1276 * @since 1.8.0
1277 */
1278 public function enqueue_admin_pointer() {
1279 if ( ! $this->is_admin_pointer_visible() ) {
1280 return;
1281 }
1282 wp_enqueue_style( 'wp-pointer' );
1283 wp_enqueue_script( 'wp-pointer' );
1284 wp_enqueue_script(
1285 'sureforms-admin-pointer',
1286 plugins_url( 'admin/assets/js/sureforms-pointer.js', SRFM_FILE ),
1287 [ 'wp-pointer', 'jquery' ],
1288 SRFM_VER,
1289 true
1290 );
1291 wp_localize_script(
1292 'sureforms-admin-pointer',
1293 'sureformsPointerData',
1294 [
1295 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1296 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
1297 ]
1298 );
1299 }
1300
1301 /**
1302 * Ajax handler for pointer popup visibility.
1303 *
1304 * @return void
1305 * @since 1.8.0
1306 */
1307 public function pointer_should_show() {
1308 // Security: Check user capability.
1309 if ( ! Helper::current_user_can() ) {
1310 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1311 }
1312 // Security: Nonce check.
1313 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1314 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1315 }
1316
1317 $content_markup = sprintf(
1318 /* translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong */
1319 __( '%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' ),
1320 '<span>',
1321 '<strong>',
1322 '</strong>',
1323 '</span><br/>',
1324 '<strong style="font-size:1.1em;">',
1325 '</strong>'
1326 );
1327 wp_send_json(
1328 [
1329 'show' => true,
1330 'title' => esc_html( __( 'SureForms is waiting for you!', 'sureforms' ) ),
1331 'content' => wp_kses_post( $content_markup ),
1332 'button_text' => esc_html( __( 'Build My First Form', 'sureforms' ) ),
1333 'dismiss' => esc_html( __( 'Dismiss', 'sureforms' ) ),
1334 'button_url' => admin_url( 'admin.php?page=add-new-form' ),
1335 ]
1336 );
1337 }
1338
1339 /**
1340 * Ajax callback for pointer popup dismissed action.
1341 *
1342 * @return void
1343 * @since 1.8.0
1344 */
1345 public function pointer_dismissed() {
1346 // Security: Check user capability.
1347 if ( ! Helper::current_user_can() ) {
1348 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1349 }
1350 // Security: Nonce check.
1351 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1352 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1353 }
1354 // Use Helper to update srfm_options key.
1355 Helper::update_srfm_option( 'pointer_popup_dismissed', time() );
1356
1357 wp_send_json_success();
1358 }
1359
1360 /**
1361 * Ajax pointer accepted CTA callback.
1362 *
1363 * @return void
1364 * @since 1.8.0
1365 */
1366 public function pointer_accepted_cta() {
1367 // Security: Check user capability.
1368 if ( ! Helper::current_user_can() ) {
1369 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1370 }
1371 // Security: Nonce check.
1372 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1373 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1374 }
1375 // Use Helper to update srfm_options key.
1376 Helper::update_srfm_option( 'pointer_popup_accepted', time() );
1377
1378 wp_send_json_success();
1379 }
1380
1381 /**
1382 * Maybe register the dashboard widget based on entries.
1383 *
1384 * @return void
1385 * @since 1.9.1
1386 */
1387 public function maybe_register_dashboard_widget() {
1388
1389 // Only for users with manage_options capability.
1390 if ( ! Helper::current_user_can() ) {
1391 return;
1392 }
1393
1394 // Quick check if there are any entries in the last 7 days.
1395 $seven_days_ago = strtotime( '-7 days' );
1396 $total_entries = Entries::get_entries_count_after( $seven_days_ago );
1397
1398 // Only add the dashboard setup hook if there are entries.
1399 if ( $total_entries > 0 ) {
1400 // Get forms with entries (limit 4 for dashboard widget).
1401 $this->dashboard_widget_data = Helper::get_forms_with_entry_counts( $seven_days_ago, 4 );
1402
1403 // Only show dashboard widget if there are forms with entries.
1404 if ( ! empty( $this->dashboard_widget_data ) ) {
1405 add_action( 'wp_dashboard_setup', [ $this, 'register_dashboard_widget' ] );
1406 }
1407 }
1408 }
1409
1410 /**
1411 * Register the dashboard widget.
1412 *
1413 * @return void
1414 * @since 1.9.1
1415 */
1416 public function register_dashboard_widget() {
1417 // Add the widget with high priority to position it at the top.
1418 wp_add_dashboard_widget(
1419 'sureforms_recent_entries',
1420 __( 'SureForms', 'sureforms' ),
1421 [ $this, 'render_dashboard_widget' ],
1422 null,
1423 null,
1424 'normal',
1425 'high'
1426 );
1427 }
1428
1429 /**
1430 * Render the dashboard widget content.
1431 *
1432 * @return void
1433 * @since 1.9.1
1434 */
1435 public function render_dashboard_widget() {
1436 // Use the pre-fetched data to avoid duplicate queries.
1437 $entries_data = $this->dashboard_widget_data;
1438
1439 // Display the widget content.
1440 ?>
1441 <div class="srfm-dashboard-widget">
1442 <div class="srfm-widget-header">
1443 <h3 class="srfm-widget-title">
1444 <?php esc_html_e( 'Recent Entries', 'sureforms' ); ?>
1445 <span class="srfm-widget-subtitle"><?php esc_html_e( '( Last 7 days )', 'sureforms' ); ?></span>
1446 </h3>
1447 <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_entries' ) ); ?>" class="srfm-widget-view-link">
1448 <?php esc_html_e( 'View', 'sureforms' ); ?>
1449 </a>
1450 </div>
1451
1452 <div class="srfm-table-wrapper">
1453 <table class="srfm-entries-table">
1454 <thead>
1455 <tr>
1456 <th><?php esc_html_e( 'Form Name', 'sureforms' ); ?></th>
1457 <th><?php esc_html_e( 'Entries', 'sureforms' ); ?></th>
1458 </tr>
1459 </thead>
1460 <tbody>
1461 <?php foreach ( $entries_data as $form_data ) { ?>
1462 <tr>
1463 <td class="form-name"><?php echo esc_html( $form_data['title'] ); ?></td>
1464 <td class="entry-count"><?php echo esc_html( $form_data['count'] ); ?></td>
1465 </tr>
1466 <?php } ?>
1467 </tbody>
1468 </table>
1469 </div>
1470
1471 <?php
1472 // Render footer if applicable.
1473 $this->render_dashboard_widget_footer( $entries_data );
1474 ?>
1475 </div>
1476 <?php
1477 }
1478
1479 /**
1480 * Get random premium feature text.
1481 *
1482 * @return string Random feature text.
1483 * @since 1.9.1
1484 */
1485 private function get_random_premium_feature_text() {
1486 $features = [
1487 __( 'Use Conditional Logic to show only what matters', 'sureforms' ),
1488 __( 'Split your form into steps to keep it easy', 'sureforms' ),
1489 __( 'Let people upload files directly to your form', 'sureforms' ),
1490 __( 'Turn responses into downloadable PDFs automatically', 'sureforms' ),
1491 __( 'Let users sign with a simple signature field', 'sureforms' ),
1492 __( 'Connect your form to other tools using webhooks', 'sureforms' ),
1493 __( 'Use Conversational Forms for a chat-like experience', 'sureforms' ),
1494 __( 'Let users register or log in through your form', 'sureforms' ),
1495 __( 'Build forms that create WordPress user accounts', 'sureforms' ),
1496 __( 'Add calculations to auto-total scores or prices', 'sureforms' ),
1497 ];
1498
1499 // Get a random feature.
1500 $random_key = array_rand( $features );
1501 return $features[ $random_key ];
1502 }
1503
1504 /**
1505 * Render the dashboard widget footer for upsell.
1506 *
1507 * @param array $entries_data The entries data array.
1508 * @return void
1509 * @since 1.9.1
1510 */
1511 private function render_dashboard_widget_footer( $entries_data ) {
1512 // Only show footer if Pro is not active.
1513 if ( Helper::has_pro() ) {
1514 return;
1515 }
1516
1517 // Count total entries in last 7 days.
1518 $total_entries = 0;
1519 foreach ( $entries_data as $form_data ) {
1520 $total_entries += $form_data['count'];
1521 }
1522
1523 // Count total published forms.
1524 $published_forms_count = wp_count_posts( SRFM_FORMS_POST_TYPE )->publish;
1525
1526 // Show footer only if 3+ entries received OR 3+ forms published.
1527 if ( $total_entries >= 3 || $published_forms_count >= 3 ) {
1528 ?>
1529 <div class="srfm-widget-footer">
1530 <div class="srfm-upgrade-content">
1531 <svg class="srfm-logo-icon" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
1532 <rect width="20" height="20" fill="#D54407"/>
1533 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1534 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1535 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1536 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1537 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1538 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1539 </svg>
1540 <span><?php echo esc_html( $this->get_random_premium_feature_text() ); ?></span>
1541 </div>
1542 <?php
1543 $upgrade_url = add_query_arg(
1544 [
1545 'utm_medium' => 'dashboard-widget',
1546 ],
1547 Helper::get_sureforms_website_url( 'pricing' )
1548 );
1549 ?>
1550 <a href="<?php echo esc_url( $upgrade_url ); ?>" class="srfm-upgrade-link" target="_blank">
1551 <?php esc_html_e( 'Upgrade', 'sureforms' ); ?>
1552 </a>
1553 </div>
1554 <?php
1555 }
1556 }
1557
1558 /**
1559 * Determine if the admin pointer should be visible on this page.
1560 *
1561 * @since 1.8.0
1562 * @return bool
1563 */
1564 private function is_admin_pointer_visible() {
1565 global $pagenow;
1566 $allowed_pages = [ 'index.php', 'options-general.php' ];
1567
1568 // Do not show if pointer dismissed, accepted, or more than 1 form exists.
1569 if (
1570 ! empty( Helper::get_srfm_option( 'pointer_popup_dismissed' ) )
1571 || ! empty( Helper::get_srfm_option( 'pointer_popup_accepted' ) )
1572 || (int) ( wp_count_posts( SRFM_FORMS_POST_TYPE )->publish ?? 0 ) > 1
1573 ) {
1574 return false;
1575 }
1576
1577 if ( in_array( $pagenow, $allowed_pages, true ) ) {
1578 return true;
1579 }
1580
1581 return false;
1582 }
1583
1584 }
1585