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