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

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

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