StrahinjaL
StrahinjaL

Reputation: 45

Stripe API Checkout WIth Multiple Items

I've got problem with Checkout Session method in Stripe API. When I hardcode values for price and quantity, Stripe will allow me to use multiple items in checkout, but when I try to load those values dynamically, it only lists first product in cart. Here is example of hardcoded values:

          $product = \Stripe\Product::create([
            'name' => "{$row['product_title']}",
            'images' => [
              "https://moto-d.net/wp-content/uploads/2018/01/webshop.jpg"
              ]
          ]);
          
          $price_100 = $row['product_price'] * 100;

          $price = \Stripe\Price::create([
            'product' => "{$product['id']}",
            'unit_amount' => "{$price_100}",
            'currency' => 'eur'
          ]);
  
      $session = \Stripe\Checkout\Session::create([
        'payment_method_types' => ['card'],
        'line_items' => [[
          'price' => 'price_1H1qQRAvwpgnxaFsFErrYUQs',
          'quantity' => 1
        ], [
          'price' => 'price_1H1qQSAvwpgnxaFsXR3XO8Sg',
          'quantity' => 1
        ], [
          'price' => 'price_1H1qQTAvwpgnxaFsfAAn8FMI',
          'quantity' => 1
        ], [
          'price' => 'price_1H1qQUAvwpgnxaFsX9KRfDPE',
          'quantity' => 1
        ]],
        'mode' => 'payment',
        'success_url' => "http://localhost/e-com-master/public/thank_you.php",
        'cancel_url' => "http://localhost/e-com-master/public/index.php",
     ]);
    }
   }
  }
      return $session['id'];

With this code, it works perfectly. But, problems are here (I am using array for storing theese values):

         $line_items_array = array(
           "price" => $price['id'],
           "quantity" => $value
          );

      $session = \Stripe\Checkout\Session::create([
        'payment_method_types' => ['card'],
        'line_items' => [$line_items_array],
        'mode' => 'payment',
        'success_url' => "http://localhost/e-com-master/public/thank_you.php",
        'cancel_url' => "http://localhost/e-com-master/public/index.php",
      ]);

Could anyone notice mistake I am making? I suppose that I am not pushing values in array in appropriate way.

Upvotes: 1

Views: 3741

Answers (4)

thereiswaterinthecup
thereiswaterinthecup

Reputation: 31

Edited: I did some tests using the Stripe PHP library and their example code. I think your error is that you left the brackets in:

'line_items' => [$line_items_array],

It should look like this instead.

'line_items' => $line_items_array,

The readymade array for the line_items parameter should be a numeric index, with a nested multidimensional associative array.

//Here is a functional example that returns a successful checkout session:
<pre>
<?php

$currency = 'eur';

$products = array (
    array (
        'unit_amount' => 1000,
        'name' => 'product 1',
        'images' => 'https://i.imgur.com/EHyR2nP.png',
        'quantity' => '1'
    ),
    array (
        'unit_amount' => 2000,
        'name' => 'product 2',
        'images' => 'https://i.imgur.com/EHyR2nP.png',
        'quantity' => '2'
    ),
);

foreach ($products as $product) {
    $line_items_array[] = array(
        'price_data' => array(
            'currency' => $currency,
            'unit_amount' => $product['unit_amount'],
            'product_data' => array(
                'name' => $product['name'],
                'images' => array($product['images']),
            ),
        ),
        'quantity' => $product['quantity'],
    );
}
print_r ($line_items_array);
?>
</pre>


//the output
Array
(
    [0] => Array
        (
            [price_data] => Array
                (
                    [currency] => eur
                    [unit_amount] => 1000
                    [product_data] => Array
                        (
                            [name] => product 1
                            [images] => Array
                                (
                                    [0] => https://i.imgur.com/EHyR2nP.png
                                )
                        )
                )
            [quantity] => 1
        )

    [1] => Array
        (
            [price_data] => Array
                (
                    [currency] => eur
                    [unit_amount] => 2000
                    [product_data] => Array
                        (
                            [name] => product 2
                            [images] => Array
                                (
                                    [0] => https://i.imgur.com/EHyR2nP.png
                                )
                        )
                )
            [quantity] => 2
        )
)

