PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.13.2
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.13.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
1,573 lines 53.2 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() ) {
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 <script type="text/javascript">
360 document.addEventListener('DOMContentLoaded', function () {
361 // Upgrade link handler.
362 // IMPORTANT: If this URL changes, also update it in the `add_upgrade_to_pro` function.
363 const upgradeLink = document.querySelector('a[href*="https://sureforms.com/upgrade"]');
364 if (upgradeLink) {
365 upgradeLink.addEventListener('click', e => {
366 e.preventDefault();
367 window.open(upgradeLink.href, '_blank');
368 });
369 }
370 });
371 </script>
372 <?php
373 }
374
375 /**
376 * Add Upgrade to pro menu item.
377 *
378 * @return void
379 * @since 1.6.1
380 */
381 public function add_upgrade_to_pro() {
382 // The url used here is used as a selector for css to style the upgrade to pro submenu.
383 // If you are changing this url, please make sure to update the css as well.
384 $upgrade_url = add_query_arg(
385 [
386 'utm_medium' => 'submenu_link_upgrade',
387 ],
388 Helper::get_sureforms_website_url( 'upgrade' )
389 );
390
391 add_submenu_page(
392 'sureforms_menu',
393 __( 'Upgrade', 'sureforms' ),
394 __( 'Upgrade', 'sureforms' ),
395 self::$sureforms_page_default_capability,
396 $upgrade_url
397 );
398 }
399
400 /**
401 * Add SMTP promotional submenu page.
402 *
403 * @return void
404 * @since 1.7.1
405 */
406 public function add_suremail_page() {
407 add_submenu_page(
408 'sureforms_menu',
409 __( 'SMTP', 'sureforms' ),
410 __( 'SMTP', 'sureforms' ),
411 self::$sureforms_page_default_capability,
412 'sureforms_smtp',
413 [ $this, 'suremail_page_callback' ]
414 );
415
416 // Get the current submenu page.
417 $submenu_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
418
419 // Check if SureMail is installed and active.
420 if ( 'sureforms_smtp' === $submenu_page && file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' ) && is_plugin_active( 'suremails/suremails.php' ) ) {
421 // Plugin is installed and active - redirect to SureMail dashboard.
422 wp_safe_redirect( admin_url( 'options-general.php?page=suremail#/dashboard' ) );
423 exit;
424 }
425 }
426
427 /**
428 * SMTP promotional page callback.
429 *
430 * @return void
431 * @since 1.7.1
432 */
433 public function suremail_page_callback() {
434 ?>
435 <div id="srfm-suremail-container" class="srfm-admin-wrapper"></div>
436 <?php
437 }
438
439 /**
440 * Render Admin Dashboard.
441 *
442 * @return void
443 * @since 0.0.1
444 */
445 public function render_dashboard() {
446 ?>
447 <div id="srfm-dashboard-container" class="srfm-admin-wrapper"></div>
448 <?php
449 }
450
451 /**
452 * Settings page callback.
453 *
454 * @return void
455 * @since 0.0.1
456 */
457 public function settings_page_callback() {
458 ?>
459 <div id="srfm-settings-container" class="srfm-admin-wrapper"></div>
460 <?php
461 }
462
463 /**
464 * Add new form menu item.
465 *
466 * @return void
467 * @since 0.0.1
468 */
469 public function add_new_form() {
470 add_submenu_page(
471 'sureforms_menu',
472 __( 'New Form', 'sureforms' ),
473 __( 'New Form', 'sureforms' ),
474 self::$sureforms_page_default_capability,
475 'add-new-form',
476 [ $this, 'add_new_form_callback' ],
477 2
478 );
479 $entries_hook = add_submenu_page(
480 'sureforms_menu',
481 __( 'Entries', 'sureforms' ),
482 __( 'Entries', 'sureforms' ),
483 self::$sureforms_page_default_capability,
484 SRFM_ENTRIES,
485 [ $this, 'render_entries' ],
486 3
487 );
488
489 if ( $entries_hook ) {
490 add_action( 'load-' . $entries_hook, [ $this, 'mark_entries_page_visit' ] );
491 }
492 }
493
494 /**
495 * Add new form mentu item callback.
496 *
497 * @return void
498 * @since 0.0.1
499 */
500 public function add_new_form_callback() {
501 ?>
502 <div id="srfm-add-new-form-container" class="srfm-admin-wrapper"></div>
503 <?php
504 }
505
506 /**
507 * Entries page callback.
508 *
509 * @since 0.0.13
510 * @return void
511 */
512 public function render_entries() {
513 // Render single entry view.
514 // Adding the phpcs ignore nonce verification as no database operations are performed in this function, it is used to display the single entry view.
515 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.
516 $single_entry_view = new Single_Entry();
517 $single_entry_view->render();
518 return;
519 }
520
521 // Render all entries view.
522 $entries_table = new Entries_List_Table();
523 $entries_table->prepare_items();
524 ?>
525 <div class="wrap">
526 <h1 class="wp-heading-inline"><?php echo esc_html__( 'Entries', 'sureforms' ); ?></h1>
527 <?php
528 if ( empty( $entries_table->all_entries_count ) && empty( $entries_table->trash_entries_count ) ) {
529 $instance = Post_Types::get_instance();
530 $instance->sureforms_render_blank_state( SRFM_ENTRIES );
531 $instance->get_blank_state_styles();
532 return;
533 }
534 ?>
535 <form method="get">
536 <input type="hidden" name="page" value="sureforms_entries">
537 <?php $entries_table->display(); ?>
538 </form>
539 </div>
540 <?php
541 }
542
543 /**
544 * Add notification badge to SureForms menu when there are new entries.
545 *
546 * @since 1.7.3
547 * @return void
548 */
549 public function maybe_add_entries_badge() {
550 if ( ! Helper::current_user_can() ) {
551 return;
552 }
553
554 // If currently viewing the entries listing page, mark it as visited and skip the badge.
555 if ( isset( $_GET['page'] ) && SRFM_ENTRIES === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only checking the page slug.
556 $this->mark_entries_page_visit();
557 return;
558 }
559
560 $srfm_options = get_option( 'srfm_options', [] );
561 $last_visit = isset( $srfm_options['entries_last_visited'] ) ? absint( $srfm_options['entries_last_visited'] ) : 0;
562 $new_entries = Entries::get_entries_count_after( $last_visit );
563
564 if ( $new_entries <= 0 ) {
565 return;
566 }
567
568 global $menu;
569 foreach ( $menu as $index => $item ) {
570 if ( isset( $item[2] ) && 'sureforms_menu' === $item[2] ) {
571 ob_start();
572 ?>
573 <span class="srfm-update-dot"></span>
574 <?php
575 $dot_html = ob_get_clean();
576 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for menu item.
577 $menu[ $index ][0] .= $dot_html;
578 break;
579 }
580 }
581
582 global $submenu;
583 if ( isset( $submenu['sureforms_menu'] ) ) {
584 foreach ( $submenu['sureforms_menu'] as $index => $sub_item ) {
585 if ( isset( $sub_item[2] ) && SRFM_ENTRIES === $sub_item[2] ) {
586 ob_start();
587 ?>
588 <span class="update-plugins count-<?php echo absint( $new_entries ); ?>">
589 <span class="plugin-count"><?php echo absint( $new_entries ); ?></span>
590 </span>
591 <?php
592 $badge_html = ob_get_clean();
593 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for submenu item.
594 $submenu['sureforms_menu'][ $index ][0] .= $badge_html;
595 break;
596 }
597 }
598 }
599 }
600
601 /**
602 * Mark the user's visit to the entries page.
603 *
604 * @since 1.7.3
605 * @return void
606 */
607 public function mark_entries_page_visit() {
608 if ( Helper::current_user_can() ) {
609 $srfm_options = get_option( 'srfm_options', [] );
610 $srfm_options['entries_last_visited'] = time();
611 \SRFM\Inc\Helper::update_admin_settings_option( 'srfm_options', $srfm_options );
612 }
613 }
614
615 /**
616 * Adds a settings link to the plugin action links on the plugins page.
617 *
618 * @param array $links An array of plugin action links.
619 * @param string $file The plugin file path.
620 * @return array The updated array of plugin action links.
621 * @since 0.0.1
622 */
623 public function add_settings_link( $links, $file ) {
624 if ( 'sureforms/sureforms.php' === $file ) {
625 ob_start();
626 ?>
627 <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_form_settings&tab=general-settings' ) ); ?>">
628 <?php echo esc_html__( 'Settings', 'sureforms' ); ?>
629 </a>
630 <?php
631 $settings_link_html = ob_get_clean();
632 $plugin_links = apply_filters(
633 'sureforms_plugin_action_links',
634 [
635 'sureforms_settings' => $settings_link_html,
636 ]
637 );
638 $links = array_merge( $plugin_links, $links );
639 }
640 return $links;
641 }
642
643 /**
644 * Sureforms block editor styles.
645 *
646 * @since 0.0.1
647 */
648 public function enqueue_styles() {
649 $current_screen = get_current_screen();
650 global $wp_version;
651
652 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
653 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
654
655 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
656 $vendor_css_uri = SRFM_URL . 'assets/css/minified/deps/';
657
658 /* RTL */
659 if ( is_rtl() ) {
660 $file_prefix .= '-rtl';
661 }
662
663 // Enqueue editor styles for post and page.
664 if ( SRFM_FORMS_POST_TYPE === $current_screen->post_type ) {
665 wp_enqueue_style( SRFM_SLUG . '-editor', $css_uri . 'backend/editor' . $file_prefix . '.css', [], SRFM_VER );
666 wp_enqueue_style( SRFM_SLUG . '-backend-blocks', $css_uri . 'blocks/default/backend' . $file_prefix . '.css', [], SRFM_VER );
667 wp_enqueue_style( SRFM_SLUG . '-intl', $vendor_css_uri . 'intl/intlTelInput-backend.min.css', [], SRFM_VER );
668 wp_enqueue_style( SRFM_SLUG . '-common', $css_uri . 'common' . $file_prefix . '.css', [], SRFM_VER );
669 wp_enqueue_style( SRFM_SLUG . '-reactQuill', $vendor_css_uri . 'quill/quill.snow.css', [], SRFM_VER );
670 wp_enqueue_style( SRFM_SLUG . '-single-form-modal', $css_uri . 'single-form-setting' . $file_prefix . '.css', [], SRFM_VER );
671
672 // if version is equal to or lower than 6.6.2 then add compatibility css.
673 if ( version_compare( $wp_version, '6.6.2', '<=' ) ) {
674 $srfm_inline_css = '.srfm-settings-modal .srfm-setting-modal-container .components-toggle-control .components-base-control__help{
675 margin-left: 4em;
676 }';
677 wp_add_inline_style( SRFM_SLUG . '-single-form-modal', $srfm_inline_css );
678 }
679 }
680
681 wp_enqueue_style( SRFM_SLUG . '-form-selector', $css_uri . 'srfm-form-selector' . $file_prefix . '.css', [], SRFM_VER );
682 wp_enqueue_style( SRFM_SLUG . '-common-editor', SRFM_URL . 'assets/build/common-editor.css', [], SRFM_VER, 'all' );
683 }
684
685 /**
686 * Get Breadcrumbs for current page.
687 *
688 * @since 0.0.1
689 * @return array Breadcrumbs Array.
690 */
691 public function get_breadcrumbs_for_current_page() {
692 global $post, $pagenow;
693 $breadcrumbs = [];
694
695 if ( 'admin.php' === $pagenow && isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
696 $page_title = get_admin_page_title();
697 $breadcrumbs[] = [
698 'title' => $page_title,
699 'link' => '',
700 ];
701 } elseif ( $post && in_array( $pagenow, [ 'post.php', 'post-new.php', 'edit.php' ], true ) ) {
702 $post_type_obj = get_post_type_object( get_post_type() );
703 if ( $post_type_obj ) {
704 $post_type_plural = $post_type_obj->labels->name;
705 $breadcrumbs[] = [
706 'title' => $post_type_plural,
707 'link' => admin_url( 'edit.php?post_type=' . $post_type_obj->name ),
708 ];
709
710 if ( 'edit.php' === $pagenow && ! isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
711 $breadcrumbs[ count( $breadcrumbs ) - 1 ]['link'] = '';
712 } else {
713 $breadcrumbs[] = [
714 /* Translators: Post Title. */
715 'title' => sprintf( __( 'Edit %1$s', 'sureforms' ), get_the_title() ),
716 'link' => get_edit_post_link( $post->ID ),
717 ];
718 }
719 }
720 } else {
721 $current_screen = get_current_screen();
722 if ( $current_screen && 'sureforms_form' === $current_screen->post_type ) {
723 $breadcrumbs[] = [
724 'title' => 'Forms',
725 'link' => '',
726 ];
727 } else {
728 $breadcrumbs[] = [
729 'title' => '',
730 'link' => '',
731 ];
732 }
733 }
734
735 return $breadcrumbs;
736 }
737
738 /**
739 * Enqueue Admin Scripts.
740 *
741 * @return void
742 * @since 0.0.1
743 */
744 public function enqueue_scripts() {
745 $current_screen = get_current_screen();
746 global $wp_version;
747
748 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
749 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
750 $js_uri = SRFM_URL . 'assets/js/' . $dir_name . '/';
751 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
752 $is_rtl = is_rtl();
753 $rtl = $is_rtl ? '-rtl' : '';
754
755 /**
756 * List of the handles in which we need to add translation compatibility.
757 */
758 $script_translations_handlers = [];
759 $onboarding_instance = Onboarding::get_instance();
760
761 $localization_data = [
762 'site_url' => get_site_url(),
763 'breadcrumbs' => $this->get_breadcrumbs_for_current_page(),
764 'sureforms_dashboard_url' => admin_url( '/admin.php?page=sureforms_menu' ),
765 'plugin_version' => SRFM_VER,
766 'global_settings_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
767 'is_pro_active' => Helper::has_pro(),
768 'is_first_form_created' => self::is_first_form_created(),
769 'check_three_days_threshold' => self::check_first_form_creation_threshold(),
770 'check_eight_days_threshold' => self::check_first_form_creation_threshold( 8 ),
771 'pro_plugin_version' => Helper::has_pro() ? SRFM_PRO_VER : '',
772 'pro_plugin_name' => Helper::has_pro() && defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro',
773 'sureforms_pricing_page' => Helper::get_sureforms_website_url( 'pricing' ),
774 'field_spacing_vars' => Helper::get_css_vars(),
775 'is_ver_lower_than_6_7' => version_compare( $wp_version, '6.6.2', '<=' ),
776 'integrations' => Helper::sureforms_get_integration(),
777 'ajax_url' => admin_url( 'admin-ajax.php' ),
778 'sf_plugin_manager_nonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
779 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
780 'plugin_activating_text' => __( 'Activating...', 'sureforms' ),
781 'plugin_activated_text' => __( 'Activated', 'sureforms' ),
782 'plugin_activate_text' => __( 'Activate', 'sureforms' ),
783 'plugin_installing_text' => __( 'Installing...', 'sureforms' ),
784 'plugin_installed_text' => __( 'Installed', 'sureforms' ),
785 'is_rtl' => $is_rtl,
786 'onboarding_completed' => method_exists( $onboarding_instance, 'get_onboarding_status' ) ? $onboarding_instance->get_onboarding_status() : false,
787 'onboarding_redirect' => isset( $_GET['srfm-activation-redirect'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce is not required for the activation redirection.
788 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
789 'general_settings_url' => admin_url( '/options-general.php' ),
790 ];
791
792 $is_screen_sureforms_menu = Helper::validate_request_context( 'sureforms_menu', 'page' );
793 $is_screen_add_new_form = Helper::validate_request_context( 'add-new-form', 'page' );
794 $is_screen_sureforms_form_settings = Helper::validate_request_context( 'sureforms_form_settings', 'page' );
795 $is_screen_sureforms_entries = Helper::validate_request_context( SRFM_ENTRIES, 'page' );
796 $is_post_type_sureforms_form = SRFM_FORMS_POST_TYPE === $current_screen->post_type;
797
798 /**
799 * Check if the current screen is the SureForms Menu and AI Auth Email is present then we will add user type as registered.
800 * Compatibility with existing UI code that checks for this condition.
801 */
802 if ( $is_screen_sureforms_menu ) {
803 // If email is stored send the user type as registered else non-registered.
804 $localization_data['srfm_ai_details'] = [
805 'type' => ! empty( get_option( 'srfm_ai_auth_user_email' ) ) ? 'registered' : 'non-registered',
806 ];
807 }
808
809 if ( $is_screen_sureforms_menu || $is_post_type_sureforms_form || $is_screen_add_new_form || $is_screen_sureforms_form_settings || $is_screen_sureforms_entries ) {
810 $asset_handle = '-dashboard';
811
812 wp_enqueue_style( SRFM_SLUG . $asset_handle . '-font', 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap', [], SRFM_VER );
813
814 $script_asset_path = SRFM_DIR . 'assets/build/dashboard.asset.php';
815 $script_info = file_exists( $script_asset_path )
816 ? include $script_asset_path
817 : [
818 'dependencies' => [],
819 'version' => SRFM_VER,
820 ];
821 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/dashboard.js', $script_info['dependencies'], SRFM_VER, true );
822
823 wp_localize_script( SRFM_SLUG . $asset_handle, 'scIcons', [ 'path' => SRFM_URL . 'assets/build/icon-assets' ] );
824
825 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
826
827 if ( class_exists( 'SRFM_PRO\Admin\Licensing' ) ) {
828 $license_active = \SRFM_PRO\Admin\Licensing::is_license_active();
829 $localization_data['is_license_active'] = $license_active;
830
831 // Updating current licensing status.
832 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
833 $current_license_status = $license_active ? 'licensed' : 'unlicensed';
834 if ( $current_license_status !== $srfm_pro_license_status ) {
835 update_option( 'srfm_pro_license_status', $current_license_status );
836 }
837 }
838
839 $localization_data['security_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=security-settings' );
840 $localization_data['integration_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=integration-settings' );
841 wp_localize_script(
842 SRFM_SLUG . $asset_handle,
843 SRFM_SLUG . '_admin',
844 apply_filters(
845 SRFM_SLUG . '_admin_filter',
846 $localization_data
847 )
848 );
849 wp_enqueue_style( SRFM_SLUG . '-dashboard', SRFM_URL . 'assets/build/dashboard.css', [], SRFM_VER, 'all' );
850
851 }
852
853 if ( $is_screen_sureforms_form_settings ) {
854 wp_enqueue_style( SRFM_SLUG . '-settings', $css_uri . 'backend/settings' . $file_prefix . $rtl . '.css', [], SRFM_VER );
855 }
856
857 // Enqueue styles for the entries page.
858 if ( $is_screen_sureforms_entries ) {
859 $asset_handle = '-entries';
860 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/entries.js', $script_info['dependencies'], SRFM_VER, true );
861
862 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
863 }
864
865 // Enqueue scripts for the SureMail promotional page.
866 $is_screen_sureforms_smtp = Helper::validate_request_context( 'sureforms_smtp', 'page' );
867 if ( $is_screen_sureforms_smtp ) {
868 $asset_handle = 'suremail';
869
870 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
871 $script_info = file_exists( $script_asset_path )
872 ? include $script_asset_path
873 : [
874 'dependencies' => [],
875 'version' => SRFM_VER,
876 ];
877
878 wp_enqueue_script( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
879 wp_enqueue_style( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/suremail.css', [], SRFM_VER, 'all' );
880
881 // Localize script for SureMail page.
882 $suremail_localization_data = [
883 'ajax_url' => admin_url( 'admin-ajax.php' ),
884 'admin_url' => admin_url(),
885 'suremail_url' => 'https://sureforms.com/suremail/',
886 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
887 'sfPluginManagerNonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
888 'suremail_status' => file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' )
889 ? ( is_plugin_active( 'suremails/suremails.php' ) ? 'active' : 'installed' )
890 : 'not_installed',
891 ];
892
893 wp_localize_script(
894 SRFM_SLUG . '-suremail',
895 SRFM_SLUG . '_admin',
896 apply_filters(
897 SRFM_SLUG . '_suremail_admin_filter',
898 $suremail_localization_data
899 )
900 );
901
902 $script_translations_handlers[] = SRFM_SLUG . '-suremail';
903 }
904
905 // Admin Submenu Styles.
906 wp_enqueue_style( SRFM_SLUG . '-admin', $css_uri . 'backend/admin' . $file_prefix . $rtl . '.css', [], SRFM_VER );
907
908 if ( 'edit-' . SRFM_FORMS_POST_TYPE === $current_screen->id ) {
909 $asset_handle = 'page_header';
910
911 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
912 $script_info = file_exists( $script_asset_path )
913 ? include $script_asset_path
914 : [
915 'dependencies' => [],
916 'version' => SRFM_VER,
917 ];
918 wp_enqueue_script( SRFM_SLUG . '-form-page-header', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
919 wp_enqueue_style( SRFM_SLUG . '-form-archive-styles', $css_uri . 'form-archive-styles' . $file_prefix . $rtl . '.css', [], SRFM_VER );
920
921 $script_translations_handlers[] = SRFM_SLUG . '-form-page-header';
922 }
923
924 if ( $is_screen_sureforms_form_settings ) {
925 $asset_handle = 'settings';
926
927 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
928 $script_info = file_exists( $script_asset_path )
929 ? include $script_asset_path
930 : [
931 'dependencies' => [],
932 'version' => SRFM_VER,
933 ];
934
935 wp_enqueue_script( SRFM_SLUG . '-settings', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
936 wp_localize_script(
937 SRFM_SLUG . '-settings',
938 SRFM_SLUG . '_admin',
939 $localization_data
940 );
941
942 $script_translations_handlers[] = SRFM_SLUG . '-settings';
943 }
944 if ( 'edit-' . SRFM_FORMS_POST_TYPE === $current_screen->id ) {
945 wp_enqueue_script( SRFM_SLUG . '-form-archive', $js_uri . 'form-archive' . $file_prefix . '.js', [], SRFM_VER, true );
946 wp_enqueue_script( SRFM_SLUG . '-export', $js_uri . 'export' . $file_prefix . '.js', [ 'wp-i18n' ], SRFM_VER, true );
947 wp_localize_script(
948 SRFM_SLUG . '-export',
949 SRFM_SLUG . '_export',
950 [
951 'ajaxurl' => admin_url( 'admin-ajax.php' ),
952 'srfm_export_nonce' => wp_create_nonce( 'export_form_nonce' ),
953 'site_url' => get_site_url(),
954 'import_form_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
955 'import_btn_string' => __( 'Import Form', 'sureforms' ),
956 ]
957 );
958
959 wp_enqueue_script( SRFM_SLUG . '-backend', $js_uri . 'backend' . $file_prefix . '.js', [], SRFM_VER, true );
960 wp_localize_script(
961 SRFM_SLUG . '-backend',
962 SRFM_SLUG . '_backend',
963 [
964 'site_url' => get_site_url(),
965 ]
966 );
967
968 $script_translations_handlers[] = SRFM_SLUG . '-form-archive';
969 $script_translations_handlers[] = SRFM_SLUG . '-export';
970 $script_translations_handlers[] = SRFM_SLUG . '-backend';
971 }
972
973 if ( $is_screen_add_new_form ) {
974 wp_enqueue_style( SRFM_SLUG . '-template-picker', $css_uri . 'template-picker' . $file_prefix . $rtl . '.css', [], SRFM_VER );
975
976 $sureforms_admin = 'templatePicker';
977
978 $script_asset_path = SRFM_DIR . 'assets/build/' . $sureforms_admin . '.asset.php';
979 $script_info = file_exists( $script_asset_path )
980 ? include $script_asset_path
981 : [
982 'dependencies' => [],
983 'version' => SRFM_VER,
984 ];
985 wp_enqueue_script( SRFM_SLUG . '-template-picker', SRFM_URL . 'assets/build/' . $sureforms_admin . '.js', $script_info['dependencies'], SRFM_VER, true );
986
987 wp_localize_script(
988 SRFM_SLUG . '-template-picker',
989 SRFM_SLUG . '_admin',
990 [
991 'site_url' => get_site_url(),
992 'plugin_url' => SRFM_URL,
993 'admin_url' => admin_url( 'admin.php' ),
994 'new_template_picker_base_url' => admin_url( 'post-new.php?post_type=sureforms_form' ),
995 'capability' => Helper::current_user_can(),
996 'template_picker_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
997 'is_pro_active' => Helper::has_pro(),
998 'srfm_ai_usage_details' => AI_Helper::get_current_usage_details(),
999 'is_pro_license_active' => AI_Helper::is_pro_license_active(),
1000 'srfm_ai_auth_user_email' => get_option( 'srfm_ai_auth_user_email' ),
1001 'pricing_page_url' => Helper::get_sureforms_website_url( 'pricing' ),
1002 'licensing_nonce' => wp_create_nonce( 'srfm_pro_licensing_nonce' ),
1003 ]
1004 );
1005
1006 $script_translations_handlers[] = SRFM_SLUG . '-template-picker';
1007 }
1008 // Quick action sidebar.
1009 $default_allowed_quick_sidebar_blocks = apply_filters(
1010 'srfm_quick_sidebar_allowed_blocks',
1011 [
1012 'srfm/input',
1013 'srfm/email',
1014 'srfm/textarea',
1015 'srfm/checkbox',
1016 'srfm/number',
1017 'srfm/inline-button',
1018 'srfm/advanced-heading',
1019 ]
1020 );
1021 if ( ! is_array( $default_allowed_quick_sidebar_blocks ) ) {
1022 $default_allowed_quick_sidebar_blocks = [];
1023 }
1024
1025 $srfm_enable_quick_action_sidebar = get_option( 'srfm_enable_quick_action_sidebar' );
1026 if ( ! $srfm_enable_quick_action_sidebar ) {
1027 $srfm_enable_quick_action_sidebar = 'disabled';
1028 }
1029 $quick_sidebar_allowed_blocks = get_option( 'srfm_quick_sidebar_allowed_blocks' );
1030 $quick_sidebar_allowed_blocks = ! empty( $quick_sidebar_allowed_blocks ) && is_array( $quick_sidebar_allowed_blocks ) ? $quick_sidebar_allowed_blocks : $default_allowed_quick_sidebar_blocks;
1031 $srfm_ajax_nonce = wp_create_nonce( 'srfm_ajax_nonce' );
1032
1033 if ( Helper::is_sureforms_admin_page() ) {
1034 wp_enqueue_script( SRFM_SLUG . '-quick-action-siderbar', SRFM_URL . 'assets/build/quickActionSidebar.js', [], SRFM_VER, true );
1035 wp_localize_script(
1036 SRFM_SLUG . '-quick-action-siderbar',
1037 SRFM_SLUG . '_quick_sidebar_blocks',
1038 [
1039 'allowed_blocks' => $quick_sidebar_allowed_blocks,
1040 'srfm_enable_quick_action_sidebar' => $srfm_enable_quick_action_sidebar,
1041 'srfm_ajax_nonce' => $srfm_ajax_nonce,
1042 'srfm_ajax_url' => admin_url( 'admin-ajax.php' ),
1043 ]
1044 );
1045
1046 $script_translations_handlers[] = SRFM_SLUG . '-quick-action-siderbar';
1047 }
1048
1049 /**
1050 * Enqueuing SureTriggers Integration script.
1051 * This script loads suretriggers iframe in Intergations tab.
1052 */
1053 if ( $is_post_type_sureforms_form ) {
1054 wp_enqueue_script( SRFM_SLUG . '-suretriggers-integration', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL . 'js/v2/embed.js', [], SRFM_VER, true );
1055 }
1056
1057 // Check $script_translations_handlers is not empty before calling the function.
1058 if ( ! empty( $script_translations_handlers ) ) {
1059 // Remove duplicates values from the array.
1060 $script_translations_handlers = array_unique( $script_translations_handlers );
1061
1062 foreach ( $script_translations_handlers as $script_handle ) {
1063 Helper::register_script_translations( $script_handle );
1064 }
1065 }
1066 }
1067
1068 /**
1069 * Form Template Picker Admin Body Classes
1070 * WordPress sometimes translates class names in the admin body tag, which can result in
1071 * incorrect or missing class names when rendering the admin pages. This function ensures
1072 * that essential class names are manually added to the body tag to maintain proper functionality.
1073 *
1074 * @since 0.0.1
1075 * @param string $classes Space separated class string.
1076 */
1077 public function admin_template_picker_body_class( $classes = '' ) {
1078 // Define an associative array of class names and their corresponding conditions.
1079 // Each condition checks whether a specific request context matches.
1080 $srfm_classes = [
1081 'sureforms_page_sureforms_entries' => Helper::validate_request_context( SRFM_ENTRIES, 'page' ),
1082 'sureforms_page_sureforms_form_settings' => Helper::validate_request_context( 'sureforms_form_settings', 'page' ),
1083 'srfm-template-picker' => Helper::validate_request_context( 'add-new-form', 'page' ),
1084 ];
1085
1086 $add_srfm_classes = '';
1087
1088 // Loop through the defined classes and conditions.
1089 foreach ( $srfm_classes as $class => $condition ) {
1090 // Check if the condition evaluates to true.
1091 if ( $condition ) {
1092 // Append the class to the existing classes string, followed by a space.
1093 $add_srfm_classes .= empty( $add_srfm_classes ) ? $class : ' ' . $class;
1094 }
1095 }
1096
1097 // Append the new classes to the existing classes string.
1098 if ( ! empty( $add_srfm_classes ) ) {
1099 $classes .= ' ' . $add_srfm_classes;
1100 }
1101
1102 // Return the updated list of classes.
1103 return $classes;
1104 }
1105
1106 /**
1107 * Disable spectra's quick action bar in sureforms CPT.
1108 *
1109 * @param string $status current status of the quick action bar.
1110 * @since 0.0.2
1111 * @return string
1112 */
1113 public function restrict_spectra_quick_action_bar( $status ) {
1114 $screen = get_current_screen();
1115 if ( 'disabled' !== $status && isset( $screen->id ) && 'sureforms_form' === $screen->id ) {
1116 $status = 'disabled';
1117 }
1118
1119 return $status;
1120 }
1121
1122 // Entries methods.
1123
1124 /**
1125 * Handle entry actions.
1126 *
1127 * @since 0.0.13
1128 * @return void
1129 */
1130 public function handle_entry_actions() {
1131 Entries_List_Table::process_bulk_actions();
1132
1133 if ( ! isset( $_GET['page'] ) || SRFM_ENTRIES !== $_GET['page'] ) {
1134 return;
1135 }
1136 if ( ! isset( $_GET['entry_id'] ) || ! isset( $_GET['action'] ) ) {
1137 return;
1138 }
1139 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'srfm_entries_action' ) ) {
1140 wp_die( esc_html__( 'Nonce verification failed.', 'sureforms' ) );
1141 }
1142 $action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : '';
1143 $entry_id = Helper::get_integer_value( sanitize_text_field( wp_unslash( $_GET['entry_id'] ) ) );
1144 $view = isset( $_GET['view'] ) ? sanitize_text_field( wp_unslash( $_GET['view'] ) ) : '';
1145 if ( $entry_id > 0 ) {
1146 if ( 'read' === $action && 'details' === $view ) {
1147 $entry_status = Entries::get( $entry_id )['status'];
1148 if ( 'trash' === $entry_status ) {
1149 wp_die( esc_html__( 'You cannot view this entry because it is in trash.', 'sureforms' ) );
1150 }
1151 }
1152 Entries_List_Table::handle_entry_status( $entry_id, $action, $view );
1153 }
1154 }
1155
1156 /**
1157 * Admin Notice Callback if sureforms pro is out of date.
1158 *
1159 * Hooked - admin_notices
1160 *
1161 * @return void
1162 * @since 1.0.4
1163 */
1164 public function srfm_pro_version_compatibility() {
1165 if ( ! Helper::has_pro() ) {
1166 return;
1167 }
1168
1169 if ( empty( get_current_screen() ) ) {
1170 return;
1171 }
1172
1173 if ( ! Helper::current_user_can() ) {
1174 return;
1175 }
1176
1177 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
1178 /**
1179 * If the license status is not set then get the license status and update the option accordingly.
1180 * This will be executed only once. Subsequently, the option status is updated by the licensing class on license activation or deactivation.
1181 */
1182 if ( empty( $srfm_pro_license_status ) && class_exists( 'SRFM_PRO\Admin\Licensing' ) ) {
1183 $srfm_pro_license_status = \SRFM_PRO\Admin\Licensing::is_license_active() ? 'licensed' : 'unlicensed';
1184 update_option( 'srfm_pro_license_status', $srfm_pro_license_status );
1185 }
1186
1187 $pro_plugin_name = defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro';
1188 $message = '';
1189 $url = admin_url( 'admin.php?page=sureforms_form_settings&tab=account-settings' );
1190 if ( 'unlicensed' === $srfm_pro_license_status ) {
1191 ob_start();
1192 ?>
1193 <p>
1194 <?php
1195 printf(
1196 // translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name.
1197 esc_html__( 'Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more.', 'sureforms' ),
1198 '<a href="' . esc_url( $url ) . '">',
1199 '</a>',
1200 '<i>' . esc_html( $pro_plugin_name ) . '</i>'
1201 );
1202 ?>
1203 </p>
1204 <?php
1205 $message = ob_get_clean();
1206 }
1207
1208 if ( ! version_compare( SRFM_PRO_VER, SRFM_PRO_RECOMMENDED_VER, '>=' ) ) {
1209 ob_start();
1210 ?>
1211 <p>
1212 <?php
1213 printf(
1214 // 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.
1215 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' ),
1216 esc_html( SRFM_VER ),
1217 esc_html( $pro_plugin_name ),
1218 esc_html( SRFM_PRO_RECOMMENDED_VER ),
1219 '<a href="' . esc_url( admin_url( 'update-core.php' ) ) . '">',
1220 '</a>'
1221 );
1222 ?>
1223 </p>
1224 <?php
1225 $message .= ob_get_clean();
1226 }
1227
1228 if ( ! empty( $message ) ) {
1229 // Phpcs ignore comment is required as $message variable is already escaped.
1230 ?>
1231 <div class="notice notice-warning"><?php echo wp_kses_post( $message ); ?></div>
1232 <?php
1233 }
1234 }
1235
1236 /**
1237 * Disables the capabilities for WPForms to avoid conflicts when enqueueing
1238 * scripts and styles for WPForms.
1239 *
1240 * This function is intended to prevent any potential conflicts that may arise
1241 * when WPForms scripts and styles are enqueued. By disabling certain capabilities,
1242 * it ensures that WPForms does not interfere with other functionalities.
1243 *
1244 * @param bool $user_can A boolean indicating whether the user has the capability.
1245 * @return bool Returns true if the capabilities are successfully disabled, false otherwise.
1246 * @since 1.4.2
1247 */
1248 public function disable_wpforms_capabilities( $user_can ) {
1249 // Note: Nonce verification is intentionally omitted here as no database operations are performed.
1250 // The values of the $_REQUEST variables are strictly validated, ensuring security without the need for nonce verification.
1251
1252 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1253 $post_id = ! empty( $_REQUEST['post'] ) && ! empty( $_REQUEST['action'] ) ? absint( $_REQUEST['post'] ) : 0;
1254
1255 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1256 $post_type = $post_id ? get_post_type( $post_id ) : sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ?? '' ) );
1257 return SRFM_FORMS_POST_TYPE === $post_type ? false : $user_can;
1258 }
1259
1260 /**
1261 * Enqueueus the admin pointer script and styles.
1262 *
1263 * @return void
1264 * @since 1.8.0
1265 */
1266 public function enqueue_admin_pointer() {
1267 if ( ! $this->is_admin_pointer_visible() ) {
1268 return;
1269 }
1270 wp_enqueue_style( 'wp-pointer' );
1271 wp_enqueue_script( 'wp-pointer' );
1272 wp_enqueue_script(
1273 'sureforms-admin-pointer',
1274 plugins_url( 'admin/assets/js/sureforms-pointer.js', SRFM_FILE ),
1275 [ 'wp-pointer', 'jquery' ],
1276 SRFM_VER,
1277 true
1278 );
1279 wp_localize_script(
1280 'sureforms-admin-pointer',
1281 'sureformsPointerData',
1282 [
1283 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1284 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
1285 ]
1286 );
1287 }
1288
1289 /**
1290 * Ajax handler for pointer popup visibility.
1291 *
1292 * @return void
1293 * @since 1.8.0
1294 */
1295 public function pointer_should_show() {
1296 // Security: Check user capability.
1297 if ( ! Helper::current_user_can() ) {
1298 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1299 }
1300 // Security: Nonce check.
1301 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1302 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1303 }
1304
1305 $content_markup = sprintf(
1306 /* translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong */
1307 __( '%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' ),
1308 '<span>',
1309 '<strong>',
1310 '</strong>',
1311 '</span><br/>',
1312 '<strong style="font-size:1.1em;">',
1313 '</strong>'
1314 );
1315 wp_send_json(
1316 [
1317 'show' => true,
1318 'title' => esc_html( __( 'SureForms is waiting for you!', 'sureforms' ) ),
1319 'content' => wp_kses_post( $content_markup ),
1320 'button_text' => esc_html( __( 'Build My First Form', 'sureforms' ) ),
1321 'dismiss' => esc_html( __( 'Dismiss', 'sureforms' ) ),
1322 'button_url' => admin_url( 'admin.php?page=add-new-form' ),
1323 ]
1324 );
1325 }
1326
1327 /**
1328 * Ajax callback for pointer popup dismissed action.
1329 *
1330 * @return void
1331 * @since 1.8.0
1332 */
1333 public function pointer_dismissed() {
1334 // Security: Check user capability.
1335 if ( ! Helper::current_user_can() ) {
1336 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1337 }
1338 // Security: Nonce check.
1339 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1340 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1341 }
1342 // Use Helper to update srfm_options key.
1343 Helper::update_srfm_option( 'pointer_popup_dismissed', time() );
1344
1345 wp_send_json_success();
1346 }
1347
1348 /**
1349 * Ajax pointer accepted CTA callback.
1350 *
1351 * @return void
1352 * @since 1.8.0
1353 */
1354 public function pointer_accepted_cta() {
1355 // Security: Check user capability.
1356 if ( ! Helper::current_user_can() ) {
1357 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1358 }
1359 // Security: Nonce check.
1360 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1361 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1362 }
1363 // Use Helper to update srfm_options key.
1364 Helper::update_srfm_option( 'pointer_popup_accepted', time() );
1365
1366 wp_send_json_success();
1367 }
1368
1369 /**
1370 * Maybe register the dashboard widget based on entries.
1371 *
1372 * @return void
1373 * @since 1.9.1
1374 */
1375 public function maybe_register_dashboard_widget() {
1376
1377 // Only for users with manage_options capability.
1378 if ( ! Helper::current_user_can() ) {
1379 return;
1380 }
1381
1382 // Quick check if there are any entries in the last 7 days.
1383 $seven_days_ago = strtotime( '-7 days' );
1384 $total_entries = Entries::get_entries_count_after( $seven_days_ago );
1385
1386 // Only add the dashboard setup hook if there are entries.
1387 if ( $total_entries > 0 ) {
1388 // Get forms with entries (limit 4 for dashboard widget).
1389 $this->dashboard_widget_data = Helper::get_forms_with_entry_counts( $seven_days_ago, 4 );
1390
1391 // Only show dashboard widget if there are forms with entries.
1392 if ( ! empty( $this->dashboard_widget_data ) ) {
1393 add_action( 'wp_dashboard_setup', [ $this, 'register_dashboard_widget' ] );
1394 }
1395 }
1396 }
1397
1398 /**
1399 * Register the dashboard widget.
1400 *
1401 * @return void
1402 * @since 1.9.1
1403 */
1404 public function register_dashboard_widget() {
1405 // Add the widget with high priority to position it at the top.
1406 wp_add_dashboard_widget(
1407 'sureforms_recent_entries',
1408 __( 'SureForms', 'sureforms' ),
1409 [ $this, 'render_dashboard_widget' ],
1410 null,
1411 null,
1412 'normal',
1413 'high'
1414 );
1415 }
1416
1417 /**
1418 * Render the dashboard widget content.
1419 *
1420 * @return void
1421 * @since 1.9.1
1422 */
1423 public function render_dashboard_widget() {
1424 // Use the pre-fetched data to avoid duplicate queries.
1425 $entries_data = $this->dashboard_widget_data;
1426
1427 // Display the widget content.
1428 ?>
1429 <div class="srfm-dashboard-widget">
1430 <div class="srfm-widget-header">
1431 <h3 class="srfm-widget-title">
1432 <?php esc_html_e( 'Recent Entries', 'sureforms' ); ?>
1433 <span class="srfm-widget-subtitle"><?php esc_html_e( '( Last 7 days )', 'sureforms' ); ?></span>
1434 </h3>
1435 <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_entries' ) ); ?>" class="srfm-widget-view-link">
1436 <?php esc_html_e( 'View', 'sureforms' ); ?>
1437 </a>
1438 </div>
1439
1440 <div class="srfm-table-wrapper">
1441 <table class="srfm-entries-table">
1442 <thead>
1443 <tr>
1444 <th><?php esc_html_e( 'Form Name', 'sureforms' ); ?></th>
1445 <th><?php esc_html_e( 'Entries', 'sureforms' ); ?></th>
1446 </tr>
1447 </thead>
1448 <tbody>
1449 <?php foreach ( $entries_data as $form_data ) { ?>
1450 <tr>
1451 <td class="form-name"><?php echo esc_html( $form_data['title'] ); ?></td>
1452 <td class="entry-count"><?php echo esc_html( $form_data['count'] ); ?></td>
1453 </tr>
1454 <?php } ?>
1455 </tbody>
1456 </table>
1457 </div>
1458
1459 <?php
1460 // Render footer if applicable.
1461 $this->render_dashboard_widget_footer( $entries_data );
1462 ?>
1463 </div>
1464 <?php
1465 }
1466
1467 /**
1468 * Get random premium feature text.
1469 *
1470 * @return string Random feature text.
1471 * @since 1.9.1
1472 */
1473 private function get_random_premium_feature_text() {
1474 $features = [
1475 __( 'Use Conditional Logic to show only what matters', 'sureforms' ),
1476 __( 'Split your form into steps to keep it easy', 'sureforms' ),
1477 __( 'Let people upload files directly to your form', 'sureforms' ),
1478 __( 'Turn responses into downloadable PDFs automatically', 'sureforms' ),
1479 __( 'Let users sign with a simple signature field', 'sureforms' ),
1480 __( 'Connect your form to other tools using webhooks', 'sureforms' ),
1481 __( 'Use Conversational Forms for a chat-like experience', 'sureforms' ),
1482 __( 'Let users register or log in through your form', 'sureforms' ),
1483 __( 'Build forms that create WordPress user accounts', 'sureforms' ),
1484 __( 'Add calculations to auto-total scores or prices', 'sureforms' ),
1485 ];
1486
1487 // Get a random feature.
1488 $random_key = array_rand( $features );
1489 return $features[ $random_key ];
1490 }
1491
1492 /**
1493 * Render the dashboard widget footer for upsell.
1494 *
1495 * @param array $entries_data The entries data array.
1496 * @return void
1497 * @since 1.9.1
1498 */
1499 private function render_dashboard_widget_footer( $entries_data ) {
1500 // Only show footer if Pro is not active.
1501 if ( Helper::has_pro() ) {
1502 return;
1503 }
1504
1505 // Count total entries in last 7 days.
1506 $total_entries = 0;
1507 foreach ( $entries_data as $form_data ) {
1508 $total_entries += $form_data['count'];
1509 }
1510
1511 // Count total published forms.
1512 $published_forms_count = wp_count_posts( SRFM_FORMS_POST_TYPE )->publish;
1513
1514 // Show footer only if 3+ entries received OR 3+ forms published.
1515 if ( $total_entries >= 3 || $published_forms_count >= 3 ) {
1516 ?>
1517 <div class="srfm-widget-footer">
1518 <div class="srfm-upgrade-content">
1519 <svg class="srfm-logo-icon" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
1520 <rect width="20" height="20" fill="#D54407"/>
1521 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1522 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1523 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1524 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1525 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1526 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1527 </svg>
1528 <span><?php echo esc_html( $this->get_random_premium_feature_text() ); ?></span>
1529 </div>
1530 <?php
1531 $upgrade_url = add_query_arg(
1532 [
1533 'utm_medium' => 'dashboard-widget',
1534 ],
1535 Helper::get_sureforms_website_url( 'pricing' )
1536 );
1537 ?>
1538 <a href="<?php echo esc_url( $upgrade_url ); ?>" class="srfm-upgrade-link" target="_blank">
1539 <?php esc_html_e( 'Upgrade', 'sureforms' ); ?>
1540 </a>
1541 </div>
1542 <?php
1543 }
1544 }
1545
1546 /**
1547 * Determine if the admin pointer should be visible on this page.
1548 *
1549 * @since 1.8.0
1550 * @return bool
1551 */
1552 private function is_admin_pointer_visible() {
1553 global $pagenow;
1554 $allowed_pages = [ 'index.php', 'options-general.php' ];
1555
1556 // Do not show if pointer dismissed, accepted, or more than 1 form exists.
1557 if (
1558 ! empty( Helper::get_srfm_option( 'pointer_popup_dismissed' ) )
1559 || ! empty( Helper::get_srfm_option( 'pointer_popup_accepted' ) )
1560 || (int) ( wp_count_posts( SRFM_FORMS_POST_TYPE )->publish ?? 0 ) > 1
1561 ) {
1562 return false;
1563 }
1564
1565 if ( in_array( $pagenow, $allowed_pages, true ) ) {
1566 return true;
1567 }
1568
1569 return false;
1570 }
1571
1572 }
1573