Migrating Products between Web Shops Using Node.js

Web Shop solutions that we utilize are changing over time. One becoming better than another regarding the business needs. Effective data migration between the different systems is very often needed. In this article, we describe how to perform simple migration of products from the WooCommerce store to the Webflow store.

Migrating Products between Web Shops Using Node.js

Migration of a Single Product from WooCommerce to Webflow

In this article are provided steps that need to be executed to properly fetch product information from the WooCommerce store and upload it to the Webflow store. We will pick a single product by its slug and create the same one on the Webflow store where we map the product's name, slug, description, main image, and price. Extending this functionality to migrate multiple products is relatively simple, and is briefly mentioned at the end.

GitHub Repository

Complete implementation of the solution shown in this article can be cloned from GitHub repository: https://github.com/emir-gradient/woocommerce-to-webflow-migration.

Preparing stores for local development

For the WooCommerce store, one should first install WordPress and then WooCommerce plugin.

When it comes to Webflow since it is SaaS and not open source, for local development, we register one account on webflow.com and then follow available Webflow instructions to create an e-commerce website. While one can not publish an e-commerce site on Webflow for free, one can test it out and Webflow API can be utilized.

Once both stores are ready, we need to configure WooCommerce for API usage and get API keys. On the Webflow site, we only need to retrieve API keys.

Starting Node.js project and installing dependencies

Having the necessary API keys, we are ready to start developing integration code between WooCommerce and Webflow. We will utilize Node.js to implement the solution that performs product migration from WooCommerce to WebFlow.

Let us initialize an empty Node.js project:

$ yarn init

If you do not have or use yarn, you can utilize npm.

$ npm install -g yarn

Both products (WooCommerce and Webflow) have Node API clients developed and shared on the npm repository. So, we install API clients as dependencies of our project:

$ yarn add @woocommerce/woocommerce-rest-api webflow-api

In package.json, make sure to add the start script and define the project type as a module:

{
  "name": "woocommerce-to-webflow-migration",
  "version": "1.0.0",
  "license": "MIT",
  "type": "module",
  "scripts": {
    "start": "node src/main.js"
  },
  "dependencies": {
    "@woocommerce/woocommerce-rest-api": "^1.0.1",
    "webflow-api": "^0.8.1"
  }
}

Finally, we create a directory src and create a main.js file with the following content:

async function main() {
  console.log('Running');
}

main().then(() => {
  console.log('Finished');
});

Run the following command in the root of the project:

$ yarn start

If all went properly, the result should be similar to this:

yarn run v1.22.19
$ node src/main.js
Running
Finished

Fetching products from WooCommerce

To be able to publish products to Webflow, we need to fetch them from WooCommerce store first. For this purpose, WooCommerceRestApi class is designed and utilized.

How to retrieve products from the WooCommerce store is presented in the following code snippet:

const wooCommerceApiClient = new WooCommerceRestApi({
  url: 'woo-commerce store url',
  consumerKey: 'ck_abcabcabcabcabcabcbacbabcbabbcabcbabc',
  consumerSecret: 'cs_alkjlskdfjlskdfjlskdfjlskdfjlskdjflsdk',
  version: 'wc/v3'
});

const productsResult = await this.api.get('products');

All products from our WooCommerce store are referenced by productsResult.

To retrieve one product (by its slug) we will utilize the get products API endpoint with a slug filter. Also, to organize our code a bit, we will define one WooCommerceIntegration class. It will be utilized for all API operations related to WooCommerce API usage. The content of WooCommerceIntegration class is:

import pkg from "@woocommerce/woocommerce-rest-api";
const WooCommerceRestApi = pkg.default;

export class WooCommerceIntegration {
  
  constructor(consumerKey, consumerSecret, storeUrl) {
    this.consumerKey = consumerKey;
    this.consumerSecret = consumerSecret;
    this.storeUrl = storeUrl;

    this.api = new WooCommerceRestApi({
      url: this.storeUrl,
      consumerKey: this.consumerKey,
      consumerSecret: this.consumerSecret,
      version: 'wc/v3'
    });
  }

  async getProduct(slug) {
    const products = await this.api.get('products', {
      slug
    });

    return products.data.length ? products.data[0] : null;
  }

  async getStoreCurrencyCode() {
    const currentCurrency = await this.api.get('data/currencies/current');

    return currentCurrency.data.code;
  }
}

Except for instantiating WooCommerceRestApi and retrieving products by slug, we can also see getStoreCurrencyCode method in the example. We will utilize it to transfer product currency to Webflow store. An assumption is made here that all articles in source WooCommerce store have price defined in the same currency.

Mapping WooCommerce product structure to Webflow

As independent services, WooCommerce and Webflow have different data structures for representing products. To be able to provide products to Webflow API, we need to perform mapping of WooCommerce product structure to Webflow. To do so, we write mapping method as follows:

toCreateWebflowProductDto(wooCommerceProduct, wooCommerceStoreCurrencyCode) {
  
  return {
    product: {
      fields: {
        _draft: true,
        _archived: false,
        name: wooCommerceProduct.name,
        slug: wooCommerceProduct.slug,
        description: wooCommerceProduct.description,
      }
    },
    sku: {
      fields: {
        _archived: false,
        _draft: true,
        name: wooCommerceProduct.name,
        slug: wooCommerceProduct.sku,
        'main-image': {
          url: wooCommerceProduct.images[0].url
        },
        price: {
          unit: wooCommerceStoreCurrencyCode,
          value: wooCommerceProduct.price,
        }
      },
    }
  };
}

