Stock of products on snipcart with Kirby

Hello, I use Kirby with snipcart.com and it’s pretty easy to set up.

However, I need to use the snipcart API to be able to take out the stock of products. This lacks a concrete example on snipcart.

I wanted to know if a Kirby user had successfully displayed the stock of snipcart products? If yes, how did you do it?

I manage to interrogate the API and output the json data.

But to display them in Kirby I do not see how?

Thank you in advance for your help.

1 Like

Which version of the script are you using? Stock levels where not possible until version 3.10.

Its something I will be adding to my Snipcart plugin but not any time soon.

1 Like

How far have you got with the json data? Could you post the relevant code?

Hello,

Thanks jimbobrjames. As a starting project I used the Plainkit: Shop.

I use snipcart in v3.12.0.

texnixe, thanks !

here PHP code:

<?php
    function call_snipcart_api($url, $method = "GET", $post_data = null) {
        $url = 'https://app.snipcart.com/api' . $url;

        $query = curl_init();

        $headers = array();
        $headers[] = 'Content-type: application/json';
        if ($post_data)
            $headers[] = 'Content-Length: ' . strlen($post_data);
        $headers[] = 'Accept: application/json';

        // API KEY TEST MODE SNIPCART
        $secret = 'ST_YmZjMmUzZWMtYjMzOC00OGQ0LWI3ZjAtNDBmNDJmMzQxNGQxNjM3MjU0MzQyODAxNzgyNzM1';
        $headers[] = 'Authorization: Basic '.base64_encode($secret . ":");
        $options = array(
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_URL => $url,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_SSL_VERIFYPEER => 0
        );

        if ($post_data) {
            $options[CURLOPT_CUSTOMREQUEST] = $method;
            $options[CURLOPT_POSTFIELDS] = $post_data;
        }

        curl_setopt_array($query, $options);
        $resp = curl_exec($query);
        curl_close($query);

        return json_decode($resp);
    }

$orders = call_snipcart_api('/products');
echo json_encode($orders);

?>

here is the JSON code:

{
  keywords: null,
  userDefinedId: null,
  archived: false,
  excludeZeroSales: false,
  from: null,
  to: null,
  orderBy: "SalesValue",
  hasMoreResults: false,
  totalItems: 4,
  offset: 0,
  limit: 20,
  items: [
   {
      mode: "Test",
      userDefinedId: "watch",
      url: "http://dev.siteinternetfacile.com/_demokitmaster/demokit-master/shop/watch",
      name: "Watch",
      description: "A watch without a face. No longer get distracted by the vague concept of time.",
      fileGuid: null,
      price: 249,
      categories: [ ],
      image: null,
      archived: false,
      inventoryManagementMethod: "Single",
      stock: 10,
      totalStock: 10,
      allowOutOfStockPurchases: false,
      statistics: {
      numberOfSales: 0,
      totalSales: 0
},
customFields: [ ],
variants: [ ],
metadata: null,
id: "59415ccf-64d5-4e35-82e0-190675ca89ea",
creationDate: "2020-04-07T20:28:11.673Z",
modificationDate: "2020-04-07T20:28:11.673Z"
},
{ ... },
{ ... },
{ ... }
]
}

To display the stock of a product I take its “id” and I put it in the url with this little piece of php code:

$orders = call_snipcart_api('/products/59415ccf-64d5-4e35-82e0-190675ca89ea');
echo $orders->stock;

I don’t know if you know snipcart well. For a product to be added to the inventory, you must send its url in the snipcart administration interface.

Then click on the product and add the stock:

For the moment the support of snipcart told me to look at these links there but the documentation is not as simple as Kirby. There is no very concrete example.

General: https://docs.snipcart.com/v3/api-reference/introduction
Product: https://docs.snipcart.com/v3/api-reference/products

He indicated me a single project which manages the stock:

Indeed in the demonstration he manages to report products in “out of stock”:

Thanks for help !

Ok, so you seem to fetch the stock of a single product alright, which seemed to be your original question? Or is there another problem and you want to post to the API as well?

BTW: You can make your calls to the API less verbose by using Kirby’s handy Remote class, which uses cUrl internally.

Okay,

I don’t understand how to match the id of a snipcart product (json) with the id of a product in Kirby?

If I add a new field in kirby will I have to add all the ids by hand?

With more than 600 products it may be complicated. There should be something automatic.

Instead of the ID, you can also pass the user defined ID. Where does this come from? From the ID of the product in Kirby? Looks as if that’s the one you have to pass in the data-item-id when defining a product. So you don’t need this long snipcart ID at all to get the information you need.

$orders = call_snipcart_api('/products/watch');
dump($orders->stock);

If necessary, you can always fetch all products from the API, then loop through your products, find the product from the items array by URL and store the snipcart ID for each product in the content file for subsequent use.

Hello,

Thank you for all these details, I managed to display the stock.

My brother also helped me a lot to make the PHP code and I thank him;)

Here is the code that manages:

  1. In stock (If you have not indicated anything in snipcart.com (Unspecified) we consider that it is in stock)

  2. In stock. Only X copies left in stock. (stock indicated in snipcart.com)

  3. Out of stock. This product is being restocked. + Email form. (stock at 0 in snipcart.com)

The result of the 3 possibilities in image side by side:

This code:

I. The same code as in my first message

