PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / controllers / FrmSettingsController.php

FrmSettingsController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More trunk, at classes/controllers/FrmSettingsController.php

647 lines 18.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmSettingsController {
7
8 /**
9 * Icon for the API section, used whether the add-on is active or only a placeholder.
10 *
11 * @since 6.35
12 *
13 * @var string
14 */
15 private static $api_section_icon = 'frmfont frm_cloud_icon';
16
17 /**
18 * Payments sections are removed from the top level and added to a payments section.
19 *
20 * @since 6.22.1
21 *
22 * @var array
23 */
24 private static $removed_payments_sections = array();
25
26 /**
27 * @return void
28 */
29 public static function menu() {
30 // Make sure admins can see the menu items
31 FrmAppHelper::force_capability( 'frm_change_settings' );
32
33 add_submenu_page( 'formidable', 'Formidable | ' . __( 'Global Settings', 'formidable' ), __( 'Global Settings', 'formidable' ), 'frm_change_settings', 'formidable-settings', 'FrmSettingsController::route' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
34 }
35
36 /**
37 * Include license box template on demand.
38 *
39 * @return void
40 */
41 public static function license_box() {
42 if ( ! current_user_can( 'activate_plugins' ) ) {
43 return;
44 }
45 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/license_box.php';
46 }
47
48 /**
49 * @param array $errors
50 * @param string $message
51 *
52 * @return void
53 */
54 public static function display_form( $errors = array(), $message = '' ) {
55 global $frm_vars;
56
57 $frm_settings = FrmAppHelper::get_settings();
58 $uploads = wp_upload_dir();
59 $target_path = $uploads['basedir'] . '/formidable/css';
60 $sections = self::get_settings_tabs();
61 $current = FrmAppHelper::simple_get( 't', 'sanitize_title', 'general_settings' );
62
63 if ( in_array( $current, array( 'stripe_settings', 'square_settings', 'authorize_net_settings', 'paypal_settings' ), true ) ) {
64 $current = 'payments_settings';
65 }
66
67 require FrmAppHelper::plugin_path() . '/classes/views/frm-settings/form.php';
68 }
69
70 /**
71 * Get sections to use for Global Settings.
72 *
73 * @return array<array>
74 */
75 private static function get_settings_tabs() {
76 $sections = array(
77 'general' => array(
78 'class' => self::class,
79 'function' => 'general_settings',
80 'name' => __( 'General Settings', 'formidable' ),
81 'icon' => 'frmfont frm_settings_icon',
82 ),
83 'messages' => array(
84 'class' => self::class,
85 'function' => 'message_settings',
86 'name' => __( 'Message Defaults', 'formidable' ),
87 'icon' => 'frmfont frm_stamp_icon',
88 ),
89 'permissions' => array(
90 'class' => self::class,
91 'function' => 'permission_settings',
92 'name' => __( 'Permissions', 'formidable' ),
93 'icon' => 'frmfont frm_lock_icon',
94 ),
95 'payments' => array(
96 'name' => __( 'Payments', 'formidable' ),
97 'icon' => 'frmfont frm_simple_cc_icon',
98 'class' => self::class,
99 'function' => 'payments_settings',
100 ),
101 'custom_css' => array(
102 'class' => 'FrmStylesController',
103 'function' => 'custom_css',
104 'name' => __( 'Custom CSS', 'formidable' ),
105 'icon' => 'frmfont frm_code_icon',
106 ),
107 'manage_styles' => array(
108 'class' => 'FrmStylesController',
109 'function' => 'manage',
110 'name' => __( 'Manage Styles', 'formidable' ),
111 'icon' => 'frmfont frm_pallet_icon',
112 ),
113 'captcha' => array(
114 'class' => self::class,
115 'function' => 'captcha_settings',
116 'name' => __( 'Captcha/Spam', 'formidable' ),
117 'icon' => 'frmfont frm_shield_check_icon',
118 ),
119 'email' => array(
120 'class' => self::class,
121 'function' => 'email_settings',
122 'name' => __( 'Email', 'formidable' ),
123 'icon' => 'frmfont frm_email_icon',
124 ),
125 'white_label' => array(
126 'name' => __( 'White Labeling', 'formidable' ),
127 'icon' => 'frmfont frm_ghost_icon',
128 'html_class' => 'frm_show_upgrade_tab frm_noallow',
129 'data' => array(
130 'medium' => 'white-label',
131 'upgrade' => __( 'White labeling options', 'formidable' ),
132 'screenshot' => 'white-label.png',
133 'learn-more' => FrmAppHelper::get_doc_url( 'features/white-label-form-builder-wordpress', 'white-labeling-global-settings', false ),
134 ),
135 ),
136 'inbox' => array(
137 'name' => __( 'Inbox', 'formidable' ),
138 'icon' => 'frmfont frm_email_icon',
139 'html_class' => 'frm_show_upgrade_tab frm_noallow',
140 'data' => array(
141 'medium' => 'inbox-settings',
142 'upgrade' => __( 'Inbox settings', 'formidable' ),
143 'screenshot' => 'inbox.png',
144 'learn-more' => FrmAppHelper::get_doc_url( 'global-settings-overview/#kb-inbox', 'inbox-global-settings' ),
145 ),
146 ),
147 );
148
149 if ( apply_filters( 'frm_include_addon_page', false ) ) {
150 // If no addons need a license, skip this page
151 $show_licenses = false;
152 $installed_addons = apply_filters( 'frm_installed_addons', array() );
153
154 foreach ( $installed_addons as $installed_addon ) {
155 if ( ! $installed_addon->is_parent_licence && $installed_addon->plugin_name !== 'Formidable Pro' && $installed_addon->needs_license ) {
156 $show_licenses = true;
157 break;
158 }
159 }
160
161 if ( $show_licenses ) {
162 $sections['licenses'] = array(
163 'class' => 'FrmAddonsController',
164 'function' => 'license_settings',
165 'name' => __( 'Plugin Licenses', 'formidable' ),
166 'icon' => 'frmfont frm_key_icon',
167 'ajax' => true,
168 );
169 }
170 }//end if
171
172 /**
173 * @param array<array> $sections
174 */
175 $sections = apply_filters( 'frm_add_settings_section', $sections );
176 self::add_inactive_addon_sections( $sections );
177 self::remove_payments_sections( $sections );
178
179 $sections['misc'] = array(
180 'name' => __( 'Miscellaneous', 'formidable' ),
181 'icon' => 'frmfont frm_shuffle_icon',
182 'class' => self::class,
183 'function' => 'misc_settings',
184 );
185
186 foreach ( $sections as $key => $section ) {
187 $original = $section;
188 $defaults = array(
189 'html_class' => '',
190 'name' => ucfirst( $key ),
191 'icon' => 'frmfont frm_settings_icon',
192 'anchor' => $key . '_settings',
193 'data' => array(),
194 );
195
196 $section = array_merge( $defaults, $section );
197
198 if ( isset( $section['ajax'] ) && ! isset( $section['data']['frmajax'] ) ) {
199 $section['data']['frmajax'] = $section['ajax'];
200 }
201
202 // For reverse compatibility.
203 if ( ! isset( $section['function'] ) && ( ! is_array( $original ) || ! isset( $original['name'] ) ) ) {
204 $section['function'] = $original;
205 }
206
207 $sections[ $key ] = $section;
208 }//end foreach
209
210 return $sections;
211 }
212
213 /**
214 * Add a placeholder section for each add-on that owns a Global Settings
215 * section but is not active.
216 *
217 * A placeholder reads as disabled and opens a page offering to activate the
218 * add-on or to upgrade, depending on what the license allows. It goes at the
219 * head of the add-on sections, right after Inbox, so it sits with the rest of
220 * the add-on settings instead of trailing them. A section already claimed by
221 * an active plugin is left alone, so nothing stands in for a section that is
222 * really there.
223 *
224 * @since 6.35
225 *
226 * @param array<array> $sections Sections registered for the Global Settings page so far.
227 *
228 * @return void
229 */
230 private static function add_inactive_addon_sections( &$sections ) {
231 if ( isset( $sections['api'] ) ) {
232 // The add-on is active, so it owns the section. Only the icon is taken over,
233 // so the tab looks the same whether or not the add-on is installed.
234 $sections['api']['icon'] = self::$api_section_icon;
235 return;
236 }
237
238 self::insert_section_after( $sections, 'inbox', 'api', self::get_api_placeholder_section() );
239 }
240
241 /**
242 * Insert a section directly after another one, leaving the rest of the order alone.
243 *
244 * Assigning a new key lands the section at the end of the array, so the array
245 * is rebuilt to put it where it belongs.
246 *
247 * @since 6.35
248 *
249 * @param array<array> $sections Sections registered for the Global Settings page so far.
250 * @param string $after Key of the section the new one follows. The new section goes last when this key is not there.
251 * @param string $key Key for the new section.
252 * @param array $section The section to insert.
253 *
254 * @return void
255 */
256 private static function insert_section_after( &$sections, $after, $key, $section ) {
257 if ( ! isset( $sections[ $after ] ) ) {
258 $sections[ $key ] = $section;
259 return;
260 }
261
262 $ordered = array();
263
264 foreach ( $sections as $section_key => $existing_section ) {
265 $ordered[ $section_key ] = $existing_section;
266
267 if ( $section_key === $after ) {
268 $ordered[ $key ] = $section;
269 }
270 }
271
272 $sections = $ordered;
273 }
274
275 /**
276 * Get the placeholder that stands in for the API add-on's section.
277 *
278 * The upgrade data decides which call to action the page shows. When the
279 * license covers the add-on, it carries the one click install or activate
280 * link. Otherwise it carries the plan the add-on needs, and the page asks
281 * the user to upgrade to it, on a gradient button that sets the upgrade
282 * apart from a one click install.
283 *
284 * @since 6.35
285 *
286 * @return array
287 */
288 private static function get_api_placeholder_section() {
289 $data = FrmAppHelper::get_upgrade_data_params(
290 'api',
291 array(
292 'medium' => 'api-settings',
293 'upgrade' => __( 'API settings', 'formidable' ),
294 'message' => __( 'Send entries to any site with a REST API, and let AI assistants build your forms. Upgrade to get the API add-on.', 'formidable' ),
295 'learn-more' => FrmAppHelper::get_doc_url( 'formidable-api', 'api-global-settings' ),
296 'upsell-images' => 'api-settings-1.png,api-settings-2.png,api-settings-3.png',
297 )
298 );
299
300 if ( ! FrmAppHelper::pro_is_installed() ) {
301 $data['gradient-upgrade'] = 1;
302 }
303
304 return array(
305 'name' => __( 'API', 'formidable' ),
306 'icon' => self::$api_section_icon,
307 'html_class' => 'frm_show_upgrade_tab frm_noallow',
308 'data' => $data,
309 );
310 }
311
312 /**
313 * Remove the payments sections (PayPal, Square, Stripe, Authorize.Net)
314 * and show them all on the payments section in separate tabs.
315 *
316 * @since 6.22.1
317 *
318 * @param array $sections
319 *
320 * @return void
321 */
322 private static function remove_payments_sections( &$sections ) {
323 $payment_section_keys = array( 'paypal', 'square', 'stripe', 'authorize_net' );
324
325 foreach ( $sections as $key => $section ) {
326 if ( ! in_array( $key, $payment_section_keys, true ) ) {
327 continue;
328 }
329
330 self::$removed_payments_sections[ $key ] = $section;
331 unset( $sections[ $key ] );
332 }
333
334 uksort( self::$removed_payments_sections, array( self::class, 'payment_sections_sort_callback' ) );
335 }
336
337 /**
338 * Sort the payments sections (PayPal, Square, Stripe, Authorize.Net)
339 *
340 * @since 6.22.1
341 *
342 * @param string $a
343 * @param string $b
344 *
345 * @return int
346 */
347 private static function payment_sections_sort_callback( $a, $b ) {
348 $order = array( 'stripe', 'square', 'paypal', 'authorize_net' );
349 $first_key = array_search( $a, $order, true );
350 $second_key = array_search( $b, $order, true );
351
352 if ( false === $first_key || false === $second_key ) {
353 return 0;
354 }
355
356 return $first_key - $second_key;
357 }
358
359 public static function load_settings_tab() {
360 FrmAppHelper::permission_check( 'frm_change_settings' );
361 check_ajax_referer( 'frm_ajax', 'nonce' );
362
363 $section = FrmAppHelper::get_post_param( 'tab', '', 'sanitize_text_field' );
364 $sections = self::get_settings_tabs();
365
366 if ( ! isset( $sections[ $section ] ) ) {
367 wp_die();
368 }
369
370 $section = $sections[ $section ];
371
372 if ( isset( $section['class'] ) ) {
373 call_user_func( array( $section['class'], $section['function'] ) );
374 } else {
375 call_user_func( $section['function'] ?? $section );
376 }
377
378 wp_die();
379 }
380
381 /**
382 * Render the general global settings section.
383 *
384 * @since 4.0
385 *
386 * @return void
387 */
388 public static function general_settings() {
389 $frm_settings = FrmAppHelper::get_settings();
390 $uploads = wp_upload_dir();
391 $target_path = $uploads['basedir'] . '/formidable/css';
392
393 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/general.php';
394 }
395
396 /**
397 * Render the global currency selector if Pro is up to date.
398 *
399 * @param FrmSettings $frm_settings
400 *
401 * @return void
402 */
403 public static function maybe_render_currency_selector( $frm_settings ) {
404 if ( is_callable( 'FrmProSettingsController::add_currency_settings' ) ) {
405 FrmProSettingsController::add_currency_settings();
406 return;
407 }
408
409 $currencies = FrmCurrencyHelper::get_currencies();
410 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/_currency.php';
411 }
412
413 /**
414 * @since 4.0
415 *
416 * @return void
417 */
418 public static function message_settings() {
419 $frm_settings = FrmAppHelper::get_settings();
420 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/messages.php';
421 }
422
423 /**
424 * @since 4.0
425 *
426 * @return void
427 */
428 public static function captcha_settings() {
429 $frm_settings = FrmAppHelper::get_settings();
430 $captcha_lang = FrmAppHelper::locales( 'captcha' );
431
432 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/captcha/captcha.php';
433 }
434
435 /**
436 * Shows email settings.
437 *
438 * @since 6.25
439 *
440 * @return void
441 */
442 public static function email_settings() {
443 $frm_settings = FrmAppHelper::get_settings();
444 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/email/email-styles.php';
445 }
446
447 /**
448 * @since 4.0
449 *
450 * @return void
451 */
452 public static function permission_settings() {
453 $frm_settings = FrmAppHelper::get_settings();
454 $frm_roles = FrmAppHelper::frm_capabilities();
455
456 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/permissions.php';
457 }
458
459 /**
460 * @return void
461 */
462 public static function payments_settings() {
463 $payment_sections = self::$removed_payments_sections;
464 $tab = FrmAppHelper::simple_get( 't', 'sanitize_title', 'general_settings' );
465
466 if ( $tab && in_array( $tab, array( 'stripe_settings', 'square_settings', 'authorize_net_settings', 'paypal_settings' ), true ) ) {
467 $tab = str_replace( '_settings', '', $tab );
468 } else {
469 $tab = 'stripe';
470 }
471
472 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/payments.php';
473 }
474
475 /**
476 * @since 4.0
477 *
478 * @return void
479 */
480 public static function misc_settings() {
481 $frm_settings = FrmAppHelper::get_settings();
482 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/misc.php';
483 }
484
485 /**
486 * Save form data submitted from the Global settings page.
487 *
488 * @param bool|string $stop_load
489 *
490 * @return void
491 */
492 public static function process_form( $stop_load = false ) {
493 global $frm_vars;
494
495 $frm_settings = FrmAppHelper::get_settings();
496 $process_form = FrmAppHelper::get_post_param( 'process_form', '', 'sanitize_text_field' );
497
498 if ( ! wp_verify_nonce( $process_form, 'process_form_nonce' ) ) {
499 $error_args = array(
500 'title' => __( 'Verification failed', 'formidable' ),
501 'body' => $frm_settings->admin_permission,
502 'cancel_text' => __( 'Cancel', 'formidable' ),
503 );
504 FrmAppController::show_error_modal( $error_args );
505 return;
506 }
507
508 $errors = array();
509 $message = '';
510
511 if ( empty( $frm_vars['settings_routed'] ) ) {
512 $errors = $frm_settings->validate( $_POST, array() );
513
514 $frm_settings->update( wp_unslash( $_POST ) );
515
516 if ( ! $errors ) {
517 $frm_settings->store();
518 $message = __( 'Settings Saved', 'formidable' );
519 }
520 } else {
521 $message = __( 'Settings Saved', 'formidable' );
522 }
523
524 if ( $stop_load === 'stop_load' ) {
525 $frm_vars['settings_routed'] = true;
526 return;
527 }
528
529 self::display_form( $errors, $message );
530 }
531
532 /**
533 * Include the Update button on the global settings page.
534 *
535 * @since 4.0.02
536 *
537 * @return void
538 */
539 public static function save_button() {
540 echo '<input class="button-primary frm-button-primary" type="submit"
541 value="' . esc_attr__( 'Update', 'formidable' ) . '"/>';
542 }
543
544 /**
545 * @param bool|string $stop_load
546 *
547 * @return void
548 */
549 public static function route( $stop_load = false ) {
550 $action = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action';
551 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
552 FrmAppHelper::include_svg();
553
554 if ( $action === 'process-form' ) {
555 self::process_form( $stop_load );
556 } elseif ( $stop_load !== 'stop_load' ) {
557 self::display_form();
558 }
559 }
560
561 /**
562 * Add CTA to the bottom on the plugin settings pages.
563 *
564 * @since 3.04.02
565 *
566 * @return void
567 */
568 public static function settings_cta() {
569 if ( get_option( 'frm_lite_settings_upgrade', false ) ) {
570 return;
571 }
572
573 include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/settings_cta.php';
574 }
575
576 /**
577 * Dismiss upgrade notice at the bottom on the plugin settings pages.
578 *
579 * @since 3.04.02
580 */
581 public static function settings_cta_dismiss() {
582 check_ajax_referer( 'frm_ajax', 'nonce' );
583 FrmAppHelper::permission_check( 'frm_change_settings' );
584
585 update_option( 'frm_lite_settings_upgrade', time(), false );
586
587 wp_send_json_success();
588 }
589
590 /**
591 * Autocomplete page admin ajax endpoint
592 *
593 * @since 4.03.06
594 */
595 public static function page_search() {
596 FrmAppHelper::permission_check( 'frm_edit_forms' );
597 check_ajax_referer( 'frm_ajax', 'nonce' );
598
599 global $wpdb;
600
601 $term = FrmAppHelper::get_param( 'term', '', 'get', 'sanitize_text_field' );
602 $post_type = FrmAppHelper::get_param( 'post_type', 'page', 'get', 'sanitize_text_field' );
603
604 $where = array(
605 'post_status' => 'publish',
606 'post_type' => $post_type,
607 'post_title LIKE' => $term,
608 );
609
610 $atts = array(
611 'limit' => 25,
612 'order_by' => 'post_title',
613 );
614
615 $pages = FrmDb::get_results( $wpdb->posts, $where, 'ID, post_title', $atts );
616 $results = array();
617
618 foreach ( $pages as $page ) {
619 $results[] = array(
620 'value' => $page->ID,
621 'label' => $page->post_title,
622 );
623 }
624
625 wp_send_json( $results );
626 }
627
628 /**
629 * Shows a fake color picker.
630 *
631 * @since 6.25
632 *
633 * @param string $color Color value.
634 *
635 * @return void
636 */
637 public static function fake_color_picker( $color ) {
638 ?>
639 <div class="wp-picker-container">
640 <button type="button" class="button wp-color-result" aria-expanded="false" aria-disabled="true" tabindex="-1" style="background-color:<?php echo esc_attr( $color ); ?>;"><?php // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong ?>
641 <span class="wp-color-result-text" style="color:#a7aaad;"><?php esc_html_e( 'Select Color', 'formidable' ); ?></span>
642 </button>
643 </div>
644 <?php
645 }
646 }
647