The resulting data structure is applicable for Webflow API to create products.

Some changes/adaptations are needed though.

When we analyze further, we can recognize the two important notes why this mapper will not work properly:

  1. The description in WooCommerce is HTML5 since it includes styling of the Product description.
  2. The price in WooCommerce is retrieved as a string. Also, it includes the decimal point. Webflow API accepts product price as the integer. So, if we want the price to be $42.00 we need to send 4200. Or, as another example, if we want the price to be $243.55, we need to send 24355 as the price value.

Considering these two notes, the final ProductMapper implementation looks like:

export class ProductMapper {
  toCreateWebflowProductDto(wooCommerceProduct, wooCommerceStoreCurrencyCode) {
    
    return {
      product: {
        fields: {
          _draft: true,
          _archived: false,
          name: wooCommerceProduct.name,
          slug: wooCommerceProduct.slug,
          description: this.parseDescriptionStripTags(wooCommerceProduct.description),
        }
      },
      sku: {
        fields: {
          _archived: false,
          _draft: true,
          name: wooCommerceProduct.name,
          slug: wooCommerceProduct.sku,
          'main-image': {
            url: wooCommerceProduct.images[0].url
          },
          price: {
            unit: wooCommerceStoreCurrencyCode,
            value: this.parsePriceToInt(wooCommerceProduct.price),
          }
        },
      }
    };
  }

  parseDescriptionStripTags(description) {
    return description.replace(/<\/?[^>]+(>|$)/g, "");
  }

  parsePriceToInt(price) {
    if (price.indexOf('.') === -1) {
      return parseInt(price) * 100;
    } else {
      const parts = price.split('.');
      if (parts[1].length > 2) {
        parts[1] = parts[1].substring(0, 2);
      } else if (parts[1].length === 1) {
        parts[1] += '0';
      }

      price = parts.join('');

      return parseInt(price);
    }
  }
}

By finalizing this step, we are able to retrieve the product from WooCommerce and map it to the appropriate structure for WebFlow API.

Creating products in the Webflow store

The next step in our integration is to actually upload product data to Webflow. For this purpose, we utilize WebflowApi class. To upload the product we need to identify our site id first. After that, we execute the following method:

async createProduct(siteId, createWebflowProductDto) {
   try {
       await this.api.post(`/sites/${siteId}/products`, createWebflowProductDto);
   } catch (e) {
       console.log(e);
   }
}

Complete implementation of the WebflowIntegration class, which utilizes all Webflow API operations is given in the following section:

import Webflow from "webflow-api";

export class WebflowIntegration {
    apiKey = null;
    api = null;

    constructor(apiKey) {
        this.apiKey = apiKey;
        this.api = new Webflow({ token: this.apiKey });
    }

    async getFirstSite() {
        const sites = await this.api.sites();

        return sites.length ? sites[0] : null;
    }

    async createProduct(siteId, createWebflowProductDto) {
       try {
           await this.api.post(`/sites/${siteId}/products`, createWebflowProductDto);
       } catch (e) {
           console.log(e);
       }
    }
}

In this example, it is assumed that the user of API has only one site on Webflow. With that assumption, it is safe to take the first site (on index 0) since it should be the only one retrieved from the API.

Usage of all created modules

With all modules ready, all necessary steps for product migration from WooCommerce to Webflow are covered. The following is implemented:

  1. Retrieving product from WooCommerce,
  2. Mapping products from WooCommerce to Webflow structure,
  3. Publishing the product to Webflow.

Finally, in the main.js we are utilizing all created modules having the following result:

import { WebflowIntegration } from "./integrations/WebflowIntegration.js";
import { WooCommerceIntegration } from "./integrations/WooCommerceIntegration.js";
import { ApiKeys } from "./constants/api-keys.js";
import { ProductMapper } from "./mapper/product-mapper.js";


async function load() {
  const productSlug = 'shoes';

  const webflowIntegration = new WebflowIntegration(ApiKeys.Webflow);
  const wooCommerceIntegration = new WooCommerceIntegration(
    ApiKeys.WooCommerceConsumerKey,
    ApiKeys.WooCommerceConsumerSecret,
    "http://host:port");
  const productMapper = new ProductMapper();

  const webflowSite = await webflowIntegration.getFirstSite();

  const wooCommerceProduct = await wooCommerceIntegration.getProduct(productSlug);
  const wooCommerceStoreCurrencyCode = await wooCommerceIntegration.getStoreCurrencyCode();

  const createWebflowProductDto = productMapper.toCreateWebflowProductDto(wooCommerceProduct, wooCommerceStoreCurrencyCode);

  await webflowIntegration.createProduct(webflowSite._id, createWebflowProductDto);
}

load().then(() => {
  console.log("Finished!");
});

By starting this program with the following command, the product with slug 'shoes' should be properly published to the Webflow store.

$ yarn start

Get an Offer

Contact Us or Schedule a Meeting with us to get an offer for our development & consulting services regarding your current or next WooCommerce or WebFlow project.

02 Comments

  • Sp collection

    Electronic items watches,smart watch, headphones air buds, airports, speaker all electronic items for girls and boys

  • Vel voluptas quidem

    Explicabo Lorem dol

Leave your comment