Upvotes: 0

aa.
aa.

Reputation: 11

I just ran into this a few weeks ago. Stripe Support wasn't interested in helping.

Overview:

  • Construct the line_items you want via your frontend code.
  • i.e.: An array of objects with keys like: product, quantity, etc.
  • Pass that array of objects (via JSON.stringify()) to the backend PHP.
  • Loop through it in the PHP and push it into an array.
  • Pass that array in the line_items key of \Stripe\Checkout\Session::create().

It's pretty straight forward, but was tricky to get right because I wasn't used to PHP.

These were really helpful to me, as a PHP novice:

I'm including everything for your create-checkout-session.php file. Not just the foreach().

<?php


/* Standard Stripe API stuff */
require 'vendor/autoload.php';
\Stripe\Stripe::setApiKey("STRIPE_LIVE_SECRET_KEY_HERE");
header('Content-Type: application/json');
$YOUR_DOMAIN = 'http://localhost:4242';


/* Read in the JSON sent via the frontend */
$json_str = file_get_contents('php://input');


/*
 * Convert to PHP object
 * - NOT setting `json_decode($json_str, TRUE)` because having the data decoded into an *object* seems to work well. Also, Stripe's own sample code, for custom flows, does not set to `TRUE`.
 * - https://www.php.net/manual/en/function.json-decode.php
 */
$data = json_decode($json_str);


/* Create array to accept multiple `line_item` objects */
$lineItemsArray = [];


/*
 * [OPTIONAL] Create array to combine multiple keys from each`line_item` into a single one for `payment_intent_data.description`
 * - Only required if you want to pass along this type of description that's either provided by the user or by your frontend logic.
 * - IOW: It was useful to me, but it might not be to you.
 */
$descriptionInternal = [];


/* Convert the incoming JSON key/values into a PHP array() that the Stripe API will accept below in `\Stripe\Checkout\Session::create()` */
foreach($data as $key => $value) {

  /*
   * Swap frontend `price` for backend Stripe `price id`
   * - If you have Products/Prices that you created in the Stripe Dashboard, you might want to keep those Ids secret (although I don't know if that matters).
   * - So you'll need to convert whatever you define them as on the frontend (public), to the Stripe PriceId equivalents (private).
   * - This switch statement does that.
   */
  switch ($value->price) {
    case 50:
      $value->price = "price_1Iaxxxxxxx";
      break;
    case 100:
      $value->price = "price_1Ibxxxxxxx";
      break;
    case 150:
      $value->price = "price_1Icxxxxxxx";
      break;
    default:
      $value->price = "price_1Iaxxxxxxx";
  }


  /* `array_push` this object shape, for each `line_item` entry, into the array created outside of this `foreach()` loop. */
  array_push($lineItemsArray, 
    [
      "price" => $value->price, 
      "quantity" => $value->quantity,
      "customerName" => $value->customer_name,
      "recipientName" => $value->recipient_name,
      "description" => $value->description /* Customer facing on the Stripe "Pay" page */
      /*
       * Add whatever else you want to include, with each `line_item`, here.
       * - Stripe API allows:
       * - https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-line_items
      */
    ]);


  /*
   * [OPTIONAL] `array_push` some or all of the `line_item` key values in a combined form.
   * - Handy (in some cases) if you want to see a quick readout of the entire purchase in your Stripe Dashboard "Purchases" listing (i.e.: Saves you from having click into it to see the details).
   * - Or you could construct this via your frontend code and pass it as a string.
   * - But I'm including this here, in case you want to do it, or something like it, in in PHP.
   * - Example final result: "[Axl: 3 Guns N' Roses for Duff] [Slash: 6 Guns N' Roses for Izzy]"
   */
  array_push(
    $descriptionInternal, 
    ("[" . $value->customerName . ": " . $value->quantity . " Guns N' Roses for " . $value->recipientName) . "]");

}


