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
← All changes | admin/admin.php +311 -10 2.5.02.5.2 View file →
@@ -6,9 +6,11 @@
6 6 */
7 7
8 8 namespace SRFM\Admin;
9 9
10 +use Astra_Notices;
10 11 use SRFM\Inc\AI_Form_Builder\AI_Helper;
12 +use SRFM\Inc\Analytics_Events;
11 13 use SRFM\Inc\Database\Tables\Entries;
12 14 use SRFM\Inc\Helper;
13 15 use SRFM\Inc\Onboarding;
14 16 use SRFM\Inc\Payments\Payment_Helper;
@@ -17,8 +19,12 @@
17 19
18 20 if ( ! defined( 'ABSPATH' ) ) {
19 21 exit; // Exit if accessed directly.
20 22 }
23 +
24 +if ( ! class_exists( 'Astra_Notices' ) ) {
25 + require_once SRFM_DIR . 'inc/lib/astra-notices/class-astra-notices.php';
26 +}
21 27 /**
22 28 * Admin handler class.
23 29 *
24 30 * @since 0.0.1
@@ -26,8 +32,15 @@
26 32 class Admin {
27 33 use Get_Instance;
28 34
29 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 + /**
30 43 * Dashboard widget entries data.
31 44 *
32 45 * @var array
33 46 * @since 1.9.1
@@ -34,8 +47,16 @@
34 47 */
35 48 private $dashboard_widget_data = [];
36 49
37 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 + /**
38 59 * SureForms Page Default permission.
39 60 *
40 61 * @var string
41 62 * @since 1.12.2
@@ -51,8 +72,9 @@
51 72 public function __construct() {
52 73 add_action( 'admin_menu', [ $this, 'add_menu_page' ], 9 );
53 74 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
54 75 add_action( 'admin_menu', [ $this, 'settings_page' ] );
76 + add_action( 'admin_menu', [ $this, 'add_learn_page' ] );
55 77 add_action( 'admin_menu', [ $this, 'add_new_form' ] );
56 78 add_action( 'admin_menu', [ $this, 'add_suremail_page' ] );
57 79 if ( ! Helper::has_pro() ) {
58 80 add_action( 'admin_menu', [ $this, 'add_upgrade_to_pro' ] );
@@ -72,17 +94,8 @@
72 94 add_action( 'admin_init', [ $this, 'register_pro_compatibility_notices' ], 5 );
73 95 // Display notices on traditional WordPress admin pages.
74 96 add_action( 'admin_notices', [ $this, 'srfm_pro_version_compatibility' ] );
75 97
76 - // This action enqueues translations for NPS Survey library.
77 - // A better solution will be required from library to resolve plugin conflict.
78 - add_action(
79 - 'admin_footer',
80 - static function() {
81 - Helper::register_script_translations( 'nps-survey-script' );
82 - },
83 - 1000
84 - );
85 98 // Enfold theme compatibility to enable block editor for SureForms post type.
86 99 add_filter( 'avf_use_block_editor_for_post', [ $this, 'enable_block_editor_in_enfold_theme' ] );
87 100
88 101 // Add action links to the plugin page.
@@ -103,8 +116,9 @@
103 116 // Ajax callbacks for wp-pointer functionality.
104 117 add_action( 'wp_ajax_should_show_pointer', [ $this, 'pointer_should_show' ] );
105 118 add_action( 'wp_ajax_sureforms_dismiss_pointer', [ $this, 'pointer_dismissed' ] );
106 119 add_action( 'wp_ajax_sureforms_accept_cta', [ $this, 'pointer_accepted_cta' ] );
120 + add_action( 'wp_ajax_srfm_notice_response', [ $this, 'handle_notice_response' ] );
107 121
108 122 // Register dashboard widget only if there are recent entries.
109 123 add_action( 'admin_init', [ $this, 'maybe_register_dashboard_widget' ] );
110 124
@@ -109,8 +123,10 @@
109 123 add_action( 'admin_init', [ $this, 'maybe_register_dashboard_widget' ] );
110 124
111 125 // Save first form creation time stamp.
112 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' ] );
113 129 }
114 130
115 131 /**
116 132 * Get the first form creation time stamp.
@@ -461,8 +477,37 @@
461 477 <?php
462 478 }
463 479
464 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 + /**
465 510 * Add new form menu item.
466 511 *
467 512 * @return void
468 513 * @since 0.0.1
@@ -845,8 +890,9 @@
845 890 'webhook_test_connected' => Stripe_Helper::is_webhook_configured( 'test', true ),
846 891 'webhook_live_connected' => Stripe_Helper::is_webhook_configured( 'live', true ),
847 892 'is_transaction_present' => Stripe_Helper::is_transaction_present(),
848 893 'payment_currency' => Payment_Helper::get_currency(),
894 + 'currency_sign_position' => Payment_Helper::get_currency_sign_position(),
849 895 ]
850 896 ),
851 897 ];
852 898
@@ -855,8 +901,9 @@
855 901 $is_screen_sureforms_forms = Helper::validate_request_context( 'sureforms_forms', 'page' );
856 902 $is_screen_sureforms_form_settings = Helper::validate_request_context( 'sureforms_form_settings', 'page' );
857 903 $is_screen_sureforms_payments = Helper::validate_request_context( 'sureforms_payments', 'page' );
858 904 $is_screen_sureforms_entries = Helper::validate_request_context( SRFM_ENTRIES, 'page' );
905 + $is_screen_sureforms_learn = Helper::validate_request_context( 'sureforms_learn', 'page' );
859 906 $is_post_type_sureforms_form = SRFM_FORMS_POST_TYPE === $current_screen->post_type;
860 907
861 908 /**
862 909 * Check if the current screen is the SureForms Menu and AI Auth Email is present then we will add user type as registered.
@@ -868,9 +915,9 @@
868 915 'type' => ! empty( get_option( 'srfm_ai_auth_user_email' ) ) ? 'registered' : 'non-registered',
869 916 ];
870 917 }
871 918
872 - 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 ) {
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 ) {
873 920 $asset_handle = '-dashboard';
874 921
875 922 wp_enqueue_style( SRFM_SLUG . $asset_handle . '-font', 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap', [], SRFM_VER );
876 923
@@ -931,8 +978,24 @@
931 978 );
932 979 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
933 980 }
934 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 +
935 998 // Enqueue scripts for the forms page.
936 999 if ( $is_screen_sureforms_forms ) {
937 1000 $asset_handle = '-forms';
938 1001
@@ -1299,8 +1362,168 @@
1299 1362 }
1300 1363 }
1301 1364
1302 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 + /**
1303 1526 * Disables the capabilities for WPForms to avoid conflicts when enqueueing
1304 1527 * scripts and styles for WPForms.
1305 1528 *
1306 1529 * This function is intended to prevent any potential conflicts that may arise
@@ -1527,8 +1750,86 @@
1527 1750 $this->render_dashboard_widget_footer( $entries_data );
1528 1751 ?>
1529 1752 </div>
1530 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;
1531 1832 }
1532 1833
1533 1834 /**
1534 1835 * Get random premium feature text.