Automattic\WooCommerce\Gateways\PayPal

Request::get_paypal_create_order_request_paramsprivateWC 1.0

Build the request parameters for the PayPal create-order request.

Method of the class: Request{}

Returns

Array.

Usage

// private - for code of main (parent) class only
$result = $this->get_paypal_create_order_request_params( $order, $payment_source, $js_sdk_params ): array;
$order(WC_Order) (required)
Order object.
$payment_source(string) (required)
The payment source.
$js_sdk_params(array) (required)
Extra parameters for a PayPal JS SDK (Buttons) request.

Request::get_paypal_create_order_request_params() code WC 10.7.0

private function get_paypal_create_order_request_params( WC_Order $order, string $payment_source, array $js_sdk_params ): array {
	$payee_email         = sanitize_email( (string) $this->gateway->get_option( 'email' ) );
	$shipping_preference = $this->get_paypal_shipping_preference( $order );

	/**
	 * Filter the supported currencies for PayPal.
	 *
	 * @since 2.0.0
	 *
	 * @param array $supported_currencies Array of supported currency codes.
	 * @return array
	 */
	$supported_currencies = apply_filters(
		'woocommerce_paypal_supported_currencies',
		PayPalConstants::SUPPORTED_CURRENCIES
	);
	if ( ! in_array( strtoupper( $order->get_currency() ), $supported_currencies, true ) ) {
		throw new Exception( 'Currency is not supported by PayPal. Order ID: ' . esc_html( (string) $order->get_id() ) );
	}

	$purchase_unit_amount = $this->get_paypal_order_purchase_unit_amount( $order );
	if ( $purchase_unit_amount['value'] <= 0 ) {
		// If we cannot build purchase unit amount (e.g. negative or zero order total),
		// we should not proceed with the create-order request.
		throw new Exception( 'Cannot build PayPal order purchase unit amount. Order total is not valid. Order ID: ' . esc_html( (string) $order->get_id() ) . ', Total: ' . esc_html( (string) $purchase_unit_amount['value'] ) );
	}

	$order_items = $this->get_paypal_order_items( $order );

	$src_locale = get_locale();
	// If the locale is longer than PayPal's string limit (10).
	if ( strlen( $src_locale ) > PayPalConstants::PAYPAL_LOCALE_MAX_LENGTH ) {
		// Keep only the main language and region parts.
		$locale_parts = explode( '_', $src_locale );
		if ( count( $locale_parts ) > 2 ) {
			$src_locale = $locale_parts[0] . '_' . $locale_parts[1];
		}
	}

	$params = array(
		'intent'         => $this->get_paypal_order_intent(),
		'payment_source' => array(
			$payment_source => array(
				'experience_context' => array(
					'user_action'           => PayPalConstants::USER_ACTION_PAY_NOW,
					'shipping_preference'   => $shipping_preference,
					// Customer redirected here on approval.
					'return_url'            => $this->normalize_url_for_paypal( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
					// Customer redirected back to checkout if they cancel the PayPal flow.
					'cancel_url'            => $this->normalize_url_for_paypal( wc_get_checkout_url() ),
					// Convert WordPress locale format (e.g., 'en_US') to PayPal's expected format (e.g., 'en-US').
					'locale'                => str_replace( '_', '-', $src_locale ),
					'app_switch_preference' => array(
						'launch_paypal_app' => true,
					),
				),
			),
		),
		'purchase_units' => array(
			array(
				'custom_id'  => $this->get_paypal_order_custom_id( $order ),
				'amount'     => $purchase_unit_amount,
				'invoice_id' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), PayPalConstants::PAYPAL_INVOICE_ID_MAX_LENGTH ),
				'items'      => $order_items,
				'payee'      => array(
					'email_address' => $payee_email,
				),
			),
		),
	);

	if ( ! in_array(
		$shipping_preference,
		array(
			PayPalConstants::SHIPPING_NO_SHIPPING,
			PayPalConstants::SHIPPING_SET_PROVIDED_ADDRESS,
		),
		true
	) ) {
		$shipping_callback_token = $this->generate_shipping_callback_token( $order );
		$callback_url            = add_query_arg(
			'token',
			$shipping_callback_token,
			rest_url( 'wc/v3/paypal-standard/update-shipping' )
		);

		$params['payment_source'][ $payment_source ]['experience_context']['order_update_callback_config'] = array(
			'callback_events' => array( 'SHIPPING_ADDRESS', 'SHIPPING_OPTIONS' ),
			'callback_url'    => $this->normalize_url_for_paypal( $callback_url ),
		);
	}

	// If the request is from PayPal JS SDK (Buttons), we need a cancel URL that is compatible with App Switch.
	if ( ! empty( $js_sdk_params['is_js_sdk_flow'] ) && ! empty( $js_sdk_params['app_switch_request_origin'] ) ) {
		// App Switch may open a new tab, so we cannot rely on client-side data.
		// We need to pass the order ID manually.
		// See https://developer.paypal.com/docs/checkout/standard/customize/app-switch/#resume-flow.

		$request_origin = $js_sdk_params['app_switch_request_origin'];

		// Check if $request_origin is a valid URL, and matches the current site.
		$origin_parts       = wp_parse_url( $request_origin );
		$site_parts         = wp_parse_url( get_site_url() );
		$is_valid_url       = filter_var( $request_origin, FILTER_VALIDATE_URL );
		$is_expected_scheme = isset( $origin_parts['scheme'], $site_parts['scheme'] ) && strcasecmp( $origin_parts['scheme'], $site_parts['scheme'] ) === 0;
		$is_expected_host   = isset( $origin_parts['host'], $site_parts['host'] ) && strcasecmp( $origin_parts['host'], $site_parts['host'] ) === 0;
		if ( $is_valid_url && $is_expected_scheme && $is_expected_host ) {
			$cancel_url = add_query_arg(
				array(
					'order_id' => $order->get_id(),
				),
				$request_origin
			);
			$params['payment_source'][ $payment_source ]['experience_context']['cancel_url'] = $this->normalize_url_for_paypal( $cancel_url );
		}
	}

	$shipping = $this->get_paypal_order_shipping( $order );
	if ( $shipping ) {
		$params['purchase_units'][0]['shipping'] = $shipping;
	} elseif ( PayPalConstants::SHIPPING_SET_PROVIDED_ADDRESS === $shipping_preference ) {
		// If the shipping preference is set to SET_PROVIDED_ADDRESS, but no shipping information is provided, PayPal create order request will fail.
		// Throw an exception to prevent the request from being sent.
		throw new Exception( 'Shipping address is required for PayPal create-order request. Order ID: ' . esc_html( (string) $order->get_id() ) );
	}

	return $params;
}