PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.9.1
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.9.1
2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 All 96 releases
sureforms / admin / admin.php
admin.php
1,489 lines 52.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Admin Class.
4 *
5 * @package sureforms.
6 */
7
8 namespace SRFM\Admin;
9
10 use SRFM\Admin\Views\Entries_List_Table;
11 use SRFM\Admin\Views\Single_Entry;
12 use SRFM\Inc\AI_Form_Builder\AI_Helper;
13 use SRFM\Inc\Database\Tables\Entries;
14 use SRFM\Inc\Helper;
15 use SRFM\Inc\Onboarding;
16 use SRFM\Inc\Post_Types;
17 use SRFM\Inc\Traits\Get_Instance;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit; // Exit if accessed directly.
21 }
22 /**
23 * Admin handler class.
24 *
25 * @since 0.0.1
26 */
27 class Admin {
28 use Get_Instance;
29
30 /**
31 * Dashboard widget entries data.
32 *
33 * @var array
34 * @since 1.9.1
35 */
36 private $dashboard_widget_data = [];
37
38 /**
39 * Class constructor.
40 *
41 * @return void
42 * @since 0.0.1
43 */
44 public function __construct() {
45 add_action( 'admin_menu', [ $this, 'add_menu_page' ], 9 );
46 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
47 add_action( 'admin_menu', [ $this, 'settings_page' ] );
48 add_action( 'admin_menu', [ $this, 'add_new_form' ] );
49 add_action( 'admin_menu', [ $this, 'add_suremail_page' ] );
50 if ( ! Helper::has_pro() ) {
51 add_action( 'admin_menu', [ $this, 'add_upgrade_to_pro' ] );
52 add_action( 'admin_footer', [ $this, 'add_upgrade_to_pro_target_attr' ] );
53 }
54
55 add_filter( 'plugin_action_links', [ $this, 'add_settings_link' ], 10, 2 );
56 add_action( 'enqueue_block_assets', [ $this, 'enqueue_styles' ] );
57 add_action( 'admin_head', [ $this, 'enqueue_header_styles' ] );
58 add_filter( 'admin_body_class', [ $this, 'admin_template_picker_body_class' ] );
59
60 // this action is used to restrict Spectra's quick action bar on SureForms CPTS.
61 add_action( 'uag_enable_quick_action_sidebar', [ $this, 'restrict_spectra_quick_action_bar' ] );
62
63 add_action( 'current_screen', [ $this, 'enable_gutenberg_for_sureforms' ], 100 );
64 add_action( 'admin_notices', [ $this, 'srfm_pro_version_compatibility' ] );
65 add_action( 'admin_notices', [ $this, 'add_smtp_warning_notice' ] );
66
67 // Handle entry actions.
68 add_action( 'admin_init', [ $this, 'handle_entry_actions' ] );
69 add_action( 'admin_notices', [ Entries_List_Table::class, 'display_bulk_action_notice' ] );
70
71 // This action enqueues translations for NPS Survey library.
72 // A better solution will be required from library to resolve plugin conflict.
73 add_action(
74 'admin_footer',
75 static function() {
76 Helper::register_script_translations( 'nps-survey-script' );
77 },
78 1000
79 );
80 // Enfold theme compatibility to enable block editor for SureForms post type.
81 add_filter( 'avf_use_block_editor_for_post', [ $this, 'enable_block_editor_in_enfold_theme' ] );
82
83 // Add action links to the plugin page.
84 add_filter( 'plugin_action_links_' . SRFM_BASENAME, [ $this, 'add_action_links' ] );
85 // Check if admin notification is enabled and add entries badge.
86 $general_options = get_option( 'srfm_general_settings_options', [] );
87 $admin_notification_on = isset( $general_options['srfm_admin_notification'] ) ? (bool) $general_options['srfm_admin_notification'] : true;
88
89 if ( $admin_notification_on ) {
90 add_action( 'admin_menu', [ $this, 'maybe_add_entries_badge' ], 99 );
91 }
92 add_filter( 'wpforms_current_user_can', [ $this, 'disable_wpforms_capabilities' ], 10, 3 );
93
94 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_pointer' ] );
95 // Ajax callbacks for wp-pointer functionality.
96 add_action( 'wp_ajax_should_show_pointer', [ $this, 'pointer_should_show' ] );
97 add_action( 'wp_ajax_sureforms_dismiss_pointer', [ $this, 'pointer_dismissed' ] );
98 add_action( 'wp_ajax_sureforms_accept_cta', [ $this, 'pointer_accepted_cta' ] );
99
100 // Register dashboard widget only if there are recent entries.
101 add_action( 'admin_init', [ $this, 'maybe_register_dashboard_widget' ] );
102 }
103
104 /**
105 * Show action on plugin page.
106 *
107 * @param array $links links.
108 * @return array
109 * @since 1.4.2
110 */
111 public function add_action_links( $links ) {
112 if ( ! Helper::has_pro() ) {
113 // Display upsell link if SureForms Pro is not installed.
114 $upsell_link = add_query_arg(
115 [
116 'utm_medium' => 'plugin-list',
117 ],
118 Helper::get_sureforms_website_url( 'pricing' )
119 );
120 $links[] = '<a href="' . esc_url( $upsell_link ) . '" target="_blank" rel="noreferrer" class="sureforms-plugins-go-pro">' . esc_html__( 'Get SureForms Pro', 'sureforms' ) . '</a>';
121 }
122
123 return $links;
124 }
125
126 /**
127 * Enable block editor in Enfold theme for SureForms post type.
128 *
129 * @param bool $use_block_editor Whether to use block editor.
130 * @since 1.3.1
131 */
132 public function enable_block_editor_in_enfold_theme( $use_block_editor ) {
133 // if SureForms form post type then return true.
134 if ( SRFM_FORMS_POST_TYPE === get_current_screen()->post_type ) {
135 return true;
136 }
137 return $use_block_editor;
138 }
139
140 /**
141 * Enable Gutenberg for SureForms associated post types.
142 *
143 * @since 0.0.10
144 */
145 public function enable_gutenberg_for_sureforms() {
146 /**
147 * Check if the classic editor is enabled from Classic Editor plugin settings or Divi settings.
148 */
149 if ( 'block' === get_option( 'classic-editor-replace' ) || 'on' === get_option( 'et_enable_classic_editor' ) ) {
150 return;
151 }
152
153 $srfm_post_types = apply_filters( 'srfm_enable_gutenberg_post_types', [ SRFM_FORMS_POST_TYPE ] );
154
155 if ( in_array( get_current_screen()->post_type, $srfm_post_types, true ) ) {
156 add_filter( 'use_block_editor_for_post_type', '__return_true', 110 );
157 add_filter( 'gutenberg_can_edit_post_type', '__return_true', 110 );
158 }
159 }
160
161 /**
162 * Sureforms editor header styles.
163 *
164 * @since 0.0.1
165 */
166 public function enqueue_header_styles() {
167 $current_screen = get_current_screen();
168 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
169 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
170
171 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
172
173 /* RTL */
174 if ( is_rtl() ) {
175 $file_prefix .= '-rtl';
176 }
177
178 if ( 'sureforms_form' === $current_screen->id ) {
179 wp_enqueue_style( SRFM_SLUG . '-editor-header-styles', $css_uri . 'header-styles' . $file_prefix . '.css', [], SRFM_VER );
180 }
181 }
182
183 /**
184 * Add menu page.
185 *
186 * @return void
187 * @since 0.0.1
188 */
189 public function add_menu_page() {
190 if ( ! current_user_can( 'manage_options' ) ) {
191 return;
192 }
193
194 $capability = 'manage_options';
195 $menu_slug = 'sureforms_menu';
196
197 $logo = file_get_contents( plugin_dir_path( SRFM_FILE ) . 'images/icon.svg' );
198 add_menu_page(
199 __( 'SureForms', 'sureforms' ),
200 __( 'SureForms', 'sureforms' ),
201 'edit_others_posts',
202 $menu_slug,
203 static function () {
204 },
205 'data:image/svg+xml;base64,' . base64_encode( $logo ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
206 30
207 );
208
209 // Add the Dashboard Submenu.
210 add_submenu_page(
211 $menu_slug,
212 __( 'Dashboard', 'sureforms' ),
213 __( 'Dashboard', 'sureforms' ),
214 $capability,
215 $menu_slug,
216 [ $this, 'render_dashboard' ]
217 );
218 }
219
220 /**
221 * Add Settings page.
222 *
223 * @return void
224 * @since 0.0.1
225 */
226 public function settings_page() {
227 $callback = [ $this, 'settings_page_callback' ];
228 add_submenu_page(
229 'sureforms_menu',
230 __( 'Settings', 'sureforms' ),
231 __( 'Settings', 'sureforms' ),
232 'edit_others_posts',
233 'sureforms_form_settings',
234 $callback
235 );
236
237 // Get the current submenu page.
238 $submenu_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
239
240 if ( ! isset( $_GET['tab'] ) && 'sureforms_form_settings' === $submenu_page ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
241 wp_safe_redirect( admin_url( 'admin.php?page=sureforms_form_settings&tab=general-settings' ) );
242 exit;
243 }
244 }
245
246 /**
247 * Open to Upgrade to Pro submenu link in new tab.
248 *
249 * @return void
250 * @since 1.6.1
251 */
252 public function add_upgrade_to_pro_target_attr() {
253 ?>
254 <script type="text/javascript">
255 document.addEventListener('DOMContentLoaded', function () {
256 // Upgrade link handler.
257 // IMPORTANT: If this URL changes, also update it in the `add_upgrade_to_pro` function.
258 const upgradeLink = document.querySelector('a[href*="https://sureforms.com/upgrade"]');
259 if (upgradeLink) {
260 upgradeLink.addEventListener('click', e => {
261 e.preventDefault();
262 window.open(upgradeLink.href, '_blank');
263 });
264 }
265 });
266 </script>
267 <?php
268 }
269
270 /**
271 * Add Upgrade to pro menu item.
272 *
273 * @return void
274 * @since 1.6.1
275 */
276 public function add_upgrade_to_pro() {
277 // The url used here is used as a selector for css to style the upgrade to pro submenu.
278 // If you are changing this url, please make sure to update the css as well.
279 $upgrade_url = add_query_arg(
280 [
281 'utm_medium' => 'submenu_link_upgrade',
282 ],
283 Helper::get_sureforms_website_url( 'upgrade' )
284 );
285
286 add_submenu_page(
287 'sureforms_menu',
288 __( 'Upgrade', 'sureforms' ),
289 __( 'Upgrade', 'sureforms' ),
290 'edit_others_posts',
291 $upgrade_url
292 );
293 }
294
295 /**
296 * Add SMTP promotional submenu page.
297 *
298 * @return void
299 * @since 1.7.1
300 */
301 public function add_suremail_page() {
302 add_submenu_page(
303 'sureforms_menu',
304 __( 'SMTP', 'sureforms' ),
305 __( 'SMTP', 'sureforms' ),
306 'edit_others_posts',
307 'sureforms_smtp',
308 [ $this, 'suremail_page_callback' ]
309 );
310
311 // Get the current submenu page.
312 $submenu_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- $_GET['page'] does not provide nonce.
313
314 // Check if SureMail is installed and active.
315 if ( 'sureforms_smtp' === $submenu_page && file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' ) && is_plugin_active( 'suremails/suremails.php' ) ) {
316 // Plugin is installed and active - redirect to SureMail dashboard.
317 wp_safe_redirect( admin_url( 'options-general.php?page=suremail#/dashboard' ) );
318 exit;
319 }
320 }
321
322 /**
323 * SMTP promotional page callback.
324 *
325 * @return void
326 * @since 1.7.1
327 */
328 public function suremail_page_callback() {
329 echo '<div id="srfm-suremail-container" class="srfm-admin-wrapper"></div>';
330 }
331
332 /**
333 * Render Admin Dashboard.
334 *
335 * @return void
336 * @since 0.0.1
337 */
338 public function render_dashboard() {
339 echo '<div id="srfm-dashboard-container" class="srfm-admin-wrapper"></div>';
340 }
341
342 /**
343 * Settings page callback.
344 *
345 * @return void
346 * @since 0.0.1
347 */
348 public function settings_page_callback() {
349 echo '<div id="srfm-settings-container" class="srfm-admin-wrapper"></div>';
350 }
351
352 /**
353 * Add new form menu item.
354 *
355 * @return void
356 * @since 0.0.1
357 */
358 public function add_new_form() {
359 add_submenu_page(
360 'sureforms_menu',
361 __( 'New Form', 'sureforms' ),
362 __( 'New Form', 'sureforms' ),
363 'edit_others_posts',
364 'add-new-form',
365 [ $this, 'add_new_form_callback' ],
366 2
367 );
368 $entries_hook = add_submenu_page(
369 'sureforms_menu',
370 __( 'Entries', 'sureforms' ),
371 __( 'Entries', 'sureforms' ),
372 'edit_others_posts',
373 SRFM_ENTRIES,
374 [ $this, 'render_entries' ],
375 3
376 );
377
378 if ( $entries_hook ) {
379 add_action( 'load-' . $entries_hook, [ $this, 'mark_entries_page_visit' ] );
380 }
381 }
382
383 /**
384 * Add new form mentu item callback.
385 *
386 * @return void
387 * @since 0.0.1
388 */
389 public function add_new_form_callback() {
390 echo '<div id="srfm-add-new-form-container" class="srfm-admin-wrapper"></div>';
391 }
392
393 /**
394 * Entries page callback.
395 *
396 * @since 0.0.13
397 * @return void
398 */
399 public function render_entries() {
400 // Render single entry view.
401 // Adding the phpcs ignore nonce verification as no database operations are performed in this function, it is used to display the single entry view.
402 if ( isset( $_GET['entry_id'] ) && is_numeric( $_GET['entry_id'] ) && isset( $_GET['view'] ) && 'details' === $_GET['view'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not needed here and explained in the comments above as well.
403 $single_entry_view = new Single_Entry();
404 $single_entry_view->render();
405 return;
406 }
407
408 // Render all entries view.
409 $entries_table = new Entries_List_Table();
410 $entries_table->prepare_items();
411 echo '<div class="wrap"><h1 class="wp-heading-inline">' . esc_html__( 'Entries', 'sureforms' ) . '</h1>';
412 if ( empty( $entries_table->all_entries_count ) && empty( $entries_table->trash_entries_count ) ) {
413 $instance = Post_Types::get_instance();
414 $instance->sureforms_render_blank_state( SRFM_ENTRIES );
415 $instance->get_blank_state_styles();
416 return;
417 }
418 echo '<form method="get">';
419 echo '<input type="hidden" name="page" value="sureforms_entries">';
420 $entries_table->display();
421 echo '</form>';
422 echo '</div>';
423 }
424
425 /**
426 * Add notification badge to SureForms menu when there are new entries.
427 *
428 * @since 1.7.3
429 * @return void
430 */
431 public function maybe_add_entries_badge() {
432 if ( ! current_user_can( 'edit_others_posts' ) ) {
433 return;
434 }
435
436 // If currently viewing the entries listing page, mark it as visited and skip the badge.
437 if ( isset( $_GET['page'] ) && SRFM_ENTRIES === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only checking the page slug.
438 $this->mark_entries_page_visit();
439 return;
440 }
441
442 $srfm_options = get_option( 'srfm_options', [] );
443 $last_visit = isset( $srfm_options['entries_last_visited'] ) ? absint( $srfm_options['entries_last_visited'] ) : 0;
444 $new_entries = Entries::get_entries_count_after( $last_visit );
445
446 if ( $new_entries <= 0 ) {
447 return;
448 }
449
450 global $menu;
451 foreach ( $menu as $index => $item ) {
452 if ( isset( $item[2] ) && 'sureforms_menu' === $item[2] ) {
453 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for menu item.
454 $menu[ $index ][0] .= ' <span class="srfm-update-dot"></span>';
455 break;
456 }
457 }
458
459 global $submenu;
460 if ( isset( $submenu['sureforms_menu'] ) ) {
461 foreach ( $submenu['sureforms_menu'] as $index => $sub_item ) {
462 if ( isset( $sub_item[2] ) && SRFM_ENTRIES === $sub_item[2] ) {
463 $submenu['sureforms_menu'][ $index ][0] .= sprintf( // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Adding notifications for submenu item.
464 ' <span class="update-plugins count-%1$d"><span class="plugin-count">%1$d</span></span>',
465 absint( $new_entries )
466 );
467 break;
468 }
469 }
470 }
471 }
472
473 /**
474 * Mark the user's visit to the entries page.
475 *
476 * @since 1.7.3
477 * @return void
478 */
479 public function mark_entries_page_visit() {
480 if ( current_user_can( 'edit_others_posts' ) ) {
481 $srfm_options = get_option( 'srfm_options', [] );
482 $srfm_options['entries_last_visited'] = time();
483 \SRFM\Inc\Helper::update_admin_settings_option( 'srfm_options', $srfm_options );
484 }
485 }
486
487 /**
488 * Adds a settings link to the plugin action links on the plugins page.
489 *
490 * @param array $links An array of plugin action links.
491 * @param string $file The plugin file path.
492 * @return array The updated array of plugin action links.
493 * @since 0.0.1
494 */
495 public function add_settings_link( $links, $file ) {
496 if ( 'sureforms/sureforms.php' === $file ) {
497 $plugin_links = apply_filters(
498 'sureforms_plugin_action_links',
499 [
500 'sureforms_settings' => '<a href="' . esc_url( admin_url( 'admin.php?page=sureforms_form_settings&tab=general-settings' ) ) . '">' . esc_html__( 'Settings', 'sureforms' ) . '</a>',
501 ]
502 );
503 $links = array_merge( $plugin_links, $links );
504 }
505 return $links;
506 }
507
508 /**
509 * Sureforms block editor styles.
510 *
511 * @since 0.0.1
512 */
513 public function enqueue_styles() {
514 $current_screen = get_current_screen();
515 global $wp_version;
516
517 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
518 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
519
520 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
521 $vendor_css_uri = SRFM_URL . 'assets/css/minified/deps/';
522
523 /* RTL */
524 if ( is_rtl() ) {
525 $file_prefix .= '-rtl';
526 }
527
528 // Enqueue editor styles for post and page.
529 if ( SRFM_FORMS_POST_TYPE === $current_screen->post_type ) {
530 wp_enqueue_style( SRFM_SLUG . '-editor', $css_uri . 'backend/editor' . $file_prefix . '.css', [], SRFM_VER );
531 wp_enqueue_style( SRFM_SLUG . '-backend-blocks', $css_uri . 'blocks/default/backend' . $file_prefix . '.css', [], SRFM_VER );
532 wp_enqueue_style( SRFM_SLUG . '-intl', $vendor_css_uri . 'intl/intlTelInput-backend.min.css', [], SRFM_VER );
533 wp_enqueue_style( SRFM_SLUG . '-common', $css_uri . 'common' . $file_prefix . '.css', [], SRFM_VER );
534 wp_enqueue_style( SRFM_SLUG . '-reactQuill', $vendor_css_uri . 'quill/quill.snow.css', [], SRFM_VER );
535 wp_enqueue_style( SRFM_SLUG . '-single-form-modal', $css_uri . 'single-form-setting' . $file_prefix . '.css', [], SRFM_VER );
536
537 // if version is equal to or lower than 6.6.2 then add compatibility css.
538 if ( version_compare( $wp_version, '6.6.2', '<=' ) ) {
539 $srfm_inline_css = '.srfm-settings-modal .srfm-setting-modal-container .components-toggle-control .components-base-control__help{
540 margin-left: 4em;
541 }';
542 wp_add_inline_style( SRFM_SLUG . '-single-form-modal', $srfm_inline_css );
543 }
544 }
545
546 wp_enqueue_style( SRFM_SLUG . '-form-selector', $css_uri . 'srfm-form-selector' . $file_prefix . '.css', [], SRFM_VER );
547 wp_enqueue_style( SRFM_SLUG . '-common-editor', SRFM_URL . 'assets/build/common-editor.css', [], SRFM_VER, 'all' );
548 }
549
550 /**
551 * Get Breadcrumbs for current page.
552 *
553 * @since 0.0.1
554 * @return array Breadcrumbs Array.
555 */
556 public function get_breadcrumbs_for_current_page() {
557 global $post, $pagenow;
558 $breadcrumbs = [];
559
560 if ( 'admin.php' === $pagenow && isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
561 $page_title = get_admin_page_title();
562 $breadcrumbs[] = [
563 'title' => $page_title,
564 'link' => '',
565 ];
566 } elseif ( $post && in_array( $pagenow, [ 'post.php', 'post-new.php', 'edit.php' ], true ) ) {
567 $post_type_obj = get_post_type_object( get_post_type() );
568 if ( $post_type_obj ) {
569 $post_type_plural = $post_type_obj->labels->name;
570 $breadcrumbs[] = [
571 'title' => $post_type_plural,
572 'link' => admin_url( 'edit.php?post_type=' . $post_type_obj->name ),
573 ];
574
575 if ( 'edit.php' === $pagenow && ! isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We don't need nonce verification here.
576 $breadcrumbs[ count( $breadcrumbs ) - 1 ]['link'] = '';
577 } else {
578 $breadcrumbs[] = [
579 /* Translators: Post Title. */
580 'title' => sprintf( __( 'Edit %1$s', 'sureforms' ), get_the_title() ),
581 'link' => get_edit_post_link( $post->ID ),
582 ];
583 }
584 }
585 } else {
586 $current_screen = get_current_screen();
587 if ( $current_screen && 'sureforms_form' === $current_screen->post_type ) {
588 $breadcrumbs[] = [
589 'title' => 'Forms',
590 'link' => '',
591 ];
592 } else {
593 $breadcrumbs[] = [
594 'title' => '',
595 'link' => '',
596 ];
597 }
598 }
599
600 return $breadcrumbs;
601 }
602
603 /**
604 * Enqueue Admin Scripts.
605 *
606 * @return void
607 * @since 0.0.1
608 */
609 public function enqueue_scripts() {
610 $current_screen = get_current_screen();
611 global $wp_version;
612
613 $file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
614 $dir_name = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
615 $js_uri = SRFM_URL . 'assets/js/' . $dir_name . '/';
616 $css_uri = SRFM_URL . 'assets/css/' . $dir_name . '/';
617 $is_rtl = is_rtl();
618 $rtl = $is_rtl ? '-rtl' : '';
619
620 /**
621 * List of the handles in which we need to add translation compatibility.
622 */
623 $script_translations_handlers = [];
624 $onboarding_instance = Onboarding::get_instance();
625
626 $localization_data = [
627 'site_url' => get_site_url(),
628 'breadcrumbs' => $this->get_breadcrumbs_for_current_page(),
629 'sureforms_dashboard_url' => admin_url( '/admin.php?page=sureforms_menu' ),
630 'plugin_version' => SRFM_VER,
631 'global_settings_nonce' => current_user_can( 'manage_options' ) ? wp_create_nonce( 'wp_rest' ) : '',
632 'is_pro_active' => Helper::has_pro(),
633 'pro_plugin_version' => Helper::has_pro() ? SRFM_PRO_VER : '',
634 'pro_plugin_name' => Helper::has_pro() && defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro',
635 'sureforms_pricing_page' => Helper::get_sureforms_website_url( 'pricing' ),
636 'field_spacing_vars' => Helper::get_css_vars(),
637 'is_ver_lower_than_6_7' => version_compare( $wp_version, '6.6.2', '<=' ),
638 'integrations' => Helper::sureforms_get_integration(),
639 'ajax_url' => admin_url( 'admin-ajax.php' ),
640 'sf_plugin_manager_nonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
641 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
642 'plugin_activating_text' => __( 'Activating...', 'sureforms' ),
643 'plugin_activated_text' => __( 'Activated', 'sureforms' ),
644 'plugin_activate_text' => __( 'Activate', 'sureforms' ),
645 'plugin_installing_text' => __( 'Installing...', 'sureforms' ),
646 'plugin_installed_text' => __( 'Installed', 'sureforms' ),
647 'is_rtl' => $is_rtl,
648 'onboarding_completed' => method_exists( $onboarding_instance, 'get_onboarding_status' ) ? $onboarding_instance->get_onboarding_status() : false,
649 'onboarding_redirect' => isset( $_GET['srfm-activation-redirect'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce is not required for the activation redirection.
650 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
651 'srfm_ai_details' => AI_Helper::get_current_usage_details(),
652 ];
653
654 $is_screen_sureforms_menu = Helper::validate_request_context( 'sureforms_menu', 'page' );
655 $is_screen_add_new_form = Helper::validate_request_context( 'add-new-form', 'page' );
656 $is_screen_sureforms_form_settings = Helper::validate_request_context( 'sureforms_form_settings', 'page' );
657 $is_screen_sureforms_entries = Helper::validate_request_context( SRFM_ENTRIES, 'page' );
658 $is_post_type_sureforms_form = SRFM_FORMS_POST_TYPE === $current_screen->post_type;
659
660 if ( $is_screen_sureforms_menu || $is_post_type_sureforms_form || $is_screen_add_new_form || $is_screen_sureforms_form_settings || $is_screen_sureforms_entries ) {
661 $asset_handle = '-dashboard';
662
663 wp_enqueue_style( SRFM_SLUG . $asset_handle . '-font', 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap', [], SRFM_VER );
664
665 $script_asset_path = SRFM_DIR . 'assets/build/dashboard.asset.php';
666 $script_info = file_exists( $script_asset_path )
667 ? include $script_asset_path
668 : [
669 'dependencies' => [],
670 'version' => SRFM_VER,
671 ];
672 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/dashboard.js', $script_info['dependencies'], SRFM_VER, true );
673
674 wp_localize_script( SRFM_SLUG . $asset_handle, 'scIcons', [ 'path' => SRFM_URL . 'assets/build/icon-assets' ] );
675
676 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
677
678 if ( class_exists( 'SRFM_PRO\Admin\Licensing' ) ) {
679 $license_active = \SRFM_PRO\Admin\Licensing::is_license_active();
680 $localization_data['is_license_active'] = $license_active;
681
682 // Updating current licensing status.
683 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
684 $current_license_status = $license_active ? 'licensed' : 'unlicensed';
685 if ( $current_license_status !== $srfm_pro_license_status ) {
686 update_option( 'srfm_pro_license_status', $current_license_status );
687 }
688 }
689
690 $localization_data['security_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=security-settings' );
691 $localization_data['integration_settings_url'] = admin_url( '/admin.php?page=sureforms_form_settings&tab=integration-settings' );
692 wp_localize_script(
693 SRFM_SLUG . $asset_handle,
694 SRFM_SLUG . '_admin',
695 apply_filters(
696 SRFM_SLUG . '_admin_filter',
697 $localization_data
698 )
699 );
700 wp_enqueue_style( SRFM_SLUG . '-dashboard', SRFM_URL . 'assets/build/dashboard.css', [], SRFM_VER, 'all' );
701
702 }
703
704 if ( $is_screen_sureforms_form_settings ) {
705 wp_enqueue_style( SRFM_SLUG . '-settings', $css_uri . 'backend/settings' . $file_prefix . $rtl . '.css', [], SRFM_VER );
706 }
707
708 // Enqueue styles for the entries page.
709 if ( $is_screen_sureforms_entries ) {
710 $asset_handle = '-entries';
711 wp_enqueue_script( SRFM_SLUG . $asset_handle, SRFM_URL . 'assets/build/entries.js', $script_info['dependencies'], SRFM_VER, true );
712
713 $script_translations_handlers[] = SRFM_SLUG . $asset_handle;
714 }
715
716 // Enqueue scripts for the SureMail promotional page.
717 $is_screen_sureforms_smtp = Helper::validate_request_context( 'sureforms_smtp', 'page' );
718 if ( $is_screen_sureforms_smtp ) {
719 $asset_handle = 'suremail';
720
721 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
722 $script_info = file_exists( $script_asset_path )
723 ? include $script_asset_path
724 : [
725 'dependencies' => [],
726 'version' => SRFM_VER,
727 ];
728
729 wp_enqueue_script( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
730 wp_enqueue_style( SRFM_SLUG . '-suremail', SRFM_URL . 'assets/build/suremail.css', [], SRFM_VER, 'all' );
731
732 // Localize script for SureMail page.
733 $suremail_localization_data = [
734 'ajax_url' => admin_url( 'admin-ajax.php' ),
735 'admin_url' => admin_url(),
736 'suremail_url' => 'https://sureforms.com/suremail/',
737 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
738 'sfPluginManagerNonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
739 'suremail_status' => file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' )
740 ? ( is_plugin_active( 'suremails/suremails.php' ) ? 'active' : 'installed' )
741 : 'not_installed',
742 ];
743
744 wp_localize_script(
745 SRFM_SLUG . '-suremail',
746 SRFM_SLUG . '_admin',
747 apply_filters(
748 SRFM_SLUG . '_suremail_admin_filter',
749 $suremail_localization_data
750 )
751 );
752
753 $script_translations_handlers[] = SRFM_SLUG . '-suremail';
754 }
755
756 // Admin Submenu Styles.
757 wp_enqueue_style( SRFM_SLUG . '-admin', $css_uri . 'backend/admin' . $file_prefix . $rtl . '.css', [], SRFM_VER );
758
759 if ( 'edit-' . SRFM_FORMS_POST_TYPE === $current_screen->id ) {
760 $asset_handle = 'page_header';
761
762 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
763 $script_info = file_exists( $script_asset_path )
764 ? include $script_asset_path
765 : [
766 'dependencies' => [],
767 'version' => SRFM_VER,
768 ];
769 wp_enqueue_script( SRFM_SLUG . '-form-page-header', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
770 wp_enqueue_style( SRFM_SLUG . '-form-archive-styles', $css_uri . 'form-archive-styles' . $file_prefix . $rtl . '.css', [], SRFM_VER );
771
772 $script_translations_handlers[] = SRFM_SLUG . '-form-page-header';
773 }
774
775 if ( $is_screen_sureforms_form_settings ) {
776 $asset_handle = 'settings';
777
778 $script_asset_path = SRFM_DIR . 'assets/build/' . $asset_handle . '.asset.php';
779 $script_info = file_exists( $script_asset_path )
780 ? include $script_asset_path
781 : [
782 'dependencies' => [],
783 'version' => SRFM_VER,
784 ];
785
786 wp_enqueue_script( SRFM_SLUG . '-settings', SRFM_URL . 'assets/build/' . $asset_handle . '.js', $script_info['dependencies'], SRFM_VER, true );
787 wp_localize_script(
788 SRFM_SLUG . '-settings',
789 SRFM_SLUG . '_admin',
790 $localization_data
791 );
792
793 $script_translations_handlers[] = SRFM_SLUG . '-settings';
794 }
795 if ( 'edit-' . SRFM_FORMS_POST_TYPE === $current_screen->id ) {
796 wp_enqueue_script( SRFM_SLUG . '-form-archive', $js_uri . 'form-archive' . $file_prefix . '.js', [], SRFM_VER, true );
797 wp_enqueue_script( SRFM_SLUG . '-export', $js_uri . 'export' . $file_prefix . '.js', [ 'wp-i18n' ], SRFM_VER, true );
798 wp_localize_script(
799 SRFM_SLUG . '-export',
800 SRFM_SLUG . '_export',
801 [
802 'ajaxurl' => admin_url( 'admin-ajax.php' ),
803 'srfm_export_nonce' => wp_create_nonce( 'export_form_nonce' ),
804 'site_url' => get_site_url(),
805 'import_form_nonce' => current_user_can( 'edit_posts' ) ? wp_create_nonce( 'wp_rest' ) : '',
806 'import_btn_string' => __( 'Import Form', 'sureforms' ),
807 ]
808 );
809
810 wp_enqueue_script( SRFM_SLUG . '-backend', $js_uri . 'backend' . $file_prefix . '.js', [], SRFM_VER, true );
811 wp_localize_script(
812 SRFM_SLUG . '-backend',
813 SRFM_SLUG . '_backend',
814 [
815 'site_url' => get_site_url(),
816 ]
817 );
818
819 $script_translations_handlers[] = SRFM_SLUG . '-form-archive';
820 $script_translations_handlers[] = SRFM_SLUG . '-export';
821 $script_translations_handlers[] = SRFM_SLUG . '-backend';
822 }
823
824 if ( $is_screen_add_new_form ) {
825 wp_enqueue_style( SRFM_SLUG . '-template-picker', $css_uri . 'template-picker' . $file_prefix . $rtl . '.css', [], SRFM_VER );
826
827 $sureforms_admin = 'templatePicker';
828
829 $script_asset_path = SRFM_DIR . 'assets/build/' . $sureforms_admin . '.asset.php';
830 $script_info = file_exists( $script_asset_path )
831 ? include $script_asset_path
832 : [
833 'dependencies' => [],
834 'version' => SRFM_VER,
835 ];
836 wp_enqueue_script( SRFM_SLUG . '-template-picker', SRFM_URL . 'assets/build/' . $sureforms_admin . '.js', $script_info['dependencies'], SRFM_VER, true );
837
838 wp_localize_script(
839 SRFM_SLUG . '-template-picker',
840 SRFM_SLUG . '_admin',
841 [
842 'site_url' => get_site_url(),
843 'plugin_url' => SRFM_URL,
844 'preview_images_url' => SRFM_URL . 'images/template-previews/',
845 'admin_url' => admin_url( 'admin.php' ),
846 'new_template_picker_base_url' => admin_url( 'post-new.php?post_type=sureforms_form' ),
847 'capability' => current_user_can( 'edit_posts' ),
848 'template_picker_nonce' => current_user_can( 'edit_posts' ) ? wp_create_nonce( 'wp_rest' ) : '',
849 'is_pro_active' => Helper::has_pro(),
850 'srfm_ai_usage_details' => AI_Helper::get_current_usage_details(),
851 'is_pro_license_active' => AI_Helper::is_pro_license_active(),
852 'srfm_ai_auth_user_email' => get_option( 'srfm_ai_auth_user_email' ),
853 'pricing_page_url' => Helper::get_sureforms_website_url( 'pricing' ),
854 'licensing_nonce' => wp_create_nonce( 'srfm_pro_licensing_nonce' ),
855 ]
856 );
857
858 $script_translations_handlers[] = SRFM_SLUG . '-template-picker';
859 }
860 // Quick action sidebar.
861 $default_allowed_quick_sidebar_blocks = apply_filters(
862 'srfm_quick_sidebar_allowed_blocks',
863 [
864 'srfm/input',
865 'srfm/email',
866 'srfm/textarea',
867 'srfm/checkbox',
868 'srfm/number',
869 'srfm/inline-button',
870 'srfm/advanced-heading',
871 ]
872 );
873 if ( ! is_array( $default_allowed_quick_sidebar_blocks ) ) {
874 $default_allowed_quick_sidebar_blocks = [];
875 }
876
877 $srfm_enable_quick_action_sidebar = get_option( 'srfm_enable_quick_action_sidebar' );
878 if ( ! $srfm_enable_quick_action_sidebar ) {
879 $srfm_enable_quick_action_sidebar = 'disabled';
880 }
881 $quick_sidebar_allowed_blocks = get_option( 'srfm_quick_sidebar_allowed_blocks' );
882 $quick_sidebar_allowed_blocks = ! empty( $quick_sidebar_allowed_blocks ) && is_array( $quick_sidebar_allowed_blocks ) ? $quick_sidebar_allowed_blocks : $default_allowed_quick_sidebar_blocks;
883 $srfm_ajax_nonce = wp_create_nonce( 'srfm_ajax_nonce' );
884 wp_enqueue_script( SRFM_SLUG . '-quick-action-siderbar', SRFM_URL . 'assets/build/quickActionSidebar.js', [], SRFM_VER, true );
885 wp_localize_script(
886 SRFM_SLUG . '-quick-action-siderbar',
887 SRFM_SLUG . '_quick_sidebar_blocks',
888 [
889 'allowed_blocks' => $quick_sidebar_allowed_blocks,
890 'srfm_enable_quick_action_sidebar' => $srfm_enable_quick_action_sidebar,
891 'srfm_ajax_nonce' => $srfm_ajax_nonce,
892 'srfm_ajax_url' => admin_url( 'admin-ajax.php' ),
893 ]
894 );
895
896 $script_translations_handlers[] = SRFM_SLUG . '-quick-action-siderbar';
897
898 /**
899 * Enqueuing SureTriggers Integration script.
900 * This script loads suretriggers iframe in Intergations tab.
901 */
902 if ( $is_post_type_sureforms_form ) {
903 wp_enqueue_script( SRFM_SLUG . '-suretriggers-integration', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL . 'js/v2/embed.js', [], SRFM_VER, true );
904 }
905
906 // Check $script_translations_handlers is not empty before calling the function.
907 if ( ! empty( $script_translations_handlers ) ) {
908 // Remove duplicates values from the array.
909 $script_translations_handlers = array_unique( $script_translations_handlers );
910
911 foreach ( $script_translations_handlers as $script_handle ) {
912 Helper::register_script_translations( $script_handle );
913 }
914 }
915 }
916
917 /**
918 * Form Template Picker Admin Body Classes
919 * WordPress sometimes translates class names in the admin body tag, which can result in
920 * incorrect or missing class names when rendering the admin pages. This function ensures
921 * that essential class names are manually added to the body tag to maintain proper functionality.
922 *
923 * @since 0.0.1
924 * @param string $classes Space separated class string.
925 */
926 public function admin_template_picker_body_class( $classes = '' ) {
927 // Define an associative array of class names and their corresponding conditions.
928 // Each condition checks whether a specific request context matches.
929 $srfm_classes = [
930 'sureforms_page_sureforms_entries' => Helper::validate_request_context( SRFM_ENTRIES, 'page' ),
931 'sureforms_page_sureforms_form_settings' => Helper::validate_request_context( 'sureforms_form_settings', 'page' ),
932 'srfm-template-picker' => Helper::validate_request_context( 'add-new-form', 'page' ),
933 ];
934
935 $add_srfm_classes = '';
936
937 // Loop through the defined classes and conditions.
938 foreach ( $srfm_classes as $class => $condition ) {
939 // Check if the condition evaluates to true.
940 if ( $condition ) {
941 // Append the class to the existing classes string, followed by a space.
942 $add_srfm_classes .= empty( $add_srfm_classes ) ? $class : ' ' . $class;
943 }
944 }
945
946 // Append the new classes to the existing classes string.
947 if ( ! empty( $add_srfm_classes ) ) {
948 $classes .= ' ' . $add_srfm_classes;
949 }
950
951 // Return the updated list of classes.
952 return $classes;
953 }
954
955 /**
956 * Disable spectra's quick action bar in sureforms CPT.
957 *
958 * @param string $status current status of the quick action bar.
959 * @since 0.0.2
960 * @return string
961 */
962 public function restrict_spectra_quick_action_bar( $status ) {
963 $screen = get_current_screen();
964 if ( 'disabled' !== $status && isset( $screen->id ) && 'sureforms_form' === $screen->id ) {
965 $status = 'disabled';
966 }
967
968 return $status;
969 }
970
971 // Entries methods.
972
973 /**
974 * Handle entry actions.
975 *
976 * @since 0.0.13
977 * @return void
978 */
979 public function handle_entry_actions() {
980 Entries_List_Table::process_bulk_actions();
981
982 if ( ! isset( $_GET['page'] ) || SRFM_ENTRIES !== $_GET['page'] ) {
983 return;
984 }
985 if ( ! isset( $_GET['entry_id'] ) || ! isset( $_GET['action'] ) ) {
986 return;
987 }
988 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'srfm_entries_action' ) ) {
989 wp_die( esc_html__( 'Nonce verification failed.', 'sureforms' ) );
990 }
991 $action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : '';
992 $entry_id = Helper::get_integer_value( sanitize_text_field( wp_unslash( $_GET['entry_id'] ) ) );
993 $view = isset( $_GET['view'] ) ? sanitize_text_field( wp_unslash( $_GET['view'] ) ) : '';
994 if ( $entry_id > 0 ) {
995 if ( 'read' === $action && 'details' === $view ) {
996 $entry_status = Entries::get( $entry_id )['status'];
997 if ( 'trash' === $entry_status ) {
998 wp_die( esc_html__( 'You cannot view this entry because it is in trash.', 'sureforms' ) );
999 }
1000 }
1001 Entries_List_Table::handle_entry_status( $entry_id, $action, $view );
1002 }
1003 }
1004
1005 /**
1006 * Admin Notice Callback if sureforms pro is out of date.
1007 *
1008 * Hooked - admin_notices
1009 *
1010 * @return void
1011 * @since 1.0.4
1012 */
1013 public function srfm_pro_version_compatibility() {
1014 if ( ! Helper::has_pro() ) {
1015 return;
1016 }
1017
1018 if ( empty( get_current_screen() ) ) {
1019 return;
1020 }
1021
1022 if ( ! current_user_can( 'update_plugins' ) ) {
1023 return;
1024 }
1025
1026 $srfm_pro_license_status = get_option( 'srfm_pro_license_status', '' );
1027 /**
1028 * If the license status is not set then get the license status and update the option accordingly.
1029 * This will be executed only once. Subsequently, the option status is updated by the licensing class on license activation or deactivation.
1030 */
1031 if ( empty( $srfm_pro_license_status ) && class_exists( 'SRFM_PRO\Admin\Licensing' ) ) {
1032 $srfm_pro_license_status = \SRFM_PRO\Admin\Licensing::is_license_active() ? 'licensed' : 'unlicensed';
1033 update_option( 'srfm_pro_license_status', $srfm_pro_license_status );
1034 }
1035
1036 $pro_plugin_name = defined( 'SRFM_PRO_PRODUCT' ) ? SRFM_PRO_PRODUCT : 'SureForms Pro';
1037 $message = '';
1038 $url = admin_url( 'admin.php?page=sureforms_form_settings&tab=account-settings' );
1039 if ( 'unlicensed' === $srfm_pro_license_status ) {
1040 $message = '<p>' . sprintf(
1041 // translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name.
1042 esc_html__( 'Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more.', 'sureforms' ),
1043 '<a href="' . esc_url( $url ) . '">',
1044 '</a>',
1045 '<i>' . esc_html( $pro_plugin_name ) . '</i>'
1046 ) . '</p>';
1047 }
1048
1049 if ( ! version_compare( SRFM_PRO_VER, SRFM_PRO_RECOMMENDED_VER, '>=' ) ) {
1050 $message .= '<p>' . sprintf(
1051 // 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.
1052 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' ),
1053 esc_html( SRFM_VER ),
1054 esc_html( $pro_plugin_name ),
1055 esc_html( SRFM_PRO_RECOMMENDED_VER ),
1056 '<a href=' . esc_url( admin_url( 'update-core.php' ) ) . '>',
1057 '</a>'
1058 ) . '</p>';
1059 }
1060
1061 if ( ! empty( $message ) ) {
1062 // Phpcs ignore comment is required as $message variable is already escaped.
1063 echo '<div class="notice notice-warning">' . wp_kses_post( $message ) . '</div>';
1064 }
1065 }
1066
1067 /**
1068 * Add SMTP warning admin notice if no SMTP plugin is active
1069 *
1070 * Hooked - admin_notices
1071 *
1072 * @return void
1073 * @since 1.9.1
1074 */
1075 public function add_smtp_warning_notice() {
1076 if ( ! current_user_can( 'manage_options' ) ) {
1077 return;
1078 }
1079 // Only show on dashboard or SureForms admin pages.
1080 $screen = get_current_screen();
1081 if ( ! $screen || ( false === strpos( $screen->id, 'sureforms' ) && 'dashboard' !== $screen->id ) ) {
1082 return;
1083 }
1084 // Dismiss logic.
1085 if ( isset( $_GET['srfm_dismiss_smtp_notice'] ) && '1' === $_GET['srfm_dismiss_smtp_notice'] ) {
1086 // Verify nonce for security.
1087 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'srfm_dismiss_smtp_notice' ) ) {
1088 return;
1089 }
1090 update_user_meta( get_current_user_id(), 'srfm_dismiss_smtp_notice', 1 );
1091 return;
1092 }
1093 if ( get_user_meta( get_current_user_id(), 'srfm_dismiss_smtp_notice', true ) ) {
1094 return;
1095 }
1096 // Determine SureMail plugin status and link.
1097 $plugin_file = 'suremails/suremails.php';
1098 if ( file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' ) && is_plugin_active( $plugin_file ) ) {
1099 // SureMail is active, do not show the notice.
1100 return;
1101 }
1102 if ( ! Helper::is_any_smtp_plugin_active() ) {
1103 if ( file_exists( WP_PLUGIN_DIR . '/suremails/suremails.php' ) ) {
1104 if ( is_plugin_active( $plugin_file ) ) {
1105 $suremail_url = admin_url( 'options-general.php?page=suremail#/dashboard' );
1106 } else {
1107 $suremail_url = wp_nonce_url( admin_url( 'plugins.php?action=activate&plugin=' . $plugin_file ), 'activate-plugin_' . $plugin_file );
1108 }
1109 } else {
1110 $suremail_url = admin_url( 'plugin-install.php?s=suremail&tab=search&type=term' );
1111 }
1112 $dismiss_url = wp_nonce_url( add_query_arg( 'srfm_dismiss_smtp_notice', '1' ), 'srfm_dismiss_smtp_notice' );
1113 printf(
1114 '<div class="notice notice-warning is-dismissible srfm-smtp-warning" data-dismiss-url="%1$s"><p>%2$s</p></div>',
1115 esc_url( $dismiss_url ),
1116 sprintf(
1117 /* translators: 1: line break, 2: SureMail link opening tag, 3: SureMail link closing tag */
1118 esc_html__( 'It looks like there\'s no SMTP plugin running on your site. That means emails sent from SureForms might not go through.%1$sYou can use %2$sSureMail%3$s to get email delivery working.', 'sureforms' ),
1119 '<br />',
1120 '<a href="' . esc_url( $suremail_url ) . '" target="_blank">',
1121 '</a>'
1122 )
1123 );
1124 ?>
1125 <script type="text/javascript">
1126 document.addEventListener('DOMContentLoaded', function() {
1127 // Handle SMTP notice dismissal using event delegation
1128 // This works even if the dismiss button is added dynamically by WordPress
1129 document.addEventListener('click', function(e) {
1130 // Check if clicked element is a dismiss button within our SMTP notice
1131 if (e.target.classList.contains('notice-dismiss') && e.target.closest('.srfm-smtp-warning')) {
1132 const smtpNotice = e.target.closest('.srfm-smtp-warning');
1133 const dismissUrl = smtpNotice.dataset.dismissUrl;
1134
1135 if (dismissUrl) {
1136 // Security: Validate URL is safe before redirecting
1137 try {
1138 const url = new URL(dismissUrl, window.location.origin);
1139 // Only allow same-origin URLs for security
1140 if (url.origin === window.location.origin && url.protocol === window.location.protocol) {
1141 window.location.href = url.href;
1142 }
1143 } catch (error) {
1144 // Invalid URL - ignore the redirect for security
1145 console.warn('Invalid dismiss URL detected:', dismissUrl);
1146 }
1147 e.preventDefault();
1148 e.stopPropagation();
1149 }
1150 }
1151 });
1152 });
1153 </script>
1154 <?php
1155 }
1156 }
1157
1158 /**
1159 * Disables the capabilities for WPForms to avoid conflicts when enqueueing
1160 * scripts and styles for WPForms.
1161 *
1162 * This function is intended to prevent any potential conflicts that may arise
1163 * when WPForms scripts and styles are enqueued. By disabling certain capabilities,
1164 * it ensures that WPForms does not interfere with other functionalities.
1165 *
1166 * @param bool $user_can A boolean indicating whether the user has the capability.
1167 * @return bool Returns true if the capabilities are successfully disabled, false otherwise.
1168 * @since 1.4.2
1169 */
1170 public function disable_wpforms_capabilities( $user_can ) {
1171 // Note: Nonce verification is intentionally omitted here as no database operations are performed.
1172 // The values of the $_REQUEST variables are strictly validated, ensuring security without the need for nonce verification.
1173
1174 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1175 $post_id = ! empty( $_REQUEST['post'] ) && ! empty( $_REQUEST['action'] ) ? absint( $_REQUEST['post'] ) : 0;
1176
1177 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1178 $post_type = $post_id ? get_post_type( $post_id ) : sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ?? '' ) );
1179 return SRFM_FORMS_POST_TYPE === $post_type ? false : $user_can;
1180 }
1181
1182 /**
1183 * Enqueueus the admin pointer script and styles.
1184 *
1185 * @return void
1186 * @since 1.8.0
1187 */
1188 public function enqueue_admin_pointer() {
1189 if ( ! $this->is_admin_pointer_visible() ) {
1190 return;
1191 }
1192 wp_enqueue_style( 'wp-pointer' );
1193 wp_enqueue_script( 'wp-pointer' );
1194 wp_enqueue_script(
1195 'sureforms-admin-pointer',
1196 plugins_url( 'admin/assets/js/sureforms-pointer.js', SRFM_FILE ),
1197 [ 'wp-pointer', 'jquery' ],
1198 SRFM_VER,
1199 true
1200 );
1201 wp_localize_script(
1202 'sureforms-admin-pointer',
1203 'sureformsPointerData',
1204 [
1205 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1206 'pointer_nonce' => wp_create_nonce( 'sureforms_pointer_action' ),
1207 ]
1208 );
1209 }
1210
1211 /**
1212 * Ajax handler for pointer popup visibility.
1213 *
1214 * @return void
1215 * @since 1.8.0
1216 */
1217 public function pointer_should_show() {
1218 // Security: Check user capability.
1219 if ( ! current_user_can( 'manage_options' ) ) {
1220 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1221 }
1222 // Security: Nonce check.
1223 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1224 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1225 }
1226
1227 $content_markup = sprintf(
1228 /* translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong */
1229 __( '%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' ),
1230 '<span>',
1231 '<strong>',
1232 '</strong>',
1233 '</span><br/>',
1234 '<strong style="font-size:1.1em;">',
1235 '</strong>'
1236 );
1237 wp_send_json(
1238 [
1239 'show' => true,
1240 'title' => esc_html( __( 'SureForms is waiting for you!', 'sureforms' ) ),
1241 'content' => wp_kses_post( $content_markup ),
1242 'button_text' => esc_html( __( 'Build My First Form', 'sureforms' ) ),
1243 'dismiss' => esc_html( __( 'Dismiss', 'sureforms' ) ),
1244 'button_url' => admin_url( 'admin.php?page=add-new-form' ),
1245 ]
1246 );
1247 }
1248
1249 /**
1250 * Ajax callback for pointer popup dismissed action.
1251 *
1252 * @return void
1253 * @since 1.8.0
1254 */
1255 public function pointer_dismissed() {
1256 // Security: Check user capability.
1257 if ( ! current_user_can( 'manage_options' ) ) {
1258 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1259 }
1260 // Security: Nonce check.
1261 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1262 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1263 }
1264 // Use Helper to update srfm_options key.
1265 Helper::update_srfm_option( 'pointer_popup_dismissed', time() );
1266
1267 wp_send_json_success();
1268 }
1269
1270 /**
1271 * Ajax pointer accepted CTA callback.
1272 *
1273 * @return void
1274 * @since 1.8.0
1275 */
1276 public function pointer_accepted_cta() {
1277 // Security: Check user capability.
1278 if ( ! current_user_can( 'manage_options' ) ) {
1279 wp_send_json_error( [ 'message' => __( 'Unauthorized user.', 'sureforms' ) ], 403 );
1280 }
1281 // Security: Nonce check.
1282 if ( empty( $_POST['pointer_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pointer_nonce'] ) ), 'sureforms_pointer_action' ) ) {
1283 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ], 403 );
1284 }
1285 // Use Helper to update srfm_options key.
1286 Helper::update_srfm_option( 'pointer_popup_accepted', time() );
1287
1288 wp_send_json_success();
1289 }
1290
1291 /**
1292 * Maybe register the dashboard widget based on entries.
1293 *
1294 * @return void
1295 * @since 1.9.1
1296 */
1297 public function maybe_register_dashboard_widget() {
1298 // Quick check if there are any entries in the last 7 days.
1299 $seven_days_ago = strtotime( '-7 days' );
1300 $total_entries = Entries::get_entries_count_after( $seven_days_ago );
1301
1302 // Only add the dashboard setup hook if there are entries.
1303 if ( $total_entries > 0 ) {
1304 // Get forms with entries (limit 4 for dashboard widget).
1305 $this->dashboard_widget_data = Helper::get_forms_with_entry_counts( $seven_days_ago, 4 );
1306
1307 // Only show dashboard widget if there are forms with entries.
1308 if ( ! empty( $this->dashboard_widget_data ) ) {
1309 add_action( 'wp_dashboard_setup', [ $this, 'register_dashboard_widget' ] );
1310 }
1311 }
1312 }
1313
1314 /**
1315 * Register the dashboard widget.
1316 *
1317 * @return void
1318 * @since 1.9.1
1319 */
1320 public function register_dashboard_widget() {
1321 // Add the widget with high priority to position it at the top.
1322 wp_add_dashboard_widget(
1323 'sureforms_recent_entries',
1324 __( 'SureForms', 'sureforms' ),
1325 [ $this, 'render_dashboard_widget' ],
1326 null,
1327 null,
1328 'normal',
1329 'high'
1330 );
1331 }
1332
1333 /**
1334 * Render the dashboard widget content.
1335 *
1336 * @return void
1337 * @since 1.9.1
1338 */
1339 public function render_dashboard_widget() {
1340 // Use the pre-fetched data to avoid duplicate queries.
1341 $entries_data = $this->dashboard_widget_data;
1342
1343 // Display the widget content.
1344 ?>
1345 <div class="srfm-dashboard-widget">
1346 <div class="srfm-widget-header">
1347 <h3 class="srfm-widget-title">
1348 <?php esc_html_e( 'Recent Entries', 'sureforms' ); ?>
1349 <span class="srfm-widget-subtitle"><?php esc_html_e( '( Last 7 days )', 'sureforms' ); ?></span>
1350 </h3>
1351 <a href="<?php echo esc_url( admin_url( 'admin.php?page=sureforms_entries' ) ); ?>" class="srfm-widget-view-link">
1352 <?php esc_html_e( 'View', 'sureforms' ); ?>
1353 </a>
1354 </div>
1355
1356 <div class="srfm-table-wrapper">
1357 <table class="srfm-entries-table">
1358 <thead>
1359 <tr>
1360 <th><?php esc_html_e( 'Form Name', 'sureforms' ); ?></th>
1361 <th><?php esc_html_e( 'Entries', 'sureforms' ); ?></th>
1362 </tr>
1363 </thead>
1364 <tbody>
1365 <?php foreach ( $entries_data as $form_data ) { ?>
1366 <tr>
1367 <td class="form-name"><?php echo esc_html( $form_data['title'] ); ?></td>
1368 <td class="entry-count"><?php echo esc_html( $form_data['count'] ); ?></td>
1369 </tr>
1370 <?php } ?>
1371 </tbody>
1372 </table>
1373 </div>
1374
1375 <?php
1376 // Render footer if applicable.
1377 $this->render_dashboard_widget_footer( $entries_data );
1378 ?>
1379 </div>
1380 <?php
1381 }
1382
1383 /**
1384 * Get random premium feature text.
1385 *
1386 * @return string Random feature text.
1387 * @since 1.9.1
1388 */
1389 private function get_random_premium_feature_text() {
1390 $features = [
1391 __( 'Use Conditional Logic to show only what matters', 'sureforms' ),
1392 __( 'Split your form into steps to keep it easy', 'sureforms' ),
1393 __( 'Let people upload files directly to your form', 'sureforms' ),
1394 __( 'Turn responses into downloadable PDFs automatically', 'sureforms' ),
1395 __( 'Let users sign with a simple signature field', 'sureforms' ),
1396 __( 'Connect your form to other tools using webhooks', 'sureforms' ),
1397 __( 'Use Conversational Forms for a chat-like experience', 'sureforms' ),
1398 __( 'Let users register or log in through your form', 'sureforms' ),
1399 __( 'Build forms that create WordPress user accounts', 'sureforms' ),
1400 __( 'Add calculations to auto-total scores or prices', 'sureforms' ),
1401 ];
1402
1403 // Get a random feature.
1404 $random_key = array_rand( $features );
1405 return $features[ $random_key ];
1406 }
1407
1408 /**
1409 * Render the dashboard widget footer for upsell.
1410 *
1411 * @param array $entries_data The entries data array.
1412 * @return void
1413 * @since 1.9.1
1414 */
1415 private function render_dashboard_widget_footer( $entries_data ) {
1416 // Only show footer if Pro is not active.
1417 if ( Helper::has_pro() ) {
1418 return;
1419 }
1420
1421 // Count total entries in last 7 days.
1422 $total_entries = 0;
1423 foreach ( $entries_data as $form_data ) {
1424 $total_entries += $form_data['count'];
1425 }
1426
1427 // Count total published forms.
1428 $published_forms_count = wp_count_posts( SRFM_FORMS_POST_TYPE )->publish;
1429
1430 // Show footer only if 3+ entries received OR 3+ forms published.
1431 if ( $total_entries >= 3 || $published_forms_count >= 3 ) {
1432 ?>
1433 <div class="srfm-widget-footer">
1434 <div class="srfm-upgrade-content">
1435 <svg class="srfm-logo-icon" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
1436 <rect width="20" height="20" fill="#D54407"/>
1437 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1438 <path d="M5.7139 4.2854H14.2853V7.1425H7.1424L5.7139 8.5711V7.1425V4.2854Z" fill="white"/>
1439 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1440 <path d="M5.7148 8.5713H12.8577V11.4284H7.1434L5.7148 12.857V11.4284V8.5713Z" fill="white"/>
1441 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1442 <path d="M5.7148 12.8569H10.0006V15.7141H5.7148V12.8569Z" fill="white"/>
1443 </svg>
1444 <span><?php echo esc_html( $this->get_random_premium_feature_text() ); ?></span>
1445 </div>
1446 <?php
1447 $upgrade_url = add_query_arg(
1448 [
1449 'utm_medium' => 'dashboard-widget',
1450 ],
1451 Helper::get_sureforms_website_url( 'pricing' )
1452 );
1453 ?>
1454 <a href="<?php echo esc_url( $upgrade_url ); ?>" class="srfm-upgrade-link" target="_blank">
1455 <?php esc_html_e( 'Upgrade', 'sureforms' ); ?>
1456 </a>
1457 </div>
1458 <?php
1459 }
1460 }
1461
1462 /**
1463 * Determine if the admin pointer should be visible on this page.
1464 *
1465 * @since 1.8.0
1466 * @return bool
1467 */
1468 private function is_admin_pointer_visible() {
1469 global $pagenow;
1470 $allowed_pages = [ 'index.php', 'options-general.php' ];
1471
1472 // Do not show if pointer dismissed, accepted, or more than 1 form exists.
1473 if (
1474 ! empty( Helper::get_srfm_option( 'pointer_popup_dismissed' ) )
1475 || ! empty( Helper::get_srfm_option( 'pointer_popup_accepted' ) )
1476 || (int) ( wp_count_posts( SRFM_FORMS_POST_TYPE )->publish ?? 0 ) > 1
1477 ) {
1478 return false;
1479 }
1480
1481 if ( in_array( $pagenow, $allowed_pages, true ) ) {
1482 return true;
1483 }
1484
1485 return false;
1486 }
1487
1488 }
1489