Shopify - Migrate assets sang store mới với File API và Node.js

postman-signpostman-sign

Nếu bạn là 1 Shopify Developer và đang có nhu cầu migrate toàn bộ data từ store của bạn sang 1 store mới mà không muốn phải pay vài chục USD cho 1 app migration thì mình tin đây bài viết bạn cần đọc

Problem

Vấn đề đã được trình bày ở trên! Vậy hãy xem chúng ta có những data gì trong 1 store và có thể migrate sang 1 store khác theo cách nào:

  • Product: có thể download file CSV chứa data của product và upload lên store mới là được

    với CSV file thì thông tin về Collection sẽ không được migrate, bạn cần phải tạo lại Collection data

  • Theme: download Zip file và upload lên store mới, data vẫn sẽ như cũ

  • Blog posts & custom pages: Sử dụng 1 app free trên Shopify store là ExIm ‑ Export / Import data để migrate

  • Assets: là toàn bộ file trong store của bạn (Có thể xem ở Admin / Settings / Files) bao gồm image, video, font... đây là những assets sử dụng cho theme settings, blog post và page. (Ảnh và video của product đã được tự động migrate khi upload file CSV rồi!)

    Và vấn đề mình gặp phải khi migrate đống assets này là:

    • Store của mình có khoảng ~1000 files, không thể dùng tay upload được
    • Sau khi upload xong cần phải vào settings của theme và page chọn lại thì mới work

Nếu làm bằng tay chỗ này chắc khỏi cần tập tạ mà tay vẫn to mất!

Solution

Giải pháp của mình ở đây chính là sử dụng Shopify File API kết hợp với Node.js để download toàn bộ file về và upload lên store mới

File API được Shopify chính thức support ở API version 2021-07 sau sự kiện Shopify Unite mới tổ chức gần đây (Thông tin trên Shopify Developer Changelog)

Sau đây sẽ là các bước kết hợp giữa công việc tay chân và trí óc để giải quyết đống Assets đó nhé

Lấy toàn bộ file URL với GraphQL

Tạo Private App

Tại sao phải tạo Private App? Vì chúng ta phải authenticate với Shopify thì mới có thể request đến các resource trong store. Cách đơn giản nhất là sử dụng Basic HTTP authentication với Private App. Các bước tạo Private App như sau:

  • Vào Store Admin / Apps
  • Click Manage private apps (ở dưới cùng của page) => Create new private app
  • Điền App nameEmergency email ở section App details
  • Click Show inactive Admin API permissions ở section Admin API, scroll đến phần Files chọn Read access
  • Click => Save => Create app
  • Như vậy là đã tạo xong Private App để authenticate với Shopify

Lấy Access Token

Cách đơn giản nhất để bắn authenticated request đến Shopify là thêm request header X-Shopify-Access-Token: {access_token}, trong đó {access_token} chính là Admin API password của Private App mà chúng ta vừa tạo

private-app-passwordprivate-app-password

Copy password trong section Admin API của Private App vừa tạo, đây chính là access_token chúng ta cần cho bước tiếp theo.

Bắn GraphQL request với Postman

Vì chúng ta cần bắn request nhiều lần, nên để tiện cho config headers và copy response các bạn hãy sử dụng 1 HTTP Client nhé (Ví dụ: Postman, Postwoman, Insomnia...) Ở đây mình chọn Postman. (Link download ở đây)

Sau khi download, các bạn tạo 1 POST request như này:

postman-1postman-1

Trong đó:

  • Request URL: https://your-store.myshopify.com/admin/api/2021-07/graphql.json với 2021-07 là API version support File API

  • chú ý: với header Content-Type bắt buộc phải sử dụng value application/json chứ không được chọn application/graphql nhé (Shopify đã note điều này)

  • Value của X-Shopify-Access-Token header chính là access_token hay password của Private App vừa tạo.

Tiếp theo switch qua tab Body, chọn GraphQL

postman-2postman-2

Và thêm query sau

{

files(first: 250) {

edges {

node {

... on MediaImage {

image {

originalSrc

}

}

}

cursor

}

pageInfo {

hasNextPage

hasPreviousPage

}

}

}

Mỗi node thuộc 2 loại là MediaImage hoặc GenericFile, trong đó GenericFile chỉ có vài file (chú yếu là Font) nên mình tập trung vào MediaImage thôi nhé.

