PHPackages                             venveo/craft-bigcommerce - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. venveo/craft-bigcommerce

ActiveCraft-plugin[API Development](/categories/api)

venveo/craft-bigcommerce
========================

BigCommerce for Craft CMS

3.0.1(3y ago)1191MITPHPPHP ^8.0.2

Since Jul 28Pushed 3y agoCompare

[ Source](https://github.com/venveo/craft-bigcommerce)[ Packagist](https://packagist.org/packages/venveo/craft-bigcommerce)[ Docs](https://github.com/craftcms/shopify)[ RSS](/packages/venveo-craft-bigcommerce/feed)WikiDiscussions develop Synced 2d ago

READMEChangelogDependencies (7)Versions (22)Used By (0)

[![BigCommerce icon](./src/icon.svg)](./src/icon.svg)

BigCommerce for Craft CMS
=========================

[](#bigcommerce-for-craft-cms)

Build a content-driven storefront by BigCommerce [BigCommerce](https://bigcommerce.com) products into [Craft CMS](https://craftcms.com/).

Topics
------

[](#topics)

- 📦 [Installation](#installation): Set up the plugin and get connected to BigCommerce.
- 🗃️ [Working with Products](#product-element): Learn what kind of data is available and how to access it.
- 📑 [Templating](#templating): Tips and tricks for using products in Twig.
- 🔭 [Advanced Features](#going-further): Go further with your integration.

Installation
------------

[](#installation)

The BigCommerce plugin requires Craft CMS 4.0.0 or later.

To install the plugin, visit the [Plugin Store](https://plugins.craftcms.com/bigcommerce) from your Craft project, or follow these instructions.

1. Navigate to your Craft project in a new terminal:

    ```
    cd /path/to/project
    ```
2. Require the package with Composer:

    ```
    composer require venveo/craft-bigcommerce -w
    ```
3. In the Control Panel, go to **Settings** → **Plugins** and click the “Install” button for BigCommerce, or run:

    ```
    php craft plugin/install bigcommerce
    ```

### Create a BigCommerce API Account

[](#create-a-bigcommerce-api-account)

> **Note**
> You must be the owner of the store in order to generate API accounts.

Login to your BigCommerce admin panel and navigate to Settings → API Accounts → Create API Account. Proceed as follows:

1. **Token type**: V2/V3 API token
2. **Name**: A descriptive name. It's a good idea to use different credentials for different environments - e.g. "\[Prod\] Craft CMS"
3. **OAuth scopes**: The following scopes are required for the plugin to function correctly:

    - Content: `read-only`
    - Checkout content: `None`
    - Customers: `modify`
    - Customer login: `login`
    - Information &amp; settings: `modify`
    - Marketing: `modify`
    - Orders: `modify`
    - Order transactions: `read-only`
    - Create payments: `None`
    - Get payment methods: `None`
    - Stored Payment Instruments: `None`
    - Products: `modify`
    - Themes: `read-only`
    - Carts: `modify`
    - Checkouts: `modify`
    - Sites &amp; routes: `modify`
    - Channel settings: `modify`
    - Channel listings: `modify`
    - Storefront API tokens: `manage`
    - Storefront API customer impersonation tokens: `manage`
    - Store logs: `read-only`
    - Store Inventory: `read-only`

Click save.

1. **Client ID**: Reveal and copy this value into your `.env` file, as `BC_CLIENT_ID`.
2. **Client secret**: Reveal and copy this value into your `.env` file, as `BC_CLIENT_SECRET`.
3. **Access token**: Reveal and copy this value into your `.env` file, as `BC_ACCESS_TOKEN`.
4. **Store Hash**: This value is found in your store URL: `https://store-**store hash**.mybigcommerce.com/` Copy this value into your `.env` file, as `BC_STORE_HASH`
5. **Sales Channel**: If you're using the default BigCommerce storefront, this value is `1`; otherwise, find the ID of your Sales Channel in the Channel Manager of Big Commerce. Copy this value into your `.env` file, as `BC_SALES_CHANNEL`

### Connect Plugin

[](#connect-plugin)

Now that you have credentials for your custom app, it’s time to add them to Craft.

1. Visit the **BigCommerce** → **Settings** screen in your project’s control panel.
2. Assign the four environment variables to the corresponding settings, using the special [config syntax](https://craftcms.com/docs/4.x/config/#control-panel-settings):
    - **API Client ID**: `$BC_CLIENT_ID`
    - **API Secret Key**: `$BC_CLIENT_SECRET`
    - **Access Token**: `$BC_ACCESS_TOKEN`
    - **Sales Channel**: `$BC_SALES_CHANNEL`
3. Click **Save**.

> **Note**
> These settings are stored in [Project Config](https://craftcms.com/docs/4.x/project-config.html), and will be automatically applied in other environments. [Webhooks](#set-up-webhooks) will still need to be configured for each environment!

### Set up Webhooks

[](#set-up-webhooks)

Once your credentials have been added to Craft, a new **Webhooks** tab will appear in the **BigCommerce** section of the control panel.

Click **Create** on the Webhooks screen to add the required webhooks to BigCommerce. The plugin will use the credentials you just configured to perform this operation—so this also serves as an initial communication test.

> **Warning**
> You will need to add webhooks for each environment you deploy the plugin to, because each webhook is tied to a specific URL.

> **Note**
> If you need to test live synchronization in development, we recommend using [ngrok](https://ngrok.com/) to create a tunnel to your local environment. DDEV makes this simple, with [the `ddev share` command](https://ddev.readthedocs.io/en/latest/users/topics/sharing/). Use the **Base URL Override** option on the webhook creation screen to provide this value. Remember to delete the test webhooks when you're done!

Product Element
---------------

[](#product-element)

Products from your BigCommerce store are represented in Craft as product [elements](https://craftcms.com/docs/4.x/elements.html), and can be found by going to **BigCommerce** → **Products** in the control panel.

### Synchronization

[](#synchronization)

Products will be automatically created, updated, and deleted via [webhooks](#set-up-webhooks)—but Craft doesn’t know about a product until a change happens.

Once the plugin has been configured, perform an initial synchronization via the command line:

```
php craft bigcommerce/sync/products

```

> **Note**
> Products can also be synchronized from the control panel using the **BigCommerce Sync** utility. Keep in mind that large stores (over a hundred products) may take some time to synchronize, and can quickly run through [PHP’s `max_execution_time`](https://www.php.net/manual/en/info.configuration.php#ini.max-execution-time).

### Native Attributes

[](#native-attributes)

In addition to the standard element attributes like `id`, `title`, and `status`, each BigCommerce product element contains the following mappings to its canonical [BigCommerce Product resource](https://bigcommerce.dev/api/admin-rest/2022-10/resources/product#resource-object):

AttributeDescriptionType`bcId`The unique product identifier in your BigCommerce store.`String``bcStatus`The status of the product in your BigCommerce store. Values can be `active`, `draft`, or `archived`.`String``handle`The product’s “URL handle” in BigCommerce, equivalent to a “slug” in Craft. For existing products, this is visible under the **Search engine listing** section of the edit screen.`String``productType`The product type of the product in your BigCommerce store.`String``vendor`Vendor of the product.`String``metaFields`Metafields associated with the product.`Array``images`Images attached to the product in BigCommerce. The complete [Product Image resources](https://bigcommerce.dev/api/admin-rest/2022-10/resources/product-image#resource-object) are stored in Craft.`Array``options`Product options, as configured in BigCommerce.`Array``variants`Product variants, as configured in BigCommerce.`Array``createdAt`When the product was created in your BigCommerce store.`DateTime``publishedAt`When the product was published in your BigCommerce store.`DateTime``updatedAt`When the product was last updated in your BigCommerce store.`DateTime`All of these properties are available when working with a product element [in your templates](#templating).

> **Note**
> See the BigCommerce documentation on the product resource for more information about what kinds of values to expect from these properties.

### Methods

[](#methods)

The product element has a few methods you might find useful in your [templates](#templating).

#### `Product::getVariants()`

[](#productgetvariants)

Returns the [variants](#variants-and-pricing) belonging to the product.

```
{% set variants = product.getVariants() %}

  {% for variant in variants %}
    {{ variant.sku }}
  {% endfor %}

```

#### `Product::getDefaultVariant()`

[](#productgetdefaultvariant)

Shortcut for getting the first/default [variant](#variants-and-pricing) belonging to the product.

```
{% set products = craft.bigcommerceProducts.all() %}

  {% for product in products %}
    {% set defaultVariant = product.getDefaultVariant() %}

      {{ product.title }}
      {{ defaultVariant.price|currency }}

  {% endfor %}

```

#### `Product::getCheapestVariant()`

[](#productgetcheapestvariant)

Shortcut for getting the lowest-priced [variant](#variants-and-pricing) belonging to the product.

```
{% set cheapestVariant = product.getCheapestVariant() %}

Starting at {{ cheapestVariant.price|currency }}!
```

#### `Product::getBigCommerceUrl()`

[](#productgetbigcommerceurl)

```
{# Get a link to the product’s page on BigCommerce: #}
View on our store

{# Link to a product with a specific variant pre-selected: #}
Buy now
```

#### `Product::getBigCommerceEditUrl()`

[](#productgetbigcommerceediturl)

For your administrators, you can even link directly to the BigCommerce admin:

```
{# Assuming you’ve created a custom group for BigCommerce admin: #}
{% if currentUser and currentUser.isInGroup('clerks') %}
  Edit product on BigCommerce
{% endif %}
```

### Custom Fields

[](#custom-fields)

Products synchronized from BigCommerce have a dedicated field layout, which means they support Craft’s full array of [content tools](https://craftcms.com/docs/4.x/fields.html).

The product field layout can be edited by going to **BigCommerce** → **Settings** → **Products**, and scrolling down to **Field Layout**.

### Routing

[](#routing)

You can give synchronized products their own on-site URLs. To set up the URI format (and the template that will be loaded when a product URL is requested), go to **BigCommerce** → **Settings** → **Products**.

If you would prefer your customers to view individual products on BigCommerce, clear out the **Product URI Format** field on the settings page, and use `product.bigcommerceUrl` instead of `product.url` in your templates.

> **Note**
> Statuses in Craft are often a synthesis of multiple properties. For example, an entry with the *Pending* status just means it is `enabled` *and* has a `postDate` in the future.

Querying Products
-----------------

[](#querying-products)

Products can be queried like any other element in the system.

A new query begins with the `craft.bigcommerceProducts` factory function:

```
{% set products = craft.bigcommerceProducts.all() %}
```

### Query Parameters

[](#query-parameters)

The following element query parameters are supported, in addition to [Craft’s standard set](https://craftcms.com/docs/4.x/element-queries.html).

> **Note**Fields stored as JSON (like `options` and `metadata`) are only queryable as plain text. If you need to do advanced organization or filtering, we recommend using custom Category or Tag fields in your Product [field layout](#custom-fields).

#### `bigcommerceId`

[](#bigcommerceid)

Filter by BigCommerce product IDs.

```
{# Watch out—these aren't the same as element IDs! #}
{% set singleProduct = craft.bigcommerceProducts
  .bigcommerceId(123456789)
  .one() %}
```

#### `handle`

[](#handle)

Query by the product’s handle, in BigCommerce.

```
{% set product = craft.bigcommerceProducts
  .handle('worlds-tallest-socks')
  .all() %}
```

> 🚨 This is not a reliable means to fetch a specific product, as the value may change during a synchronization. If you want a permanent reference to a product, consider using the BigCommerce [product field](#product-field).

#### `productType`

[](#producttype)

Find products by their “type” in BigCommerce.

```
{% set upSells = craft.bigcommerceProducts
  .productType(['physical', 'digital'])
  .all() %}
```

#### `publishedScope`

[](#publishedscope)

Show only products that are published to a matching sales channel.

```
{# Only web-ready products: #}
{% set webProducts = craft.bigcommerceProducts
  .publishedScope('web')
  .all() %}

{# Everything: #}
{% set inStoreProducts = craft.bigcommerceProducts
  .publishedScope('global')
  .all() %}
```

#### `tags`

[](#tags)

Tags are stored as a comma-separated list. You may see better results using [the `.search()` param](https://craftcms.com/docs/4.x/searching.html#development).

```
{# Find products whose tags include the term in any position, with variations on casing: #}
{% set clogs = craft.bigcommerceProducts
  .tags(['*clog*', '*Clog*'])
  .all() %}
```

#### `vendor`

[](#vendor)

Filter by the vendor information from BigCommerce.

```
{# Find products with a vendor matching either option: #}
{% set fancyBags = craft.bigcommerceProducts
  .vendor(['Louis Vuitton', 'Jansport'])
  .all() %}
```

#### `images`

[](#images)

Images are stored as a blob of JSON, and only intended for use in a template in conjunction with a loaded product. Filtering directly by [image resource](https://bigcommerce.dev/api/admin-rest/2022-10/resources/product-image#resource-object) values can be difficult and unpredictable—you may see better results using [the `.search()` param](https://craftcms.com/docs/4.x/searching.html#development).

```
{# Find products that have an image resource mentioning "stripes": #}
{% set clogs = craft.bigcommerceProducts
  .images('*stripes*')
  .all() %}
```

#### `options`

[](#options)

[Options](#using-options) are stored as a blob of JSON, and only intended for use in a template in conjunction with a loaded product. You may see better results using [the `.search()` param](https://craftcms.com/docs/4.x/searching.html#development).

```
{# Find products that use a "color" option: #}
{% set clogs = craft.bigcommerceProducts
  .options('"Color"')
  .all() %}
```

The above includes quote (`"`) literals, because it’s attempting to locate a specific key in a JSON array, which will always be surrounded by double-quotes.

Templating
----------

[](#templating)

### Product Data

[](#product-data)

Products behave just like any other element, in Twig. Once you’ve loaded a product via a [query](#querying-products) (or have a reference to one on its template), you can output its native [BigCommerce attributes](#native-attributes) and [custom field](#custom-fields) data.

> **Note**
> Some attributes are stored as JSON, which limits nested properties’s types. As a result, dates may be slightly more difficult to work with.

```
{# Standard element title: #}
{{ product.title }}
  {# -> Root Beer #}

{# BigCommerce HTML content: #}
{{ product.bodyHtml|raw }}
  {# -> ... #}

{# Tags, as list: #}
{{ product.tags|join(', ') }}
  {# -> sweet, spicy, herbal #}

{# Tags, as filter links: #}
{% for tag in tags %}
  {{ tag|title }}
  {# -> Herbal #}
{% endfor %}

{# Images: #}
{% for image in product.images %}

    {# ->  #}
{% endfor %}

{# Variants: #}

  {% for variant in product.getVariants() %}
    {{ variant.title }} ({{ variant.price|currency }})
  {% endfor %}

```

### Variants and Pricing

[](#variants-and-pricing)

Products don’t have a price, despite what the BigCommerce UI might imply—instead, every product has at least one [Variant](https://bigcommerce.dev/api/admin-rest/2022-10/resources/product-variant#resource-object).

You can get an array of variant objects for a product by calling [`product.getVariants()`](#productgetvariants). The product element also provides convenience methods for getting the [default](#productgetdefaultvariant) and [cheapest](#productgetcheapestvariant) variants, but you can filter them however you like with Craft’s [`collect()`](https://craftcms.com/docs/4.x/dev/functions.html#collect) Twig function.

Unlike products, variants in Craft…

- …are represented exactly as [the API](https://bigcommerce.dev/api/admin-rest/2022-10/resources/product-variant#resource-object) returns them;
- …use BigCommerce’s convention of underscores in property names instead of exposing [camel-cased equivalents](#native-attributes);
- …are plain associative arrays;
- …have no methods of their own;

Once you have a reference to a variant, you can output its properties:

```
{% set defaultVariant = product.getDefaultVariant() %}

{{ defaultVariant.price|currency }}
```

> **Note**
> The built-in [`currency`](https://craftcms.com/docs/4.x/dev/filters.html#currency) Twig filter is a great way to format money values.

### Using Options

[](#using-options)

Options are BigCommerce’s way of distinguishing variants on multiple axes.

If you want to let customers pick from options instead of directly select variants, you will need to resolve which variant a given combination points to.

Form```

  {# Create a hidden input to send the resolved variant ID to BigCommerce: #}
  {{ hiddenInput('id', null, {
    id: 'variant',
    data: {
      variants: product.variants,
    },
  }) }}

  {# Create a dropdown for each set of options: #}
  {% for option in product.options %}

      {{ option.name }}
      {# The dropdown includes the option’s `position`, which helps match it with the variant, later: #}

        {% for val in option.values %}
          {{ val }}
        {% endfor %}

  {% endfor %}

  Add to Cart

```

ScriptThe code below can be added to a [`{% js %}` tag](https://craftcms.com/docs/4.x/dev/tags.html#js), alongside the form code.

```
// Store references to  elements:
const $form = document.getElementById("add-to-cart");
const $variantInput = document.getElementById("variant");
const $optionInputs = document.querySelectorAll("[data-option]");

// Create a helper function to test a map of options against known variants:
const findVariant = (options) => {
  const variants = JSON.parse($variantInput.dataset.variants);

  // Use labels for the inner and outer loop so we can break out early:
  variant: for (const v in variants) {
    option: for (const o in options) {
      // Option values are stored as `option1`, `option2`, or `option3` on each variant:
      if (variants[v][`option${o}`] !== options[o]) {
        // Didn't match one of the options? Bail:
        continue variant;
      }
    }

    // Nice, all options matched this variant! Return it:
    return variants[v];
  }
};

// Listen for change events on the form, rather than the individual option menus:
$form.addEventListener("change", (e) => {
  const selectedOptions = {};

  // Loop over option menus and build an object of selected values:
  $optionInputs.forEach(($input) => {
    // Add the value under the "position" key
    selectedOptions[$input.dataset.option] = $input.value;
  });

  // Use our helper function to resolve a variant:
  const variant = findVariant(selectedOptions);

  if (!variant) {
    console.warn("No variant exists for options:", selectedOptions);

    return;
  }

  // Assign the resolved variant’s ID to the hidden input:
  $variantInput.value = variant.id;
});

// Trigger an initial `change` event to simulate a selection:
$form.dispatchEvent(new Event("change"));
```

### Cart

[](#cart)

Your customers can add products to their cart directly from your Craft site:

```
{% set product = craft.bigcommerceProducts.one() %}

    {% for variant in product.getVariants() %}
      {{ variant.title }}
    {% endfor %}

  {{ hiddenInput('qty', 1) }}

  Add to Cart

```

### JS Buy SDK

[](#js-buy-sdk)

Cart management and checkout are not currently supported in a native way.

However, BigCommerce maintains the [Javascript Buy SDK](https://bigcommerce.dev/custom-storefronts/tools/js-buy) as a means of interacting with their [Storefront API](https://bigcommerce.dev/api/storefront) to create completely custom shopping experiences.

> **Note**
> Use of the Storefront API requires a different [access key](https://help.bigcommerce.com/en/manual/apps/custom-apps#update-storefront-api-access-scopes-for-a-custom-app), and assumes that you have published your products into the Storefront app’s [sales channel](https://bigcommerce.dev/custom-storefronts/tools/js-buy#step-2-make-your-products-and-collections-available).
>
> Your public Storefront API token can be stored with your other credentials in `.env` and output in your front-end with the `{{ getenv('...') }}` Twig helper—or just baked into a Javascript bundle. **Keep your other secrets safe!** This is the only one that can be disclosed.

The plugin makes no assumptions about how you use your product data in the front-end, but provides the tools necessary to connect it with the SDK. As an example, let’s look at how you might render a list of products in Twig, and hook up a custom client-side cart…

#### Shop Template: `templates/shop.twig`

[](#shop-template-templatesshoptwig)

```
{# Include the Buy SDK on this page: #}
{% do view.registerJsFile('https://sdks.bigcommercecdn.com/js-buy-sdk/v2/latest/index.umd.min.js') %}

{# Register your own script file (see “Custom Script,” below): #}
{% do view.registerJsFile('/assets/js/shop.js') %}

{# Load some products: #}
{% set products = craft.bigcommerceProducts().all() %}

  {% for product in products %}
    {# For now, we’re only handling a single variant: #}
    {% set defaultVariant = product.getVariants()|first %}

      {{ product.title }}
      Add to Cart

  {% endfor %}

```

#### Custom Script: `assets/js/shop.js`

[](#custom-script-assetsjsshopjs)

```
// Initialize a client:
const client = BigCommerceBuy.buildClient({
  domain: "my-storefront.mybigcommerce.com",
  storefrontAccessToken: "...",
});

// Create a simple logger for the cart’s state:
const logCart = (c) => {
  console.log(c.lineItems);
  console.log(`Checkout URL: ${c.webUrl}`);
};

// Create a cart or “checkout” (or perhaps load one from `localStorage`):
client.checkout.create().then((checkout) => {
  const $buyButtons = document.querySelectorAll(".buy-button");

  // Add a listener to each button:
  $buyButtons.forEach(($b) => {
    $b.addEventListener("click", (e) => {
      // Read the variant ID off the product:
      client.checkout
        .addLineItems(checkout.id, [
          {
            // Build the Storefront-style resource identifier:
            variantId: `gid://bigcommerce/ProductVariant/${$b.dataset.defaultVariantId}`,
            quantity: 1,
          },
        ])
        .then(logCart); //  **Warning**
> Use of API calls in Twig blocks rendering and—depending on traffic—may cause timeouts and/or failures due to rate limits. Consider using the [`{% cache %}` tag](https://craftcms.com/docs/4.x/dev/tags.html#cache) with a key and specific expiry time to avoid making a request every time a template is rendered:
>
> ```
> {% cache using key "bigcommerce:collections" for 10 minutes %}
>   {# API calls + output... #}
> {% endcache %}
> ```

Issue requests to the BigCommerce Admin API via `craft.bigcommerce.api`:

```
{% set req = craft.bigcommerce.api.get('custom_collections') %}
{% set collections = req.response.custom_collections %}
```

The schema for each API resource will differ. Consult the [BigCommerce API documentation](https://bigcommerce.dev/api/admin-rest) for more information.

#### Store Service

[](#store-service)

A simple URL generator is available via `craft.bigcommerce.store`. You may have noticed it in the [cart](#cart) example, above—but it is a little more versatile than that!

```
{# Create a link to add a product/variant to the cart: #}
{{ tag('a', {
  href: craft.bigcommerce.store.getUrl('cart/add', {
    id: variant.id
  }),
  text: 'Add to Cart',
  target: '_blank',
}) }}
```

The same params argument can be passed to a product element’s `getBigCommerceUrl()` method:

```
{% for variant in product.getVariants() %}
  {{ variant.title }}
{% endfor %}
```

Product Field
-------------

[](#product-field)

The plugin provides a *BigCommerce Products* field, which uses the familiar [relational field](https://craftcms.com/docs/4.x/relations.html) UI to allow authors to select Product elements.

Relationships defined with the *BigCommerce Products* field use stable element IDs under the hood. When BigCommerce products are archived or deleted, the corresponding elements will also be updated in Craft, and naturally filtered out of your query results—including those explicitly attached via a *BigCommerce Products* field.

> **Note**
> Upgrading? Check out the [migration](#migrating-from-v2x) notes for more info.

---

Migrating from v2.x
-------------------

[](#migrating-from-v2x)

If you are upgrading a Craft 3 project to Craft 4 and have existing “BigCommerce Product” fields, you’ll need show the plugin how to translate plain BigCommerce IDs (stored as a JSON array) into element IDs, within Craft’s relations system.

> **Warning**
> Before getting started with the field data migration, make sure you have [synchronized](#synchronization) your product catalog.

It’s safe to remove the old plugin package (`nmaier95/bigcommerce-product-fetcher`) from your `composer.json`—but **do not use the control panel to uninstall it**. We want the field’s *data* to stick around, but don’t need the old field *class* to work with it.

> **Note**
> You may see a “missing field” in your field layouts during this process—that’s OK! Your data is still there.

For each legacy BigCommerce Product field in your project, do the following:

1. Create a *new* [BigCommerce Products](#product-field) field, giving it a a new handle and name;
2. Add the field to any layouts where the legacy field appeared;

### Re-saving Data

[](#re-saving-data)

Run the following command (substituting appropriate values) for each place you added the field in step #2, above:

- `resave/entries` → The [re-save command](https://craftcms.com/docs/4.x/console-commands.html#resave) for the element type the field layout is attached to;
- `mySectionHandle` → A stand-in for any criteria that need to be applied to the element type you’re re-saving;
- `oldBigCommerceField` → Field handle from the old version of the plugin (used inside the `--to` argument closure);
- `newBigCommerceField` → New field handle created in step #1, above;

    ```
    php craft resave/entries \
      --section=mySectionHandle \
      --set=newBigCommerceField \
      --to="fn(\$entry) => collect(json_decode(\$entry->oldBigCommerceField))->map(fn (\$id) => \venveo\bigcommerce\Plugin::getInstance()->getProducts()->getProductIdByBigCommerceId(\$id))->unique()->all()"
    ```

### Updating Templates

[](#updating-templates)

After your content is re-saved, update your templates:

#### Before

[](#before)

In v2.x, you were responsible for looking up product details in the template:

```
{# Product references were stored as a list of IDs: #}
{% set productIds = entry.oldBigCommerceField %}

  {% for productId in productIds %}
    {# Query BigCommerce API for Product using ID: #}
    {% set bigcommerceProduct = craft.bigcommerce.getProductById({ id: productId }) %}

    {{ product.productType }}: {{ product.title }}
  {% endfor %}

```

#### After

[](#after)

There is no need to query the BigCommerce API to render product details in your templates—all of the data is available on the returned elements!

```
{# Execute element query from your new relational field: #}
{% set relatedProducts = entry.newBigCommerceField.all() %}

  {% for product in products %}
    {# Output product data directly: #}
    {{ product.productType }}: {{ product.title }}
  {% endfor %}

```

Going Further
-------------

[](#going-further)

### Events

[](#events)

#### `venveo\bigcommerce\services\Products::EVENT_BEFORE_SYNCHRONIZE_PRODUCT`

[](#venveobigcommerceservicesproductsevent_before_synchronize_product)

Emitted just prior to a product element being saved with new BigCommerce data. The `venveo\bigcommerce\events\BigCommerceProductSyncEvent` extends `craft\events\CancelableEvent`, so setting `$event->isValid` allows you to prevent the new data from being saved.

The event object has three properties:

- `element`: The product element being updated.
- `source`: The BigCommerce product object that was applied.
- `metafields`: Additional metafields from BigCommerce that the plugin discovered while performing the synchronization.

```
use venveo\bigcommerce\events\BigCommerceProductSyncEvent;
use venveo\bigcommerce\services\Products;
use yii\base\Event;

Event::on(
  Products::class,
  Products::EVENT_BEFORE_SYNCHRONIZE_PRODUCT,
  function(BigCommerceProductSyncEvent $event) {
    // Example 1: Cancel the sync if a flag is set via a BigCommerce metafield:
    if ($event->metafields['do_not_sync'] ?? false) {
      $event->isValid = false;
    }

    // Example 2: Set a field value from metafield data:
    $event->element->setFieldValue('myNumberFieldHandle', $event->metafields['cool_factor']);
  }
);
```

> **Warning**Do not manually save changes made in this event handler. The plugin will take care of this for you!

### Element API

[](#element-api)

Your synchronized products can be published into an [Element API](https://plugins.craftcms.com/element-api) endpoint, just like any other element type. This allows you to set up a local JSON feed of products, decorated with any content you’ve added in Craft:

```
use venveo\bigcommerce\elements\Product;

return [
  'endpoints' => [
    'products.json' => function() {
      return [
        'elementType' => Product::class,
        'criteria' => [
          'publishedScope' => 'web',
          'with' => [
            ['myImageField']
          ],
        ],
        'transformer' => function(Product $product) {
          $image = $product->myImageField->one();

          return [
            'title' => $product->title,
            'variants' => $product->getVariants(),
            'image' => $image ? $image->getUrl() : null,
          ];
        },
      ];
    },
  ],
];
```

### Acknowledgements

[](#acknowledgements)

- Very helpful reference repository:

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity77

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~104 days

Recently: every ~213 days

Total

16

Last Release

1326d ago

Major Versions

1.2.1 → 2.0.02020-04-14

v2.x-dev → 3.0.02022-11-08

### Community

Maintainers

![](https://www.gravatar.com/avatar/c06cc90c1a7f274f31233258cedf58df05f581a0c1a79f44b40764a60b96f377?d=identicon)[ransom](/maintainers/ransom)

---

Top Contributors

[![lukeholder](https://avatars.githubusercontent.com/u/133571?v=4)](https://github.com/lukeholder "lukeholder (85 commits)")[![AugustMiller](https://avatars.githubusercontent.com/u/1895522?v=4)](https://github.com/AugustMiller "AugustMiller (78 commits)")[![Mosnar](https://avatars.githubusercontent.com/u/3810939?v=4)](https://github.com/Mosnar "Mosnar (75 commits)")[![brandonkelly](https://avatars.githubusercontent.com/u/47792?v=4)](https://github.com/brandonkelly "brandonkelly (16 commits)")[![angrybrad](https://avatars.githubusercontent.com/u/61869?v=4)](https://github.com/angrybrad "angrybrad (8 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")[![vnali](https://avatars.githubusercontent.com/u/55586085?v=4)](https://github.com/vnali "vnali (1 commits)")

---

Tags

cmscraftcmsshopify

### Embed Badge

![Health badge](/badges/venveo-craft-bigcommerce/health.svg)

```
[![Health](https://phpackages.com/badges/venveo-craft-bigcommerce/health.svg)](https://phpackages.com/packages/venveo-craft-bigcommerce)
```

###  Alternatives

[craftcms/shopify

Shopify for Craft CMS

5310.1k1](/packages/craftcms-shopify)[spicyweb/craft-neo

A Matrix-like field type with block hierarchy

393813.5k10](/packages/spicyweb-craft-neo)[nmaier95/shopify-product-fetcher

Shopify for Craft CMS

534.9k](/packages/nmaier95-shopify-product-fetcher)[verbb/formie

The most user-friendly forms plugin for Craft.

102393.6k70](/packages/verbb-formie)[wrav/oembed

A simple plugin to extract media information from websites, like youtube videos, twitter statuses or blog articles.

36208.3k3](/packages/wrav-oembed)[verbb/vizy

A flexible visual editor field for Craft.

4250.4k](/packages/verbb-vizy)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
