PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 2.4.1
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v2.4.1
2.4.1 2.4.0 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.2 2.2.1 2.2.0 2.1.2 2.1.1 trunk 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 All 68 releases
← All changes | includes/Blocks/BlockActions.php +75 -99 2.3.0 → 2.4.1 View file →
@@ -11,8 +11,10 @@
11 11
12 12 namespace Better_Payment\Lite\Blocks;
13 13
14 14 use Better_Payment\Lite\Classes\Handler;
15 +use Better_Payment\Lite\Classes\PaymentEntitlement;
16 +use Better_Payment\Lite\Classes\PaymentRequestGuard;
15 17 use Better_Payment\Lite\Traits\Helper as TraitsHelper;
16 18
17 19 if ( ! defined( 'ABSPATH' ) ) {
18 20 exit;
@@ -55,8 +57,15 @@
55 57 * @param string $widget_id The widget/block ID.
56 58 * @return array|false The block settings or false if not found.
57 59 */
58 60 private function get_block_settings( $page_id, $widget_id ) {
61 + // page_id is the visitor's to choose. A form on a page they cannot see — draft,
62 + // private, scheduled, password-protected — must be neither payable nor probeable,
63 + // and that holds for the cached transient as much as for the post content.
64 + if ( ! $this->is_payable_form_page( $page_id ) ) {
65 + return false;
66 + }
67 +
59 68 // First, try to get from transient (fastest).
60 69 $transient_key = 'bp_block_settings_' . $page_id . '_' . $widget_id;
61 70 $settings = get_transient( $transient_key );
62 71
@@ -225,45 +234,33 @@
225 234 $woo_product_id = ! empty( $el_settings['better_payment_form_woocommerce_product_id'] ) ? intval( $el_settings['better_payment_form_woocommerce_product_id'] ) : 0;
226 235 $woo_product_ids = ! empty( $el_settings['better_payment_form_woocommerce_product_ids'] ) ? $el_settings['better_payment_form_woocommerce_product_ids'] : array( 0 );
227 236 $fluentcart_product_id = ! empty( $el_settings['better_payment_form_fluentcart_product_id'] ) ? intval( $el_settings['better_payment_form_fluentcart_product_id'] ) : 0;
228 237 $fluentcart_product_ids = ! empty( $el_settings['better_payment_form_fluentcart_product_ids'] ) ? $el_settings['better_payment_form_fluentcart_product_ids'] : array( 0 );
229 - $is_layout_6 = ! empty( $el_settings['better_payment_form_layout'] ) && 'layout-6-pro' === $el_settings['better_payment_form_layout'];
230 - $is_fluentcart_layout = $is_layout_6 && ! empty( $el_settings['better_payment_form_layout_6_ecommerce_platform'] ) && 'fluentcart' === $el_settings['better_payment_form_layout_6_ecommerce_platform'];
231 - $is_woo_layout = $is_layout_6 && ( empty( $el_settings['better_payment_form_layout_6_ecommerce_platform'] ) || 'woocommerce' === $el_settings['better_payment_form_layout_6_ecommerce_platform'] );
232 238
233 - // Currency handling.
234 - if ( ! empty( $el_settings['better_payment_form_currency_use_woocommerce'] ) && 'yes' === $el_settings['better_payment_form_currency_use_woocommerce'] &&
235 - ! empty( $el_settings['better_payment_form_currency_woocommerce'] ) ) {
236 - $el_settings_currency = $el_settings['better_payment_form_currency_woocommerce'];
237 - }
238 239 // phpcs:disable WordPress.Security.NonceVerification.Missing
239 - if ( ! empty( $_POST['campaign_currency'] ) ) {
240 - $el_settings_currency = sanitize_text_field( $_POST['campaign_currency'] );
240 + // Amount, quantity, currency and campaign come from the stored settings, never
241 + // from the request — see PaymentRequestGuard.
242 + $guarded = ( new PaymentRequestGuard() )->resolve_form_payment(
243 + $el_settings,
244 + wp_unslash( $_POST ),
245 + array(
246 + 'page_id' => $page_id,
247 + 'gateway' => 'paypal',
248 + )
249 + );
250 +
251 + if ( is_wp_error( $guarded ) ) {
252 + PaymentRequestGuard::reject_form_post( $guarded );
253 + return;
241 254 }
242 - // phpcs:enable WordPress.Security.NonceVerification.Missing
243 255
256 + $el_settings_currency = $guarded['currency'];
244 257 $el_settings_currency_symbol = $this->get_currency_symbol( esc_html( $el_settings_currency ) );
245 258
246 - // phpcs:disable WordPress.Security.NonceVerification.Missing
247 - $primary_payment_amount = isset( $_POST['primary_payment_amount'] ) ? floatval( $_POST['primary_payment_amount'] ) : 0;
259 + $primary_payment_amount = $guarded['amount'];
260 + $primary_payment_amount_quantity = $guarded['quantity'];
248 261
249 - if ( empty( $_POST['primary_payment_amount'] ) && ! empty( $_POST['primary_payment_amount_radio'] ) ) {
250 - $primary_payment_amount = floatval( $_POST['primary_payment_amount_radio'] );
251 - }
252 -
253 - $primary_payment_amount_quantity = ! empty( $_POST['payment_amount_quantity'] ) ? intval( $_POST['payment_amount_quantity'] ) : '';
254 - if ( $is_woo_layout ) {
255 - $primary_payment_amount_quantity = 1;
256 - }
257 -
258 - $primary_payment_amount = ! empty( $primary_payment_amount_quantity ) ? $primary_payment_amount * $primary_payment_amount_quantity : $primary_payment_amount;
259 -
260 - if ( $primary_payment_amount <= 0 ) {
261 - $this->redirect_previous_page();
262 - return;
263 - }
264 -
265 - $order_id = 'paypal_' . uniqid();
262 + $order_id = Handler::new_order_id( 'paypal' );
266 263 $paypal_button_type = ! empty( $el_settings['better_payment_paypal_button_type'] ) ? $el_settings['better_payment_paypal_button_type'] : '_xclick';
267 264 $site_url = get_permalink( $page_id );
268 265 $return_url = ! empty( $_POST['return'] ) ? wp_validate_redirect( esc_url_raw( $_POST['return'] ), $site_url ) : '';
269 266 $cancel_return_url = ! empty( $_POST['cancel_return'] ) ? wp_validate_redirect( esc_url_raw( $_POST['cancel_return'] ), $site_url ) : '';
@@ -299,16 +296,19 @@
299 296 'fluentcart_product_id' => $fluentcart_product_id,
300 297 'fluentcart_product_ids' => maybe_serialize( $fluentcart_product_ids ),
301 298 'source' => 'paypal',
302 299 'amount_quantity' => ! empty( $primary_payment_amount_quantity ) ? intval( $primary_payment_amount_quantity ) : '',
303 - 'is_woo_layout' => $is_woo_layout,
304 - 'is_fluentcart_layout' => $is_fluentcart_layout,
305 300 'detailed_product_info' => maybe_serialize( $detailed_product_info ),
306 301 'paypal_business_email' => sanitize_email( $el_settings['better_payment_paypal_business_email'] ),
302 + // The PayPal environment the order was sent to; the IPN must come from the same one.
303 + 'paypal_mode' => 'yes' === $el_settings['better_payment_paypal_live_mode'] ? 'live' : 'sandbox',
307 304 // Persisted so the async PayPal IPN can rebuild the e-mail body + on/off toggle.
308 305 'email_settings' => Handler::extract_email_settings( $el_settings ),
309 306 );
310 307
308 + // Fields only Pro's forms store (layout 6's platform flags) — see PaymentEntitlement.
309 + $better_form_fields = PaymentEntitlement::transaction_fields( $better_form_fields, $el_settings );
310 +
311 311 $better_form_fields = array_merge( $better_form_fields, $this->fetch_better_form_fields( $el_settings, $_POST ) );
312 312
313 313 if ( ! empty( $better_form_fields['primary_first_name'] ) ) {
314 314 $request_data['primary_first_name'] = sanitize_text_field( $better_form_fields['primary_first_name'] );
@@ -325,9 +325,9 @@
325 325 if ( ! empty( $better_form_fields['primary_reference_number'] ) ) {
326 326 $request_data['invoice'] = sanitize_text_field( $better_form_fields['primary_reference_number'] );
327 327 }
328 328
329 - $campaign_id = ! empty( $_POST['campaign_id'] ) ? sanitize_text_field( $_POST['campaign_id'] ) : '';
329 + $campaign_id = $guarded['campaign_id'];
330 330 // phpcs:enable WordPress.Security.NonceVerification.Missing
331 331
332 332 Handler::payment_create(
333 333 array(
@@ -444,38 +444,35 @@
444 444 wp_send_json_error( esc_html__( 'Stripe Key missing', 'better-payment' ) );
445 445 }
446 446
447 447 // phpcs:disable WordPress.Security.NonceVerification.Missing
448 - $amount = isset( $_POST['fields']['primary_payment_amount'] ) ? floatval( $_POST['fields']['primary_payment_amount'] ) : 0;
448 + // Amount, quantity, currency and campaign come from the stored settings, never
449 + // from the request — see PaymentRequestGuard.
450 + $guarded = ( new PaymentRequestGuard() )->resolve_form_payment(
451 + $el_settings,
452 + isset( $_POST['fields'] ) && is_array( $_POST['fields'] ) ? wp_unslash( $_POST['fields'] ) : array(),
453 + array(
454 + 'page_id' => $page_id,
455 + 'gateway' => 'stripe',
456 + )
457 + );
449 458
450 - if ( empty( $_POST['fields']['primary_payment_amount'] ) && ! empty( $_POST['fields']['primary_payment_amount_radio'] ) ) {
451 - $amount = floatval( $_POST['fields']['primary_payment_amount_radio'] );
459 + if ( is_wp_error( $guarded ) ) {
460 + wp_send_json_error( esc_html( $guarded->get_error_message() ) );
461 + return;
452 462 }
453 463
454 - $amount_quantity = ! empty( $_POST['fields']['payment_amount_quantity'] ) ? intval( $_POST['fields']['payment_amount_quantity'] ) : '';
455 - $amount = ! empty( $amount_quantity ) ? $amount * $amount_quantity : $amount;
464 + $amount = $guarded['amount'];
465 + $amount_quantity = $guarded['quantity'];
456 466
457 - if ( $amount <= 0 ) {
458 - wp_send_json_error( esc_html__( 'Invalid payment amount.', 'better-payment' ) );
459 - return;
460 - }
461 -
462 467 $header_info = array(
463 468 'Authorization' => 'Basic ' . base64_encode( sanitize_text_field( $better_payment_keys['secret_key'] ) . ':' ),
464 469 'Stripe-Version' => '2019-05-16',
465 470 );
466 471
467 - $order_id = 'stripe_' . uniqid();
468 - $el_settings_currency = $el_settings['better_payment_form_currency'];
472 + $order_id = Handler::new_order_id( 'stripe' );
473 + $el_settings_currency = $guarded['currency'];
469 474
470 - if ( ! empty( $el_settings['better_payment_form_currency_use_woocommerce'] ) && 'yes' === $el_settings['better_payment_form_currency_use_woocommerce'] &&
471 - ! empty( $el_settings['better_payment_form_currency_woocommerce'] ) ) {
472 - $el_settings_currency = $el_settings['better_payment_form_currency_woocommerce'];
473 - }
474 - if ( ! empty( $_POST['fields']['campaign_currency'] ) ) {
475 - $el_settings_currency = sanitize_text_field( $_POST['fields']['campaign_currency'] );
476 - }
477 -
478 475 $el_settings_currency_symbol = $this->get_currency_symbol( esc_html( $el_settings_currency ) );
479 476
480 477 $redirection_url_success = get_permalink( $page_id );
481 478 $redirection_url_error = get_permalink( $page_id );
@@ -610,9 +607,9 @@
610 607 return;
611 608 }
612 609
613 610 if ( ! empty( $response_ar->payment_intent ) || ( ! empty( $response_ar->mode ) && 'subscription' === $response_ar->mode ) ) {
614 - $campaign_id = ! empty( $_POST['fields']['campaign_id'] ) ? sanitize_text_field( $_POST['fields']['campaign_id'] ) : '';
611 + $campaign_id = $guarded['campaign_id'];
615 612
616 613 Handler::payment_create(
617 614 array(
618 615 'amount' => floatval( $amount ),
@@ -665,38 +662,35 @@
665 662 wp_send_json_error( esc_html__( 'Paystack Key missing', 'better-payment' ) );
666 663 }
667 664
668 665 // phpcs:disable WordPress.Security.NonceVerification.Missing
669 - $amount = isset( $_POST['fields']['primary_payment_amount'] ) ? floatval( $_POST['fields']['primary_payment_amount'] ) : 0;
666 + // Amount, quantity, currency and campaign come from the stored settings, never
667 + // from the request — see PaymentRequestGuard.
668 + $guarded = ( new PaymentRequestGuard() )->resolve_form_payment(
669 + $el_settings,
670 + isset( $_POST['fields'] ) && is_array( $_POST['fields'] ) ? wp_unslash( $_POST['fields'] ) : array(),
671 + array(
672 + 'page_id' => $page_id,
673 + 'gateway' => 'paystack',
674 + )
675 + );
670 676
671 - if ( empty( $_POST['fields']['primary_payment_amount'] ) && ! empty( $_POST['fields']['primary_payment_amount_radio'] ) ) {
672 - $amount = floatval( $_POST['fields']['primary_payment_amount_radio'] );
677 + if ( is_wp_error( $guarded ) ) {
678 + wp_send_json_error( esc_html( $guarded->get_error_message() ) );
679 + return;
673 680 }
674 681
675 - $amount_quantity = ! empty( $_POST['fields']['payment_amount_quantity'] ) ? intval( $_POST['fields']['payment_amount_quantity'] ) : '';
676 - $amount = ! empty( $amount_quantity ) ? $amount * $amount_quantity : $amount;
682 + $amount = $guarded['amount'];
683 + $amount_quantity = $guarded['quantity'];
677 684
678 - if ( $amount <= 0 ) {
679 - wp_send_json_error( esc_html__( 'Invalid payment amount.', 'better-payment' ) );
680 - return;
681 - }
682 -
683 685 $header_info = array(
684 686 'Authorization' => 'Bearer ' . sanitize_text_field( $el_settings['better_payment_paystack_secret_key'] ),
685 687 'Cache-Control: no-cache',
686 688 );
687 689
688 - $order_id = 'paystack_' . uniqid();
689 - $el_settings_currency = $el_settings['better_payment_form_currency'];
690 + $order_id = Handler::new_order_id( 'paystack' );
691 + $el_settings_currency = $guarded['currency'];
690 692
691 - if ( ! empty( $el_settings['better_payment_form_currency_use_woocommerce'] ) && 'yes' === $el_settings['better_payment_form_currency_use_woocommerce'] &&
692 - ! empty( $el_settings['better_payment_form_currency_woocommerce'] ) ) {
693 - $el_settings_currency = $el_settings['better_payment_form_currency_woocommerce'];
694 - }
695 - if ( ! empty( $_POST['fields']['campaign_currency'] ) ) {
696 - $el_settings_currency = sanitize_text_field( $_POST['fields']['campaign_currency'] );
697 - }
698 -
699 693 $el_settings_currency_symbol = $this->get_currency_symbol( esc_html( $el_settings_currency ) );
700 694
701 695 $redirection_url_success = get_permalink( $page_id );
702 696 $redirection_url_error = get_permalink( $page_id );
@@ -791,9 +785,9 @@
791 785
792 786 wp_send_json_error( $error_message );
793 787 }
794 788
795 - $campaign_id = ! empty( $_POST['fields']['campaign_id'] ) ? sanitize_text_field( $_POST['fields']['campaign_id'] ) : '';
789 + $campaign_id = $guarded['campaign_id'];
796 790
797 791 Handler::payment_create(
798 792 array(
799 793 'amount' => floatval( $amount ),
@@ -799,9 +793,10 @@
799 793 'amount' => floatval( $amount ),
800 794 'order_id' => $order_id,
801 795 'payment_date' => gmdate( 'Y-m-d H:i:s' ),
802 796 'source' => 'paystack',
803 - 'transaction_id' => '',
797 + // Paystack's reference, so verification can bind it to this order.
798 + 'transaction_id' => ! empty( $response_ar->data->reference ) ? sanitize_text_field( $response_ar->data->reference ) : '',
804 799 'customer_info' => maybe_serialize( $response_ar ),
805 800 'form_fields_info' => maybe_serialize( $better_form_fields ),
806 801 'status' => 'unpaid',
807 802 'currency' => sanitize_text_field( $el_settings_currency ),
@@ -857,9 +852,9 @@
857 852 $detailed_product_info['woo_products'][ $product_id ] = array(
858 853 'name' => sanitize_text_field( $product->get_name() ),
859 854 'product_id' => intval( $product_id ),
860 855 'permalink' => esc_url( $product->get_permalink() ),
861 - 'image_src' => esc_url( wp_get_attachment_url( $product->get_image_id() ) ),
856 + 'image_src' => esc_url( wp_get_attachment_url( (int) $product->get_image_id() ) ),
862 857 'price' => $price,
863 858 'quantity' => $quantity,
864 859 'total_price' => $total_price,
865 860 );
@@ -885,31 +880,12 @@
885 880 $post_data_primary_email = '';
886 881
887 882 $post_fields = $post_data_form_fields;
888 883
889 - $layout = ! empty( $el_settings['better_payment_form_layout'] ) ? sanitize_text_field( $el_settings['better_payment_form_layout'] ) : 'layout-1';
884 + // The fields repeater a Pro form renders is Pro's to name — see PaymentEntitlement.
885 + $form_fields = PaymentEntitlement::form_fields( $el_settings );
890 886
891 - // Handle different layouts.
892 - switch ( $layout ) {
893 - case 'layout-4-pro':
894 - $el_settings['better_payment_form_fields'] = isset( $el_settings['better_payment_form_fields_layout_4_5_6'] ) ? $el_settings['better_payment_form_fields_layout_4_5_6'] : array();
895 - break;
896 -
897 - case 'layout-5-pro':
898 - $el_settings['better_payment_form_fields'] = isset( $el_settings['better_payment_form_fields_layout_4_5_6_desc'] ) ? $el_settings['better_payment_form_fields_layout_4_5_6_desc'] : array();
899 - break;
900 -
901 - case 'layout-6-pro':
902 - $el_settings['better_payment_form_fields'] = isset( $el_settings['better_payment_form_fields_layout_4_5_6_woo'] ) ? $el_settings['better_payment_form_fields_layout_4_5_6_woo'] : array();
903 - break;
904 -
905 - default:
906 - break;
907 - }
908 -
909 - $form_fields = isset( $el_settings['better_payment_form_fields'] ) ? $el_settings['better_payment_form_fields'] : array();
910 -
911 - if ( ! empty( $form_fields ) && is_array( $form_fields ) ) {
887 + if ( ! empty( $form_fields ) ) {
912 888 foreach ( $form_fields as $form_field ) {
913 889 $field_type = ! empty( $form_field['better_payment_primary_field_type'] ) ? sanitize_text_field( $form_field['better_payment_primary_field_type'] ) : '';
914 890 $field_name = ! empty( $form_field['better_payment_field_name_heading'] ) ? sanitize_text_field( $form_field['better_payment_field_name_heading'] ) : '';
915 891