PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.3
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.3
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
← All changes | includes/core/rest-api/Controllers/class-settings-controller.php +234 -59 2.8.16 → 3.13.3 View file →
@@ -1,8 +1,8 @@
1 1 <?php
2 2 /**
3 3 * Settings controller
4 - *
4 + *
5 5 * @package WPFunnels\Rest\Controllers
6 6 */
7 7 namespace WPFunnels\Rest\Controllers;
8 8
@@ -37,11 +37,11 @@
37 37
38 38 protected $rest_funnel_settings = 'settings';
39 39
40 40 public function update_items_permissions_check( $request ) {
41 - $permission = current_user_can('manage_options');
41 + $permission = current_user_can('wpf_manage_funnels');
42 42 if ( ! Wpfnl_functions::wpfnl_rest_check_manager_permissions( 'settings' ) ) {
43 - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'wpfnl' ), array( 'status' => rest_authorization_required_code() ) );
43 + return new WP_Error( 'wpfunnels_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'wpfnl' ), array( 'status' => rest_authorization_required_code() ) );
44 44 }
45 45 return true;
46 46 }
47 47
@@ -48,9 +48,9 @@
48 48 /**
49 49 * Makes sure the current user has access to READ the settings APIs.
50 50 *
51 51 * @param WP_REST_Request $request Full data about the request.
52 - *
52 + *
53 53 * @return WP_Error|boolean
54 54 * @since 3.0.0
55 55 */
56 56 public function get_items_permissions_check( $request ) {
@@ -93,9 +93,9 @@
93 93 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
94 94 )
95 95 )
96 96 );
97 -
97 +
98 98 register_rest_route(
99 99 $this->namespace, '/' . $this->rest_mrm_plugin_active_base , array(
100 100 array(
101 101 'methods' => WP_REST_Server::EDITABLE,
@@ -116,14 +116,14 @@
116 116 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
117 117 )
118 118 )
119 119 );
120 -
120 +
121 121 register_rest_route(
122 - $this->namespace, '/' . $this->rest_funnel_settings . '/update-funnel-type' , array(
122 + $this->namespace, '/' . $this->rest_funnel_settings . '/activate-plugins' , array(
123 123 array(
124 124 'methods' => 'POST',
125 - 'callback' => array( $this, 'update_funnel_type' ),
125 + 'callback' => array( $this, 'activate_plugins' ),
126 126 'permission_callback' => array( $this, 'update_items_permissions_check' ),
127 127 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
128 128 )
129 129 )
@@ -129,8 +129,30 @@
129 129 )
130 130 );
131 131
132 132 register_rest_route(
133 + $this->namespace, '/' . $this->rest_funnel_settings . '/create-contact' , array(
134 + array(
135 + 'methods' => 'POST',
136 + 'callback' => array( $this, 'create_contact' ),
137 + 'permission_callback' => array( $this, 'update_items_permissions_check' ),
138 + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
139 + )
140 + )
141 + );
142 +
143 + register_rest_route(
144 + $this->namespace, '/' . $this->rest_funnel_settings . '/save-setup-wizard-settings' , array(
145 + array(
146 + 'methods' => 'POST',
147 + 'callback' => array( $this, 'save_setup_wizard_settings' ),
148 + 'permission_callback' => array( $this, 'update_items_permissions_check' ),
149 + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
150 + )
151 + )
152 + );
153 +
154 + register_rest_route(
133 155 $this->namespace, '/' . $this->rest_funnel_settings . '/update-builder-type' , array(
134 156 array(
135 157 'methods' => 'POST',
136 158 'callback' => array( $this, 'update_builder_type' ),
@@ -149,9 +171,20 @@
149 171 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
150 172 )
151 173 )
152 174 );
153 -
175 +
176 + register_rest_route(
177 + $this->namespace, '/' . $this->rest_funnel_settings . '/canvas-view-mode' , array(
178 + array(
179 + 'methods' => 'POST',
180 + 'callback' => array( $this, 'update_canvas_view_mode' ),
181 + 'permission_callback' => array( $this, 'update_items_permissions_check' ),
182 + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
183 + )
184 + )
185 + );
186 +
154 187 }
155 188
156 189
157 190 /**
@@ -157,9 +190,9 @@
157 190 /**
158 191 * Get all settings in a group.
159 192 *
160 193 * @param string $group_id Group ID.
161 - *
194 + *
162 195 * @return array|WP_Error
163 196 */
164 197 public function get_group_settings( $group_id ) {
165 198 if ( empty( $group_id ) ) {
@@ -164,8 +197,11 @@
164 197 public function get_group_settings( $group_id ) {
165 198 if ( empty( $group_id ) ) {
166 199 return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'wpfnl' ), array( 'status' => 404 ) );
167 200 }
201 + if ( ! $this->is_allowed_settings_group( $group_id ) ) {
202 + return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'wpfnl' ), array( 'status' => 403 ) );
203 + }
168 204 $settings = Wpfnl_functions::get_admin_settings( $group_id );
169 205 if ( empty( $settings ) ) {
170 206 return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'wpfnl' ), array( 'status' => 404 ) );
171 207 }
@@ -185,9 +221,9 @@
185 221 * Get setting data.
186 222 *
187 223 * @param string $group_id Group ID.
188 224 * @param string $setting_id Setting ID.
189 - *
225 + *
190 226 * @return stdClass|WP_Error
191 227 * @since 3.0.0
192 228 */
193 229 public function get_setting( $group_id, $setting_id ) {
@@ -215,9 +251,9 @@
215 251 /**
216 252 * Active required plugin based on slug
217 253 *
218 254 * @param $plugin_name
219 - *
255 + *
220 256 * @return WP_Error|WP_REST_Response
221 257 * @since 1.0.0
222 258 */
223 259 public function activate_wc_plugins( \WP_REST_Request $request ) {
@@ -224,10 +260,10 @@
224 260 if( !function_exists('activate_plugin') ) {
225 261 include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
226 262 }
227 263
228 -
229 264
265 +
230 266 $permission = $request['permission'];
231 267 $islms = $request['islms'];
232 268 $isWc = $request['isWc'];
233 269
@@ -244,9 +280,9 @@
244 280 if($permission == '' ){
245 281 unset($should_activated[ 'cart-lift/cart-lift.php' ]);
246 282 unset($plugin_slug_arr[ 'cart-lift/cart-lift.php' ]);
247 283 }
248 -
284 +
249 285 if($permission == '' ){
250 286 unset($should_activated[ 'cart-lift/cart-lift.php' ]);
251 287 unset($plugin_slug_arr[ 'cart-lift/cart-lift.php' ]);
252 288 }
@@ -267,9 +303,9 @@
267 303
268 304 }
269 305 }
270 306 delete_transient( '_wc_activation_redirect' );
271 -
307 +
272 308 foreach ( $should_activated as $slug => $is_activated ) {
273 309 if(!$is_activated) {
274 310 $settings['success'] = false;
275 311 return rest_ensure_response( $settings );
@@ -282,9 +318,9 @@
282 318 /**
283 319 * Active required plugin based on slug
284 320 *
285 321 * @param $plugin_name
286 - *
322 + *
287 323 * @return WP_Error|WP_REST_Response
288 324 * @since 1.0.0
289 325 */
290 326 public function activate_mrm_plugins( \WP_REST_Request $request ) {
@@ -295,9 +331,9 @@
295 331 $plugin_slug_arr = [];
296 332 $should_activated = [];
297 333 if( !empty($plugins) ){
298 334 foreach( $plugins as $plugin ){
299 - if( 'mail-mint' == $plugin ) {
335 + if( 'mail-mint' == $plugin ) {
300 336 $plugin_slug_arr['mail-mint/mail-mint.php'] = false;
301 337 $should_activated['mail-mint/mail-mint.php'] = false;
302 338 }
303 339 }
@@ -303,9 +339,9 @@
303 339 }
304 340 }
305 341 foreach ( $plugin_slug_arr as $slug => $is_silent ) {
306 342 $data = activate_plugin( $slug, '', false, $is_silent );
307 -
343 +
308 344 if ( !is_wp_error( $data ) ) {
309 345 $should_activated[ $slug ] = true;
310 346 }
311 347 }
@@ -315,9 +351,9 @@
315 351 $settings['success'] = false;
316 352 return rest_ensure_response( $settings );
317 353 }
318 354 }
319 -
355 +
320 356 $settings['success'] = true;
321 357 return rest_ensure_response( $settings );
322 358 }
323 359
@@ -375,29 +411,70 @@
375 411 }
376 412
377 413
378 414 /**
415 + * Validate a settings group_id against WPFunnels-owned option keys.
416 + *
417 + * The `group_id` path parameter is passed straight into get_option()/update_option(),
418 + * so it MUST be restricted to plugin-owned option names. Without this guard a request
419 + * could target arbitrary WordPress options (e.g. `wp_user_roles`) and escalate privileges.
420 + *
421 + * @param string $group_id Option key supplied via the route.
422 + *
423 + * @return bool True when the key is a WPFunnels-owned option, false otherwise.
424 + * @since 3.12.9
425 + */
426 + protected function is_allowed_settings_group( $group_id ) {
427 + if ( ! is_string( $group_id ) || '' === $group_id ) {
428 + return false;
429 + }
430 +
431 + $allowed = array(
432 + '_wpfunnels_general_settings',
433 + '_wpfunnels_permalink_settings',
434 + '_wpfunnels_optin_settings',
435 + '_wpfunnels_advanced_settings',
436 + '_wpfunnels_integrations',
437 + '_wpfunnels_notification_settings',
438 + '_wpfunnels_lms_settings',
439 + '_wpfunnels_recaptcha_setting',
440 + '_wpfunnels_google_map_api_key',
441 + '_wpfunnels_user_roles',
442 + );
443 +
444 + if ( in_array( $group_id, $allowed, true ) ) {
445 + return true;
446 + }
447 +
448 + // Defense in depth: only allow plugin-prefixed option keys so add-ons that
449 + // register their own `_wpfunnels_*` settings groups keep working, while any
450 + // WordPress core / third-party option name is rejected.
451 + return 0 === strpos( $group_id, '_wpfunnels_' );
452 + }
453 +
454 +
455 + /**
379 456 * Update a single setting in a group.
380 457 *
381 458 * @param WP_REST_Request $request Request data.
382 - *
459 + *
383 460 * @return WP_Error|WP_REST_Response
384 461 * @since 1.0.0
385 462 */
386 463 public function update_settings( $request ) {
387 464 if( isset( $request['settings_id'], $request['group_id'] )){
465 + if ( ! $this->is_allowed_settings_group( $request['group_id'] ) ) {
466 + return new WP_Error( 'rest_setting_group_invalid', __( 'Invalid setting group.', 'wpfnl' ), array( 'status' => 403 ) );
467 + }
388 468 if( $request['settings_id'] === 'permalink') {
389 469 $default = Wpfnl_functions::get_permalink_settings();
390 470 $settings = Wpfnl_functions::get_admin_settings( '_wpfunnels_permalink_settings', $default);
391 - } elseif ($request['settings_id'] === 'funnel_type') {
471 + } elseif( $request['settings_id'] === 'optin') {
472 + $default = Wpfnl_functions::get_optin_settings();
473 + $settings = Wpfnl_functions::get_admin_settings( '_wpfunnels_optin_settings', $default);
474 + } else {
392 475 $default = Wpfnl_functions::get_general_settings();
393 - $settings = Wpfnl_functions::get_admin_settings( $request['group_id'], $default);
394 - }
395 - else {
396 - $default = Wpfnl_functions::get_general_settings();
397 476 $settings = Wpfnl_functions::get_admin_settings( $request['group_id'], $default );
398 -
399 -
400 477 }
401 478
402 479 if ( !$settings ) {
403 480 return new WP_Error( 'rest_setting_invalid', __( 'Invalid setting.', 'wpfnl' ), array( 'status' => 404 ) );
@@ -415,19 +492,14 @@
415 492 $settings['funnel_base'] = $request['funnelBase'];
416 493 $settings['step_base'] = $request['stepBase'];
417 494 Wpfnl_functions::update_admin_settings('_wpfunnels_permalink_saved', true);
418 495 Wpfnl_functions::update_admin_settings($request['group_id'], $settings);
419 -
496 +
420 497 }else {
421 - if( 'funnel_type' === $request['settings_id'] ) {
422 - $general_settings = get_option( '_wpfunnels_general_settings' );
423 - $settings[$request['settings_id']] = isset($general_settings['funnel_type']) ? $general_settings['funnel_type'] : 'sales';
424 - }else{
425 - $settings[$request['settings_id']] = $request['value'];
426 - }
427 -
498 + $settings[$request['settings_id']] = $request['value'];
499 +
428 500 Wpfnl_functions::update_admin_settings($request['group_id'], $settings);
429 -
501 +
430 502 }
431 503 }
432 504 $settings['success'] = true;
433 505 $settings = $this->prepare_item_for_response( $settings, $request );
@@ -445,9 +517,9 @@
445 517 $response = [
446 518 'success' => false,
447 519 'is_lms' => false,
448 520 ];
449 -
521 +
450 522 if( $request['funnel_id'] ){
451 523 $funnel_id = $request['funnel_id'];
452 524 $type = get_post_meta( $funnel_id, '_wpfnl_funnel_type', true );
453 525 if( Wpfnl_functions::is_lms_addon_active() && $type == 'lms' ){
@@ -462,25 +534,25 @@
462 534 }
463 535
464 536
465 537 /**
466 - * Update funnel type
538 + * Update funnel builder
467 539 *
468 540 * @param Array $request
469 - *
470 - * @return Array
541 + *
542 + * @return Array
471 543 * @since 2.5.3
472 544 */
473 - public function update_funnel_type( $request ){
545 + public function update_builder_type( $request ){
474 546
475 547 $response = [
476 548 'success' => false,
477 549 ];
478 -
479 - if( $request['type'] ){
480 - $type = $request['type'];
550 +
551 + if( $request['builder'] ){
552 + $builder = $request['builder'];
481 553 $general_settings = get_option( '_wpfunnels_general_settings' );
482 - $general_settings['funnel_type'] = $type;
554 + $general_settings['builder'] = $builder;
483 555 update_option('_wpfunnels_general_settings', $general_settings );
484 556 $response = [
485 557 'success' => true,
486 558 ];
@@ -489,26 +561,105 @@
489 561 }
490 562
491 563
492 564 /**
493 - * Update funnel builder
565 + * Remember which canvas layout the current user last switched to.
494 566 *
495 - * @param Array $request
567 + * Stored per user rather than in the shared settings, so one admin flipping
568 + * the view switcher does not change the canvas for the rest of the team. The
569 + * site-wide default in Settings still applies to anyone who never switched.
570 + *
571 + * @param WP_REST_Request $request The REST request object.
572 + *
573 + * @return WP_REST_Response
574 + * @since 3.12.13
575 + */
576 + public function update_canvas_view_mode( $request ) {
577 + $mode = isset( $request['mode'] ) ? sanitize_text_field( $request['mode'] ) : '';
578 + $user_id = get_current_user_id();
579 +
580 + if ( ! $user_id || ! in_array( $mode, Wpfnl_functions::get_funnel_builder_modes(), true ) ) {
581 + return rest_ensure_response( array( 'success' => false ) );
582 + }
583 +
584 + update_user_meta( $user_id, Wpfnl_functions::CANVAS_VIEW_MODE_META_KEY, $mode );
585 +
586 + if ( 'vertical' === $mode ) {
587 + do_action( 'wpfunnels_vertical_mode_used' );
588 + }
589 +
590 + return rest_ensure_response(
591 + array(
592 + 'success' => true,
593 + 'mode' => $mode,
594 + )
595 + );
596 + }
597 +
598 +
599 + /**
600 + * Activates plugins.
601 + *
602 + * @param WP_REST_Request $request The REST request object.
603 + */
604 + public function activate_plugins( $request ){
605 + $response = [
606 + 'success' => false,
607 + ];
608 +
609 + if( !isset( $request['plugins'] )){
610 + rest_ensure_response( $response );
611 + }
612 +
613 + $plugins = $request['plugins'];
614 + $activatePluginInstance = new \WPFunnels\Admin\SetupWizard\ActivatePlugin( $plugins );
615 + $response = $activatePluginInstance->activate_plugins();
616 + return rest_ensure_response( $response );
617 + }
618 +
619 +
620 + /**
621 + * Save setup wizard settings
622 + *
623 + * @param WP_REST_Request $request The REST request object containing name and value.
496 624 *
497 - * @return Array
498 - * @since 2.5.3
625 + * @return WP_REST_Response Response object with success status and message.
626 + * @since 2.5.20
499 627 */
500 - public function update_builder_type( $request ){
501 -
628 + public function save_setup_wizard_settings( $request ){
502 629 $response = [
503 630 'success' => false,
504 631 ];
505 632
506 - if( $request['builder'] ){
507 - $builder = $request['builder'];
508 - $general_settings = get_option( '_wpfunnels_general_settings' );
509 - $general_settings['builder'] = $builder;
510 - update_option('_wpfunnels_general_settings', $general_settings );
633 + // Validate required parameters.
634 + if( !isset( $request['name'],$request['value'] )){
635 + rest_ensure_response( $response );
636 + }
637 +
638 + if( 'builder' === $request['name'] ){
639 + // Get and process the value using the appropriate method.
640 + $name = sanitize_text_field($request['name']);
641 + $value = sanitize_text_field($request['value']);
642 +
643 + // Process the value based on the name.
644 + if( 'builder' === $name ){
645 + $value = 'qubely' === $value ? 'gutenberg' : $value;
646 + }
647 +
648 + // Update the setting.
649 + $settings = Wpfnl_functions::get_general_settings();
650 + $settings[$name] = $value;
651 + update_option('_wpfunnels_general_settings', $settings );
652 +
653 + if( 'builder' === $name ){
654 + delete_option(WPFNL_TEMPLATES_OPTION_KEY.'_wc');
655 + delete_option(WPFNL_TEMPLATES_OPTION_KEY.'_lms');
656 + delete_transient('wpfunnels_remote_template_data_wc_' . WPFNL_VERSION);
657 + delete_transient('wpfunnels_remote_template_data_lms_' . WPFNL_VERSION);
658 + delete_transient('wpfunnels_remote_template_data_lead_' . WPFNL_VERSION);
659 + delete_transient('wpfunnels_remote_template_data_store_checkout_' . WPFNL_VERSION);
660 + }
661 +
511 662 $response = [
512 663 'success' => true,
513 664 ];
514 665 }
@@ -515,9 +666,33 @@
515 666 return rest_ensure_response( $response );
516 667 }
517 668
518 669
670 + /**
671 + * Create contact to Mail Mint.
672 + *
673 + * @param WP_REST_Request $request The REST request object.
674 + */
675 + public function create_contact( $request ){
676 + $response = [
677 + 'success' => false,
678 + ];
679 +
680 + if( !isset( $request['email'] )){
681 + rest_ensure_response( $response );
682 + }
519 683
684 + $email = sanitize_text_field($request['email']);
685 + $name = isset($request['name']) ? sanitize_text_field($request['name']) : '';
686 + $createContactInstance = new \WPFunnels\Admin\SetupWizard\CreateContact($email, $name );
687 + $response = $createContactInstance->create_contact_via_webhook();
688 + update_option( 'wpfunnels_activation_email', $email );
689 + $createContactInstance->send_contact_to_appsero();
690 + return rest_ensure_response( $response );
691 + }
692 +
693 +
694 +
520 695 /**
521 696 * Get funnel type id
522 697 */
523 698 public function get_funnel_type_id( $request ){
@@ -535,21 +710,21 @@
535 710 $response['success'] = true;
536 711 $response['type_id'] = $term->term_id;
537 712 }
538 713 }
539 -
714 +
540 715 return rest_ensure_response( $response );
541 716 }
542 717
543 -
544 718
545 719
720 +
546 721 /**
547 722 * Prepare a single setting object for response.
548 723 *
549 724 * @param object $item Setting object.
550 725 * @param WP_REST_Request $request Request object.
551 - *
726 + *
552 727 * @return WP_REST_Response $response Response data.
553 728 * @since 3.0.0
554 729 */
555 730 public function prepare_item_for_response( $item, $request ) {