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