/* [OPTIONAL] `payment_intent_data.description` takes a string, not an array. */
$descriptionInternal = implode(" ", $descriptionInternal);


/* https://stripe.com/docs/api/checkout/sessions/create */
$checkout_session = \Stripe\Checkout\Session::create([
  'payment_method_types' => ['card'],

  /* Takes in the array from above */
  'line_items' => $lineItemsArray,

  /* [OPTIONAL] Single `payment_intent_data.description` */
  'payment_intent_data' => [
    'description' => $descriptionInternal, /* This version of "Description" is displayed in the Dashboard and on Customer email receipts. */

  ],

  'mode' => 'payment',

  'success_url' => $YOUR_DOMAIN . '/success.html',
  'cancel_url' => $YOUR_DOMAIN . '/cancel.html',
]);

echo json_encode(['id' => $checkout_session->id]);

Upvotes: 1

Peter Pugh-Jones
Peter Pugh-Jones

Reputation: 1

Probably a bit late to reply now, but anyway after much testing and trial and error here is what worked for me.

I found that passing the array list was a major pain, so I had to reassemble the array once I recieved it from input as json, before passing it to Stripe Create, which even then, only seemed to work properly when I used eval on the array when passing it. Mainly posting this to help anyone avoid the pain I went through :), I am sure there are way better ways to do it, but I could find no examples anywhere at the time and this has been working fine now for almost a year so I haven't looked to improve or modify as yet.

<?php

header("Content-Type: application/json");

require_once('stripe/vendor/autoload.php');

// Set your secret key. Remember to switch to your live secret key in production!
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey('whateveryouroneis');

// grab the json data from the cart, sent via php input
$data = (array) json_decode(file_get_contents("php://input"), TRUE);

//get the current webpage URL
$returnToPage = $_COOKIE["whateveryoursis"];

/**
* recursive read though what we recieved, try to get it to pass by rebuilding it
*/
function displayArrayRecursively($arr) {
if ($arr) {
    foreach ($arr as $key => $value) {
        if (is_array($value)) {

          $arrs .= displayArrayRecursively($value);

         } else {
            //  Output
             if ( $key == 'name' ) {
                $arrs .= " [ \"$key\" => '$value', \n";
                }
             elseif ( $key == 'quantity' ) {
                $arrs .= " \"$key\" => $value , ], \n";
                }
             elseif ( in_array($key, ['description','currency'], true )) {
                $arrs .= " \"$key\" => '$value', \n";
                }
             elseif ( $key == 'amount' ) {
                $arrs .= " \"$key\" => " . $value * 100 . ", \n";
                }
             else {
                $arrs .= " \"$key\" => ['$value'], \n";
                 }
             }
        }
   }

return $arrs;
  }

$line_items_str = displayArrayRecursively($data);

$createSession_str = (
      "'payment_method_types' => ['card']," .
      "'success_url' => '" . $returnToPage . "?success=1'," .
      "'cancel_url' => '" . $returnToPage . "'," .
      "'shipping_address_collection' => [" .
      "'allowed_countries' => ['GB'], ]," .
      "'line_items' => [" . $line_items_str . " ], ");

// create the checkout session on Stripe
eval ( $session = "\$session = \Stripe\Checkout\Session::create( [ " . 
$createSession_str . " ] );" );

$stripeSession = array($session);
// test while working on it :-
// var_dump($stripeSession);
$sessId = ($stripeSession[0]['id']);

echo $sessId;    

Upvotes: 0

user14447501
user14447501

Reputation: 11

     $line_items_array = array(
       'price' => "{$price['id']}",
       'quantity' => "{$value}"
      ); 

and

'line_items' => [[$line_items_array]],

Upvotes: 1

Related Questions