PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.7.1
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.7.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 in SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz 2.7.1, at admin/admin.php

1,997 lines 66.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Admin Class.
4 *
5 * @package sureforms.
6 */
7
8 namespace SRFM\Admin;
9
10 use Astra_Notices;
11 use SRFM\Inc\AI_Form_Builder\AI_Helper;
12 use SRFM\Inc\Database\Tables\Entries;
13 use SRFM\Inc\Helper;
14 use SRFM\Inc\Onboarding;
15 use SRFM\Inc\Payments\Payment_Helper;
16 use SRFM\Inc\Payments\Stripe\Stripe_Helper;
17 use SRFM\Inc\Traits\Get_Instance;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit; // Exit if accessed directly.
21 }
22
23 if ( ! class_exists( 'Astra_Notices' ) ) {
24 require_once SRFM_DIR . 'inc/lib/astra-notices/class-astra-notices.php';
25 }
26 /**
27 * Admin handler class.
28 *
29 * @since 0.0.1
30 */
31 class Admin {
32 use Get_Instance;
33
34 /**
35 * Minimum number of forms or entries required to show the rating notice.
36 *
37 * @since 2.5.2
38 */
39 public const RATING_NOTICE_THRESHOLD = 3;
40
41 /**
42 * Dashboard widget entries data.
43 *
44 * @var array
45 * @since 1.9.1
46 */
47 private $dashboard_widget_data = [];
48
49 /**
50 * Cached result for whether the rating notice should display.
51 *
52 * @var bool|null
53 * @since 2.5.2
54 */
55 private $should_show_rating = null;
56
57 /**
58 * SureForms Page Default permission.
59 *
60 * @var string
61 * @since 1.12.2
62 */
63 private static $sureforms_page_default_capability = 'manage_options';
64
65 /**
66 * Class constructor.
67 *
68 * @return void
69 * @since 0.0.1
70 */
71 public function __construct() {
72 add_action( 'admin_menu', [ $this, 'add_menu_page' ], 9 );
73 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
74 add_action( 'admin_menu', [ $this, 'settings_page' ] );
75 add_action( 'admin_menu', [ $this, 'add_learn_page' ] );
76 add_action( 'admin_menu', [ $this, 'add_new_form' ] );
77 add_action( 'admin_menu', [ $this, 'add_suremail_page' ] );
78 if ( ! Helper::has_pro() ) {
79 add_action( 'admin_menu', [ $this, 'add_quiz_page' ] );
80 add_action( 'admin_menu', [ $this, 'add_upgrade_to_pro' ] );
81 add_action( 'admin_footer', [ $this, 'add_upgrade_to_pro_target_attr' ] );
82 }
83
84 add_filter( 'plugin_action_links', [ $this, 'add_settings_link' ], 10, 2 );
85 add_action( 'enqueue_block_assets', [ $this, 'enqueue_styles' ] );
86 add_action( 'admin_head', [ $this, 'enqueue_header_styles' ] );
87 add_filter( 'admin_body_class', [ $this, 'admin_template_picker_body_class' ] );
88
89 // this action is used to restrict Spectra's quick action bar on SureForms CPTS.
90 add_action( 'uag_enable_quick_action_sidebar', [ $this, 'restrict_spectra_quick_action_bar' ] );
91
92 add_action( 'current_screen', [ $this, 'enable_gutenberg_for_sureforms' ], 100 );
93 // Register notices early for React pages (before admin_enqueue_scripts).
94 add_action( 'admin_init', [ $this, 'register_pro_compatibility_notices' ], 5 );
95 // Display notices on traditional WordPress admin pages.
96 add_action( 'admin_notices', [ $this, 'srfm_pro_version_compatibility' ] );
97
98 // Enfold theme compatibility to enable block editor for SureForms post type.
99 add_filter( 'avf_use_block_editor_for_post', [ $this, 'enable_block_editor_in_enfold_theme' ] );
100
101 // Add action links to the plugin page.
102 add_filter( 'plugin_action_links_' . SRFM_BASENAME, [ $this, 'add_action_links' ] );
103 // Check if admin notification is enabled and add entries badge.
104 $general_options = get_option( 'srfm_general_settings_options', [] );
105 $admin_notification_on = isset( $general_options['srfm_admin_notification'] ) ? (bool) $general_options['srfm_admin_notification'] : true;
106
107 if ( $admin_notification_on ) {
108 add_action( 'admin_menu', [ $this, 'maybe_add_entries_badge' ], 99 );
109 }
110
111 add_filter( 'wpforms_current_user_can', [ $this, 'disable_wpforms_capabilities' ], 10, 3 );
112
113 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_pointer' ] );
114 // Ajax callbacks for wp-pointer functionality.
115 add_action( 'wp_ajax_should_show_pointer', [ $this, 'pointer_should_show' ] );
116 add_action( 'wp_ajax_sureforms_dismiss_pointer', [ $this, 'pointer_dismissed' ] );
117 add_action( 'wp_ajax_sureforms_accept_cta', [ $this, 'pointer_accepted_cta' ] );
118 add_action( 'wp_ajax_srfm_notice_response', [ $this, 'handle_notice_response' ] );
119
120 // Register dashboard widget only if there are recent entries.
121 add_action( 'admin_init', [ $this, 'maybe_register_dashboard_widget' ] );
122
123 // Save first form creation time stamp.
124 add_action( 'admin_init', [ $this, 'save_first_form_creation_time_stamp' ] );
125 add_action( 'admin_notices', [ $this, 'display_srfm_rating_notice' ] );
126 add_action( 'admin_notices', [ $this, 'display_srfm_getting_started_notice' ] );
127 }
128
129 /**
130 * Get the first form creation time stamp.
131 *
132 * @since 1.10.1
133 * @return int|false
134 */
135 public static function get_first_form_creation_time_stamp() {
136 return Helper::get_srfm_option( 'first_form_created_at', false );
137 }
138
139 /**
140 * Check if the first form has been created.
141 *
142 * @since 1.10.1
143 * @return bool
144 */
145 public static function is_first_form_created() {
146 // Convert the first form creation time stamp to a boolean. If it exists, it will return true, otherwise false.
147 $first_form_creation_time_stamp = self::get_first_form_creation_time_stamp();
148
149 // If the first form creation time stamp is not set, return false.
150 if ( ! $first_form_creation_time_stamp ) {
151 return false; // No forms created yet.
152 }
153
154 // Check if the first form creation time stamp is a valid integer and greater than zero.
155 return is_int( $first_form_creation_time_stamp ) && $first_form_creation_time_stamp > 0;
156 }
157
158 /**
159 * Check and save the first form creation time stamp.
160 * If not already saved.
161 *
162 * @since 1.10.1
163 * @return void
164 */
165 public static function save_first_form_creation_time_stamp() {
166 if ( ! Helper::current_user_can() || self::is_first_form_created() || ! defined( 'SRFM_FORMS_POST_TYPE' ) || ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) {
167 return;
168 }
169
170 // Get the first form creation time from the database that is published.
171 $query = new \WP_Query(
172 [
173 'post_type' => SRFM_FORMS_POST_TYPE,
174 'posts_per_page' => 1,
175 'orderby' => 'date',
176 'order' => 'ASC',
177 'fields' => 'ids',
178 'post_status' => 'publish',
179 ]
180 );
181
182 if ( ! empty( $query->posts ) && isset( $query->posts[0] ) ) {
183 // Get the first post from the query result.
184 $post_id = $query->posts[0];
185 // Get the post creation time in GMT.
186 $creation_time = get_post_field( 'post_date_gmt', $post_id );
187 // Convert the creation time to a timestamp.
188 $timestamp = strtotime( $creation_time );
189
190 if ( ! $timestamp ) {
191 return;
192 }
193
194 Helper::update_srfm_option( 'first_form_created_at', $timestamp );
195 }
196 }
197
198 /**
199 * Check if n days have passed since the first form creation.
200 * This is used to determine if the dynamic nudges should be shown.
201 *
202 * @param int $days Number of days to check.
203 * @since 1.10.1
204 * @return bool
205 */
206 public static function check_first_form_creation_threshold( $days = 3 ) {
207 $first_form_creation_time_stamp = self::get_first_form_creation_time_stamp();
208
209 if ( ! $first_form_creation_time_stamp ) {
210 return false; // No forms created yet.
211 }
212
213 /**
214 * Calculate the number of days since the first form was created.
215 */
216 $days_from_creation = ( strtotime( current_time( 'mysql' ) ) - $first_form_creation_time_stamp ) / DAY_IN_SECONDS;
217
218 // Return a boolean indicating if the number of days since creation is greater than the specified days.
219 return $days_from_creation > $days;
220 }
221
222 /**
223 * Show action on plugin page.
224 *
225 * @param array $links links.
226 * @return array
227 * @since 1.4.2
228 */
229 public function add_action_links( $links ) {
230 if ( ! Helper::has_pro() ) {
231 // Display upsell link if SureForms Pro is not installed.
232 $upsell_link = add_query_arg(
233 [
234 'utm_medium' => 'plugin-list',
235 ],
236 Helper::get_sureforms_website_url( 'pricing' )
237 );
238
239 ob_start();
240 ?>
241 <a href="<?php echo esc_url( $upsell_link ); ?>" target="_blank" rel="noreferrer" class="sureforms-plugins-go-pro">
242 <?php echo esc_html__( 'Get SureForms Pro', 'sureforms' ); ?>
243 </a>
244 <?php
245 $links[] = trim( ob_get_clean() );
246 }
247
248 return $links;
249 }
250
251 /**
252 * Enable block editor in Enfold theme for SureForms post type.
253 *
254 * @param bool $use_block_editor Whether to use block editor.
255 * @since 1.3.1
256 */
257 public function enable_block_editor_in_enfold_theme( $use_block_editor ) {
258 // if SureForms form post type then return true.
259 if ( SRFM_FORMS_POST_TYPE === get_current_screen()->post_type ) {
260 return true;
261 }
262 return $use_block_editor;
263 }
264
265 /**
266 * Enable Gutenberg for SureForms associated post types.
267 *
268 * @since 0.0.10
269 */
270 public function enable_gutenberg_for_sureforms() {
271 /**
272 * Check if the classic editor is enabled from Classic Editor plugin settings or Divi settings.
273 */
274 if ( 'block' === get_option( 'classic-editor-replace' ) || 'on' === get_option( 'et_enable_classic_editor' ) ) {
275 return;
276 }
277
278 $srfm_post_types = apply_filters( 'srfm_enable_gutenberg_post_types', [ SRFM_FORMS_POST_TYPE ] );
279
280 if ( in_array( get_current_screen()->post_type, $srfm_post_types, true ) ) {
281 add_filter( 'use_block_editor_for_post_type', '__return_true', 110 );
282 add_filter( 'gutenberg_can_edit_post_type', '__return_true', 110 );
283 }
284 }
285
286 /**
287 * Sureforms editor header styles.
288 *
289 * @since 0.0.1
290 */
291 public function enqueue_header_styles() {
292 $current_screen = get_current_screen();
293 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
294 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
295
296 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
297
298 /* RTL */
299 if ( is_rtl() ) {
300 $file_prefix .= '-rtl';
301 }
302
303 if ( 'sureforms_form' === $current_screen->id ) {
304 wp_enqueue_style( SRFM_SLUG . '-editor-header-styles', $css_uri . 'header-styles' . $file_prefix . '.css', [], SRFM_VER );
305 }
306 }
307
308 /**
309 * Add menu page.
310 *
311 * @return void
312 * @since 0.0.1
313 */
314 public function add_menu_page() {
315 $menu_slug = 'sureforms_menu';
316
317 $logo = file_get_contents( plugin_dir_path( SRFM_FILE ) . 'images/icon.svg' );
318 add_menu_page(
319 __( 'SureForms', 'sureforms' ),
320 __( 'SureForms', 'sureforms' ),
321 self::$sureforms_page_default_capability,
322 $menu_slug,
323 static function () {
324 },
325 'data:image/svg+xml;base64,' . base64_encode( $logo ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
326 30
327 );
328
329 // Add the Dashboard Submenu.
330 add_submenu_page(
331 $menu_slug,
332 __( 'Dashboard', 'sureforms' ),
333 __( 'Dashboard', 'sureforms' ),
334 self::$sureforms_page_default_capability,
335 $menu_slug,
336 [ $this, 'render_dashboard' ]
337 );
338 }
339
340 /**
341 * Add Settings page.
342 *
343 * @return void
344 * @since 0.0.1
345 */
346 public function settings_page() {
347 $callback = [ $this, 'settings_page_callback' ];
348 add_submenu_page(
349 'sureforms_menu',
350 __( 'Settings', 'sureforms' ),
351 __( 'Settings', 'sureforms' ),
352 self::$sureforms_page_default_capability,
353 'sureforms_form_settings',
354 $callback
355 );
356
357 // Get the current submenu page.
358 $submenu_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
359
360 if ( ! isset( $_GET['tab'] ) && 'sureforms_form_settings' === $submenu_page ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
361 wp_safe_redirect( admin_url( 'admin.php?page=sureforms_form_settings&tab=general-settings' ) );
362 exit;
363 }
364 }
365
366 /**
367 * Open to Upgrade to Pro submenu link in new tab.
368 *
369 * @return void
370 * @since 1.6.1
371 */
372 public function add_upgrade_to_pro_target_attr() {
373 ?>
374 <script type="text/javascript">
375 document.addEventListener('DOMContentLoaded', function () {
376 // Upgrade link handler.
377 // IMPORTANT: If this URL changes, also update it in the `add_upgrade_to_pro` function.
378 const upgradeLink = document.querySelector('a[href*="https://sureforms.com/upgrade"]');
379 if (upgradeLink) {
380 upgradeLink.addEventListener('click', e => {
381 e.preventDefault();
382 window.open(upgradeLink.href, '_blank');
383 });
384 }
385 });
386 </script>
387 <?php
388 }
389
390 /**
391 * Add Upgrade to pro menu item.
392 *
393 * @return void
394 * @since 1.6.1
395 */
396 public function add_upgrade_to_pro() {
397 // The url used here is used as a selector for css to style the upgrade to pro submenu.
398 // If you are changing this url, please make sure to update the css as well.
399 $upgrade_url = add_query_arg(
400 [
401 'utm_medium' => 'submenu_link_upgrade',
402 ],
403 Helper::get_sureforms_website_url( 'upgrade' )
404 );
405
406 add_submenu_page(
407 'sureforms_menu',
408 __( 'Upgrade', 'sureforms' ),
409 __( 'Upgrade', 'sureforms' ),
410 self::$sureforms_page_default_capability,
411 $upgrade_url
412 );
413 }
414
415 /**
416 * Add Quiz empty state submenu page for free users.
417 *
418 * @return void
419 * @since 2.7.0
420 */
421 public function add_quiz_page() {
422 add_submenu_page(
423 'sureforms_menu',
424 __( 'Quiz Entries', 'sureforms' ),
425 __( 'Quizzes', 'sureforms' ) .
426 ' <span style="color:#4ADE80;font-size:9px;font-weight:600;">' .
427 esc_html__( 'New', 'sureforms' ) .
428 '</span>',
429 self::$sureforms_page_default_capability,
430 'sureforms_quiz_entries',
431 [ $this, 'render_quiz_empty_state' ],
432 5
433 );
434 }
435
436 /**
437 * Quiz empty state page callback.
438 *
439 * @return void
440 * @since 2.7.0
441 */
442 public function render_quiz_empty_state() {
443 ?>
444 <div id="srfm-quiz-entries-root" class="srfm-admin-wrapper"></div>
445 <?php
446 }
447
448 /**
449 * Add SMTP promotional submenu page.
450 *
451 * @return void
452 * @since 1.7.1
453 */
454 public function add_suremail_page() {
455 add_submenu_page(
456 'sureforms_menu',
457 __( 'SMTP', 'sureforms' ),
458 __( 'SMTP', 'sureforms' ),
459 self::$sureforms_page_default_capability,
460 'sureforms_smtp',
461 [ $this, 'suremail_page_callback' ]
462 );
463
464 // Get the current submenu page.
465 $submenu_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
466
467 // Check if SureMail is installed and active.
468 if ( 'sureforms_smtp' === $submenu_page && file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' ) && is_plugin_active( 'suremails/suremails.php' ) ) {
469 // Plugin is installed and active - redirect to SureMail dashboard.
470 wp_safe_redirect( admin_url( 'options-general.php?page=suremail#/dashboard' ) );
471 exit;
472 }
473 }
474
475 /**
476 * SMTP promotional page callback.
477 *
478 * @return void
479 * @since 1.7.1
480 */
481 public function suremail_page_callback() {
482 ?>
483 <div id="srfm-suremail-container" class="srfm-admin-wrapper"></div>
484 <?php
485 }
486
487 /**
488 * Render Admin Dashboard.
489 *
490 * @return void
491 * @since 0.0.1
492 */
493 public function render_dashboard() {
494 ?>
495 <div id="srfm-dashboard-container" class="srfm-admin-wrapper"></div>
496 <?php
497 }
498
499 /**
500 * Settings page callback.
501 *
502 * @return void
503 * @since 0.0.1
504 */
505 public function settings_page_callback() {
506 ?>
507 <div id="srfm-settings-container" class="srfm-admin-wrapper"></div>
508 <?php
509 }
510
511 /**
512 * Add Learn submenu page.
513 *
514 * @return void
515 * @since 2.5.2
516 */
517 public function add_learn_page() {
518 add_submenu_page(
519 'sureforms_menu',
520 __( 'Learn', 'sureforms' ),
521 __( 'Learn', 'sureforms' ),
522 self::$sureforms_page_default_capability,
523 'sureforms_learn',
524 [ $this, 'render_learn' ]
525 );
526 }
527
528 /**
529 * Learn page callback.
530 *
531 * @return void
532 * @since 2.5.2
533 */
534 public function render_learn() {
535 ?>
536 <div id="srfm-learn-root" class="srfm-admin-wrapper"></div>
537 <?php
538 }
539
540 /**
541 * Add new form menu item.
542 *
543 * @return void
544 * @since 0.0.1
545 */
546 public function add_new_form() {
547 add_submenu_page(
548 'sureforms_menu',
549 __( 'Forms', 'sureforms' ),
550 __( 'Forms', 'sureforms' ),
551 self::$sureforms_page_default_capability,
552 'sureforms_forms',
553 [ $this, 'render_forms' ],
554 1
555 );
556 add_submenu_page(
557 'sureforms_menu',
558 __( 'New Form', 'sureforms' ),
559 __( 'New Form', 'sureforms' ),
560 self::$sureforms_page_default_capability,
561 'add-new-form',
562 [ $this, 'add_new_form_callback' ],
563 2
564 );
565 $entries_hook = add_submenu_page(
566 'sureforms_menu',
567 __( 'Entries', 'sureforms' ),
568 __( 'Entries', 'sureforms' ),
569 self::$sureforms_page_default_capability,
570 SRFM_ENTRIES,
571 [ $this, 'render_entries' ],
572 3
573 );
574
575 add_submenu_page(
576 'sureforms_menu',
577 __( 'Payments', 'sureforms' ),
578 __( 'Payments', 'sureforms' ),
579 self::$sureforms_page_default_capability,
580 SRFM_PAYMENTS,
581 [ $this, 'render_payments' ],
582 4
583 );
584
585 if ( $entries_hook ) {
586 add_action( 'load-' . $entries_hook, [ $this, 'mark_entries_page_visit' ] );
587 }
588 }
589
590 /**
591 * Payments page callback.
592 *
593 * @return void
594 * @since 2.0.0
595 */
596 public function render_payments() {
597 ?>
598 <div id="srfm-payments-react-container" class="srfm-admin-wrapper"></div>
599 <?php
600 }
601
602 /**
603 * Add new form mentu item callback.
604 *
605 * @return void
606 * @since 0.0.1
607 */
608 public function add_new_form_callback() {
609 ?>
610 <div id="srfm-add-new-form-container" class="srfm-admin-wrapper"></div>
611 <?php
612 }
613
614 /**
615 * Forms page callback.
616 *
617 * @return void
618 * @since 2.0.0
619 */
620 public function render_forms() {
621 ?>
622 <div id="srfm-forms-root" class="srfm-admin-wrapper"></div>
623 <?php
624 }
625
626 /**
627 * Entries page callback.
628 *
629 * @since 0.0.13
630 * @since 2.0.0 - Updated the entries UI and the function definition.
631 * @return void
632 */
633 public function render_entries() {
634 echo '<div id="srfm-entries-root"></div>';
635 }
636
637 /**
638 * Add notification badge to SureForms menu when there are new entries.
639 *
640 * @since 1.7.3
641 * @return void
642 */
643 public function maybe_add_entries_badge() {
644 if ( ! Helper::current_user_can() ) {
645 return;
646 }
647
648 // If currently viewing the entries listing page, mark it as visited and skip the badge.
649 if ( isset( $_GET['page'] ) && SRFM_ENTRIES === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only checking the page slug.
650 $this->mark_entries_page_visit();
651 return;
652 }
653
654 $srfm_options = get_option( 'srfm_options', [] );
655 $last_visit = isset( $srfm_options['entries_last_visited'] ) ? absint( $srfm_options['entries_last_visited'] ) : 0;
656 $new_entries = Entries::get_entries_count_after( $last_visit );
657
658 if ( $new_entries <= 0 ) {
659 return;
660 }
661
662 global $menu;
663 foreach ( $menu as $index => $item ) {
664 if ( isset( $item[2] ) && 'sureforms_menu' === $item[2] ) {
665 ob_start();
666 ?>
667 <span class="srfm-update-dot"></span>
668 <?php
669 $dot_html = ob_get_clean();
670 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for menu item.
671 $menu[ $index ][0] .= $dot_html;
672 break;
673 }
674 }
675
676 global $submenu;
677 if ( isset( $submenu['sureforms_menu'] ) ) {
678 foreach ( $submenu['sureforms_menu'] as $index => $sub_item ) {
679 if ( isset( $sub_item[2] ) && SRFM_ENTRIES === $sub_item[2] ) {
680 ob_start();
681 ?>
682 <span class="update-plugins count-<?php echo absint( $new_entries ); ?>">
683 <span class="plugin-count"><?php echo absint( $new_entries ); ?></span>
684 </span>
685 <?php
686 $badge_html = ob_get_clean();
687 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for submenu item.
688 $submenu['sureforms_menu'][ $index ][0] .= $badge_html;
689 break;
690 }
691 }
692 }
693 }
694
695 /**
696 * Mark the user's visit to the entries page.
697 *
698 * @since 1.7.3
699 * @return void
700 */
701 public function mark_entries_page_visit() {
702 if ( Helper::current_user_can() ) {
703 $srfm_options = get_option( 'srfm_options', [] );
704 $srfm_options['entries_last_visited'] = time();
705 \SRFM\Inc\Helper::update_admin_settings_option( 'srfm_options', $srfm_options );
706 }
707 }
708
709 /**
710 * Adds a settings link to the plugin action links on the plugins page.
711 *
712 * @param array $links An array of plugin action links.
713 * @param string $file The plugin file path.
714 * @return array The updated array of plugin action links.
715 * @since 0.0.1
716 */
717 public function add_settings_link( $links, $file ) {
718 if ( 'sureforms/sureforms.php' === $file ) {
719 ob_start();
720 ?>
721 <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_form_settings&tab=general-settings' ) ); ?>">
722 <?php echo esc_html__( 'Settings', 'sureforms' ); ?>
723 </a>
724 <?php
725 $settings_link_html = ob_get_clean();
726 $plugin_links = apply_filters(
727 'sureforms_plugin_action_links',
728 [
729 'sureforms_settings' => $settings_link_html,
730 ]
731 );
732 $links = array_merge( $plugin_links, $links );
733 }
734 return $links;
735 }
736
737 /**
738 * Sureforms block editor styles.
739 *
740 * @since 0.0.1
741 */
742 public function enqueue_styles() {
743 $current_screen = get_current_screen();
744 global $wp_version;
745
746 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
747 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
748
749 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
750 $vendor_css_uri = SRFM_URL . 'assets/css/minified/deps/';
751
752 /* RTL */
753 if ( is_rtl() ) {
754 $file_prefix .= '-rtl';
755 }
756
757 // Enqueue editor styles for post and page.
758 if ( SRFM_FORMS_POST_TYPE === $current_screen->post_type ) {
759 wp_enqueue_style( SRFM_SLUG . '-editor', $css_uri . 'backend/editor' . $file_prefix . '.css', [], SRFM_VER );
760 wp_enqueue_style( SRFM_SLUG . '-backend-blocks', $css_uri . 'blocks/default/backend' . $file_prefix . '.css', [], SRFM_VER );
761 wp_enqueue_style( SRFM_SLUG . '-intl', $vendor_css_uri . 'intl/intlTelInput-backend.min.css', [], SRFM_VER );
762 wp_enqueue_style( SRFM_SLUG . '-common', $css_uri . 'common' . $file_prefix . '.css', [], SRFM_VER );
763 wp_enqueue_style( SRFM_SLUG . '-reactQuill', $vendor_css_uri . 'quill/quill.snow.css', [], SRFM_VER );
764 wp_enqueue_style( SRFM_SLUG . '-single-form-modal', $css_uri . 'single-form-setting' . $file_prefix . '.css', [], SRFM_VER );
765
766 // if version is equal to or lower than 6.6.2 then add compatibility css.
767 if ( version_compare( $wp_version, '6.6.2', '<=' ) ) {
768 $srfm_inline_css = '.srfm-settings-modal .srfm-setting-modal-container .components-toggle-control .components-base-control__help{
769 margin-left: 4em;
770 }';
771 wp_add_inline_style( SRFM_SLUG . '-single-form-modal', $srfm_inline_css );
772 }
773 }
774
775 wp_enqueue_style( SRFM_SLUG . '-form-selector', $css_uri . 'srfm-form-selector' . $file_prefix . '.css', [], SRFM_VER );
776 wp_enqueue_style( SRFM_SLUG . '-common-editor', SRFM_URL . 'assets/build/common-editor.css', [], SRFM_VER, 'all' );
777 }
778
779 /**
780 * Get Breadcrumbs for current page.
781 *
782 * @since 0.0.1
783 * @return array Breadcrumbs Array.
784 */
785 public function get_breadcrumbs_for_current_page() {
786 global $post, $pagenow;
787 $breadcrumbs = [];
788
789 if ( 'admin.php' === $pagenow && isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
790 $page_title = get_admin_page_title();
791 $breadcrumbs[] = [
792 'title' => $page_title,
793 'link' => '',
794 ];
795 } elseif ( $post && in_array( $pagenow, [ 'post.php', 'post-new.php', 'edit.php' ], true ) ) {
796 $post_type_obj = get_post_type_object( get_post_type() );
797 if ( $post_type_obj ) {
798 $post_type_plural = $post_type_obj->labels->name;
799 $breadcrumbs[] = [
800 'title' => $post_type_plural,
801 'link' => admin_url( 'edit.php?post_type=' . $post_type_obj->name ),
802 ];
803
804 if ( 'edit.php' === $pagenow && ! isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
805 $breadcrumbs[ count( $breadcrumbs ) - 1 ]['link'] = '';
806 } else {
807 $breadcrumbs[] = [
808 /* Translators: Post Title. */
809 'title' => sprintf( __( 'Edit %1$s', 'sureforms' ), get_the_title() ),
810 'link' => get_edit_post_link( $post->ID ),
811 ];
812 }
813 }
814 } else {
815 $current_screen = get_current_screen();
816 if ( $current_screen && 'sureforms_form' === $current_screen->post_type ) {
817 $breadcrumbs[] = [
818 'title' => 'Forms',
819 'link' => '',
820 ];
821 } else {
822 $breadcrumbs[] = [
823 'title' => '',
824 'link' => '',
825 ];
826 }
827 }
828
829 return $breadcrumbs;
830 }
831
832 /**
833 * Enqueue Admin Scripts.
834 *
835 * @return void
836 * @since 0.0.1
837 */
838 public function enqueue_scripts() {
839 $current_screen = get_current_screen();
840 global $wp_version;
841
842 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
843 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
844 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
845 $is_rtl = is_rtl();
846 $rtl = $is_rtl ? '-rtl' : '';
847
848 /**
849 * List of the handles in which we need to add translation compatibility.
850 */
851 $script_translations_handlers = [];
852 $onboarding_instance = Onboarding::get_instance();
853 $current_user = wp_get_current_user();
854
855 $localization_data = [
856 'site_url' => get_site_url(),
857 'current_user_login' => $current_user->user_login ?? '',
858 'website_lead_details' => [
859 'first_name' => $current_user->first_name ?? '',
860 'last_name' => $current_user->last_name ?? '',
861 'email' => $current_user->user_email ?? '',
862 ],
863 'breadcrumbs' => $this->get_breadcrumbs_for_current_page(),
864 'sureforms_dashboard_url' => admin_url( '/admin.php?page=sureforms_menu' ),
865 'plugin_version' => SRFM_VER,
866 'global_settings_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
867 'is_pro_active' => Helper::has_pro(),
868 'is_first_form_created' => self::is_first_form_created(),
869 'check_three_days_threshold' => self::check_first_form_creation_threshold(),
870 'check_eight_days_threshold' => self::check_first_form_creation_threshold( 8 ),
871 'pro_plugin_version' => Helper::has_pro() ? SRFM_PRO_VER : '',
872 'pro_plugin_name' => Helper::has_pro() && defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro',
873 'sureforms_pricing_page' => Helper::get_sureforms_website_url( 'pricing' ),
874 'field_spacing_vars' => Helper::get_css_vars(),
875 'is_ver_lower_than_6_7' => version_compare( $wp_version, '6.6.2', '<=' ),
876 'integrations' => Helper::sureforms_get_integration(),
877 'rotating_plugin_banner' => Helper::get_rotating_plugin_banner(),
878 'ajax_url' => admin_url( 'admin-ajax.php' ),
879 'sf_plugin_manager_nonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
880 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
881 'plugin_activating_text' => __( 'Activating...', 'sureforms' ),
882 'plugin_activated_text' => __( 'Activated', 'sureforms' ),
883 'plugin_activate_text' => __( 'Activate', 'sureforms' ),
884 'plugin_installing_text' => __( 'Installing...', 'sureforms' ),
885 'plugin_installed_text' => __( 'Installed', 'sureforms' ),
886 'privacy_policy_url' => Helper::get_sureforms_website_url( 'privacy-policy/' ),
887 'is_rtl' => $is_rtl,
888 'onboarding_completed' => method_exists( $onboarding_instance, 'get_onboarding_status' ) ? $onboarding_instance->get_onboarding_status() : false,
889 'onboarding_redirect' => isset( $_GET['srfm-activation-redirect'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce is not required for the activation redirection.
890 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
891 'general_settings_url' => admin_url( '/options-general.php' ),
892 'additional_header_nav_items' => [],
893 'payments' => apply_filters(
894 'srfm_admin_localize_payments_data',
895 [
896 'stripe_connected' => Stripe_Helper::is_stripe_connected(),
897 'stripe_mode' => Stripe_Helper::get_stripe_mode(),
898 'stripe_connect_url' => Stripe_Helper::get_stripe_settings_url(),
899 'currencies_data' => Payment_Helper::get_all_currencies_data(),
900 'zero_decimal_currencies' => Payment_Helper::get_zero_decimal_currencies(),
901 'webhook_url' => Stripe_Helper::get_webhook_url(),
902 'webhook_test_connected' => Stripe_Helper::is_webhook_configured( 'test', true ),
903 'webhook_live_connected' => Stripe_Helper::is_webhook_configured( 'live', true ),
904 'is_transaction_present' => Stripe_Helper::is_transaction_present(),
905 'payment_currency' => Payment_Helper::get_currency(),
906 'currency_sign_position' => Payment_Helper::get_currency_sign_position(),
907 ]
908 ),
909 'mcp_adapter_status' => file_exists( WP_PLUGIN_DIR . '/mcp-adapter/mcp-adapter.php' )
910 ? ( is_plugin_active( 'mcp-adapter/mcp-adapter.php' ) ? 'active' : 'installed' )
911 : 'not_installed',
912 ];
913
914 $is_screen_sureforms_menu = Helper::validate_request_context( 'sureforms_menu', 'page' );
915 $is_screen_add_new_form = Helper::validate_request_context( 'add-new-form', 'page' );
916 $is_screen_sureforms_forms = Helper::validate_request_context( 'sureforms_forms', 'page' );
917 $is_screen_sureforms_form_settings = Helper::validate_request_context( 'sureforms_form_settings', 'page' );
918 $is_screen_sureforms_payments = Helper::validate_request_context( 'sureforms_payments', 'page' );
919 $is_screen_sureforms_entries = Helper::validate_request_context( SRFM_ENTRIES, 'page' );
920 $is_screen_sureforms_learn = Helper::validate_request_context( 'sureforms_learn', 'page' );
921 $is_screen_quiz_empty_state = Helper::validate_request_context( 'sureforms_quiz_entries', 'page' );
922 $is_post_type_sureforms_form = SRFM_FORMS_POST_TYPE === $current_screen->post_type;
923
924 /**
925 * Check if the current screen is the SureForms Menu and AI Auth Email is present then we will add user type as registered.
926 * Compatibility with existing UI code that checks for this condition.
927 */
928 if ( $is_screen_sureforms_menu ) {
929 // If email is stored send the user type as registered else non-registered.
930 $localization_data['srfm_ai_details'] = [
931 'type' => ! empty( get_option( 'srfm_ai_auth_user_email' ) ) ? 'registered' : 'non-registered',
932 ];
933 }
934
935 // Add the Quizzes nav item to the header when pro is not active.
936 if ( ! Helper::has_pro() ) {
937 $localization_data['additional_header_nav_items'][] = [
938 'slug' => 'sureforms_quiz_entries',
939 'text' => __( 'Quizzes', 'sureforms' ),
940 'link' => admin_url( 'admin.php?page=sureforms_quiz_entries' ),
941 ];
942 }
943
944 $is_sureforms_screen = $is_screen_sureforms_menu || $is_post_type_sureforms_form || $is_screen_add_new_form || $is_screen_sureforms_forms || $is_screen_sureforms_form_settings || $is_screen_sureforms_entries || $is_screen_sureforms_payments || $is_screen_sureforms_learn || $is_screen_quiz_empty_state;
945
946 /**
947 * Filter to allow extending the SureForms dashboard screen check.
948 *
949 * @since 2.6.0
950 *
951 * @param bool $is_sureforms_screen Whether the current screen is a SureForms dashboard screen.
952 */
953 $is_sureforms_screen = apply_filters( 'srfm_is_dashboard_screen', $is_sureforms_screen );
954
955 if ( $is_sureforms_screen ) {
956 $asset_handle = '-dashboard';
957
958 wp_enqueue_style( SRFM_SLUG . $asset_handle . '-font', 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap', [], SRFM_VER );
959
960 $script_asset_path = SRFM_DIR . 'assets/build/dashboard.asset.php';
961 $script_info = file_exists( $script_asset_path )
962 ? include $script_asset_path
963 : [
964 'dependencies' => [],
965 'version' => SRFM_VER,
966 ];
967 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/dashboard.js', $script_info['dependencies'], SRFM_VER, true );
968
969 wp_localize_script( SRFM_SLUG . $asset_handle, 'scIcons', [ 'path' => SRFM_URL . 'assets/build/icon-assets' ] );
970
971 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
972
973 if ( class_exists( 'SRFM_PRO\Admin\Licensing' ) ) {
974 $license_active = \SRFM_PRO\Admin\Licensing::is_license_active();
975 $localization_data['is_license_active'] = $license_active;
976
977 // Updating current licensing status.
978 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
979 $current_license_status = $license_active ? 'licensed' : 'unlicensed';
980 if ( $current_license_status !== $srfm_pro_license_status ) {
981 update_option( 'srfm_pro_license_status', $current_license_status );
982 }
983 }
984
985 $localization_data['security_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=security-settings&subpage=recaptcha' );
986 $localization_data['integration_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=integration-settings' );
987 wp_localize_script(
988 SRFM_SLUG . $asset_handle,
989 SRFM_SLUG . '_admin',
990 apply_filters(
991 SRFM_SLUG . '_admin_filter',
992 $localization_data
993 )
994 );
995 wp_enqueue_style( SRFM_SLUG . '-dashboard', SRFM_URL . 'assets/build/dashboard.css', [], SRFM_VER, 'all' );
996 }
997
998 if ( $is_screen_sureforms_form_settings || $is_screen_sureforms_forms ) {
999 wp_enqueue_style( SRFM_SLUG . '-settings', $css_uri . 'backend/settings' . $file_prefix . $rtl . '.css', [], SRFM_VER );
1000 }
1001
1002 // Enqueue styles for the entries page.
1003 if ( $is_screen_sureforms_entries ) {
1004 $asset_handle = '-entries';
1005 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/entries.js', $script_info['dependencies'], SRFM_VER, true );
1006
1007 wp_localize_script(
1008 SRFM_SLUG . $asset_handle,
1009 SRFM_SLUG . '_admin',
1010 apply_filters(
1011 SRFM_SLUG . '_admin_filter',
1012 $localization_data
1013 )
1014 );
1015 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
1016 }
1017
1018 // Enqueue scripts for the learn page.
1019 if ( $is_screen_sureforms_learn ) {
1020 $asset_handle = '-learn';
1021 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/learn.js', $script_info['dependencies'], SRFM_VER, true );
1022
1023 wp_localize_script(
1024 SRFM_SLUG . $asset_handle,
1025 SRFM_SLUG . '_admin',
1026 apply_filters(
1027 SRFM_SLUG . '_admin_filter',
1028 $localization_data
1029 )
1030 );
1031 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
1032 }
1033
1034 // Enqueue scripts for the forms page.
1035 if ( $is_screen_sureforms_forms ) {
1036 $asset_handle = '-forms';
1037
1038 $script_asset_path = SRFM_DIR . 'assets/build/forms.asset.php';
1039 $script_info = file_exists( $script_asset_path )
1040 ? include $script_asset_path
1041 : [
1042 'dependencies' => [],
1043 'version' => SRFM_VER,
1044 ];
1045
1046 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/forms.js', $script_info['dependencies'], SRFM_VER, true );
1047 wp_localize_script(
1048 SRFM_SLUG . $asset_handle,
1049 SRFM_SLUG . '_admin',
1050 apply_filters(
1051 SRFM_SLUG . '_admin_filter',
1052 $localization_data
1053 )
1054 );
1055 wp_enqueue_style( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/forms.css', [], SRFM_VER, 'all' );
1056
1057 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
1058 }
1059
1060 // Enqueue scripts for the SureMail promotional page.
1061 $is_screen_sureforms_smtp = Helper::validate_request_context( 'sureforms_smtp', 'page' );
1062 if ( $is_screen_sureforms_smtp ) {
1063 $asset_handle = 'suremail';
1064
1065 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
1066 $script_info = file_exists( $script_asset_path )
1067 ? include $script_asset_path
1068 : [
1069 'dependencies' => [],
1070 'version' => SRFM_VER,
1071 ];
1072
1073 wp_enqueue_script( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
1074 wp_enqueue_style( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/suremail.css', [], SRFM_VER, 'all' );
1075
1076 // Localize script for SureMail page.
1077 $suremail_localization_data = [
1078 'ajax_url' => admin_url( 'admin-ajax.php' ),
1079 'admin_url' => admin_url(),
1080 'suremail_url' => 'https://sureforms.com/suremail/',
1081 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
1082 'sfPluginManagerNonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
1083 'suremail_status' => file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' )
1084 ? ( is_plugin_active( 'suremails/suremails.php' ) ? 'active' : 'installed' )
1085 : 'not_installed',
1086 ];
1087
1088 wp_localize_script(
1089 SRFM_SLUG . '-suremail',
1090 SRFM_SLUG . '_admin',
1091 apply_filters(
1092 SRFM_SLUG . '_suremail_admin_filter',
1093 $suremail_localization_data
1094 )
1095 );
1096
1097 $script_translations_handlers[] = SRFM_SLUG . '-suremail';
1098 }
1099
1100 // Enqueue scripts for the Quiz empty state page (free users only).
1101 if ( $is_screen_quiz_empty_state && ! Helper::has_pro() ) {
1102 $asset_handle = 'quizEmptyState';
1103
1104 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
1105 $script_info = file_exists( $script_asset_path )
1106 ? include $script_asset_path
1107 : [
1108 'dependencies' => [],
1109 'version' => SRFM_VER,
1110 ];
1111
1112 wp_enqueue_script( SRFM_SLUG . '-quiz-empty-state', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
1113 wp_enqueue_style( SRFM_SLUG . '-quiz-empty-state', SRFM_URL . 'assets/build/' . $asset_handle . '.css', [], SRFM_VER, 'all' );
1114
1115 $script_translations_handlers[] = SRFM_SLUG . '-quiz-empty-state';
1116 }
1117
1118 // Admin Submenu Styles.
1119 wp_enqueue_style( SRFM_SLUG . '-admin', $css_uri . 'backend/admin' . $file_prefix . $rtl . '.css', [], SRFM_VER );
1120
1121 if ( $is_screen_sureforms_form_settings ) {
1122 $asset_handle = 'settings';
1123
1124 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
1125 $script_info = file_exists( $script_asset_path )
1126 ? include $script_asset_path
1127 : [
1128 'dependencies' => [],
1129 'version' => SRFM_VER,
1130 ];
1131
1132 wp_enqueue_script( SRFM_SLUG . '-settings', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
1133 wp_localize_script(
1134 SRFM_SLUG . '-settings',
1135 SRFM_SLUG . '_admin',
1136 apply_filters(
1137 SRFM_SLUG . '_admin_filter',
1138 $localization_data
1139 )
1140 );
1141
1142 $script_translations_handlers[] = SRFM_SLUG . '-settings';
1143 }
1144
1145 if ( $is_screen_add_new_form ) {
1146 wp_enqueue_style( SRFM_SLUG . '-template-picker', $css_uri . 'template-picker' . $file_prefix . $rtl . '.css', [], SRFM_VER );
1147
1148 $sureforms_admin = 'templatePicker';
1149
1150 $script_asset_path = SRFM_DIR . 'assets/build/' . $sureforms_admin . '.asset.php';
1151 $script_info = file_exists( $script_asset_path )
1152 ? include $script_asset_path
1153 : [
1154 'dependencies' => [],
1155 'version' => SRFM_VER,
1156 ];
1157 wp_enqueue_script( SRFM_SLUG . '-template-picker', SRFM_URL . 'assets/build/' . $sureforms_admin . '.js', $script_info['dependencies'], SRFM_VER, true );
1158
1159 wp_localize_script(
1160 SRFM_SLUG . '-template-picker',
1161 SRFM_SLUG . '_admin',
1162 [
1163 'site_url' => get_site_url(),
1164 'plugin_url' => SRFM_URL,
1165 'admin_url' => admin_url( 'admin.php' ),
1166 'new_template_picker_base_url' => admin_url( 'post-new.php?post_type=sureforms_form' ),
1167 'capability' => Helper::current_user_can(),
1168 'template_picker_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
1169 'is_pro_active' => Helper::has_pro(),
1170 'srfm_ai_usage_details' => AI_Helper::get_current_usage_details(),
1171 'is_pro_license_active' => AI_Helper::is_pro_license_active(),
1172 'srfm_ai_auth_user_email' => get_option( 'srfm_ai_auth_user_email' ),
1173 'pricing_page_url' => Helper::get_sureforms_website_url( 'pricing' ),
1174 'licensing_nonce' => wp_create_nonce( 'srfm_pro_licensing_nonce' ),
1175 ]
1176 );
1177
1178 $script_translations_handlers[] = SRFM_SLUG . '-template-picker';
1179 }
1180 // Quick action sidebar.
1181 $default_allowed_quick_sidebar_blocks = apply_filters(
1182 'srfm_quick_sidebar_allowed_blocks',
1183 [
1184 'srfm/input',
1185 'srfm/email',
1186 'srfm/textarea',
1187 'srfm/checkbox',
1188 'srfm/number',
1189 'srfm/inline-button',
1190 'srfm/advanced-heading',
1191 'srfm/payment',
1192 ]
1193 );
1194 if ( ! is_array( $default_allowed_quick_sidebar_blocks ) ) {
1195 $default_allowed_quick_sidebar_blocks = [];
1196 }
1197
1198 $srfm_enable_quick_action_sidebar = get_option( 'srfm_enable_quick_action_sidebar' );
1199 if ( ! $srfm_enable_quick_action_sidebar ) {
1200 $srfm_enable_quick_action_sidebar = 'disabled';
1201 }
1202 $quick_sidebar_allowed_blocks = get_option( 'srfm_quick_sidebar_allowed_blocks' );
1203 $quick_sidebar_allowed_blocks = ! empty( $quick_sidebar_allowed_blocks ) && is_array( $quick_sidebar_allowed_blocks ) ? $quick_sidebar_allowed_blocks : $default_allowed_quick_sidebar_blocks;
1204 $srfm_ajax_nonce = wp_create_nonce( 'srfm_ajax_nonce' );
1205
1206 if ( Helper::is_sureforms_admin_page() ) {
1207 wp_enqueue_script( SRFM_SLUG . '-quick-action-siderbar', SRFM_URL . 'assets/build/quickActionSidebar.js', [], SRFM_VER, true );
1208 wp_localize_script(
1209 SRFM_SLUG . '-quick-action-siderbar',
1210 SRFM_SLUG . '_quick_sidebar_blocks',
1211 [
1212 'allowed_blocks' => $quick_sidebar_allowed_blocks,
1213 'srfm_enable_quick_action_sidebar' => $srfm_enable_quick_action_sidebar,
1214 'srfm_ajax_nonce' => $srfm_ajax_nonce,
1215 'srfm_ajax_url' => admin_url( 'admin-ajax.php' ),
1216 ]
1217 );
1218
1219 $script_translations_handlers[] = SRFM_SLUG . '-quick-action-siderbar';
1220 }
1221
1222 /**
1223 * Enqueuing SureTriggers Integration script.
1224 * This script loads suretriggers iframe in Intergations tab.
1225 */
1226 if ( $is_post_type_sureforms_form ) {
1227 wp_enqueue_script( SRFM_SLUG . '-suretriggers-integration', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL . 'js/v2/embed.js', [], SRFM_VER, true );
1228 }
1229
1230 // Check $script_translations_handlers is not empty before calling the function.
1231 if ( ! empty( $script_translations_handlers ) ) {
1232 // Remove duplicates values from the array.
1233 $script_translations_handlers = array_unique( $script_translations_handlers );
1234
1235 foreach ( $script_translations_handlers as $script_handle ) {
1236 Helper::register_script_translations( $script_handle );
1237 }
1238 }
1239 }
1240
1241 /**
1242 * Form Template Picker Admin Body Classes
1243 * WordPress sometimes translates class names in the admin body tag, which can result in
1244 * incorrect or missing class names when rendering the admin pages. This function ensures
1245 * that essential class names are manually added to the body tag to maintain proper functionality.
1246 *
1247 * @since 0.0.1
1248 * @param string $classes Space separated class string.
1249 */
1250 public function admin_template_picker_body_class( $classes = '' ) {
1251 // Define an associative array of class names and their corresponding conditions.
1252 // Each condition checks whether a specific request context matches.
1253 $srfm_classes = [
1254 'sureforms_page_sureforms_entries' => Helper::validate_request_context( SRFM_ENTRIES, 'page' ),
1255 'sureforms_page_sureforms_form_settings' => Helper::validate_request_context( 'sureforms_form_settings', 'page' ),
1256 'srfm-template-picker' => Helper::validate_request_context( 'add-new-form', 'page' ),
1257 ];
1258
1259 $add_srfm_classes = '';
1260
1261 // Loop through the defined classes and conditions.
1262 foreach ( $srfm_classes as $class => $condition ) {
1263 // Check if the condition evaluates to true.
1264 if ( $condition ) {
1265 // Append the class to the existing classes string, followed by a space.
1266 $add_srfm_classes .= empty( $add_srfm_classes ) ? $class : ' ' . $class;
1267 }
1268 }
1269
1270 // Append the new classes to the existing classes string.
1271 if ( ! empty( $add_srfm_classes ) ) {
1272 $classes .= ' ' . $add_srfm_classes;
1273 }
1274
1275 // Return the updated list of classes.
1276 return $classes;
1277 }
1278
1279 /**
1280 * Disable spectra's quick action bar in sureforms CPT.
1281 *
1282 * @param string $status current status of the quick action bar.
1283 * @since 0.0.2
1284 * @return string
1285 */
1286 public function restrict_spectra_quick_action_bar( $status ) {
1287 $screen = get_current_screen();
1288 if ( 'disabled' !== $status && isset( $screen->id ) && 'sureforms_form' === $screen->id ) {
1289 $status = 'disabled';
1290 }
1291
1292 return $status;
1293 }
1294
1295 /**
1296 * Register Pro compatibility notices early for React pages.
1297 *
1298 * This method runs on admin_init (priority 5) to ensure notices are
1299 * registered BEFORE admin_enqueue_scripts, so they're available when
1300 * wp_localize_script runs.
1301 *
1302 * Hooked - admin_init (priority 5)
1303 *
1304 * @return void
1305 * @since 2.5.0
1306 */
1307 public function register_pro_compatibility_notices() {
1308 // Early exit if Pro is not active, user lacks permissions, or Notice_Manager is unavailable.
1309 if ( ! Helper::has_pro() || ! Helper::current_user_can() || ! class_exists( 'SRFM\Admin\Notice_Manager' ) ) {
1310 return;
1311 }
1312
1313 // Register version outdated notice for React pages.
1314 if ( ! version_compare( SRFM_PRO_VER, SRFM_PRO_RECOMMENDED_VER, '>=' ) ) {
1315 $pro_plugin_name = defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro';
1316 $react_outdated_message = sprintf(
1317 // translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version.
1318 esc_html__( 'SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version.', 'sureforms' ),
1319 esc_html( SRFM_VER ),
1320 esc_html( $pro_plugin_name ),
1321 esc_html( SRFM_PRO_RECOMMENDED_VER )
1322 );
1323
1324 \SRFM\Admin\Notice_Manager::register_notice(
1325 [
1326 'id' => 'sureforms-pro-version-outdated',
1327 'variant' => 'warning',
1328 'message' => $react_outdated_message,
1329 'actions' => [
1330 [
1331 'label' => esc_html__( 'Update Now', 'sureforms' ),
1332 'url' => admin_url( 'update-core.php' ),
1333 'variant' => 'primary',
1334 ],
1335 ],
1336 'pages' => [ 'all' ],
1337 ]
1338 );
1339 }
1340 }
1341
1342 /**
1343 * Admin Notice Callback if sureforms pro is out of date.
1344 *
1345 * Hooked - admin_notices
1346 *
1347 * @return void
1348 * @since 1.0.4
1349 */
1350 public function srfm_pro_version_compatibility() {
1351 if ( ! Helper::has_pro() ) {
1352 return;
1353 }
1354
1355 if ( empty( get_current_screen() ) ) {
1356 return;
1357 }
1358
1359 if ( ! Helper::current_user_can() ) {
1360 return;
1361 }
1362
1363 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
1364 /**
1365 * If the license status is not set then get the license status and update the option accordingly.
1366 * This will be executed only once. Subsequently, the option status is updated by the licensing class on license activation or deactivation.
1367 */
1368 if ( empty( $srfm_pro_license_status ) && class_exists( 'SRFM_PRO\Admin\Licensing' ) ) {
1369 $srfm_pro_license_status = \SRFM_PRO\Admin\Licensing::is_license_active() ? 'licensed' : 'unlicensed';
1370 update_option( 'srfm_pro_license_status', $srfm_pro_license_status );
1371 }
1372
1373 $pro_plugin_name = defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro';
1374 $message = '';
1375 $url = admin_url( 'admin.php?page=sureforms_form_settings&tab=account-settings' );
1376 if ( 'unlicensed' === $srfm_pro_license_status ) {
1377 ob_start();
1378 ?>
1379 <p>
1380 <?php
1381 printf(
1382 // translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name.
1383 esc_html__( 'Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more.', 'sureforms' ),
1384 '<a href="' . esc_url( $url ) . '">',
1385 '</a>',
1386 '<i>' . esc_html( $pro_plugin_name ) . '</i>'
1387 );
1388 ?>
1389 </p>
1390 <?php
1391 $message = ob_get_clean();
1392 }
1393
1394 if ( ! version_compare( SRFM_PRO_VER, SRFM_PRO_RECOMMENDED_VER, '>=' ) ) {
1395 ob_start();
1396 ?>
1397 <p>
1398 <?php
1399 printf(
1400 // 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.
1401 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' ),
1402 esc_html( SRFM_VER ),
1403 esc_html( $pro_plugin_name ),
1404 esc_html( SRFM_PRO_RECOMMENDED_VER ),
1405 '<a href="' . esc_url( admin_url( 'update-core.php' ) ) . '">',
1406 '</a>'
1407 );
1408 ?>
1409 </p>
1410 <?php
1411 $message .= ob_get_clean();
1412 }
1413
1414 if ( ! empty( $message ) ) {
1415 // Phpcs ignore comment is required as $message variable is already escaped.
1416 ?>
1417 <div class="notice notice-warning"><?php echo wp_kses_post( $message ); ?></div>
1418 <?php
1419 }
1420 }
1421
1422 /**
1423 * Display a notice to the user about providing a review.
1424 *
1425 * @since 2.5.2
1426 * @return void
1427 */
1428 public function display_srfm_rating_notice() {
1429 // Only show to admins.
1430 if ( ! Helper::current_user_can() ) {
1431 return;
1432 }
1433
1434 // Allow the notice to be disabled.
1435 if ( ! apply_filters( 'srfm_show_rating_notice', true ) ) {
1436 return;
1437 }
1438
1439 Astra_Notices::add_notice(
1440 [
1441 'id' => 'srfm-plugin-review-notice',
1442 'type' => '',
1443 'message' => $this->build_notice_markup(
1444 esc_html__( 'Amazing! SureForms is powering your forms and submissions - let\'s keep growing together!', 'sureforms' ),
1445 esc_html__( 'If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?', 'sureforms' ),
1446 esc_url( 'https://wordpress.org/support/plugin/sureforms/reviews/?filter=5#new-post' ),
1447 esc_html__( 'Rate SureForms', 'sureforms' ),
1448 esc_html__( 'Maybe later', 'sureforms' ),
1449 esc_html__( 'I already did', 'sureforms' ),
1450 WEEK_IN_SECONDS,
1451 true
1452 ),
1453 'repeat-notice-after' => WEEK_IN_SECONDS,
1454 'show_if' => $this->maybe_display_rating_notice(),
1455 'display-with-other-notices' => true,
1456 ]
1457 );
1458
1459 add_action( 'astra_notice_after_markup_srfm-plugin-review-notice', [ $this, 'enqueue_notice_response_script' ] );
1460 }
1461
1462 /**
1463 * Display a "Getting Started" admin notice for new users who haven't yet
1464 * reached the rating-notice milestone (3+ forms or 3+ entries).
1465 *
1466 * The Astra Notices library handles the 7-day delay via the
1467 * `display-notice-after` parameter.
1468 *
1469 * @since 2.5.2
1470 * @return void
1471 */
1472 public function display_srfm_getting_started_notice() {
1473 // Only show to admins.
1474 if ( ! Helper::current_user_can() ) {
1475 return;
1476 }
1477
1478 // Allow the notice to be disabled programmatically.
1479 if ( ! apply_filters( 'srfm_show_getting_started_notice', true ) ) {
1480 return;
1481 }
1482
1483 Astra_Notices::add_notice(
1484 [
1485 'id' => 'srfm-getting-started-notice',
1486 'type' => '',
1487 'message' => $this->build_notice_markup(
1488 esc_html__( 'SureForms is ready to power your forms — explore what\'s possible!', 'sureforms' ),
1489 esc_html__( 'Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard.', 'sureforms' ),
1490 esc_url( admin_url( 'admin.php?page=sureforms_menu' ) ),
1491 esc_html__( 'Go to Dashboard', 'sureforms' ),
1492 esc_html__( 'Maybe later', 'sureforms' ),
1493 esc_html__( 'I already know', 'sureforms' ),
1494 WEEK_IN_SECONDS
1495 ),
1496 'repeat-notice-after' => WEEK_IN_SECONDS,
1497 'show_if' => ! $this->maybe_display_rating_notice(),
1498 'display-notice-after' => WEEK_IN_SECONDS,
1499 'display-with-other-notices' => true,
1500 ]
1501 );
1502
1503 add_action( 'astra_notice_after_markup_srfm-getting-started-notice', [ $this, 'enqueue_notice_response_script' ] );
1504 }
1505
1506 /**
1507 * Enqueue the notice response analytics script.
1508 *
1509 * Called via the astra_notice_after_markup_{id} hook so the script
1510 * only loads when a SureForms notice is actually rendered.
1511 *
1512 * @since 2.5.2
1513 * @return void
1514 */
1515 public function enqueue_notice_response_script() {
1516 if ( wp_script_is( 'srfm-notice-response', 'enqueued' ) ) {
1517 return;
1518 }
1519
1520 wp_enqueue_script(
1521 'srfm-notice-response',
1522 SRFM_URL . 'admin/assets/js/notice-response.js',
1523 [],
1524 SRFM_VER,
1525 true
1526 );
1527
1528 wp_localize_script(
1529 'srfm-notice-response',
1530 'srfmNoticeResponse',
1531 [
1532 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1533 'nonce' => wp_create_nonce( 'srfm_notice_response' ),
1534 ]
1535 );
1536 }
1537
1538 /**
1539 * Handle the notice response AJAX request.
1540 *
1541 * Validates the request and records the analytics event
1542 * for the notice button that was clicked.
1543 *
1544 * @since 2.5.2
1545 * @return void
1546 */
1547 public function handle_notice_response() {
1548 if ( ! check_ajax_referer( 'srfm_notice_response', 'nonce', false ) ) {
1549 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1550 }
1551
1552 if ( ! Helper::current_user_can() ) {
1553 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1554 }
1555
1556 $notice_id = isset( $_POST['notice_id'] ) ? sanitize_text_field( wp_unslash( $_POST['notice_id'] ) ) : '';
1557 $button = isset( $_POST['button'] ) ? sanitize_text_field( wp_unslash( $_POST['button'] ) ) : '';
1558
1559 $valid = [
1560 'srfm-getting-started-notice' => [
1561 'go_to_dashboard' => 'getting_started_notice_cta',
1562 'maybe_later' => 'getting_started_notice_snooze',
1563 'dismissed' => 'getting_started_notice_dismiss',
1564 ],
1565 'srfm-plugin-review-notice' => [
1566 'rate_sureforms' => 'rating_notice_cta',
1567 'maybe_later' => 'rating_notice_snooze',
1568 'dismissed' => 'rating_notice_dismiss',
1569 ],
1570 ];
1571
1572 if ( ! isset( $valid[ $notice_id ][ $button ] ) ) {
1573 wp_send_json_error( [ 'message' => __( 'Invalid parameters.', 'sureforms' ) ], 400 );
1574 }
1575
1576 $event_name = $valid[ $notice_id ][ $button ];
1577 Analytics::events()->track( $event_name, $button );
1578
1579 wp_send_json_success();
1580 }
1581
1582 /**
1583 * Disables the capabilities for WPForms to avoid conflicts when enqueueing
1584 * scripts and styles for WPForms.
1585 *
1586 * This function is intended to prevent any potential conflicts that may arise
1587 * when WPForms scripts and styles are enqueued. By disabling certain capabilities,
1588 * it ensures that WPForms does not interfere with other functionalities.
1589 *
1590 * @param bool $user_can A boolean indicating whether the user has the capability.
1591 * @return bool Returns true if the capabilities are successfully disabled, false otherwise.
1592 * @since 1.4.2
1593 */
1594 public function disable_wpforms_capabilities( $user_can ) {
1595 // Note: Nonce verification is intentionally omitted here as no database operations are performed.
1596 // The values of the $_REQUEST variables are strictly validated, ensuring security without the need for nonce verification.
1597
1598 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1599 $post_id = ! empty( $_REQUEST['post'] ) && ! empty( $_REQUEST['action'] ) ? absint( $_REQUEST['post'] ) : 0;
1600
1601 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1602 $post_type = $post_id ? get_post_type( $post_id ) : sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ?? '' ) );
1603 return SRFM_FORMS_POST_TYPE === $post_type ? false : $user_can;
1604 }
1605
1606 /**
1607 * Enqueueus the admin pointer script and styles.
1608 *
1609 * @return void
1610 * @since 1.8.0
1611 */
1612 public function enqueue_admin_pointer() {
1613 if ( ! $this->is_admin_pointer_visible() ) {
1614 return;
1615 }
1616 wp_enqueue_style( 'wp-pointer' );
1617 wp_enqueue_script( 'wp-pointer' );
1618 wp_enqueue_script(
1619 'sureforms-admin-pointer',
1620 plugins_url( 'admin/assets/js/sureforms-pointer.js', SRFM_FILE ),
1621 [ 'wp-pointer', 'jquery' ],
1622 SRFM_VER,
1623 true
1624 );
1625 wp_localize_script(
1626 'sureforms-admin-pointer',
1627 'sureformsPointerData',
1628 [
1629 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1630 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
1631 ]
1632 );
1633 }
1634
1635 /**
1636 * Ajax handler for pointer popup visibility.
1637 *
1638 * @return void
1639 * @since 1.8.0
1640 */
1641 public function pointer_should_show() {
1642 // Security: Check user capability.
1643 if ( ! Helper::current_user_can() ) {
1644 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1645 }
1646 // Security: Nonce check.
1647 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1648 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1649 }
1650
1651 $content_markup = sprintf(
1652 /* translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong */
1653 __( '%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' ),
1654 '<span>',
1655 '<strong>',
1656 '</strong>',
1657 '</span><br/>',
1658 '<strong style="font-size:1.1em;">',
1659 '</strong>'
1660 );
1661 wp_send_json(
1662 [
1663 'show' => true,
1664 'title' => esc_html( __( 'SureForms is waiting for you!', 'sureforms' ) ),
1665 'content' => wp_kses_post( $content_markup ),
1666 'button_text' => esc_html( __( 'Build My First Form', 'sureforms' ) ),
1667 'dismiss' => esc_html( __( 'Dismiss', 'sureforms' ) ),
1668 'button_url' => admin_url( 'admin.php?page=add-new-form' ),
1669 ]
1670 );
1671 }
1672
1673 /**
1674 * Ajax callback for pointer popup dismissed action.
1675 *
1676 * @return void
1677 * @since 1.8.0
1678 */
1679 public function pointer_dismissed() {
1680 // Security: Check user capability.
1681 if ( ! Helper::current_user_can() ) {
1682 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1683 }
1684 // Security: Nonce check.
1685 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1686 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1687 }
1688 // Use Helper to update srfm_options key.
1689 Helper::update_srfm_option( 'pointer_popup_dismissed', time() );
1690
1691 wp_send_json_success();
1692 }
1693
1694 /**
1695 * Ajax pointer accepted CTA callback.
1696 *
1697 * @return void
1698 * @since 1.8.0
1699 */
1700 public function pointer_accepted_cta() {
1701 // Security: Check user capability.
1702 if ( ! Helper::current_user_can() ) {
1703 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1704 }
1705 // Security: Nonce check.
1706 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1707 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1708 }
1709 // Use Helper to update srfm_options key.
1710 Helper::update_srfm_option( 'pointer_popup_accepted', time() );
1711
1712 wp_send_json_success();
1713 }
1714
1715 /**
1716 * Maybe register the dashboard widget based on entries.
1717 *
1718 * @return void
1719 * @since 1.9.1
1720 */
1721 public function maybe_register_dashboard_widget() {
1722
1723 // Only for users with manage_options capability.
1724 if ( ! Helper::current_user_can() ) {
1725 return;
1726 }
1727
1728 // Quick check if there are any entries in the last 7 days.
1729 $seven_days_ago = strtotime( '-7 days' );
1730 $total_entries = Entries::get_entries_count_after( $seven_days_ago );
1731
1732 // Only add the dashboard setup hook if there are entries.
1733 if ( $total_entries > 0 ) {
1734 // Get forms with entries (limit 4 for dashboard widget).
1735 $this->dashboard_widget_data = Helper::get_forms_with_entry_counts( $seven_days_ago, 4 );
1736
1737 // Only show dashboard widget if there are forms with entries.
1738 if ( ! empty( $this->dashboard_widget_data ) ) {
1739 add_action( 'wp_dashboard_setup', [ $this, 'register_dashboard_widget' ] );
1740 }
1741 }
1742 }
1743
1744 /**
1745 * Register the dashboard widget.
1746 *
1747 * @return void
1748 * @since 1.9.1
1749 */
1750 public function register_dashboard_widget() {
1751 // Add the widget with high priority to position it at the top.
1752 wp_add_dashboard_widget(
1753 'sureforms_recent_entries',
1754 __( 'SureForms', 'sureforms' ),
1755 [ $this, 'render_dashboard_widget' ],
1756 null,
1757 null,
1758 'normal',
1759 'high'
1760 );
1761 }
1762
1763 /**
1764 * Render the dashboard widget content.
1765 *
1766 * @return void
1767 * @since 1.9.1
1768 */
1769 public function render_dashboard_widget() {
1770 // Use the pre-fetched data to avoid duplicate queries.
1771 $entries_data = $this->dashboard_widget_data;
1772
1773 // Display the widget content.
1774 ?>
1775 <div class="srfm-dashboard-widget">
1776 <div class="srfm-widget-header">
1777 <h3 class="srfm-widget-title">
1778 <?php esc_html_e( 'Recent Entries', 'sureforms' ); ?>
1779 <span class="srfm-widget-subtitle"><?php esc_html_e( '( Last 7 days )', 'sureforms' ); ?></span>
1780 </h3>
1781 <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_entries' ) ); ?>" class="srfm-widget-view-link">
1782 <?php esc_html_e( 'View', 'sureforms' ); ?>
1783 </a>
1784 </div>
1785
1786 <div class="srfm-table-wrapper">
1787 <table class="srfm-entries-table">
1788 <thead>
1789 <tr>
1790 <th><?php esc_html_e( 'Form Name', 'sureforms' ); ?></th>
1791 <th><?php esc_html_e( 'Entries', 'sureforms' ); ?></th>
1792 </tr>
1793 </thead>
1794 <tbody>
1795 <?php foreach ( $entries_data as $form_data ) { ?>
1796 <tr>
1797 <td class="form-name"><?php echo esc_html( $form_data['title'] ); ?></td>
1798 <td class="entry-count"><?php echo esc_html( $form_data['count'] ); ?></td>
1799 </tr>
1800 <?php } ?>
1801 </tbody>
1802 </table>
1803 </div>
1804
1805 <?php
1806 // Render footer if applicable.
1807 $this->render_dashboard_widget_footer( $entries_data );
1808 ?>
1809 </div>
1810 <?php
1811 }
1812
1813 /**
1814 * Build the shared HTML markup for admin notices.
1815 *
1816 * @since 2.5.2
1817 *
1818 * All text parameters must be pre-escaped by the caller (e.g. via esc_html__()).
1819 * URL parameters must be pre-escaped via esc_url().
1820 *
1821 * @param string $heading The notice heading text (pre-escaped).
1822 * @param string $message The notice body text (pre-escaped).
1823 * @param string $cta_url The primary CTA URL (pre-escaped).
1824 * @param string $cta_text The primary CTA button text (pre-escaped).
1825 * @param string $snooze_text The snooze button text (pre-escaped).
1826 * @param string $dismiss_text The dismiss button text (pre-escaped).
1827 * @param int $snooze_duration Snooze duration in seconds for the data-repeat-notice-after attribute.
1828 * @param bool $external_cta Whether the CTA opens in a new tab and also dismisses the notice
1829 * via the astra-notice-close class. Default false.
1830 * @return string The notice HTML markup.
1831 */
1832 private function build_notice_markup( $heading, $message, $cta_url, $cta_text, $snooze_text, $dismiss_text, $snooze_duration, $external_cta = false ) {
1833 $image_path = esc_url( SRFM_URL . 'admin/assets/sureforms-logo.png' );
1834 $cta_class = $external_cta ? 'astra-notice-close button-primary' : 'button-primary';
1835 $cta_attrs = $external_cta ? ' target="_blank" rel="noopener noreferrer"' : '';
1836
1837 return sprintf(
1838 '<div class="notice-image">
1839 <img src="%1$s" class="custom-logo" alt="SureForms" itemprop="logo">
1840 </div>
1841 <div class="notice-content">
1842 <div class="notice-heading">
1843 %2$s
1844 </div>
1845 %3$s<br />
1846 <div class="astra-review-notice-container">
1847 <a href="%4$s" class="%5$s"%6$s>
1848 %7$s
1849 </a>
1850 <span class="dashicons dashicons-clock" aria-hidden="true"></span>
1851 <a href="#" data-repeat-notice-after="%8$s" class="astra-notice-close">
1852 %9$s
1853 </a>
1854 <span class="dashicons dashicons-smiley" aria-hidden="true"></span>
1855 <a href="#" class="astra-notice-close">
1856 %10$s
1857 </a>
1858 </div>
1859 </div>',
1860 $image_path,
1861 $heading,
1862 $message,
1863 $cta_url,
1864 esc_attr( $cta_class ),
1865 $cta_attrs,
1866 $cta_text,
1867 $snooze_duration,
1868 $snooze_text,
1869 $dismiss_text
1870 );
1871 }
1872
1873 /**
1874 * Callback for displaying the rating notice conditionally.
1875 *
1876 * Returns true if the user has 3 or more published forms or 3 or more form entries.
1877 *
1878 * @since 2.5.2
1879 * @return bool
1880 */
1881 private function maybe_display_rating_notice() {
1882 if ( null === $this->should_show_rating ) {
1883 $entries_count = Entries::get_total_entries_by_status( 'all' );
1884 $form_count = wp_count_posts( SRFM_FORMS_POST_TYPE );
1885 $this->should_show_rating = $entries_count >= self::RATING_NOTICE_THRESHOLD || Helper::get_integer_value( $form_count->publish ?? 0 ) >= self::RATING_NOTICE_THRESHOLD;
1886 }
1887
1888 return $this->should_show_rating;
1889 }
1890
1891 /**
1892 * Get random premium feature text.
1893 *
1894 * @return string Random feature text.
1895 * @since 1.9.1
1896 */
1897 private function get_random_premium_feature_text() {
1898 $features = [
1899 __( 'Use Conditional Logic to show only what matters', 'sureforms' ),
1900 __( 'Split your form into steps to keep it easy', 'sureforms' ),
1901 __( 'Let people upload files directly to your form', 'sureforms' ),
1902 __( 'Turn responses into downloadable PDFs automatically', 'sureforms' ),
1903 __( 'Let users sign with a simple signature field', 'sureforms' ),
1904 __( 'Connect your form to other tools using webhooks', 'sureforms' ),
1905 __( 'Use Conversational Forms for a chat-like experience', 'sureforms' ),
1906 __( 'Let users register or log in through your form', 'sureforms' ),
1907 __( 'Build forms that create WordPress user accounts', 'sureforms' ),
1908 __( 'Add calculations to auto-total scores or prices', 'sureforms' ),
1909 ];
1910
1911 // Get a random feature.
1912 $random_key = array_rand( $features );
1913 return $features[ $random_key ];
1914 }
1915
1916 /**
1917 * Render the dashboard widget footer for upsell.
1918 *
1919 * @param array $entries_data The entries data array.
1920 * @return void
1921 * @since 1.9.1
1922 */
1923 private function render_dashboard_widget_footer( $entries_data ) {
1924 // Only show footer if Pro is not active.
1925 if ( Helper::has_pro() ) {
1926 return;
1927 }
1928
1929 // Count total entries in last 7 days.
1930 $total_entries = 0;
1931 foreach ( $entries_data as $form_data ) {
1932 $total_entries += $form_data['count'];
1933 }
1934
1935 // Count total published forms.
1936 $published_forms_count = wp_count_posts( SRFM_FORMS_POST_TYPE )->publish;
1937
1938 // Show footer only if 3+ entries received OR 3+ forms published.
1939 if ( $total_entries >= 3 || $published_forms_count >= 3 ) {
1940 ?>
1941 <div class="srfm-widget-footer">
1942 <div class="srfm-upgrade-content">
1943 <svg class="srfm-logo-icon" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
1944 <rect width="20" height="20" fill="#D54407"/>
1945 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1946 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1947 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1948 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1949 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1950 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1951 </svg>
1952 <span><?php echo esc_html( $this->get_random_premium_feature_text() ); ?></span>
1953 </div>
1954 <?php
1955 $upgrade_url = add_query_arg(
1956 [
1957 'utm_medium' => 'dashboard-widget',
1958 ],
1959 Helper::get_sureforms_website_url( 'pricing' )
1960 );
1961 ?>
1962 <a href="<?php echo esc_url( $upgrade_url ); ?>" class="srfm-upgrade-link" target="_blank">
1963 <?php esc_html_e( 'Upgrade', 'sureforms' ); ?>
1964 </a>
1965 </div>
1966 <?php
1967 }
1968 }
1969
1970 /**
1971 * Determine if the admin pointer should be visible on this page.
1972 *
1973 * @since 1.8.0
1974 * @return bool
1975 */
1976 private function is_admin_pointer_visible() {
1977 global $pagenow;
1978 $allowed_pages = [ 'index.php', 'options-general.php' ];
1979
1980 // Do not show if pointer dismissed, accepted, or more than 1 form exists.
1981 if (
1982 ! empty( Helper::get_srfm_option( 'pointer_popup_dismissed' ) )
1983 || ! empty( Helper::get_srfm_option( 'pointer_popup_accepted' ) )
1984 || (int) ( wp_count_posts( SRFM_FORMS_POST_TYPE )->publish ?? 0 ) > 1
1985 ) {
1986 return false;
1987 }
1988
1989 if ( in_array( $pagenow, $allowed_pages, true ) ) {
1990 return true;
1991 }
1992
1993 return false;
1994 }
1995
1996 }
1997