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

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

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