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 +77 -99 2.2.1 → 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,14 +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',
304 + // Persisted so the async PayPal IPN can rebuild the e-mail body + on/off toggle.
305 + 'email_settings' => Handler::extract_email_settings( $el_settings ),
307 306 );
308 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 +
309 311 $better_form_fields = array_merge( $better_form_fields, $this->fetch_better_form_fields( $el_settings, $_POST ) );
310 312
311 313 if ( ! empty( $better_form_fields['primary_first_name'] ) ) {
312 314 $request_data['primary_first_name'] = sanitize_text_field( $better_form_fields['primary_first_name'] );
@@ -323,9 +325,9 @@
323 325 if ( ! empty( $better_form_fields['primary_reference_number'] ) ) {
324 326 $request_data['invoice'] = sanitize_text_field( $better_form_fields['primary_reference_number'] );
325 327 }
326 328
327 - $campaign_id = ! empty( $_POST['campaign_id'] ) ? sanitize_text_field( $_POST['campaign_id'] ) : '';
329 + $campaign_id = $guarded['campaign_id'];
328 330 // phpcs:enable WordPress.Security.NonceVerification.Missing
329 331
330 332 Handler::payment_create(
331 333 array(
@@ -442,38 +444,35 @@
442 444 wp_send_json_error( esc_html__( 'Stripe Key missing', 'better-payment' ) );
443 445 }
444 446
445 447 // phpcs:disable WordPress.Security.NonceVerification.Missing
446 - $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 + );
447 458
448 - if ( empty( $_POST['fields']['primary_payment_amount'] ) && ! empty( $_POST['fields']['primary_payment_amount_radio'] ) ) {
449 - $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;
450 462 }
451 463
452 - $amount_quantity = ! empty( $_POST['fields']['payment_amount_quantity'] ) ? intval( $_POST['fields']['payment_amount_quantity'] ) : '';
453 - $amount = ! empty( $amount_quantity ) ? $amount * $amount_quantity : $amount;
464 + $amount = $guarded['amount'];
465 + $amount_quantity = $guarded['quantity'];
454 466
455 - if ( $amount <= 0 ) {
456 - wp_send_json_error( esc_html__( 'Invalid payment amount.', 'better-payment' ) );
457 - return;
458 - }
459 -
460 467 $header_info = array(
461 468 'Authorization' => 'Basic ' . base64_encode( sanitize_text_field( $better_payment_keys['secret_key'] ) . ':' ),
462 469 'Stripe-Version' => '2019-05-16',
463 470 );
464 471
465 - $order_id = 'stripe_' . uniqid();
466 - $el_settings_currency = $el_settings['better_payment_form_currency'];
472 + $order_id = Handler::new_order_id( 'stripe' );
473 + $el_settings_currency = $guarded['currency'];
467 474
468 - if ( ! empty( $el_settings['better_payment_form_currency_use_woocommerce'] ) && 'yes' === $el_settings['better_payment_form_currency_use_woocommerce'] &&
469 - ! empty( $el_settings['better_payment_form_currency_woocommerce'] ) ) {
470 - $el_settings_currency = $el_settings['better_payment_form_currency_woocommerce'];
471 - }
472 - if ( ! empty( $_POST['fields']['campaign_currency'] ) ) {
473 - $el_settings_currency = sanitize_text_field( $_POST['fields']['campaign_currency'] );
474 - }
475 -
476 475 $el_settings_currency_symbol = $this->get_currency_symbol( esc_html( $el_settings_currency ) );
477 476
478 477 $redirection_url_success = get_permalink( $page_id );
479 478 $redirection_url_error = get_permalink( $page_id );
@@ -608,9 +607,9 @@
608 607 return;
609 608 }
610 609
611 610 if ( ! empty( $response_ar->payment_intent ) || ( ! empty( $response_ar->mode ) && 'subscription' === $response_ar->mode ) ) {
612 - $campaign_id = ! empty( $_POST['fields']['campaign_id'] ) ? sanitize_text_field( $_POST['fields']['campaign_id'] ) : '';
611 + $campaign_id = $guarded['campaign_id'];
613 612
614 613 Handler::payment_create(
615 614 array(
616 615 'amount' => floatval( $amount ),
@@ -663,38 +662,35 @@
663 662 wp_send_json_error( esc_html__( 'Paystack Key missing', 'better-payment' ) );
664 663 }
665 664
666 665 // phpcs:disable WordPress.Security.NonceVerification.Missing
667 - $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 + );
668 676
669 - if ( empty( $_POST['fields']['primary_payment_amount'] ) && ! empty( $_POST['fields']['primary_payment_amount_radio'] ) ) {
670 - $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;
671 680 }
672 681
673 - $amount_quantity = ! empty( $_POST['fields']['payment_amount_quantity'] ) ? intval( $_POST['fields']['payment_amount_quantity'] ) : '';
674 - $amount = ! empty( $amount_quantity ) ? $amount * $amount_quantity : $amount;
682 + $amount = $guarded['amount'];
683 + $amount_quantity = $guarded['quantity'];
675 684
676 - if ( $amount <= 0 ) {
677 - wp_send_json_error( esc_html__( 'Invalid payment amount.', 'better-payment' ) );
678 - return;
679 - }
680 -
681 685 $header_info = array(
682 686 'Authorization' => 'Bearer ' . sanitize_text_field( $el_settings['better_payment_paystack_secret_key'] ),
683 687 'Cache-Control: no-cache',
684 688 );
685 689
686 - $order_id = 'paystack_' . uniqid();
687 - $el_settings_currency = $el_settings['better_payment_form_currency'];
690 + $order_id = Handler::new_order_id( 'paystack' );
691 + $el_settings_currency = $guarded['currency'];
688 692
689 - if ( ! empty( $el_settings['better_payment_form_currency_use_woocommerce'] ) && 'yes' === $el_settings['better_payment_form_currency_use_woocommerce'] &&
690 - ! empty( $el_settings['better_payment_form_currency_woocommerce'] ) ) {
691 - $el_settings_currency = $el_settings['better_payment_form_currency_woocommerce'];
692 - }
693 - if ( ! empty( $_POST['fields']['campaign_currency'] ) ) {
694 - $el_settings_currency = sanitize_text_field( $_POST['fields']['campaign_currency'] );
695 - }
696 -
697 693 $el_settings_currency_symbol = $this->get_currency_symbol( esc_html( $el_settings_currency ) );
698 694
699 695 $redirection_url_success = get_permalink( $page_id );
700 696 $redirection_url_error = get_permalink( $page_id );
@@ -789,9 +785,9 @@
789 785
790 786 wp_send_json_error( $error_message );
791 787 }
792 788
793 - $campaign_id = ! empty( $_POST['fields']['campaign_id'] ) ? sanitize_text_field( $_POST['fields']['campaign_id'] ) : '';
789 + $campaign_id = $guarded['campaign_id'];
794 790
795 791 Handler::payment_create(
796 792 array(
797 793 'amount' => floatval( $amount ),
@@ -797,9 +793,10 @@
797 793 'amount' => floatval( $amount ),
798 794 'order_id' => $order_id,
799 795 'payment_date' => gmdate( 'Y-m-d H:i:s' ),
800 796 'source' => 'paystack',
801 - '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 ) : '',
802 799 'customer_info' => maybe_serialize( $response_ar ),
803 800 'form_fields_info' => maybe_serialize( $better_form_fields ),
804 801 'status' => 'unpaid',
805 802 'currency' => sanitize_text_field( $el_settings_currency ),
@@ -855,9 +852,9 @@
855 852 $detailed_product_info['woo_products'][ $product_id ] = array(
856 853 'name' => sanitize_text_field( $product->get_name() ),
857 854 'product_id' => intval( $product_id ),
858 855 'permalink' => esc_url( $product->get_permalink() ),
859 - '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() ) ),
860 857 'price' => $price,
861 858 'quantity' => $quantity,
862 859 'total_price' => $total_price,
863 860 );
@@ -883,31 +880,12 @@
883 880 $post_data_primary_email = '';
884 881
885 882 $post_fields = $post_data_form_fields;
886 883
887 - $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 );
888 886
889 - // Handle different layouts.
890 - switch ( $layout ) {
891 - case 'layout-4-pro':
892 - $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();
893 - break;
894 -
895 - case 'layout-5-pro':
896 - $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();
897 - break;
898 -
899 - case 'layout-6-pro':
900 - $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();
901 - break;
902 -
903 - default:
904 - break;
905 - }
906 -
907 - $form_fields = isset( $el_settings['better_payment_form_fields'] ) ? $el_settings['better_payment_form_fields'] : array();
908 -
909 - if ( ! empty( $form_fields ) && is_array( $form_fields ) ) {
887 + if ( ! empty( $form_fields ) ) {
910 888 foreach ( $form_fields as $form_field ) {
911 889 $field_type = ! empty( $form_field['better_payment_primary_field_type'] ) ? sanitize_text_field( $form_field['better_payment_primary_field_type'] ) : '';
912 890 $field_name = ! empty( $form_field['better_payment_field_name_heading'] ) ? sanitize_text_field( $form_field['better_payment_field_name_heading'] ) : '';
913 891