Automattic\WooCommerce\Gateways\PayPal

Request::create_paypal_orderpublicWC 1.0

Create a PayPal order using the Orders v2 API.

This method creates a PayPal order and returns the order details including the approval URL where customers will be redirected to complete payment.

Method of the class: Request{}

Returns

Array|null.

Usage

$Request = new Request();
$Request->create_paypal_order( $order, $payment_source, $js_sdk_params ): ?array;
$order(WC_Order) (required)
Order object.
$payment_source(string)
The payment source.
Default: PayPalConstants::PAYMENT_SOURCE_PAYPAL
$js_sdk_params(array)
Extra parameters for a PayPal JS SDK (Buttons) request.
Default: array()

Request::create_paypal_order() code WC 10.7.0

public function create_paypal_order(
	WC_Order $order,
	string $payment_source = PayPalConstants::PAYMENT_SOURCE_PAYPAL,
	array $js_sdk_params = array()
): ?array {
	$paypal_debug_id = null;

	// While PayPal JS SDK can return 'paylater' as the payment source in the createOrder callback,
	// Orders v2 API does not accept it. We will use 'paypal' instead.
	// Accepted payment_source values for Orders v2:
	// https://developer.paypal.com/docs/api/orders/v2/#orders_create!ct=application/json&path=payment_source&t=request.
	if ( PayPalConstants::PAYMENT_SOURCE_PAYLATER === $payment_source ) {
		$payment_source = PayPalConstants::PAYMENT_SOURCE_PAYPAL;
	}

	try {
		$request_body = array(
			'test_mode' => $this->gateway->testmode,
			'order'     => $this->get_paypal_create_order_request_params( $order, $payment_source, $js_sdk_params ),
		);
		$response     = $this->send_wpcom_proxy_request( 'POST', self::WPCOM_PROXY_ORDER_ENDPOINT, $request_body );

		if ( is_wp_error( $response ) ) {
			throw new Exception( 'PayPal order creation failed. Response error: ' . $response->get_error_message() );
		}

		if ( ! is_array( $response ) ) {
			throw new Exception( 'PayPal order creation failed. Invalid response type.' );
		}

		$http_code     = wp_remote_retrieve_response_code( $response );
		$body          = wp_remote_retrieve_body( $response );
		$response_data = json_decode( $body, true );

		$response_array = is_array( $response_data ) ? $response_data : array();

		/**
		 * Fires after receiving a response from PayPal order creation.
		 *
		 * This hook allows extensions to react to PayPal API responses, such as
		 * displaying admin notices or logging response data.
		 *
		 * Note: This hook fires on EVERY order creation attempt (success or failure),
		 * and can be called multiple times for the same order if retried. Extensions
		 * hooking this should be idempotent and check order state/meta before taking
		 * action to avoid duplicate processing.
		 *
		 * @since 10.4.0
		 *
		 * @param int|string $http_code     The HTTP status code from the PayPal API response.
		 * @param array      $response_data The decoded response data from the PayPal API
		 * @param WC_Order   $order         The WooCommerce order object.
		 */
		do_action( 'woocommerce_paypal_standard_order_created_response', $http_code, $response_array, $order );

		if ( ! in_array( $http_code, array( 200, 201 ), true ) ) {
			$paypal_debug_id = isset( $response_data['debug_id'] ) ? $response_data['debug_id'] : null;
			throw new Exception( 'PayPal order creation failed. Response status: ' . $http_code . '. Response body: ' . $body );
		}

		$redirect_url = null;
		if ( empty( $js_sdk_params['is_js_sdk_flow'] ) ) {
			// We only need an approve link for the classic, redirect flow.
			$redirect_url = $this->get_approve_link( $http_code, $response_data );
			if ( empty( $redirect_url ) ) {
				throw new Exception( 'PayPal order creation failed. Missing approval link.' );
			}
		}

		// Save the PayPal order ID to the order.
		$order->update_meta_data( PayPalConstants::PAYPAL_ORDER_META_ORDER_ID, $response_data['id'] );

		// Save the PayPal order status to the order.
		$order->update_meta_data( PayPalConstants::PAYPAL_ORDER_META_STATUS, $response_data['status'] );

		// Remember the payment source: payment_source is not patchable.
		// If the payment source is changed, we need to create a new PayPal order.
		$order->update_meta_data( PayPalConstants::PAYPAL_ORDER_META_PAYMENT_SOURCE, $payment_source );
		$order->save();

		return array(
			'id'           => $response_data['id'],
			'redirect_url' => $redirect_url,
		);
	} catch ( Exception $e ) {
		\WC_Gateway_Paypal::log( $e->getMessage() );
		if ( $paypal_debug_id ) {
			$order->add_order_note(
				sprintf(
					/* translators: %1$s: PayPal debug ID */
					__( 'PayPal order creation failed. PayPal debug ID: %1$s', 'woocommerce' ),
					$paypal_debug_id
				)
			);
		}
		return null;
	}
}