PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.5.2
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.5.2
2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 All 96 releases
sureforms / admin / admin.php

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

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