<?php
    function call_snipcart_api($url, $method = "GET", $post_data = null) {
        $url = 'https://app.snipcart.com/api' . $url;

            $query = curl_init();

            $headers = array();
            $headers[] = 'Content-type: application/json';
            if ($post_data)
                $headers[] = 'Content-Length: ' . strlen($post_data);
            $headers[] = 'Accept: application/json';

            // IMPORTANT: CREATE "SECRET API KEYS" ON SNIPCART.COM
            $secret = 'API_KEY_HERE';
            $headers[] = 'Authorization: Basic '.base64_encode($secret . ":");
            $options = array(
                CURLOPT_RETURNTRANSFER => 1,
                CURLOPT_URL => $url,
                CURLOPT_HTTPHEADER => $headers,
                CURLOPT_SSL_VERIFYHOST => 0,
                CURLOPT_SSL_VERIFYPEER => 0
            );

            if ($post_data) {
                $options[CURLOPT_CUSTOMREQUEST] = $method;
                $options[CURLOPT_POSTFIELDS] = $post_data;
            }

            curl_setopt_array($query, $options);
            $resp = curl_exec($query);
            curl_close($query);

            return json_decode($resp);
        }
    ?>

II) PRODUCT CODE

                        // ON THE TOP: Name, description, price ...

                        <?php
                            // SNIPPET API CODE
                            snippet('shop/api');

                            // URL API (https://app.snipcart.com/api/**products**) + SLUG PRODUCT
                            $orders = call_snipcart_api('/products/'.$page->slug());
                        ?>

                         // THE 3 POSSIBLE DISPLAYS
                        <?php if ($orders): ?>
                            <?php $has_stock = false; ?>
                            <?php if (isset($orders->stock) && $orders->stock == 0): ?>
                            <br /><small><span style="font-size:75%;">Victime de son succès. Ce produit est en cours de réapprovisionnement.</span></small>

                            // OPTIONAL
                            <?php snippet('shop/form/shop-product') ?>


                            <?php elseif (isset($orders->stock) && $orders->stock > 0): ?>
                            <small><sup class="badge badge-success">En stock</sup><br />
                                <span style="font-size:75%;">Il ne reste plus que <?php echo $orders->stock ?> exemplaire(s) en stock.</span>
                            </small>
                            <?php $has_stock = true; ?>

                            <?php else: ?>
                            <small><sup class="badge badge-success">En stock</sup></small>
                            <?php $has_stock = true; ?>
                            <?php endif; ?>
                        </h4>

                            <?php if($has_stock): ?>
                            <a href="<?= $page->url() ?>" class="btn btn-block btn-secondary cta snipcart-add-item" data-item-id="<?= $page->slug() ?>" data-item-price="<?= $page->price()->html() ?>" data-item-url="<?= $page->url() ?>" data-item-description="<?= $page->summary()->html() ?>" <?php if ($image = $page->image()): ?> data-item-image="<?= $page->image()->url() ?>" <?php else: ?> <?php endif ?> data-item-name="<?= $page->title()->html() ?>" data-item-has-taxes-included="true" data-item-custom1-name="Consigne <?php echo number_format((float)$page->depositsystem()->value(), 2, ',', ' '); ?> €" data-item-custom1-options="Consigne[+<?= $page->depositsystem()->value() ?>]" data-item-custom1-required="false" data-item-custom1-has-taxes-included="true">
                                <i class="fas fa-shopping-cart"></i> Ajouter au panier
                            </a>
                            <?php endif; ?>
                        <?php endif; ?>

III) OPTIONAL FORM (guide: https://getkirby.com/docs/cookbook/forms/basic-contact-form). And add: controllers, templates/emails …

<!-- Début formulaire SUCCESS -->
<?php if($success): ?>

<div class="alert alert-warning alert-dismissible fade show" role="alert" data-delay="100" id="myAlert">
    <strong><?= $success ?></strong>
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
        <span aria-hidden="true">&times;</span>
    </button>
</div>

<?php else: ?>

<!-- Début formulaire -->

<?php if (isset($alert['error'])): ?>
<div><?= $alert['error'] ?></div>
<?php endif ?>

<form method="POST" action="<?= $page->url() ?>/">
    <div class="row mt-3">
        <div class="honeypot">
            <label for="website">Website <abbr title="required">*</abbr></label>
            <input type="website" id="website" name="website">
        </div>

        <div class="col-md">
            <div class="form-group">
                <label for="product" class="sr-only">Produit</label>
                <input type="text" id="product" name="product" value="<?= $page->title() ?>" class="sr-only">

                <label for="product_url" class="sr-only">Url</label>
                <input type="text" id="product_url" name="product_url" value="<?= $page->url() ?>" class="sr-only">

                <label for="email" class="sr-only">Email <abbr title="required">*</abbr></label>
                <small id="emailHelp" class="form-text mb-2">Pour être prévenu lorsque le produit est disponible:</small>
                <input type="email" id="email" name="email" value="<?= $data['email'] ?? '' ?>" class="form-control p-3 rounded-0" placeholder="indiquez votre e-mail" required>
                <?= isset($alert['email']) ? '<span class="alert error">' . html($alert['email']) . '</span>' : '' ?>
            </div>
        </div>
    </div>

    <div class="form-group">
        <input type="submit" name="submit" class="btn pb_outline-light pb_font-13 pb_letter-spacing-2  p-3 rounded-0" value="Envoyez">
    </div>
</form>
<?php endif ?>
<!-- fin formulaire -->

DEMO: https://triplehop.fr/boutique

1 Like