PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.1.1
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.1.1
2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 All 96 releases
← All changes | admin/admin.php +220 -1846 2.12.21.1.1 View file →
@@ -6,26 +6,19 @@
6 6 */
7 7
8 8 namespace SRFM\Admin;
9 9
10 -use Astra_Notices;
10 +use SRFM\Admin\Views\Entries_List_Table;
11 +use SRFM\Admin\Views\Single_Entry;
11 12 use SRFM\Inc\AI_Form_Builder\AI_Helper;
12 13 use SRFM\Inc\Database\Tables\Entries;
13 -use SRFM\Inc\Global_Settings\Global_Settings;
14 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\Smart_Tags;
15 +use SRFM\Inc\Post_Types;
19 16 use SRFM\Inc\Traits\Get_Instance;
20 17
21 18 if ( ! defined( 'ABSPATH' ) ) {
22 19 exit; // Exit if accessed directly.
23 20 }
24 -
25 -if ( ! class_exists( 'BSF_Admin_Notices' ) ) {
26 - require_once SRFM_DIR . 'inc/lib/astra-notices/class-bsf-admin-notices.php';
27 -}
28 21 /**
29 22 * Admin handler class.
30 23 *
31 24 * @since 0.0.1
@@ -33,50 +26,8 @@
33 26 class Admin {
34 27 use Get_Instance;
35 28
36 29 /**
37 - * Minimum number of forms or entries required to show the rating notice.
38 - *
39 - * @since 2.5.2
40 - */
41 - public const RATING_NOTICE_THRESHOLD = 3;
42 -
43 - /**
44 - * Inline CSS for Quill 1.x (react-quill) list markers.
45 - *
46 - * Quill 1.x renders bullet/numbered list markers via CSS ::before pseudo-elements,
47 - * whereas the vendor quill.snow.css targets .ql-ui child elements (Quill 2.x approach).
48 - * This constant is shared by enqueue_styles() and enqueue_scripts() to prevent drift.
49 - *
50 - * @since 2.5.2
51 - */
52 - public const QUILL_1X_INLINE_CSS = '.ql-editor ul,.ql-editor ol{padding-left:1.5em}.ql-editor ul>li,.ql-editor ol>li{list-style-type:none}.ql-editor ol li:not(.ql-direction-rtl),.ql-editor ul li:not(.ql-direction-rtl){padding-left:1.5em}.ql-editor ol li.ql-direction-rtl,.ql-editor ul li.ql-direction-rtl{padding-right:1.5em}.ql-editor ul>li::before{content:"\2022"}.ql-editor li::before{display:inline-block;white-space:nowrap;width:1.2em}.ql-editor li:not(.ql-direction-rtl)::before{margin-left:-1.5em;margin-right:.3em;text-align:right}.ql-editor li.ql-direction-rtl::before{margin-left:.3em;margin-right:-1.5em}.ql-editor ol li{counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;counter-increment:list-0}.ql-editor ol li::before{content:counter(list-0,decimal) ". "}.ql-editor ol li.ql-indent-1{counter-increment:list-1;counter-reset:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-1::before{content:counter(list-1,lower-alpha) ". "}.ql-editor ol li.ql-indent-2{counter-increment:list-2;counter-reset:list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-2::before{content:counter(list-2,lower-roman) ". "}.ql-editor ol li.ql-indent-3{counter-increment:list-3;counter-reset:list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-3::before{content:counter(list-3,decimal) ". "}.ql-editor ol li.ql-indent-4{counter-increment:list-4;counter-reset:list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-4::before{content:counter(list-4,lower-alpha) ". "}.ql-editor ol li.ql-indent-5{counter-increment:list-5;counter-reset:list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-5::before{content:counter(list-5,lower-roman) ". "}.ql-editor ol li.ql-indent-6{counter-increment:list-6;counter-reset:list-7 list-8 list-9}.ql-editor ol li.ql-indent-6::before{content:counter(list-6,decimal) ". "}.ql-editor ol li.ql-indent-7{counter-increment:list-7;counter-reset:list-8 list-9}.ql-editor ol li.ql-indent-7::before{content:counter(list-7,lower-alpha) ". "}.ql-editor ol li.ql-indent-8{counter-increment:list-8;counter-reset:list-9}.ql-editor ol li.ql-indent-8::before{content:counter(list-8,lower-roman) ". "}.ql-editor ol li.ql-indent-9{counter-increment:list-9}.ql-editor ol li.ql-indent-9::before{content:counter(list-9,decimal) ". "}';
53 -
54 - /**
55 - * Dashboard widget entries data.
56 - *
57 - * @var array
58 - * @since 1.9.1
59 - */
60 - private $dashboard_widget_data = [];
61 -
62 - /**
63 - * Cached result for whether the rating notice should display.
64 - *
65 - * @var bool|null
66 - * @since 2.5.2
67 - */
68 - private $should_show_rating = null;
69 -
70 - /**
71 - * SureForms Page Default permission.
72 - *
73 - * @var string
74 - * @since 1.12.2
75 - */
76 - private static $sureforms_page_default_capability = 'manage_options';
77 -
78 - /**
79 30 * Class constructor.
80 31 *
81 32 * @return void
82 33 * @since 0.0.1
@@ -84,19 +35,9 @@
84 35 public function __construct() {
85 36 add_action( 'admin_menu', [ $this, 'add_menu_page' ], 9 );
86 37 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
87 38 add_action( 'admin_menu', [ $this, 'settings_page' ] );
88 - add_action( 'admin_menu', [ $this, 'add_learn_page' ] );
89 39 add_action( 'admin_menu', [ $this, 'add_new_form' ] );
90 - add_action( 'admin_menu', [ $this, 'add_suremail_page' ] );
91 - if ( ! Helper::has_pro() ) {
92 - add_action( 'admin_menu', [ $this, 'add_quiz_page' ] );
93 - add_action( 'admin_menu', [ $this, 'add_survey_reports_page' ] );
94 - add_action( 'admin_menu', [ $this, 'add_partial_entries_page' ] );
95 - add_action( 'admin_menu', [ $this, 'add_upgrade_to_pro' ] );
96 - add_action( 'admin_footer', [ $this, 'add_upgrade_to_pro_target_attr' ] );
97 - }
98 -
99 40 add_filter( 'plugin_action_links', [ $this, 'add_settings_link' ], 10, 2 );
100 41 add_action( 'enqueue_block_assets', [ $this, 'enqueue_styles' ] );
101 42 add_action( 'admin_head', [ $this, 'enqueue_header_styles' ] );
102 43 add_filter( 'admin_body_class', [ $this, 'admin_template_picker_body_class' ] );
@@ -104,262 +45,24 @@
104 45 // this action is used to restrict Spectra's quick action bar on SureForms CPTS.
105 46 add_action( 'uag_enable_quick_action_sidebar', [ $this, 'restrict_spectra_quick_action_bar' ] );
106 47
107 48 add_action( 'current_screen', [ $this, 'enable_gutenberg_for_sureforms' ], 100 );
108 - // Register notices early for React pages (before admin_enqueue_scripts).
109 - add_action( 'admin_init', [ $this, 'register_pro_compatibility_notices' ], 5 );
110 - // Display notices on traditional WordPress admin pages.
111 49 add_action( 'admin_notices', [ $this, 'srfm_pro_version_compatibility' ] );
112 50
113 - // Enfold theme compatibility to enable block editor for SureForms post type.
114 - add_filter( 'avf_use_block_editor_for_post', [ $this, 'enable_block_editor_in_enfold_theme' ] );
115 -
116 - // Add action links to the plugin page.
117 - add_filter( 'plugin_action_links_' . SRFM_BASENAME, [ $this, 'add_action_links' ] );
118 - // Check if admin notification is enabled and add entries badge.
119 - $general_options = get_option( 'srfm_general_settings_options', [] );
120 - $admin_notification_on = isset( $general_options['srfm_admin_notification'] ) ? (bool) $general_options['srfm_admin_notification'] : true;
121 -
122 - if ( $admin_notification_on ) {
123 - add_action( 'admin_menu', [ $this, 'maybe_add_entries_badge' ], 99 );
124 - }
125 -
126 - add_filter( 'wpforms_current_user_can', [ $this, 'disable_wpforms_capabilities' ], 10, 3 );
127 -
128 - add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_pointer' ] );
129 - // Ajax callbacks for wp-pointer functionality.
130 - add_action( 'wp_ajax_should_show_pointer', [ $this, 'pointer_should_show' ] );
131 - add_action( 'wp_ajax_sureforms_dismiss_pointer', [ $this, 'pointer_dismissed' ] );
132 - add_action( 'wp_ajax_sureforms_accept_cta', [ $this, 'pointer_accepted_cta' ] );
133 - add_action( 'wp_ajax_srfm_notice_response', [ $this, 'handle_notice_response' ] );
134 - add_action( 'wp_ajax_srfm_ai_widget_usage', [ $this, 'track_ai_widget_usage' ] );
135 -
136 - // Register dashboard widget only if there are recent entries.
137 - add_action( 'admin_init', [ $this, 'maybe_register_dashboard_widget' ] );
138 -
139 - // Enqueue the AI quick draft widget script on the dashboard screen.
140 - add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_ai_dashboard_widget_assets' ] );
141 -
142 - // Save first form creation time stamp.
143 - add_action( 'admin_init', [ $this, 'save_first_form_creation_time_stamp' ] );
144 - add_action( 'admin_notices', [ $this, 'display_srfm_rating_notice' ] );
145 - add_action( 'admin_notices', [ $this, 'display_srfm_getting_started_notice' ] );
146 -
147 - /**
148 - * Suppress foreign (third-party) admin notices on SureForms admin screens.
149 - *
150 - * Some plugins (e.g. Ninja Forms) print large promotional banners on every
151 - * admin page via the admin_notices / all_admin_notices / network_admin_notices
152 - * hooks. These bleed onto SureForms' own React admin screens and break the UI.
153 - * We run at the EARLIEST priority on each notice hook (all third-party
154 - * callbacks are registered before these hooks fire, during admin_init /
155 - * plugin load) and strip the foreign ones before they are echoed, while
156 - * preserving SureForms' own notices. Scoped strictly to SureForms screens.
157 - */
158 - add_action( 'admin_notices', [ $this, 'suppress_foreign_admin_notices' ], PHP_INT_MIN );
159 - add_action( 'all_admin_notices', [ $this, 'suppress_foreign_admin_notices' ], PHP_INT_MIN );
160 - add_action( 'network_admin_notices', [ $this, 'suppress_foreign_admin_notices' ], PHP_INT_MIN );
51 + // Handle entry actions.
52 + add_action( 'admin_init', [ $this, 'handle_entry_actions' ] );
53 + add_action( 'admin_notices', [ Entries_List_Table::class, 'display_bulk_action_notice' ] );
161 54 }
162 55
163 56 /**
164 - * Remove third-party admin notices on SureForms admin screens.
165 - *
166 - * Iterates over the callbacks registered on the admin notice hooks and
167 - * removes any that are not owned by SureForms. A callback is considered
168 - * owned by SureForms when it belongs to a class in the `SRFM` / `SRFM_PRO`
169 - * namespaces or to the bundled `BSF_Admin_Notices` / `Astra_Notices`
170 - * notices library. SureForms' own notices are therefore preserved while
171 - * foreign promotional banners are suppressed.
172 - *
173 - * This callback is hooked at `PHP_INT_MIN` so that it runs first on each
174 - * notice hook and removes the foreign callbacks before WordPress echoes
175 - * them (WP_Hook honours removals made during iteration). It is strictly
176 - * scoped to SureForms admin screens via {@see Helper::is_sureforms_admin_page()}
177 - * so no other admin page is affected.
178 - *
179 - * @since 2.10.0
180 - * @return void
181 - */
182 - public function suppress_foreign_admin_notices() {
183 - // Bail early if we are not on a SureForms admin screen. This keeps the
184 - // suppression strictly scoped and avoids touching any other admin page.
185 - // is_sureforms_admin_page() covers the core screens (dashboard, add-new,
186 - // settings, entries, the form CPT); we additionally match any admin page
187 - // whose `page` slug is SureForms-owned (sureforms_* / srfm_*) so the
188 - // suppression also applies to the payments/quiz/survey/learn/SMTP screens.
189 - if ( ! Helper::is_sureforms_admin_page() && ! $this->is_sureforms_owned_admin_page() ) {
190 - return;
191 - }
192 -
193 - global $wp_filter;
194 -
195 - // The hook currently being fired (admin_notices, all_admin_notices or network_admin_notices).
196 - $current_hook = current_action();
197 -
198 - if ( empty( $current_hook ) || empty( $wp_filter[ $current_hook ] ) || ! ( $wp_filter[ $current_hook ] instanceof \WP_Hook ) ) {
199 - return;
200 - }
201 -
202 - foreach ( $wp_filter[ $current_hook ]->callbacks as $priority => $callbacks ) {
203 - foreach ( $callbacks as $callback ) {
204 - $function = $callback['function'] ?? null;
205 -
206 - // Never remove our own suppression callback.
207 - if ( is_array( $function ) && isset( $function[0] ) && $function[0] === $this && 'suppress_foreign_admin_notices' === $function[1] ) {
208 - continue;
209 - }
210 -
211 - // Preserve SureForms-owned notices, remove everything else.
212 - if ( $this->is_sureforms_owned_notice_callback( $function ) ) {
213 - continue;
214 - }
215 -
216 - remove_action( $current_hook, $function, $priority );
217 - }
218 - }
219 - }
220 -
221 - /**
222 - * Get the first form creation time stamp.
223 - *
224 - * @since 1.10.1
225 - * @return int|false
226 - */
227 - public static function get_first_form_creation_time_stamp() {
228 - return Helper::get_srfm_option( 'first_form_created_at', false );
229 - }
230 -
231 - /**
232 - * Check if the first form has been created.
233 - *
234 - * @since 1.10.1
235 - * @return bool
236 - */
237 - public static function is_first_form_created() {
238 - // Convert the first form creation time stamp to a boolean. If it exists, it will return true, otherwise false.
239 - $first_form_creation_time_stamp = self::get_first_form_creation_time_stamp();
240 -
241 - // If the first form creation time stamp is not set, return false.
242 - if ( ! $first_form_creation_time_stamp ) {
243 - return false; // No forms created yet.
244 - }
245 -
246 - // Check if the first form creation time stamp is a valid integer and greater than zero.
247 - return is_int( $first_form_creation_time_stamp ) && $first_form_creation_time_stamp > 0;
248 - }
249 -
250 - /**
251 - * Check and save the first form creation time stamp.
252 - * If not already saved.
253 - *
254 - * @since 1.10.1
255 - * @return void
256 - */
257 - public static function save_first_form_creation_time_stamp() {
258 - if ( ! Helper::current_user_can() || self::is_first_form_created() || ! defined( 'SRFM_FORMS_POST_TYPE' ) || ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) {
259 - return;
260 - }
261 -
262 - // Get the first form creation time from the database that is published.
263 - $query = new \WP_Query(
264 - [
265 - 'post_type' => SRFM_FORMS_POST_TYPE,
266 - 'posts_per_page' => 1,
267 - 'orderby' => 'date',
268 - 'order' => 'ASC',
269 - 'fields' => 'ids',
270 - 'post_status' => 'publish',
271 - ]
272 - );
273 -
274 - if ( ! empty( $query->posts ) && isset( $query->posts[0] ) ) {
275 - // Get the first post from the query result.
276 - $post_id = $query->posts[0];
277 - // Get the post creation time in GMT.
278 - $creation_time = get_post_field( 'post_date_gmt', $post_id );
279 - // Convert the creation time to a timestamp.
280 - $timestamp = strtotime( $creation_time );
281 -
282 - if ( ! $timestamp ) {
283 - return;
284 - }
285 -
286 - Helper::update_srfm_option( 'first_form_created_at', $timestamp );
287 - }
288 - }
289 -
290 - /**
291 - * Check if n days have passed since the first form creation.
292 - * This is used to determine if the dynamic nudges should be shown.
293 - *
294 - * @param int $days Number of days to check.
295 - * @since 1.10.1
296 - * @return bool
297 - */
298 - public static function check_first_form_creation_threshold( $days = 3 ) {
299 - $first_form_creation_time_stamp = self::get_first_form_creation_time_stamp();
300 -
301 - if ( ! $first_form_creation_time_stamp ) {
302 - return false; // No forms created yet.
303 - }
304 -
305 - /**
306 - * Calculate the number of days since the first form was created.
307 - */
308 - $days_from_creation = ( strtotime( current_time( 'mysql' ) ) - $first_form_creation_time_stamp ) / DAY_IN_SECONDS;
309 -
310 - // Return a boolean indicating if the number of days since creation is greater than the specified days.
311 - return $days_from_creation > $days;
312 - }
313 -
314 - /**
315 - * Show action on plugin page.
316 - *
317 - * @param array $links links.
318 - * @return array
319 - * @since 1.4.2
320 - */
321 - public function add_action_links( $links ) {
322 - if ( ! Helper::has_pro() ) {
323 - // Display upsell link if SureForms Pro is not installed.
324 - $upsell_link = Helper::get_sureforms_website_url( 'pricing', [ 'utm_medium' => 'plugin-list' ] );
325 -
326 - ob_start();
327 - ?>
328 - <a href="<?php echo esc_url( $upsell_link ); ?>" target="_blank" rel="noreferrer" class="sureforms-plugins-go-pro">
329 - <?php echo esc_html__( 'Get SureForms Pro', 'sureforms' ); ?>
330 - </a>
331 - <?php
332 - $links[] = trim( ob_get_clean() );
333 - }
334 -
335 - return $links;
336 - }
337 -
338 - /**
339 - * Enable block editor in Enfold theme for SureForms post type.
340 - *
341 - * @param bool $use_block_editor Whether to use block editor.
342 - * @since 1.3.1
343 - */
344 - public function enable_block_editor_in_enfold_theme( $use_block_editor ) {
345 - // if SureForms form post type then return true.
346 - if ( SRFM_FORMS_POST_TYPE === get_current_screen()->post_type ) {
347 - return true;
348 - }
349 - return $use_block_editor;
350 - }
351 -
352 - /**
353 57 * Enable Gutenberg for SureForms associated post types.
354 58 *
355 59 * @since 0.0.10
356 60 */
357 61 public function enable_gutenberg_for_sureforms() {
358 - /**
359 - * Check if the classic editor is enabled from Classic Editor plugin settings or Divi settings.
360 - */
361 - if ( 'block' === get_option( 'classic-editor-replace' ) || 'on' === get_option( 'et_enable_classic_editor' ) ) {
62 +
63 + // Check if the Classic Editor plugin is active and if it is set to replace the block editor.
64 + if ( ! class_exists( 'Classic_Editor' ) || 'block' === get_option( 'classic-editor-replace' ) ) {
362 65 return;
363 66 }
364 67
365 68 $srfm_post_types = apply_filters( 'srfm_enable_gutenberg_post_types', [ SRFM_FORMS_POST_TYPE ] );
@@ -398,15 +101,20 @@
398 101 * @return void
399 102 * @since 0.0.1
400 103 */
401 104 public function add_menu_page() {
402 - $menu_slug = 'sureforms_menu';
105 + if ( ! current_user_can( 'manage_options' ) ) {
106 + return;
107 + }
403 108
109 + $capability = 'manage_options';
110 + $menu_slug = 'sureforms_menu';
111 +
404 112 $logo = file_get_contents( plugin_dir_path( SRFM_FILE ) . 'images/icon.svg' );
405 113 add_menu_page(
406 114 __( 'SureForms', 'sureforms' ),
407 115 __( 'SureForms', 'sureforms' ),
408 - self::$sureforms_page_default_capability,
116 + 'edit_others_posts',
409 117 $menu_slug,
410 118 static function () {
411 119 },
412 120 'data:image/svg+xml;base64,' . base64_encode( $logo ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
@@ -417,9 +125,9 @@
417 125 add_submenu_page(
418 126 $menu_slug,
419 127 __( 'Dashboard', 'sureforms' ),
420 128 __( 'Dashboard', 'sureforms' ),
421 - self::$sureforms_page_default_capability,
129 + $capability,
422 130 $menu_slug,
423 131 [ $this, 'render_dashboard' ]
424 132 );
425 133 }
@@ -435,9 +143,9 @@
435 143 add_submenu_page(
436 144 'sureforms_menu',
437 145 __( 'Settings', 'sureforms' ),
438 146 __( 'Settings', 'sureforms' ),
439 - self::$sureforms_page_default_capability,
147 + 'edit_others_posts',
440 148 'sureforms_form_settings',
441 149 $callback
442 150 );
443 151
@@ -450,190 +158,8 @@
450 158 }
451 159 }
452 160
453 161 /**
454 - * Open to Upgrade to Pro submenu link in new tab.
455 - *
456 - * @return void
457 - * @since 1.6.1
458 - */
459 - public function add_upgrade_to_pro_target_attr() {
460 - ?>
461 - <script type="text/javascript">
462 - document.addEventListener('DOMContentLoaded', function () {
463 - // Upgrade link handler.
464 - // IMPORTANT: If this URL changes, also update it in the `add_upgrade_to_pro` function.
465 - const upgradeLink = document.querySelector('a[href*="https://sureforms.com/upgrade"]');
466 - if (upgradeLink) {
467 - upgradeLink.addEventListener('click', e => {
468 - e.preventDefault();
469 - window.open(upgradeLink.href, '_blank');
470 - });
471 - }
472 - });
473 - </script>
474 - <?php
475 - }
476 -
477 - /**
478 - * Add Upgrade to pro menu item.
479 - *
480 - * @return void
481 - * @since 1.6.1
482 - */
483 - public function add_upgrade_to_pro() {
484 - // The url used here is used as a selector for css to style the upgrade to pro submenu.
485 - // If you are changing this url, please make sure to update the css as well.
486 - $upgrade_url = Helper::get_sureforms_website_url( 'upgrade', [ 'utm_medium' => 'submenu_link_upgrade' ] );
487 -
488 - add_submenu_page(
489 - 'sureforms_menu',
490 - __( 'Upgrade', 'sureforms' ),
491 - __( 'Upgrade', 'sureforms' ),
492 - self::$sureforms_page_default_capability,
493 - $upgrade_url
494 - );
495 - }
496 -
497 - /**
498 - * Add Quiz empty state submenu page for free users.
499 - *
500 - * @return void
501 - * @since 2.7.0
502 - */
503 - public function add_quiz_page() {
504 - add_submenu_page(
505 - 'sureforms_menu',
506 - __( 'Quiz Entries', 'sureforms' ),
507 - __( 'Quizzes', 'sureforms' ) .
508 - ' <span style="color:#4ADE80;font-size:9px;font-weight:600;">' .
509 - esc_html__( 'New', 'sureforms' ) .
510 - '</span>',
511 - self::$sureforms_page_default_capability,
512 - 'sureforms_quiz_entries',
513 - [ $this, 'render_quiz_empty_state' ],
514 - 5
515 - );
516 - }
517 -
518 - /**
519 - * Quiz empty state page callback.
520 - *
521 - * @return void
522 - * @since 2.7.0
523 - */
524 - public function render_quiz_empty_state() {
525 - ?>
526 - <div id="srfm-quiz-entries-root" class="srfm-admin-wrapper"></div>
527 - <?php
528 - }
529 -
530 - /**
531 - * Add Survey Reports promotional submenu page for free users.
532 - *
533 - * @return void
534 - * @since 2.8.0
535 - */
536 - public function add_survey_reports_page() {
537 - add_submenu_page(
538 - 'sureforms_menu',
539 - __( 'Survey Reports', 'sureforms' ),
540 - __( 'Survey Reports', 'sureforms' ) .
541 - ' <span style="color:#4ADE80;font-size:9px;font-weight:600;">' .
542 - esc_html__( 'New', 'sureforms' ) .
543 - '</span>',
544 - self::$sureforms_page_default_capability,
545 - 'sureforms_survey_reports',
546 - [ $this, 'render_survey_empty_state' ],
547 - 6
548 - );
549 - }
550 -
551 - /**
552 - * Survey empty state page callback.
553 - *
554 - * @return void
555 - * @since 2.8.0
556 - */
557 - public function render_survey_empty_state() {
558 - ?>
559 - <div id="srfm-survey-empty-state-root" class="srfm-admin-wrapper"></div>
560 - <?php
561 - }
562 -
563 - /**
564 - * Add Partial Entries promotional submenu page for free users.
565 - *
566 - * @return void
567 - * @since 2.9.0
568 - */
569 - public function add_partial_entries_page() {
570 - add_submenu_page(
571 - 'sureforms_menu',
572 - __( 'Partial Entries', 'sureforms' ),
573 - __( 'Partial Entries', 'sureforms' ) .
574 - ' <span style="color:#4ADE80;font-size:9px;font-weight:600;">' .
575 - esc_html__( 'New', 'sureforms' ) .
576 - '</span>',
577 - self::$sureforms_page_default_capability,
578 - 'sureforms_partial_entries',
579 - [ $this, 'render_partial_entries_empty_state' ],
580 - 7
581 - );
582 - }
583 -
584 - /**
585 - * Partial Entries empty state page callback.
586 - *
587 - * @return void
588 - * @since 2.9.0
589 - */
590 - public function render_partial_entries_empty_state() {
591 - ?>
592 - <div id="srfm-partial-entries-empty-state-root" class="srfm-admin-wrapper"></div>
593 - <?php
594 - }
595 -
596 - /**
597 - * Add SMTP promotional submenu page.
598 - *
599 - * @return void
600 - * @since 1.7.1
601 - */
602 - public function add_suremail_page() {
603 - add_submenu_page(
604 - 'sureforms_menu',
605 - __( 'SMTP', 'sureforms' ),
606 - __( 'SMTP', 'sureforms' ),
607 - self::$sureforms_page_default_capability,
608 - 'sureforms_smtp',
609 - [ $this, 'suremail_page_callback' ]
610 - );
611 -
612 - // Get the current submenu page.
613 - $submenu_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
614 -
615 - // Check if SureMail is installed and active.
616 - if ( 'sureforms_smtp' === $submenu_page && file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' ) && is_plugin_active( 'suremails/suremails.php' ) ) {
617 - // Plugin is installed and active - redirect to SureMail dashboard.
618 - wp_safe_redirect( admin_url( 'options-general.php?page=suremail#/dashboard' ) );
619 - exit;
620 - }
621 - }
622 -
623 - /**
624 - * SMTP promotional page callback.
625 - *
626 - * @return void
627 - * @since 1.7.1
628 - */
629 - public function suremail_page_callback() {
630 - ?>
631 - <div id="srfm-suremail-container" class="srfm-admin-wrapper"></div>
632 - <?php
633 - }
634 -
635 - /**
636 162 * Render Admin Dashboard.
637 163 *
638 164 * @return void
639 165 * @since 0.0.1
@@ -638,11 +164,9 @@
638 164 * @return void
639 165 * @since 0.0.1
640 166 */
641 167 public function render_dashboard() {
642 - ?>
643 - <div id="srfm-dashboard-container" class="srfm-admin-wrapper"></div>
644 - <?php
168 + echo '<div id="srfm-dashboard-container"></div>';
645 169 }
646 170
647 171 /**
648 172 * Settings page callback.
@@ -650,43 +174,12 @@
650 174 * @return void
651 175 * @since 0.0.1
652 176 */
653 177 public function settings_page_callback() {
654 - ?>
655 - <div id="srfm-settings-container" class="srfm-admin-wrapper"></div>
656 - <?php
178 + echo '<div id="srfm-settings-container"></div>';
657 179 }
658 180
659 181 /**
660 - * Add Learn submenu page.
661 - *
662 - * @return void
663 - * @since 2.5.2
664 - */
665 - public function add_learn_page() {
666 - add_submenu_page(
667 - 'sureforms_menu',
668 - __( 'Learn', 'sureforms' ),
669 - __( 'Learn', 'sureforms' ),
670 - self::$sureforms_page_default_capability,
671 - 'sureforms_learn',
672 - [ $this, 'render_learn' ]
673 - );
674 - }
675 -
676 - /**
677 - * Learn page callback.
678 - *
679 - * @return void
680 - * @since 2.5.2
681 - */
682 - public function render_learn() {
683 - ?>
684 - <div id="srfm-learn-root" class="srfm-admin-wrapper"></div>
685 - <?php
686 - }
687 -
688 - /**
689 182 * Add new form menu item.
690 183 *
691 184 * @return void
692 185 * @since 0.0.1
@@ -693,62 +186,27 @@
693 186 */
694 187 public function add_new_form() {
695 188 add_submenu_page(
696 189 'sureforms_menu',
697 - __( 'Forms', 'sureforms' ),
698 - __( 'Forms', 'sureforms' ),
699 - self::$sureforms_page_default_capability,
700 - 'sureforms_forms',
701 - [ $this, 'render_forms' ],
702 - 1
703 - );
704 - add_submenu_page(
705 - 'sureforms_menu',
706 190 __( 'New Form', 'sureforms' ),
707 191 __( 'New Form', 'sureforms' ),
708 - self::$sureforms_page_default_capability,
192 + 'edit_others_posts',
709 193 'add-new-form',
710 194 [ $this, 'add_new_form_callback' ],
711 195 2
712 196 );
713 - $entries_hook = add_submenu_page(
197 + add_submenu_page(
714 198 'sureforms_menu',
715 199 __( 'Entries', 'sureforms' ),
716 200 __( 'Entries', 'sureforms' ),
717 - self::$sureforms_page_default_capability,
201 + 'edit_others_posts',
718 202 SRFM_ENTRIES,
719 203 [ $this, 'render_entries' ],
720 204 3
721 205 );
722 -
723 - add_submenu_page(
724 - 'sureforms_menu',
725 - __( 'Payments', 'sureforms' ),
726 - __( 'Payments', 'sureforms' ),
727 - self::$sureforms_page_default_capability,
728 - SRFM_PAYMENTS,
729 - [ $this, 'render_payments' ],
730 - 4
731 - );
732 -
733 - if ( $entries_hook ) {
734 - add_action( 'load-' . $entries_hook, [ $this, 'mark_entries_page_visit' ] );
735 - }
736 206 }
737 207
738 208 /**
739 - * Payments page callback.
740 - *
741 - * @return void
742 - * @since 2.0.0
743 - */
744 - public function render_payments() {
745 - ?>
746 - <div id="srfm-payments-react-container" class="srfm-admin-wrapper"></div>
747 - <?php
748 - }
749 -
750 - /**
751 209 * Add new form mentu item callback.
752 210 *
753 211 * @return void
754 212 * @since 0.0.1
@@ -753,109 +211,44 @@
753 211 * @return void
754 212 * @since 0.0.1
755 213 */
756 214 public function add_new_form_callback() {
757 - ?>
758 - <div id="srfm-add-new-form-container" class="srfm-admin-wrapper"></div>
759 - <?php
215 + echo '<div id="srfm-add-new-form-container"></div>';
760 216 }
761 217
762 218 /**
763 - * Forms page callback.
764 - *
765 - * @return void
766 - * @since 2.0.0
767 - */
768 - public function render_forms() {
769 - ?>
770 - <div id="srfm-forms-root" class="srfm-admin-wrapper"></div>
771 - <?php
772 - }
773 -
774 - /**
775 219 * Entries page callback.
776 220 *
777 221 * @since 0.0.13
778 - * @since 2.0.0 - Updated the entries UI and the function definition.
779 222 * @return void
780 223 */
781 224 public function render_entries() {
782 - echo '<div id="srfm-entries-root"></div>';
783 - }
784 -
785 - /**
786 - * Add notification badge to SureForms menu when there are new entries.
787 - *
788 - * @since 1.7.3
789 - * @return void
790 - */
791 - public function maybe_add_entries_badge() {
792 - if ( ! Helper::current_user_can() ) {
225 + // Render single entry view.
226 + // Adding the phpcs ignore nonce verification as no database operations are performed in this function, it is used to display the single entry view.
227 + if ( isset( $_GET['entry_id'] ) && is_numeric( $_GET['entry_id'] ) && isset( $_GET['view'] ) && 'details' === $_GET['view'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
228 + $single_entry_view = new Single_Entry();
229 + $single_entry_view->render();
793 230 return;
794 231 }
795 232
796 - // If currently viewing the entries listing page, mark it as visited and skip the badge.
797 - if ( isset( $_GET['page'] ) && SRFM_ENTRIES === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only checking the page slug.
798 - $this->mark_entries_page_visit();
233 + // Render all entries view.
234 + $entries_table = new Entries_List_Table();
235 + $entries_table->prepare_items();
236 + echo '<div class="wrap"><h1 class="wp-heading-inline">' . esc_html__( 'Entries', 'sureforms' ) . '</h1>';
237 + if ( empty( $entries_table->all_entries_count ) && empty( $entries_table->trash_entries_count ) ) {
238 + $instance = Post_Types::get_instance();
239 + $instance->sureforms_render_blank_state( SRFM_ENTRIES );
240 + $instance->get_blank_state_styles();
799 241 return;
800 242 }
801 -
802 - $srfm_options = get_option( 'srfm_options', [] );
803 - $last_visit = isset( $srfm_options['entries_last_visited'] ) ? absint( $srfm_options['entries_last_visited'] ) : 0;
804 - $new_entries = Entries::get_entries_count_after( $last_visit );
805 -
806 - if ( $new_entries <= 0 ) {
807 - return;
808 - }
809 -
810 - global $menu;
811 - foreach ( $menu as $index => $item ) {
812 - if ( isset( $item[2] ) && 'sureforms_menu' === $item[2] ) {
813 - ob_start();
814 - ?>
815 - <span class="srfm-update-dot"></span>
816 - <?php
817 - $dot_html = ob_get_clean();
818 - // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for menu item.
819 - $menu[ $index ][0] .= $dot_html;
820 - break;
821 - }
822 - }
823 -
824 - global $submenu;
825 - if ( isset( $submenu['sureforms_menu'] ) ) {
826 - foreach ( $submenu['sureforms_menu'] as $index => $sub_item ) {
827 - if ( isset( $sub_item[2] ) && SRFM_ENTRIES === $sub_item[2] ) {
828 - ob_start();
829 - ?>
830 - <span class="update-plugins count-<?php echo absint( $new_entries ); ?>">
831 - <span class="plugin-count"><?php echo absint( $new_entries ); ?></span>
832 - </span>
833 - <?php
834 - $badge_html = ob_get_clean();
835 - // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for submenu item.
836 - $submenu['sureforms_menu'][ $index ][0] .= $badge_html;
837 - break;
838 - }
839 - }
840 - }
243 + echo '<form method="get">';
244 + echo '<input type="hidden" name="page" value="sureforms_entries">';
245 + $entries_table->display();
246 + echo '</form>';
247 + echo '</div>';
841 248 }
842 249
843 250 /**
844 - * Mark the user's visit to the entries page.
845 - *
846 - * @since 1.7.3
847 - * @return void
848 - */
849 - public function mark_entries_page_visit() {
850 - if ( Helper::current_user_can() ) {
851 - $srfm_options = get_option( 'srfm_options', [] );
852 - $srfm_options['entries_last_visited'] = time();
853 - \SRFM\Inc\Helper::update_admin_settings_option( 'srfm_options', $srfm_options );
854 - }
855 - }
856 -
857 - /**
858 251 * Adds a settings link to the plugin action links on the plugins page.
859 252 *
860 253 * @param array $links An array of plugin action links.
861 254 * @param string $file The plugin file path.
@@ -863,22 +256,15 @@
863 256 * @since 0.0.1
864 257 */
865 258 public function add_settings_link( $links, $file ) {
866 259 if ( 'sureforms/sureforms.php' === $file ) {
867 - ob_start();
868 - ?>
869 - <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_form_settings&tab=general-settings' ) ); ?>">
870 - <?php echo esc_html__( 'Settings', 'sureforms' ); ?>
871 - </a>
872 - <?php
873 - $settings_link_html = ob_get_clean();
874 - $plugin_links = apply_filters(
260 + $plugin_links = apply_filters(
875 261 'sureforms_plugin_action_links',
876 262 [
877 - 'sureforms_settings' => $settings_link_html,
263 + 'sureforms_settings' => '<a href="' . esc_url( admin_url( 'admin.php?page=sureforms_form_settings&tab=general-settings' ) ) . '">' . esc_html__( 'Settings', 'sureforms' ) . '</a>',
878 264 ]
879 265 );
880 - $links = array_merge( $plugin_links, $links );
266 + $links = array_merge( $plugin_links, $links );
881 267 }
882 268 return $links;
883 269 }
884 270
@@ -908,9 +294,8 @@
908 294 wp_enqueue_style( SRFM_SLUG . '-backend-blocks', $css_uri . 'blocks/default/backend' . $file_prefix . '.css', [], SRFM_VER );
909 295 wp_enqueue_style( SRFM_SLUG . '-intl', $vendor_css_uri . 'intl/intlTelInput-backend.min.css', [], SRFM_VER );
910 296 wp_enqueue_style( SRFM_SLUG . '-common', $css_uri . 'common' . $file_prefix . '.css', [], SRFM_VER );
911 297 wp_enqueue_style( SRFM_SLUG . '-reactQuill', $vendor_css_uri . 'quill/quill.snow.css', [], SRFM_VER );
912 - wp_add_inline_style( SRFM_SLUG . '-reactQuill', self::QUILL_1X_INLINE_CSS );
913 298 wp_enqueue_style( SRFM_SLUG . '-single-form-modal', $css_uri . 'single-form-setting' . $file_prefix . '.css', [], SRFM_VER );
914 299
915 300 // if version is equal to or lower than 6.6.2 then add compatibility css.
916 301 if ( version_compare( $wp_version, '6.6.2', '<=' ) ) {
@@ -934,9 +319,9 @@
934 319 public function get_breadcrumbs_for_current_page() {
935 320 global $post, $pagenow;
936 321 $breadcrumbs = [];
937 322
938 - if ( 'admin.php' === $pagenow && isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
323 + if ( 'admin.php' === $pagenow && isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
939 324 $page_title = get_admin_page_title();
940 325 $breadcrumbs[] = [
941 326 'title' => $page_title,
942 327 'link' => '',
@@ -949,9 +334,9 @@
949 334 'title' => $post_type_plural,
950 335 'link' => admin_url( 'edit.php?post_type=' . $post_type_obj->name ),
951 336 ];
952 337
953 - if ( 'edit.php' === $pagenow && ! isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
338 + if ( 'edit.php' === $pagenow && ! isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
954 339 $breadcrumbs[ count( $breadcrumbs ) - 1 ]['link'] = '';
955 340 } else {
956 341 $breadcrumbs[] = [
957 342 /* Translators: Post Title. */
@@ -987,145 +372,44 @@
987 372 public function enqueue_scripts() {
988 373 $current_screen = get_current_screen();
989 374 global $wp_version;
990 375
991 - $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
992 - $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
993 - $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
994 - $is_rtl = is_rtl();
995 - $rtl = $is_rtl ? '-rtl' : '';
376 + $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
377 + $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
378 + $js_uri = SRFM_URL . 'assets/js/' . $dir_name . '/';
379 + $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
996 380
997 381 /**
998 382 * List of the handles in which we need to add translation compatibility.
999 383 */
1000 384 $script_translations_handlers = [];
1001 - $onboarding_instance = Onboarding::get_instance();
1002 - $current_user = wp_get_current_user();
1003 385
386 + /* RTL */
387 + if ( is_rtl() ) {
388 + $file_prefix .= '-rtl';
389 + }
390 +
1004 391 $localization_data = [
1005 - 'site_url' => get_site_url(),
1006 - 'current_user_login' => $current_user->user_login ?? '',
1007 - 'website_lead_details' => [
1008 - 'first_name' => $current_user->first_name ?? '',
1009 - 'last_name' => $current_user->last_name ?? '',
1010 - 'email' => $current_user->user_email ?? '',
1011 - ],
1012 - 'breadcrumbs' => $this->get_breadcrumbs_for_current_page(),
1013 - 'sureforms_dashboard_url' => admin_url( '/admin.php?page=sureforms_menu' ),
1014 - 'plugin_version' => SRFM_VER,
1015 - 'global_settings_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
1016 - 'is_pro_active' => Helper::has_pro(),
1017 - 'is_first_form_created' => self::is_first_form_created(),
1018 - 'check_three_days_threshold' => self::check_first_form_creation_threshold(),
1019 - 'check_eight_days_threshold' => self::check_first_form_creation_threshold( 8 ),
1020 - 'pro_plugin_version' => Helper::has_pro() ? SRFM_PRO_VER : '',
1021 - 'pro_plugin_name' => Helper::has_pro() && defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro',
1022 - 'sureforms_pricing_page' => Helper::get_sureforms_website_url( 'pricing' ),
1023 - 'field_spacing_vars' => Helper::get_css_vars(),
1024 - 'is_ver_lower_than_6_7' => version_compare( $wp_version, '6.6.2', '<=' ),
1025 - 'integrations' => Helper::sureforms_get_integration(),
1026 - 'rotating_plugin_banner' => Helper::get_rotating_plugin_banner(),
1027 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
1028 - 'sf_plugin_manager_nonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
1029 - 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
1030 - 'plugin_activating_text' => __( 'Activating...', 'sureforms' ),
1031 - 'plugin_activated_text' => __( 'Activated', 'sureforms' ),
1032 - 'plugin_activate_text' => __( 'Activate', 'sureforms' ),
1033 - 'plugin_installing_text' => __( 'Installing...', 'sureforms' ),
1034 - 'plugin_installed_text' => __( 'Installed', 'sureforms' ),
1035 - 'privacy_policy_url' => Helper::get_sureforms_website_url( 'privacy-policy/' ),
1036 - 'is_rtl' => $is_rtl,
1037 - 'onboarding_completed' => method_exists( $onboarding_instance, 'get_onboarding_status' ) ? $onboarding_instance->get_onboarding_status() : false,
1038 - 'migration_banner_dismissed' => method_exists( $onboarding_instance, 'is_migration_banner_dismissed' ) ? $onboarding_instance->is_migration_banner_dismissed() : false,
1039 - 'migration_settings_url' => admin_url( 'admin.php?page=sureforms_form_settings&tab=migration-settings' ),
1040 - 'onboarding_redirect' => isset( $_GET['srfm-activation-redirect'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce is not required for the activation redirection.
1041 - 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
1042 - 'general_settings_url' => admin_url( '/options-general.php' ),
1043 - 'additional_header_nav_items' => [],
1044 - // Smart tags for the Global Defaults email notification fields.
1045 - // srfm_block_data is only available in the block editor; these keys
1046 - // make the same data accessible on the settings page via srfm_admin.
1047 - 'smart_tags_array' => Smart_Tags::smart_tag_list(),
1048 - 'smart_tags_array_email' => Smart_Tags::email_smart_tag_list(),
1049 - // Default confirmation message HTML (icon + heading + text) used as
1050 - // the initial React state before the settings API response arrives.
1051 - 'default_confirmation_message' => Global_Settings::get_default_confirmation_message(),
1052 - 'payments' => apply_filters(
1053 - 'srfm_admin_localize_payments_data',
1054 - [
1055 - 'stripe_connected' => Stripe_Helper::is_stripe_connected(),
1056 - 'stripe_mode' => Stripe_Helper::get_stripe_mode(),
1057 - 'stripe_connect_url' => Stripe_Helper::get_stripe_settings_url(),
1058 - 'currencies_data' => Payment_Helper::get_all_currencies_data(),
1059 - 'zero_decimal_currencies' => Payment_Helper::get_zero_decimal_currencies(),
1060 - 'webhook_url' => Stripe_Helper::get_webhook_url(),
1061 - 'webhook_test_connected' => Stripe_Helper::is_webhook_configured( 'test', true ),
1062 - 'webhook_live_connected' => Stripe_Helper::is_webhook_configured( 'live', true ),
1063 - 'is_transaction_present' => Stripe_Helper::is_transaction_present(),
1064 - 'payment_currency' => Payment_Helper::get_currency(),
1065 - 'currency_sign_position' => Payment_Helper::get_currency_sign_position(),
1066 - ]
1067 - ),
1068 - 'mcp_adapter_status' => file_exists( WP_PLUGIN_DIR . '/mcp-adapter/mcp-adapter.php' )
1069 - ? ( is_plugin_active( 'mcp-adapter/mcp-adapter.php' ) ? 'active' : 'installed' )
1070 - : 'not_installed',
1071 - 'mcp_endpoint_url' => esc_url_raw( rest_url( 'sureforms/v1/mcp' ) ),
392 + 'site_url' => get_site_url(),
393 + 'breadcrumbs' => $this->get_breadcrumbs_for_current_page(),
394 + 'sureforms_dashboard_url' => admin_url( '/admin.php?page=sureforms_menu' ),
395 + 'plugin_version' => SRFM_VER,
396 + 'global_settings_nonce' => current_user_can( 'manage_options' ) ? wp_create_nonce( 'wp_rest' ) : '',
397 + 'is_pro_active' => defined( 'SRFM_PRO_VER' ),
398 + 'pro_plugin_version' => defined( 'SRFM_PRO_VER' ) ? SRFM_PRO_VER : '',
399 + 'pro_plugin_name' => defined( 'SRFM_PRO_VER' ) && defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro',
400 + 'sureforms_pricing_page' => $this->get_sureforms_website_url( 'pricing' ),
401 + 'field_spacing_vars' => Helper::get_css_vars(),
402 + 'is_ver_lower_than_6_7' => version_compare( $wp_version, '6.6.2', '<=' ),
1072 403 ];
1073 404
1074 - $is_screen_sureforms_menu = Helper::validate_request_context( 'sureforms_menu', 'page' );
1075 - $is_screen_add_new_form = Helper::validate_request_context( 'add-new-form', 'page' );
1076 - $is_screen_sureforms_forms = Helper::validate_request_context( 'sureforms_forms', 'page' );
1077 - $is_screen_sureforms_form_settings = Helper::validate_request_context( 'sureforms_form_settings', 'page' );
1078 - $is_screen_sureforms_payments = Helper::validate_request_context( 'sureforms_payments', 'page' );
1079 - $is_screen_sureforms_entries = Helper::validate_request_context( SRFM_ENTRIES, 'page' );
1080 - $is_screen_sureforms_learn = Helper::validate_request_context( 'sureforms_learn', 'page' );
1081 - $is_screen_quiz_empty_state = Helper::validate_request_context( 'sureforms_quiz_entries', 'page' );
1082 - $is_screen_survey_empty_state = Helper::validate_request_context( 'sureforms_survey_reports', 'page' );
1083 - $is_screen_partial_entries_empty_state = Helper::validate_request_context( 'sureforms_partial_entries', 'page' );
1084 - $is_post_type_sureforms_form = SRFM_FORMS_POST_TYPE === $current_screen->post_type;
405 + $is_screen_sureforms_menu = Helper::validate_request_context( 'sureforms_menu', 'page' );
406 + $is_screen_add_new_form = Helper::validate_request_context( 'add-new-form', 'page' );
407 + $is_screen_sureforms_form_settings = Helper::validate_request_context( 'sureforms_form_settings', 'page' );
408 + $is_screen_sureforms_entries = Helper::validate_request_context( SRFM_ENTRIES, 'page' );
409 + $is_post_type_sureforms_form = SRFM_FORMS_POST_TYPE === $current_screen->post_type;
1085 410
1086 - /**
1087 - * Check if the current screen is the SureForms Menu and AI Auth Email is present then we will add user type as registered.
1088 - * Compatibility with existing UI code that checks for this condition.
1089 - */
1090 - if ( $is_screen_sureforms_menu ) {
1091 - // If email is stored send the user type as registered else non-registered.
1092 - $localization_data['srfm_ai_details'] = [
1093 - 'type' => ! empty( get_option( 'srfm_ai_auth_user_email' ) ) ? 'registered' : 'non-registered',
1094 - ];
1095 - }
1096 -
1097 - // Add the Quizzes and Survey Reports nav items when pro is not active.
1098 - if ( ! Helper::has_pro() ) {
1099 - $localization_data['additional_header_nav_items'][] = [
1100 - 'slug' => 'sureforms_quiz_entries',
1101 - 'text' => __( 'Quizzes', 'sureforms' ),
1102 - 'link' => admin_url( 'admin.php?page=sureforms_quiz_entries' ),
1103 - ];
1104 - $localization_data['additional_header_nav_items'][] = [
1105 - 'slug' => 'sureforms_survey_reports',
1106 - 'text' => __( 'Survey Reports', 'sureforms' ),
1107 - 'link' => admin_url( 'admin.php?page=sureforms_survey_reports' ),
1108 - ];
1109 - $localization_data['additional_header_nav_items'][] = [
1110 - 'slug' => 'sureforms_partial_entries',
1111 - 'text' => __( 'Partial Entries', 'sureforms' ),
1112 - 'link' => admin_url( 'admin.php?page=sureforms_partial_entries' ),
1113 - ];
1114 - }
1115 -
1116 - $is_sureforms_screen = $is_screen_sureforms_menu || $is_post_type_sureforms_form || $is_screen_add_new_form || $is_screen_sureforms_forms || $is_screen_sureforms_form_settings || $is_screen_sureforms_entries || $is_screen_sureforms_payments || $is_screen_sureforms_learn || $is_screen_quiz_empty_state || $is_screen_survey_empty_state || $is_screen_partial_entries_empty_state;
1117 -
1118 - /**
1119 - * Filter to allow extending the SureForms dashboard screen check.
1120 - *
1121 - * @since 2.6.0
1122 - *
1123 - * @param bool $is_sureforms_screen Whether the current screen is a SureForms dashboard screen.
1124 - */
1125 - $is_sureforms_screen = apply_filters( 'srfm_is_dashboard_screen', $is_sureforms_screen );
1126 -
1127 - if ( $is_sureforms_screen ) {
411 + if ( $is_screen_sureforms_menu || $is_post_type_sureforms_form || $is_screen_add_new_form || $is_screen_sureforms_form_settings || $is_screen_sureforms_entries ) {
1128 412 $asset_handle = '-dashboard';
1129 413
1130 414 wp_enqueue_style( SRFM_SLUG . $asset_handle . '-font', 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap', [], SRFM_VER );
1131 415
@@ -1153,10 +437,9 @@
1153 437 update_option( 'srfm_pro_license_status', $current_license_status );
1154 438 }
1155 439 }
1156 440
1157 - $localization_data['security_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=security-settings&subpage=recaptcha' );
1158 - $localization_data['integration_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=integration-settings' );
441 + $localization_data['security_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=security-settings' );
1159 442 wp_localize_script(
1160 443 SRFM_SLUG . $asset_handle,
1161 444 SRFM_SLUG . '_admin',
1162 445 apply_filters(
@@ -1164,169 +447,57 @@
1164 447 $localization_data
1165 448 )
1166 449 );
1167 450 wp_enqueue_style( SRFM_SLUG . '-dashboard', SRFM_URL . 'assets/build/dashboard.css', [], SRFM_VER, 'all' );
451 +
1168 452 }
1169 453
1170 - if ( $is_screen_sureforms_form_settings || $is_screen_sureforms_forms ) {
1171 - wp_enqueue_style( SRFM_SLUG . '-settings', $css_uri . 'backend/settings' . $file_prefix . $rtl . '.css', [], SRFM_VER );
454 + if ( $is_screen_sureforms_form_settings ) {
455 + wp_enqueue_style( SRFM_SLUG . '-settings', $css_uri . 'backend/settings' . $file_prefix . '.css', [], SRFM_VER );
456 +
457 + // if version is equal to or lower than 6.6.2 then add compatibility css.
458 + if ( version_compare( $wp_version, '6.6.2', '<=' ) ) {
459 + $srfm_inline_css = '
460 + .srfm-settings-page-container
461 + .components-toggle-control {
462 + .components-base-control__help{
463 + margin-left: 4em;
464 + }
465 + }
466 + }
467 + ';
468 + wp_add_inline_style( SRFM_SLUG . '-settings', $srfm_inline_css );
469 + }
1172 470 }
1173 471
1174 472 // Enqueue styles for the entries page.
1175 473 if ( $is_screen_sureforms_entries ) {
1176 474 $asset_handle = '-entries';
475 + wp_enqueue_style( SRFM_SLUG . $asset_handle, $css_uri . 'backend/entries' . $file_prefix . '.css', [], SRFM_VER );
1177 476 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/entries.js', $script_info['dependencies'], SRFM_VER, true );
1178 477
1179 - wp_localize_script(
1180 - SRFM_SLUG . $asset_handle,
1181 - SRFM_SLUG . '_admin',
1182 - apply_filters(
1183 - SRFM_SLUG . '_admin_filter',
1184 - $localization_data
1185 - )
1186 - );
1187 478 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
1188 479 }
1189 480
1190 - // Enqueue scripts for the learn page.
1191 - if ( $is_screen_sureforms_learn ) {
1192 - $asset_handle = '-learn';
1193 - wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/learn.js', $script_info['dependencies'], SRFM_VER, true );
481 + // Admin Submenu Styles.
482 + wp_enqueue_style( SRFM_SLUG . '-admin', $css_uri . 'backend/admin' . $file_prefix . '.css', [], SRFM_VER );
1194 483
1195 - wp_localize_script(
1196 - SRFM_SLUG . $asset_handle,
1197 - SRFM_SLUG . '_admin',
1198 - apply_filters(
1199 - SRFM_SLUG . '_admin_filter',
1200 - $localization_data
1201 - )
1202 - );
1203 - $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
1204 - }
484 + if ( 'edit-' . SRFM_FORMS_POST_TYPE === $current_screen->id ) {
485 + $asset_handle = 'page_header';
1205 486
1206 - // Enqueue scripts for the forms page.
1207 - if ( $is_screen_sureforms_forms ) {
1208 - $asset_handle = '-forms';
1209 -
1210 - $script_asset_path = SRFM_DIR . 'assets/build/forms.asset.php';
1211 - $script_info = file_exists( $script_asset_path )
1212 - ? include $script_asset_path
1213 - : [
1214 - 'dependencies' => [],
1215 - 'version' => SRFM_VER,
1216 - ];
1217 -
1218 - wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/forms.js', $script_info['dependencies'], SRFM_VER, true );
1219 - wp_localize_script(
1220 - SRFM_SLUG . $asset_handle,
1221 - SRFM_SLUG . '_admin',
1222 - apply_filters(
1223 - SRFM_SLUG . '_admin_filter',
1224 - $localization_data
1225 - )
1226 - );
1227 - wp_enqueue_style( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/forms.css', [], SRFM_VER, 'all' );
1228 -
1229 - $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
1230 - }
1231 -
1232 - // Enqueue scripts for the SureMail promotional page.
1233 - $is_screen_sureforms_smtp = Helper::validate_request_context( 'sureforms_smtp', 'page' );
1234 - if ( $is_screen_sureforms_smtp ) {
1235 - $asset_handle = 'suremail';
1236 -
1237 487 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
1238 488 $script_info = file_exists( $script_asset_path )
1239 - ? include $script_asset_path
1240 - : [
1241 - 'dependencies' => [],
1242 - 'version' => SRFM_VER,
1243 - ];
1244 -
1245 - wp_enqueue_script( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
1246 - wp_enqueue_style( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/suremail.css', [], SRFM_VER, 'all' );
1247 -
1248 - // Localize script for SureMail page.
1249 - $suremail_localization_data = [
1250 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
1251 - 'admin_url' => admin_url(),
1252 - 'suremail_url' => 'https://sureforms.com/suremail/',
1253 - 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
1254 - 'sfPluginManagerNonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
1255 - 'suremail_status' => file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' )
1256 - ? ( is_plugin_active( 'suremails/suremails.php' ) ? 'active' : 'installed' )
1257 - : 'not_installed',
489 + ? include $script_asset_path
490 + : [
491 + 'dependencies' => [],
492 + 'version' => SRFM_VER,
1258 493 ];
494 + wp_enqueue_script( SRFM_SLUG . '-form-page-header', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
495 + wp_enqueue_style( SRFM_SLUG . '-form-archive-styles', $css_uri . 'form-archive-styles' . $file_prefix . '.css', [], SRFM_VER );
1259 496
1260 - wp_localize_script(
1261 - SRFM_SLUG . '-suremail',
1262 - SRFM_SLUG . '_admin',
1263 - apply_filters(
1264 - SRFM_SLUG . '_suremail_admin_filter',
1265 - $suremail_localization_data
1266 - )
1267 - );
1268 -
1269 - $script_translations_handlers[] = SRFM_SLUG . '-suremail';
497 + $script_translations_handlers[] = SRFM_SLUG . '-form-page-header';
1270 498 }
1271 499
1272 - // Enqueue scripts for the Quiz empty state page (free users only).
1273 - if ( $is_screen_quiz_empty_state && ! Helper::has_pro() ) {
1274 - $asset_handle = 'quizEmptyState';
1275 -
1276 - $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
1277 - $script_info = file_exists( $script_asset_path )
1278 - ? include $script_asset_path
1279 - : [
1280 - 'dependencies' => [],
1281 - 'version' => SRFM_VER,
1282 - ];
1283 -
1284 - wp_enqueue_script( SRFM_SLUG . '-quiz-empty-state', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
1285 - wp_enqueue_style( SRFM_SLUG . '-quiz-empty-state', SRFM_URL . 'assets/build/' . $asset_handle . '.css', [], SRFM_VER, 'all' );
1286 -
1287 - $script_translations_handlers[] = SRFM_SLUG . '-quiz-empty-state';
1288 - }
1289 -
1290 - // Enqueue scripts for the Survey Reports empty state page (free users only).
1291 - if ( $is_screen_survey_empty_state && ! Helper::has_pro() ) {
1292 - $asset_handle = 'surveyEmptyState';
1293 -
1294 - $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
1295 - $script_info = file_exists( $script_asset_path )
1296 - ? include $script_asset_path
1297 - : [
1298 - 'dependencies' => [],
1299 - 'version' => SRFM_VER,
1300 - ];
1301 -
1302 - wp_enqueue_script( SRFM_SLUG . '-survey-empty-state', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
1303 - wp_enqueue_style( SRFM_SLUG . '-survey-empty-state', SRFM_URL . 'assets/build/' . $asset_handle . '.css', [], SRFM_VER, 'all' );
1304 -
1305 - $script_translations_handlers[] = SRFM_SLUG . '-survey-empty-state';
1306 - }
1307 -
1308 - // Enqueue scripts for the Partial Entries empty state page (free users only).
1309 - if ( $is_screen_partial_entries_empty_state && ! Helper::has_pro() ) {
1310 - $asset_handle = 'partialEntriesEmptyState';
1311 -
1312 - $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
1313 - $script_info = file_exists( $script_asset_path )
1314 - ? include $script_asset_path
1315 - : [
1316 - 'dependencies' => [],
1317 - 'version' => SRFM_VER,
1318 - ];
1319 -
1320 - wp_enqueue_script( SRFM_SLUG . '-partial-entries-empty-state', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
1321 - wp_enqueue_style( SRFM_SLUG . '-partial-entries-empty-state', SRFM_URL . 'assets/build/' . $asset_handle . '.css', [], SRFM_VER, 'all' );
1322 -
1323 - $script_translations_handlers[] = SRFM_SLUG . '-partial-entries-empty-state';
1324 - }
1325 -
1326 - // Admin Submenu Styles.
1327 - wp_enqueue_style( SRFM_SLUG . '-admin', $css_uri . 'backend/admin' . $file_prefix . $rtl . '.css', [], SRFM_VER );
1328 -
1329 500 if ( $is_screen_sureforms_form_settings ) {
1330 501 $asset_handle = 'settings';
1331 502
1332 503 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
@@ -1337,28 +508,59 @@
1337 508 'version' => SRFM_VER,
1338 509 ];
1339 510
1340 511 wp_enqueue_script( SRFM_SLUG . '-settings', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
512 + wp_enqueue_style( SRFM_SLUG . '-setting-styles', SRFM_URL . 'assets/build/' . $asset_handle . '.css', [ 'wp-components' ], SRFM_VER, 'all' );
1341 513 wp_localize_script(
1342 514 SRFM_SLUG . '-settings',
1343 515 SRFM_SLUG . '_admin',
1344 - apply_filters(
1345 - SRFM_SLUG . '_admin_filter',
1346 - $localization_data
1347 - )
516 + $localization_data
1348 517 );
1349 518
1350 - // Enqueue Tailwind and Quill editor styles for the settings page.
1351 - wp_enqueue_style( SRFM_SLUG . '-settings-build', SRFM_URL . 'assets/build/settings.css', [], SRFM_VER, 'all' );
1352 - wp_enqueue_style( SRFM_SLUG . '-reactQuill', SRFM_URL . 'assets/css/minified/deps/quill/quill.snow.css', [], SRFM_VER );
1353 - wp_add_inline_style( SRFM_SLUG . '-reactQuill', self::QUILL_1X_INLINE_CSS );
519 + $script_translations_handlers[] = SRFM_SLUG . '-settings';
520 + }
521 + if ( 'edit-' . SRFM_FORMS_POST_TYPE === $current_screen->id ) {
522 + wp_enqueue_script( SRFM_SLUG . '-form-archive', $js_uri . 'form-archive' . $file_prefix . '.js', [], SRFM_VER, true );
523 + wp_enqueue_script( SRFM_SLUG . '-export', $js_uri . 'export' . $file_prefix . '.js', [ 'wp-i18n' ], SRFM_VER, true );
524 + wp_localize_script(
525 + SRFM_SLUG . '-export',
526 + SRFM_SLUG . '_export',
527 + [
528 + 'ajaxurl' => admin_url( 'admin-ajax.php' ),
529 + 'srfm_export_nonce' => wp_create_nonce( 'export_form_nonce' ),
530 + 'site_url' => get_site_url(),
531 + 'srfm_import_endpoint' => '/wp-json/sureforms/v1/sureforms_import',
532 + 'import_form_nonce' => current_user_can( 'edit_posts' ) ? wp_create_nonce( 'wp_rest' ) : '',
533 + ]
534 + );
1354 535
1355 - $script_translations_handlers[] = SRFM_SLUG . '-settings';
536 + wp_enqueue_script( SRFM_SLUG . '-backend', $js_uri . 'backend' . $file_prefix . '.js', [], SRFM_VER, true );
537 + wp_localize_script(
538 + SRFM_SLUG . '-backend',
539 + SRFM_SLUG . '_backend',
540 + [
541 + 'site_url' => get_site_url(),
542 + ]
543 + );
544 +
545 + $script_translations_handlers[] = SRFM_SLUG . '-form-archive';
546 + $script_translations_handlers[] = SRFM_SLUG . '-export';
547 + $script_translations_handlers[] = SRFM_SLUG . '-backend';
1356 548 }
1357 549
1358 550 if ( $is_screen_add_new_form ) {
1359 - wp_enqueue_style( SRFM_SLUG . '-template-picker', $css_uri . 'template-picker' . $file_prefix . $rtl . '.css', [], SRFM_VER );
551 + $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
552 + $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
1360 553
554 + $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
555 +
556 + /* RTL */
557 + if ( is_rtl() ) {
558 + $file_prefix .= '-rtl';
559 + }
560 +
561 + wp_enqueue_style( SRFM_SLUG . '-template-picker', $css_uri . 'template-picker' . $file_prefix . '.css', [], SRFM_VER );
562 +
1361 563 $sureforms_admin = 'templatePicker';
1362 564
1363 565 $script_asset_path = SRFM_DIR . 'assets/build/' . $sureforms_admin . '.asset.php';
1364 566 $script_info = file_exists( $script_asset_path )
@@ -1374,18 +576,18 @@
1374 576 SRFM_SLUG . '_admin',
1375 577 [
1376 578 'site_url' => get_site_url(),
1377 579 'plugin_url' => SRFM_URL,
580 + 'preview_images_url' => SRFM_URL . 'images/template-previews/',
1378 581 'admin_url' => admin_url( 'admin.php' ),
1379 582 'new_template_picker_base_url' => admin_url( 'post-new.php?post_type=sureforms_form' ),
1380 - 'capability' => Helper::current_user_can(),
1381 - 'template_picker_nonce' => Helper::current_user_can() ? wp_create_nonce( 'wp_rest' ) : '',
1382 - 'is_pro_active' => Helper::has_pro(),
583 + 'capability' => current_user_can( 'edit_posts' ),
584 + 'template_picker_nonce' => current_user_can( 'edit_posts' ) ? wp_create_nonce( 'wp_rest' ) : '',
585 + 'is_pro_active' => defined( 'SRFM_PRO_VER' ),
1383 586 'srfm_ai_usage_details' => AI_Helper::get_current_usage_details(),
1384 587 'is_pro_license_active' => AI_Helper::is_pro_license_active(),
1385 588 'srfm_ai_auth_user_email' => get_option( 'srfm_ai_auth_user_email' ),
1386 - 'pricing_page_url' => Helper::get_sureforms_website_url( 'pricing' ),
1387 - 'licensing_nonce' => wp_create_nonce( 'srfm_pro_licensing_nonce' ),
589 + 'pricing_page_url' => $this->get_sureforms_website_url( 'pricing' ),
1388 590 ]
1389 591 );
1390 592
1391 593 $script_translations_handlers[] = SRFM_SLUG . '-template-picker';
@@ -1400,9 +602,8 @@
1400 602 'srfm/checkbox',
1401 603 'srfm/number',
1402 604 'srfm/inline-button',
1403 605 'srfm/advanced-heading',
1404 - 'srfm/payment',
1405 606 ]
1406 607 );
1407 608 if ( ! is_array( $default_allowed_quick_sidebar_blocks ) ) {
1408 609 $default_allowed_quick_sidebar_blocks = [];
@@ -1414,25 +615,22 @@
1414 615 }
1415 616 $quick_sidebar_allowed_blocks = get_option( 'srfm_quick_sidebar_allowed_blocks' );
1416 617 $quick_sidebar_allowed_blocks = ! empty( $quick_sidebar_allowed_blocks ) && is_array( $quick_sidebar_allowed_blocks ) ? $quick_sidebar_allowed_blocks : $default_allowed_quick_sidebar_blocks;
1417 618 $srfm_ajax_nonce = wp_create_nonce( 'srfm_ajax_nonce' );
619 + wp_enqueue_script( SRFM_SLUG . '-quick-action-siderbar', SRFM_URL . 'assets/build/quickActionSidebar.js', [], SRFM_VER, true );
620 + wp_localize_script(
621 + SRFM_SLUG . '-quick-action-siderbar',
622 + SRFM_SLUG . '_quick_sidebar_blocks',
623 + [
624 + 'allowed_blocks' => $quick_sidebar_allowed_blocks,
625 + 'srfm_enable_quick_action_sidebar' => $srfm_enable_quick_action_sidebar,
626 + 'srfm_ajax_nonce' => $srfm_ajax_nonce,
627 + 'srfm_ajax_url' => admin_url( 'admin-ajax.php' ),
628 + ]
629 + );
1418 630
1419 - if ( Helper::is_sureforms_admin_page() ) {
1420 - wp_enqueue_script( SRFM_SLUG . '-quick-action-siderbar', SRFM_URL . 'assets/build/quickActionSidebar.js', [], SRFM_VER, true );
1421 - wp_localize_script(
1422 - SRFM_SLUG . '-quick-action-siderbar',
1423 - SRFM_SLUG . '_quick_sidebar_blocks',
1424 - [
1425 - 'allowed_blocks' => $quick_sidebar_allowed_blocks,
1426 - 'srfm_enable_quick_action_sidebar' => $srfm_enable_quick_action_sidebar,
1427 - 'srfm_ajax_nonce' => $srfm_ajax_nonce,
1428 - 'srfm_ajax_url' => admin_url( 'admin-ajax.php' ),
1429 - ]
1430 - );
631 + $script_translations_handlers[] = SRFM_SLUG . '-quick-action-siderbar';
1431 632
1432 - $script_translations_handlers[] = SRFM_SLUG . '-quick-action-siderbar';
1433 - }
1434 -
1435 633 /**
1436 634 * Enqueuing SureTriggers Integration script.
1437 635 * This script loads suretriggers iframe in Intergations tab.
1438 636 */
@@ -1468,24 +666,17 @@
1468 666 'sureforms_page_sureforms_form_settings' => Helper::validate_request_context( 'sureforms_form_settings', 'page' ),
1469 667 'srfm-template-picker' => Helper::validate_request_context( 'add-new-form', 'page' ),
1470 668 ];
1471 669
1472 - $add_srfm_classes = '';
1473 -
1474 670 // Loop through the defined classes and conditions.
1475 671 foreach ( $srfm_classes as $class => $condition ) {
1476 672 // Check if the condition evaluates to true.
1477 673 if ( $condition ) {
1478 674 // Append the class to the existing classes string, followed by a space.
1479 - $add_srfm_classes .= empty( $add_srfm_classes ) ? $class : ' ' . $class;
675 + $classes .= $class . ' ';
1480 676 }
1481 677 }
1482 678
1483 - // Append the new classes to the existing classes string.
1484 - if ( ! empty( $add_srfm_classes ) ) {
1485 - $classes .= ' ' . $add_srfm_classes;
1486 - }
1487 -
1488 679 // Return the updated list of classes.
1489 680 return $classes;
1490 681 }
1491 682
@@ -1505,52 +696,55 @@
1505 696 return $status;
1506 697 }
1507 698
1508 699 /**
1509 - * Register Pro compatibility notices early for React pages.
700 + * Get SureForms Website URL.
1510 701 *
1511 - * This method runs on admin_init (priority 5) to ensure notices are
1512 - * registered BEFORE admin_enqueue_scripts, so they're available when
1513 - * wp_localize_script runs.
702 + * @param string $trail The URL trail to append to SureForms website URL. The parameter should not include a leading slash as the base URL already ends with a trailing slash.
703 + * @since 0.0.7
704 + * @return string
705 + */
706 + public static function get_sureforms_website_url( $trail ) {
707 + $url = SRFM_WEBSITE;
708 + if ( ! empty( $trail ) && is_string( $trail ) ) {
709 + $url = SRFM_WEBSITE . $trail;
710 + }
711 +
712 + return esc_url( $url );
713 + }
714 +
715 + // Entries methods.
716 +
717 + /**
718 + * Handle entry actions.
1514 719 *
1515 - * Hooked - admin_init (priority 5)
1516 - *
720 + * @since 0.0.13
1517 721 * @return void
1518 - * @since 2.5.0
1519 722 */
1520 - public function register_pro_compatibility_notices() {
1521 - // Early exit if Pro is not active, user lacks permissions, or Notice_Manager is unavailable.
1522 - if ( ! Helper::has_pro() || ! Helper::current_user_can() || ! class_exists( 'SRFM\Admin\Notice_Manager' ) ) {
723 + public function handle_entry_actions() {
724 + Entries_List_Table::process_bulk_actions();
725 +
726 + if ( ! isset( $_GET['page'] ) || SRFM_ENTRIES !== $_GET['page'] ) {
1523 727 return;
1524 728 }
1525 -
1526 - // Register version outdated notice for React pages.
1527 - if ( ! version_compare( SRFM_PRO_VER, SRFM_PRO_RECOMMENDED_VER, '>=' ) ) {
1528 - $pro_plugin_name = defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro';
1529 - $react_outdated_message = sprintf(
1530 - // translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version.
1531 - esc_html__( 'SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version.', 'sureforms' ),
1532 - esc_html( SRFM_VER ),
1533 - esc_html( $pro_plugin_name ),
1534 - esc_html( SRFM_PRO_RECOMMENDED_VER )
1535 - );
1536 -
1537 - \SRFM\Admin\Notice_Manager::register_notice(
1538 - [
1539 - 'id' => 'sureforms-pro-version-outdated',
1540 - 'variant' => 'warning',
1541 - 'message' => $react_outdated_message,
1542 - 'actions' => [
1543 - [
1544 - 'label' => esc_html__( 'Update Now', 'sureforms' ),
1545 - 'url' => admin_url( 'update-core.php' ),
1546 - 'variant' => 'primary',
1547 - ],
1548 - ],
1549 - 'pages' => [ 'all' ],
1550 - ]
1551 - );
729 + if ( ! isset( $_GET['entry_id'] ) || ! isset( $_GET['action'] ) ) {
730 + return;
1552 731 }
732 + if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'srfm_entries_action' ) ) {
733 + wp_die( esc_html__( 'Nonce verification failed.', 'sureforms' ) );
734 + }
735 + $action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : '';
736 + $entry_id = Helper::get_integer_value( sanitize_text_field( wp_unslash( $_GET['entry_id'] ) ) );
737 + $view = isset( $_GET['view'] ) ? sanitize_text_field( wp_unslash( $_GET['view'] ) ) : '';
738 + if ( $entry_id > 0 ) {
739 + if ( 'read' === $action && 'details' === $view ) {
740 + $entry_status = Entries::get( $entry_id )['status'];
741 + if ( 'trash' === $entry_status ) {
742 + wp_die( esc_html__( 'You cannot view this entry because it is in trash.', 'sureforms' ) );
743 + }
744 + }
745 + Entries_List_Table::handle_entry_status( $entry_id, $action, $view );
746 + }
1553 747 }
1554 748
1555 749 /**
1556 750 * Admin Notice Callback if sureforms pro is out of date.
@@ -1560,9 +754,10 @@
1560 754 * @return void
1561 755 * @since 1.0.4
1562 756 */
1563 757 public function srfm_pro_version_compatibility() {
1564 - if ( ! Helper::has_pro() ) {
758 + $plugin_file = 'sureforms-pro/sureforms-pro.php';
759 + if ( ! is_plugin_active( $plugin_file ) || ! defined( 'SRFM_PRO_VER' ) ) {
1565 760 return;
1566 761 }
1567 762
1568 763 if ( empty( get_current_screen() ) ) {
@@ -1568,9 +763,9 @@
1568 763 if ( empty( get_current_screen() ) ) {
1569 764 return;
1570 765 }
1571 766
1572 - if ( ! Helper::current_user_can() ) {
767 + if ( ! current_user_can( 'update_plugins' ) ) {
1573 768 return;
1574 769 }
1575 770
1576 771 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
@@ -1586,851 +781,30 @@
1586 781 $pro_plugin_name = defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro';
1587 782 $message = '';
1588 783 $url = admin_url( 'admin.php?page=sureforms_form_settings&tab=account-settings' );
1589 784 if ( 'unlicensed' === $srfm_pro_license_status ) {
1590 - ob_start();
1591 - ?>
1592 - <p>
1593 - <?php
1594 - printf(
1595 - // translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name.
1596 - esc_html__( 'Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more.', 'sureforms' ),
1597 - '<a href="' . esc_url( $url ) . '">',
1598 - '</a>',
1599 - '<i>' . esc_html( $pro_plugin_name ) . '</i>'
1600 - );
1601 - ?>
1602 - </p>
1603 - <?php
1604 - $message = ob_get_clean();
785 + $message = '<p>' . sprintf(
786 + // translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name.
787 + esc_html__( 'Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more.', 'sureforms' ),
788 + '<a href="' . esc_url( $url ) . '">',
789 + '</a>',
790 + '<i>' . esc_html( $pro_plugin_name ) . '</i>'
791 + ) . '</p>';
1605 792 }
1606 793
1607 794 if ( ! version_compare( SRFM_PRO_VER, SRFM_PRO_RECOMMENDED_VER, '>=' ) ) {
1608 - ob_start();
1609 - ?>
1610 - <p>
1611 - <?php
1612 - printf(
1613 - // 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.
1614 - 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' ),
1615 - esc_html( SRFM_VER ),
1616 - esc_html( $pro_plugin_name ),
1617 - esc_html( SRFM_PRO_RECOMMENDED_VER ),
1618 - '<a href="' . esc_url( admin_url( 'update-core.php' ) ) . '">',
1619 - '</a>'
1620 - );
1621 - ?>
1622 - </p>
1623 - <?php
1624 - $message .= ob_get_clean();
795 + $message .= '<p>' . sprintf(
796 + // 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.
797 + esc_html__( 'SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version.', 'sureforms' ),
798 + esc_html( SRFM_VER ),
799 + esc_html( $pro_plugin_name ),
800 + esc_html( SRFM_PRO_RECOMMENDED_VER ),
801 + ) . '</p>';
1625 802 }
1626 803
1627 804 if ( ! empty( $message ) ) {
1628 805 // Phpcs ignore comment is required as $message variable is already escaped.
1629 - ?>
1630 - <div class="notice notice-warning"><?php echo wp_kses_post( $message ); ?></div>
1631 - <?php
806 + echo '<div class="notice notice-warning">' . $message . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1632 807 }
1633 - }
1634 -
1635 - /**
1636 - * Display a notice to the user about providing a review.
1637 - *
1638 - * @since 2.5.2
1639 - * @return void
1640 - */
1641 - public function display_srfm_rating_notice() {
1642 - // Only show to admins.
1643 - if ( ! Helper::current_user_can() ) {
1644 - return;
1645 - }
1646 -
1647 - // Allow the notice to be disabled.
1648 - if ( ! apply_filters( 'srfm_show_rating_notice', true ) ) {
1649 - return;
1650 - }
1651 -
1652 - Astra_Notices::add_notice(
1653 - [
1654 - 'id' => 'srfm-plugin-review-notice',
1655 - 'type' => '',
1656 - 'message' => $this->build_notice_markup(
1657 - esc_html__( 'Amazing! SureForms is powering your forms and submissions - let\'s keep growing together!', 'sureforms' ),
1658 - esc_html__( 'If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?', 'sureforms' ),
1659 - esc_url( 'https://wordpress.org/support/plugin/sureforms/reviews/' ),
1660 - esc_html__( 'Rate SureForms', 'sureforms' ),
1661 - esc_html__( 'Maybe later', 'sureforms' ),
1662 - esc_html__( 'I already did', 'sureforms' ),
1663 - WEEK_IN_SECONDS,
1664 - true
1665 - ),
1666 - 'repeat-notice-after' => WEEK_IN_SECONDS,
1667 - 'show_if' => $this->maybe_display_rating_notice(),
1668 - 'display-with-other-notices' => true,
1669 - ]
1670 - );
1671 -
1672 - add_action( 'astra_notice_after_markup_srfm-plugin-review-notice', [ $this, 'enqueue_notice_response_script' ] );
1673 - }
1674 -
1675 - /**
1676 - * Display a "Getting Started" admin notice for new users who haven't yet
1677 - * reached the rating-notice milestone (3+ forms or 3+ entries).
1678 - *
1679 - * The Astra Notices library handles the 7-day delay via the
1680 - * `display-notice-after` parameter.
1681 - *
1682 - * @since 2.5.2
1683 - * @return void
1684 - */
1685 - public function display_srfm_getting_started_notice() {
1686 - // Only show to admins.
1687 - if ( ! Helper::current_user_can() ) {
1688 - return;
1689 - }
1690 -
1691 - // Allow the notice to be disabled programmatically.
1692 - if ( ! apply_filters( 'srfm_show_getting_started_notice', true ) ) {
1693 - return;
1694 - }
1695 -
1696 - Astra_Notices::add_notice(
1697 - [
1698 - 'id' => 'srfm-getting-started-notice',
1699 - 'type' => '',
1700 - 'message' => $this->build_notice_markup(
1701 - esc_html__( 'SureForms is ready to power your forms — explore what\'s possible!', 'sureforms' ),
1702 - esc_html__( 'Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard.', 'sureforms' ),
1703 - esc_url( admin_url( 'admin.php?page=sureforms_menu' ) ),
1704 - esc_html__( 'Go to Dashboard', 'sureforms' ),
1705 - esc_html__( 'Maybe later', 'sureforms' ),
1706 - esc_html__( 'I already know', 'sureforms' ),
1707 - WEEK_IN_SECONDS
1708 - ),
1709 - 'repeat-notice-after' => WEEK_IN_SECONDS,
1710 - 'show_if' => ! $this->maybe_display_rating_notice(),
1711 - 'display-notice-after' => WEEK_IN_SECONDS,
1712 - 'display-with-other-notices' => true,
1713 - ]
1714 - );
1715 -
1716 - add_action( 'astra_notice_after_markup_srfm-getting-started-notice', [ $this, 'enqueue_notice_response_script' ] );
1717 - }
1718 -
1719 - /**
1720 - * Enqueue the notice response analytics script.
1721 - *
1722 - * Called via the astra_notice_after_markup_{id} hook so the script
1723 - * only loads when a SureForms notice is actually rendered.
1724 - *
1725 - * @since 2.5.2
1726 - * @return void
1727 - */
1728 - public function enqueue_notice_response_script() {
1729 - if ( wp_script_is( 'srfm-notice-response', 'enqueued' ) ) {
1730 - return;
1731 - }
1732 -
1733 - wp_enqueue_script(
1734 - 'srfm-notice-response',
1735 - SRFM_URL . 'admin/assets/js/notice-response.js',
1736 - [],
1737 - SRFM_VER,
1738 - true
1739 - );
1740 -
1741 - wp_localize_script(
1742 - 'srfm-notice-response',
1743 - 'srfmNoticeResponse',
1744 - [
1745 - 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1746 - 'nonce' => wp_create_nonce( 'srfm_notice_response' ),
1747 - ]
1748 - );
1749 - }
1750 -
1751 - /**
1752 - * Handle the notice response AJAX request.
1753 - *
1754 - * Validates the request and records the analytics event
1755 - * for the notice button that was clicked.
1756 - *
1757 - * @since 2.5.2
1758 - * @return void
1759 - */
1760 - public function handle_notice_response() {
1761 - if ( ! check_ajax_referer( 'srfm_notice_response', 'nonce', false ) ) {
1762 - wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1763 - }
1764 -
1765 - if ( ! Helper::current_user_can() ) {
1766 - wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1767 - }
1768 -
1769 - $notice_id = isset( $_POST['notice_id'] ) ? sanitize_text_field( wp_unslash( $_POST['notice_id'] ) ) : '';
1770 - $button = isset( $_POST['button'] ) ? sanitize_text_field( wp_unslash( $_POST['button'] ) ) : '';
1771 -
1772 - $valid = [
1773 - 'srfm-getting-started-notice' => [
1774 - 'go_to_dashboard' => 'getting_started_notice_cta',
1775 - 'maybe_later' => 'getting_started_notice_snooze',
1776 - 'dismissed' => 'getting_started_notice_dismiss',
1777 - ],
1778 - 'srfm-plugin-review-notice' => [
1779 - 'rate_sureforms' => 'rating_notice_cta',
1780 - 'maybe_later' => 'rating_notice_snooze',
1781 - 'dismissed' => 'rating_notice_dismiss',
1782 - ],
1783 - ];
1784 -
1785 - if ( ! isset( $valid[ $notice_id ][ $button ] ) ) {
1786 - wp_send_json_error( [ 'message' => __( 'Invalid parameters.', 'sureforms' ) ], 400 );
1787 - }
1788 -
1789 - $event_name = $valid[ $notice_id ][ $button ];
1790 - Analytics::events()->track( $event_name, $button );
1791 -
1792 - wp_send_json_success();
1793 - }
1794 -
1795 - /**
1796 - * Disables the capabilities for WPForms to avoid conflicts when enqueueing
1797 - * scripts and styles for WPForms.
1798 - *
1799 - * This function is intended to prevent any potential conflicts that may arise
1800 - * when WPForms scripts and styles are enqueued. By disabling certain capabilities,
1801 - * it ensures that WPForms does not interfere with other functionalities.
1802 - *
1803 - * @param bool $user_can A boolean indicating whether the user has the capability.
1804 - * @return bool Returns true if the capabilities are successfully disabled, false otherwise.
1805 - * @since 1.4.2
1806 - */
1807 - public function disable_wpforms_capabilities( $user_can ) {
1808 - // Note: Nonce verification is intentionally omitted here as no database operations are performed.
1809 - // The values of the $_REQUEST variables are strictly validated, ensuring security without the need for nonce verification.
1810 -
1811 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1812 - $post_id = ! empty( $_REQUEST['post'] ) && ! empty( $_REQUEST['action'] ) ? absint( $_REQUEST['post'] ) : 0;
1813 -
1814 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1815 - $post_type = $post_id ? get_post_type( $post_id ) : sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ?? '' ) );
1816 - return SRFM_FORMS_POST_TYPE === $post_type ? false : $user_can;
1817 - }
1818 -
1819 - /**
1820 - * Enqueueus the admin pointer script and styles.
1821 - *
1822 - * @return void
1823 - * @since 1.8.0
1824 - */
1825 - public function enqueue_admin_pointer() {
1826 - if ( ! $this->is_admin_pointer_visible() ) {
1827 - return;
1828 - }
1829 - wp_enqueue_style( 'wp-pointer' );
1830 - wp_enqueue_script( 'wp-pointer' );
1831 - wp_enqueue_script(
1832 - 'sureforms-admin-pointer',
1833 - plugins_url( 'admin/assets/js/sureforms-pointer.js', SRFM_FILE ),
1834 - [ 'wp-pointer', 'jquery' ],
1835 - SRFM_VER,
1836 - true
1837 - );
1838 - wp_localize_script(
1839 - 'sureforms-admin-pointer',
1840 - 'sureformsPointerData',
1841 - [
1842 - 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1843 - 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
1844 - ]
1845 - );
1846 - }
1847 -
1848 - /**
1849 - * Ajax handler for pointer popup visibility.
1850 - *
1851 - * @return void
1852 - * @since 1.8.0
1853 - */
1854 - public function pointer_should_show() {
1855 - // Security: Check user capability.
1856 - if ( ! Helper::current_user_can() ) {
1857 - wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1858 - }
1859 - // Security: Nonce check.
1860 - if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1861 - wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1862 - }
1863 -
1864 - $content_markup = sprintf(
1865 - /* translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong */
1866 - __( '%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' ),
1867 - '<span>',
1868 - '<strong>',
1869 - '</strong>',
1870 - '</span><br/>',
1871 - '<strong style="font-size:1.1em;">',
1872 - '</strong>'
1873 - );
1874 - wp_send_json(
1875 - [
1876 - 'show' => true,
1877 - 'title' => esc_html( __( 'SureForms is waiting for you!', 'sureforms' ) ),
1878 - 'content' => wp_kses_post( $content_markup ),
1879 - 'button_text' => esc_html( __( 'Build My First Form', 'sureforms' ) ),
1880 - 'dismiss' => esc_html( __( 'Dismiss', 'sureforms' ) ),
1881 - 'button_url' => admin_url( 'admin.php?page=add-new-form' ),
1882 - ]
1883 - );
1884 - }
1885 -
1886 - /**
1887 - * Ajax callback for pointer popup dismissed action.
1888 - *
1889 - * @return void
1890 - * @since 1.8.0
1891 - */
1892 - public function pointer_dismissed() {
1893 - // Security: Check user capability.
1894 - if ( ! Helper::current_user_can() ) {
1895 - wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1896 - }
1897 - // Security: Nonce check.
1898 - if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1899 - wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1900 - }
1901 - // Use Helper to update srfm_options key.
1902 - Helper::update_srfm_option( 'pointer_popup_dismissed', time() );
1903 -
1904 - wp_send_json_success();
1905 - }
1906 -
1907 - /**
1908 - * Ajax pointer accepted CTA callback.
1909 - *
1910 - * @return void
1911 - * @since 1.8.0
1912 - */
1913 - public function pointer_accepted_cta() {
1914 - // Security: Check user capability.
1915 - if ( ! Helper::current_user_can() ) {
1916 - wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1917 - }
1918 - // Security: Nonce check.
1919 - if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1920 - wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1921 - }
1922 - // Use Helper to update srfm_options key.
1923 - Helper::update_srfm_option( 'pointer_popup_accepted', time() );
1924 -
1925 - wp_send_json_success();
1926 - }
1927 -
1928 - /**
1929 - * Maybe register the dashboard widget based on entries.
1930 - *
1931 - * @return void
1932 - * @since 1.9.1
1933 - */
1934 - public function maybe_register_dashboard_widget() {
1935 -
1936 - // Only for users with manage_options capability.
1937 - if ( ! Helper::current_user_can() ) {
1938 - return;
1939 - }
1940 -
1941 - // Register the AI quick draft widget for capable users (the capability gate above applies); unlike the recent-entries widget below, it is not conditional on having entries.
1942 - add_action( 'wp_dashboard_setup', [ $this, 'register_ai_dashboard_widget' ] );
1943 -
1944 - // Quick check if there are any entries in the last 7 days.
1945 - $seven_days_ago = strtotime( '-7 days' );
1946 - $total_entries = Entries::get_entries_count_after( $seven_days_ago );
1947 -
1948 - // Only add the dashboard setup hook if there are entries.
1949 - if ( $total_entries > 0 ) {
1950 - // Get forms with entries (limit 4 for dashboard widget).
1951 - $this->dashboard_widget_data = Helper::get_forms_with_entry_counts( $seven_days_ago, 4 );
1952 -
1953 - // Only show dashboard widget if there are forms with entries.
1954 - if ( ! empty( $this->dashboard_widget_data ) ) {
1955 - add_action( 'wp_dashboard_setup', [ $this, 'register_dashboard_widget' ] );
1956 - }
1957 - }
1958 - }
1959 -
1960 - /**
1961 - * Register the dashboard widget.
1962 - *
1963 - * @return void
1964 - * @since 1.9.1
1965 - */
1966 - public function register_dashboard_widget() {
1967 - // Add the widget with high priority to position it at the top.
1968 - wp_add_dashboard_widget(
1969 - 'sureforms_recent_entries',
1970 - __( 'SureForms', 'sureforms' ),
1971 - [ $this, 'render_dashboard_widget' ],
1972 - null,
1973 - null,
1974 - 'normal',
1975 - 'high'
1976 - );
1977 - }
1978 -
1979 - /**
1980 - * Register the AI quick draft dashboard widget.
1981 - *
1982 - * @return void
1983 - * @since 2.12.1
1984 - */
1985 - public function register_ai_dashboard_widget() {
1986 - wp_add_dashboard_widget(
1987 - 'sureforms_ai_quick_draft',
1988 - __( 'SureForms AI Quick Draft', 'sureforms' ),
1989 - [ $this, 'render_ai_dashboard_widget' ],
1990 - null,
1991 - null,
1992 - 'normal',
1993 - 'high'
1994 - );
1995 - }
1996 -
1997 - /**
1998 - * Render AI quick draft dashboard widget content.
1999 - *
2000 - * @return void
2001 - * @since 2.12.1
2002 - */
2003 - public function render_ai_dashboard_widget() {
2004 - ?>
2005 - <div class="srfm-ai-dashboard-widget">
2006 - <p>
2007 - <?php esc_html_e( 'Describe the form and let SureForms AI generate it for you.', 'sureforms' ); ?>
2008 - </p>
2009 - <label for="srfm-ai-dashboard-prompt" class="screen-reader-text">
2010 - <?php esc_html_e( 'Describe your form', 'sureforms' ); ?>
2011 - </label>
2012 - <textarea
2013 - id="srfm-ai-dashboard-prompt"
2014 - class="widefat"
2015 - rows="5"
2016 - maxlength="2000"
2017 - placeholder="<?php esc_attr_e( 'Example: Create a contact form with name, email, phone, and message fields.', 'sureforms' ); ?>"
2018 - ></textarea>
2019 - <p style="margin-top:10px;margin-bottom:0;display:flex;align-items:center;gap:10px;">
2020 - <button type="button" class="button button-primary" id="srfm-ai-dashboard-generate" disabled>
2021 - <?php esc_html_e( 'Create New Form', 'sureforms' ); ?>
2022 - </button>
2023 - <span id="srfm-ai-dashboard-char-count" style="color:#646970;">0/2000</span>
2024 - </p>
2025 - </div>
2026 - <?php
2027 - }
2028 -
2029 - /**
2030 - * Enqueue the AI quick draft dashboard widget script on the dashboard screen.
2031 - *
2032 - * The widget's behavior lives here (attached via wp_add_inline_script) rather than as an
2033 - * inline <script> in the render callback, so it passes Plugin Check and keeps server values
2034 - * out of the markup. Server values are passed through wp_localize_script.
2035 - *
2036 - * @param string $hook_suffix The current admin page hook suffix.
2037 - * @return void
2038 - * @since 2.12.1
2039 - */
2040 - public function enqueue_ai_dashboard_widget_assets( $hook_suffix ) {
2041 - // Only on the main dashboard, and only for capable users (matches the widget gate).
2042 - if ( 'index.php' !== $hook_suffix || ! Helper::current_user_can() ) {
2043 - return;
2044 - }
2045 -
2046 - // Register an inline-only handle (empty src) — the WordPress-core pattern for attaching
2047 - // localized data plus an inline script without shipping a separate asset file.
2048 - wp_register_script( 'srfm-ai-dashboard-widget', '', [], SRFM_VER, true );
2049 - wp_enqueue_script( 'srfm-ai-dashboard-widget' );
2050 -
2051 - wp_localize_script(
2052 - 'srfm-ai-dashboard-widget',
2053 - 'srfmAiDashboardWidget',
2054 - [
2055 - 'redirectUrl' => admin_url( 'admin.php?page=add-new-form' ),
2056 - 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
2057 - 'nonce' => wp_create_nonce( 'srfm_ai_widget_usage' ),
2058 - 'redirectingTxt' => __( 'Redirecting...', 'sureforms' ),
2059 - ]
2060 - );
2061 -
2062 - $inline_script = <<<'JS'
2063 -( function () {
2064 - const config = window.srfmAiDashboardWidget || {};
2065 - const generateButton = document.getElementById( 'srfm-ai-dashboard-generate' );
2066 - const promptField = document.getElementById( 'srfm-ai-dashboard-prompt' );
2067 - const charCount = document.getElementById( 'srfm-ai-dashboard-char-count' );
2068 - if ( ! generateButton || ! promptField ) {
2069 - return;
2070 - }
2071 -
2072 - const updateWidgetState = function () {
2073 - const promptValue = promptField.value.trim();
2074 - generateButton.disabled = ! promptValue;
2075 - if ( charCount ) {
2076 - charCount.textContent = `${ promptField.value.length }/2000`;
2077 - }
2078 - };
2079 -
2080 - const triggerGeneration = function () {
2081 - const prompt = promptField.value.trim();
2082 - if ( ! prompt ) {
2083 - promptField.focus();
2084 - return;
2085 - }
2086 -
2087 - generateButton.disabled = true;
2088 - generateButton.textContent = config.redirectingTxt;
2089 -
2090 - const redirectUrl = new URL( config.redirectUrl, window.location.origin );
2091 - redirectUrl.searchParams.set( 'srfm_ai_dashboard_prompt', prompt );
2092 -
2093 - const requestBody = new URLSearchParams();
2094 - requestBody.append( 'action', 'srfm_ai_widget_usage' );
2095 - requestBody.append( 'nonce', config.nonce );
2096 -
2097 - fetch( config.ajaxUrl, {
2098 - method: 'POST',
2099 - credentials: 'same-origin',
2100 - headers: {
2101 - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
2102 - },
2103 - body: requestBody.toString(),
2104 - } ).finally( function () {
2105 - window.location.href = redirectUrl.toString();
2106 - } );
2107 - };
2108 -
2109 - promptField.addEventListener( 'input', updateWidgetState );
2110 - generateButton.addEventListener( 'click', triggerGeneration );
2111 - promptField.addEventListener( 'keydown', function ( event ) {
2112 - if ( event.key === 'Enter' && ( event.metaKey || event.ctrlKey ) ) {
2113 - event.preventDefault();
2114 - triggerGeneration();
2115 - }
2116 - } );
2117 -
2118 - updateWidgetState();
2119 -}() );
2120 -JS;
2121 -
2122 - wp_add_inline_script( 'srfm-ai-dashboard-widget', $inline_script );
2123 - }
2124 -
2125 - /**
2126 - * Track AI dashboard widget usage.
2127 - *
2128 - * @return void
2129 - * @since 2.12.1
2130 - */
2131 - public function track_ai_widget_usage() {
2132 - if ( ! check_ajax_referer( 'srfm_ai_widget_usage', 'nonce', false ) ) {
2133 - wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
2134 - }
2135 -
2136 - if ( ! Helper::current_user_can() ) {
2137 - wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
2138 - }
2139 -
2140 - $current_count = (int) Helper::get_srfm_option( 'ai_dashboard_widget_uses', 0 ) + 1;
2141 - Helper::update_srfm_option( 'ai_dashboard_widget_uses', $current_count );
2142 -
2143 - // Emit an analytics event so usage lands in the warehouse via events_record.
2144 - // $force = true because this is a cumulative counter, not a one-time event —
2145 - // it must re-send the latest count each cycle (bypasses one-time dedup).
2146 - Analytics::events()->track( 'ai_dashboard_widget_used', (string) $current_count, [], true );
2147 -
2148 - wp_send_json_success();
2149 - }
2150 -
2151 - /**
2152 - * Render the dashboard widget content.
2153 - *
2154 - * @return void
2155 - * @since 1.9.1
2156 - */
2157 - public function render_dashboard_widget() {
2158 - // Use the pre-fetched data to avoid duplicate queries.
2159 - $entries_data = $this->dashboard_widget_data;
2160 -
2161 - // Display the widget content.
2162 - ?>
2163 - <div class="srfm-dashboard-widget">
2164 - <div class="srfm-widget-header">
2165 - <h3 class="srfm-widget-title">
2166 - <?php esc_html_e( 'Recent Entries', 'sureforms' ); ?>
2167 - <span class="srfm-widget-subtitle"><?php esc_html_e( '( Last 7 days )', 'sureforms' ); ?></span>
2168 - </h3>
2169 - <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_entries' ) ); ?>" class="srfm-widget-view-link">
2170 - <?php esc_html_e( 'View', 'sureforms' ); ?>
2171 - </a>
2172 - </div>
2173 -
2174 - <div class="srfm-table-wrapper">
2175 - <table class="srfm-entries-table">
2176 - <thead>
2177 - <tr>
2178 - <th><?php esc_html_e( 'Form Name', 'sureforms' ); ?></th>
2179 - <th><?php esc_html_e( 'Entries', 'sureforms' ); ?></th>
2180 - </tr>
2181 - </thead>
2182 - <tbody>
2183 - <?php foreach ( $entries_data as $form_data ) { ?>
2184 - <tr>
2185 - <td class="form-name"><?php echo esc_html( $form_data['title'] ); ?></td>
2186 - <td class="entry-count"><?php echo esc_html( $form_data['count'] ); ?></td>
2187 - </tr>
2188 - <?php } ?>
2189 - </tbody>
2190 - </table>
2191 - </div>
2192 -
2193 - <?php
2194 - // Render footer if applicable.
2195 - $this->render_dashboard_widget_footer( $entries_data );
2196 - ?>
2197 - </div>
2198 - <?php
2199 - }
2200 -
2201 - /**
2202 - * Determine whether a notice callback is owned by SureForms.
2203 - *
2204 - * Recognises object methods on classes in the `SRFM` / `SRFM_PRO` namespaces
2205 - * as well as the bundled notices libraries (`BSF_Admin_Notices` and the
2206 - * legacy `Astra_Notices` alias). Everything else is treated as foreign.
2207 - *
2208 - * @param callable|array|string|null $function The registered callback function.
2209 - * @since 2.10.0
2210 - * @return bool True when the callback belongs to SureForms, false otherwise.
2211 - */
2212 - private function is_sureforms_owned_notice_callback( $function ) {
2213 - $class_name = '';
2214 -
2215 - if ( is_array( $function ) && isset( $function[0] ) ) {
2216 - // Object or static method callback represented as an array. The first
2217 - // element is either the object instance or the fully qualified class name.
2218 - $class_name = is_object( $function[0] ) ? get_class( $function[0] ) : (string) $function[0];
2219 - } elseif ( is_string( $function ) && false !== strpos( $function, '::' ) ) {
2220 - // Static method passed as "Class::method".
2221 - $class_name = strstr( $function, '::', true );
2222 - }
2223 -
2224 - if ( '' === $class_name ) {
2225 - // Plain function callbacks are never owned by SureForms.
2226 - return false;
2227 - }
2228 -
2229 - // SureForms (free and pro) namespaced classes. Pro's real namespace is
2230 - // `SRFM_Pro\` (case-sensitive) — not the all-caps `SRFM_PRO_` constant
2231 - // prefix — so match it case-insensitively to be safe.
2232 - if ( 0 === strpos( $class_name, 'SRFM\\' ) || 0 === stripos( $class_name, 'SRFM_Pro\\' ) ) {
2233 - return true;
2234 - }
2235 -
2236 - // Bundled notices library shipped with SureForms.
2237 - return in_array( $class_name, [ 'BSF_Admin_Notices', 'Astra_Notices' ], true );
2238 - }
2239 -
2240 - /**
2241 - * Whether the current admin page is a SureForms-owned screen identified by a
2242 - * `sureforms_*` / `srfm_*` `page` query slug. Complements
2243 - * {@see Helper::is_sureforms_admin_page()} so foreign-notice suppression also
2244 - * covers the payments / quiz / survey / learn / SMTP / partial-entries screens
2245 - * that the core helper does not enumerate. Read-only screen check.
2246 - *
2247 - * @since 2.10.0
2248 - * @return bool
2249 - */
2250 - private function is_sureforms_owned_admin_page() {
2251 - if ( ! is_admin() || empty( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen detection, no state change.
2252 - return false;
2253 - }
2254 - $page = sanitize_key( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen detection, no state change.
2255 - return 0 === strpos( $page, 'sureforms' ) || 0 === strpos( $page, 'srfm' );
2256 - }
2257 -
2258 - /**
2259 - * Build the shared HTML markup for admin notices.
2260 - *
2261 - * @since 2.5.2
2262 - *
2263 - * All text parameters must be pre-escaped by the caller (e.g. via esc_html__()).
2264 - * URL parameters must be pre-escaped via esc_url().
2265 - *
2266 - * @param string $heading The notice heading text (pre-escaped).
2267 - * @param string $message The notice body text (pre-escaped).
2268 - * @param string $cta_url The primary CTA URL (pre-escaped).
2269 - * @param string $cta_text The primary CTA button text (pre-escaped).
2270 - * @param string $snooze_text The snooze button text (pre-escaped).
2271 - * @param string $dismiss_text The dismiss button text (pre-escaped).
2272 - * @param int $snooze_duration Snooze duration in seconds for the data-repeat-notice-after attribute.
2273 - * @param bool $external_cta Whether the CTA opens in a new tab and also dismisses the notice
2274 - * via the astra-notice-close class. Default false.
2275 - * @return string The notice HTML markup.
2276 - */
2277 - private function build_notice_markup( $heading, $message, $cta_url, $cta_text, $snooze_text, $dismiss_text, $snooze_duration, $external_cta = false ) {
2278 - $image_path = esc_url( SRFM_URL . 'admin/assets/sureforms-logo.png' );
2279 - $cta_class = $external_cta ? 'astra-notice-close button-primary' : 'button-primary';
2280 - $cta_attrs = $external_cta ? ' target="_blank" rel="noopener noreferrer"' : '';
2281 -
2282 - return sprintf(
2283 - '<div class="notice-image">
2284 - <img src="%1$s" class="custom-logo" alt="SureForms" itemprop="logo">
2285 - </div>
2286 - <div class="notice-content">
2287 - <div class="notice-heading">
2288 - %2$s
2289 - </div>
2290 - %3$s<br />
2291 - <div class="astra-review-notice-container">
2292 - <a href="%4$s" class="%5$s"%6$s>
2293 - %7$s
2294 - </a>
2295 - <span class="dashicons dashicons-clock" aria-hidden="true"></span>
2296 - <a href="#" data-repeat-notice-after="%8$s" class="astra-notice-close">
2297 - %9$s
2298 - </a>
2299 - <span class="dashicons dashicons-smiley" aria-hidden="true"></span>
2300 - <a href="#" class="astra-notice-close">
2301 - %10$s
2302 - </a>
2303 - </div>
2304 - </div>',
2305 - $image_path,
2306 - $heading,
2307 - $message,
2308 - $cta_url,
2309 - esc_attr( $cta_class ),
2310 - $cta_attrs,
2311 - $cta_text,
2312 - $snooze_duration,
2313 - $snooze_text,
2314 - $dismiss_text
2315 - );
2316 - }
2317 -
2318 - /**
2319 - * Callback for displaying the rating notice conditionally.
2320 - *
2321 - * Returns true if the user has 3 or more published forms or 3 or more form entries.
2322 - *
2323 - * @since 2.5.2
2324 - * @return bool
2325 - */
2326 - private function maybe_display_rating_notice() {
2327 - if ( null === $this->should_show_rating ) {
2328 - $entries_count = Entries::get_total_entries_by_status( 'all' );
2329 - $form_count = wp_count_posts( SRFM_FORMS_POST_TYPE );
2330 - $this->should_show_rating = $entries_count >= self::RATING_NOTICE_THRESHOLD || Helper::get_integer_value( $form_count->publish ?? 0 ) >= self::RATING_NOTICE_THRESHOLD;
2331 - }
2332 -
2333 - return $this->should_show_rating;
2334 - }
2335 -
2336 - /**
2337 - * Get random premium feature text.
2338 - *
2339 - * @return string Random feature text.
2340 - * @since 1.9.1
2341 - */
2342 - private function get_random_premium_feature_text() {
2343 - $features = [
2344 - __( 'Use Conditional Logic to show only what matters', 'sureforms' ),
2345 - __( 'Split your form into steps to keep it easy', 'sureforms' ),
2346 - __( 'Let people upload files directly to your form', 'sureforms' ),
2347 - __( 'Turn responses into downloadable PDFs automatically', 'sureforms' ),
2348 - __( 'Let users sign with a simple signature field', 'sureforms' ),
2349 - __( 'Connect your form to other tools using webhooks', 'sureforms' ),
2350 - __( 'Use Conversational Forms for a chat-like experience', 'sureforms' ),
2351 - __( 'Let users register or log in through your form', 'sureforms' ),
2352 - __( 'Build forms that create WordPress user accounts', 'sureforms' ),
2353 - __( 'Add calculations to auto-total scores or prices', 'sureforms' ),
2354 - ];
2355 -
2356 - // Get a random feature.
2357 - $random_key = array_rand( $features );
2358 - return $features[ $random_key ];
2359 - }
2360 -
2361 - /**
2362 - * Render the dashboard widget footer for upsell.
2363 - *
2364 - * @param array $entries_data The entries data array.
2365 - * @return void
2366 - * @since 1.9.1
2367 - */
2368 - private function render_dashboard_widget_footer( $entries_data ) {
2369 - // Only show footer if Pro is not active.
2370 - if ( Helper::has_pro() ) {
2371 - return;
2372 - }
2373 -
2374 - // Count total entries in last 7 days.
2375 - $total_entries = 0;
2376 - foreach ( $entries_data as $form_data ) {
2377 - $total_entries += $form_data['count'];
2378 - }
2379 -
2380 - // Count total published forms.
2381 - $published_forms_count = wp_count_posts( SRFM_FORMS_POST_TYPE )->publish;
2382 -
2383 - // Show footer only if 3+ entries received OR 3+ forms published.
2384 - if ( $total_entries >= 3 || $published_forms_count >= 3 ) {
2385 - ?>
2386 - <div class="srfm-widget-footer">
2387 - <div class="srfm-upgrade-content">
2388 - <svg class="srfm-logo-icon" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2389 - <rect width="20" height="20" fill="#D54407"/>
2390 - <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
2391 - <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
2392 - <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
2393 - <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
2394 - <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
2395 - <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
2396 - </svg>
2397 - <span><?php echo esc_html( $this->get_random_premium_feature_text() ); ?></span>
2398 - </div>
2399 - <?php
2400 - $upgrade_url = Helper::get_sureforms_website_url( 'pricing', [ 'utm_medium' => 'dashboard-widget' ] );
2401 - ?>
2402 - <a href="<?php echo esc_url( $upgrade_url ); ?>" class="srfm-upgrade-link" target="_blank">
2403 - <?php esc_html_e( 'Upgrade', 'sureforms' ); ?>
2404 - </a>
2405 - </div>
2406 - <?php
2407 - }
2408 - }
2409 -
2410 - /**
2411 - * Determine if the admin pointer should be visible on this page.
2412 - *
2413 - * @since 1.8.0
2414 - * @return bool
2415 - */
2416 - private function is_admin_pointer_visible() {
2417 - global $pagenow;
2418 - $allowed_pages = [ 'index.php', 'options-general.php' ];
2419 -
2420 - // Do not show if pointer dismissed, accepted, or more than 1 form exists.
2421 - if (
2422 - ! empty( Helper::get_srfm_option( 'pointer_popup_dismissed' ) )
2423 - || ! empty( Helper::get_srfm_option( 'pointer_popup_accepted' ) )
2424 - || (int) ( wp_count_posts( SRFM_FORMS_POST_TYPE )->publish ?? 0 ) > 1
2425 - ) {
2426 - return false;
2427 - }
2428 -
2429 - if ( in_array( $pagenow, $allowed_pages, true ) ) {
2430 - return true;
2431 - }
2432 -
2433 - return false;
2434 808 }
2435 809
2436 810 }