1 số lưu ý:

  • first: 250: Đây là maximum limit của Shopify cho 1 request
  • cursor: chính vì limit nên chúng ta phải tạo nhiều request (ví dụ store mình có ~1000 image => cần 4 request). cursor ở đây chính là pagination cho GraphQL (giống như với REST, bạn sẽ dùng &page=1, &page=2... để request page tiếp theo)
  • pageInfo: thêm vào chỉ để biết mình có page tiếp theo hay không thôi

Kết quả sẽ trông như sau

postman-3postman-3

Để request để page tiếp theo, các bạn thêm vào query 1 parameter là after với value là cursor của phần tử cuối cùng trong array edgesresponse ( phần tử cuối cùng nhé!)

postman-4postman-4

Đơn giản là như vậy , với 4 request mình đã có 1000 URLs của toàn bộ image bên store cũ!

Download file với Node.js

Bây giờ chúng ta cần download toàn bộ số file này và upload lên store mới.

Vậy khi upload lên store mới thì cũng phải chọn lại settings cho đống assets này à?

Câu trả lời là không! Dựa vào 1 cơ chế cực cool của Shopify!

Nếu bạn upload file trùng tên với bên store cũ thì sẽ chúng tự ăn với các settings của theme/page/blog... được migrate sang

Và trong URL của file lấy được với GraphQL đã có chứa sẵn tên file trong đó rồi: https://cdn.shopify.com/s/files/1/0561/2742/2636/files/fav_icon_dark_1.png?v=1618297070 File name của file này là fav_icon_dark_1.png.

Bây giờ chỉ cần download 1000 file về, save với tên được extract từ URL ra, và upload lên store mới là xong rồi

Chỉ cần vài dòng Node.js kết hợp với regex là có thể extract name và download file về:

const fs = require('fs')

const fetch = require('node-fetch')

const fileData = require('./data')

async function download(url, filename) {

const response = await fetch(url)

const buffer = await response.buffer()

await fs.writeFile(filename, buffer, () => {})

}

console.time('FILE_DOWNLOAD')

Promise.all(

fileData.map(async ({ node }, ind) => {

const src = node?.image?.originalSrc

if (src) {

const filename = (src.match(/.*\/files\/(.*)\?v=.*/) || [])[1]

if (filename) {

await download(src, `./download/${filename}`)

} else {

console.warn(`Couldn't get filename of: ${src} at index ${ind}`)

}

} else {

console.log(`No file at index: ${ind}`)

}

})

).then(() => console.timeEnd('FILE_DOWNLOAD'))

Chú ý fileData chính là array edges của các request tạo ở trên!

Toàn bộ script mình ở repo này

file-downloadfile-download

Download rất nhanh nhé

Upload lên store mới

Bước này thì không cần viết dòng code nào vì làm bằng tay là nhanh nhất

Vào Store Admin / Settings / Files => click Upload files. Shopify limit 1 lần chỉ được upload tối đa 200 file, nên upload vài lần là xong!

Đến đây là hoàn thiện quá trình migrate rồi , các bạn kiểm tra kết quả trên store mới nhé - chúc các bạn thành công!

1 phút cho quảng cáo

Bạn có làm việc với Shopify không?

Team mình - Insights Studio mới cho ra lò 1 siêu phẩm là Minimog - The Next Generation Shopify Theme bán trên Themeforest. Đây là con theme tâm huyết của anh em trong nhiều tháng phát triển, với >50 demos, support Shopify Online Store 2.0, rất nhiều tính năng và design thì siêu đẹp

minimog-top-1minimog-top-1

Hiện tại theme đang đứng Top #1 Weekly Bestseller ở eCommerce category

Và giá trị đặc biệt - Unique Selling Point của theme chính là ở việc team mình đã viết riêng 1 App trên Shopify chỉ để support cho Minimog! Đó là app FoxKit - The upsells and boost conversion tools for MINIMOG theme (https://apps.shopify.com/foxecom-boost-sales - hoàn toàn FREE)

App hỗ trợ các plugin boost-sells, upsells, apply discount code, những tính năng mà theme bình thường không thể làm được!

Và đặc biệt là 1-click-install-demo - chỉ cần chọn demo bạn thích và click Install trong app là toàn bộ theme và demo data đã có, không cần phải copy-paste thủ công bằng tay như theme K, theme E hay theme W...

foxkitfoxkit

Hiện tại giá rổ đang rất là hạt dẻ - chỉ $29 (chuẩn bị tăng lên 99)

Anh em bạn gì làm Shopify ủng hộ team mình nhé (Thông tin ở đây)

Refs