Category Archives: Marketing

Cách thiết lập redirection rule cho wordpress

Cách thiết lập redirection rule sử dụng plugin redirection:

Khi thay đổi cấu trúc permalink (thay đổi cấu trúc thư mục, thay đổi plugin SEO…), chúng ta cần redirect các link bị thay đổi cấu trúc về URL mới. Các old link này có thể bị thay đổi theo một quy luật nào đó và lúc đó chúng ta có thể viết rule để apply cho tât cả các URL thuộc dạng đó thay vì sửa từng URL đơn lẻ. Dưới đây là một số ví dụ:

1. Ví dụ 1:

Cần redirect tất cả các url có dạng domain.com/abc/… thành: domain.com/shop/abc/…    (Thêm shop vào trước /abc)

URL nguồn: domain.com/abc/xyz

URL đích: domain.com/shop/abc/xyz

=> cần viết rule như sau:

URL nguồn:  ^/abc/(.*)   => Trong đó: ^ để wordpress hiểu là /abc được đặt ngay sau domain.com (tránh trường hợp infinite loop sẽ thành: domain.com/shop/shop/shop…); (.*): là bất cứ cụm ký tự đường dẫn nào ở sau đều được ghi lại và chuyển sang URL đích. 

URL đích: /shop/abc/$1/  => Trong đó: $1 – để lấy cụm đường dẫn ở URL nguồn (.*)

Trường hợp này hay gặp khi thay đổi cấu trúc thư mục hoặc sử dụng chức năng ignore base – bỏ các từ như shop/category của các plugin SEO (Rankmath/Yoast). Khi thay đổi plugin SEO sẽ làm cho các link này thành 404.

2. Ví dụ 2: 

Redirect URL có dạng: /năm/tháng/ngày/abc thành /abc 

Trường hợp này hay gặp khi chuyển permalink từ dạng ngày tháng sang URL cố định trong WordPress. 

URL nguồn: domain.com/2018/07/28/abc 

URL đích: domain.com/abc

Cần viết rule như sau: 

URL nguồn: ^/ \d{4}/ \d{2}/ \d{2}/(.*)  => trong đó (.*) được sử dụng để ghi lại cụm đường dẫn phía sau ngày tháng

URL đích: /$1/   =>$1 được dùng để hứng giá trị (.*)

Ref: https://redirection.me/support/redirect-regular-expressions/

Zalo API: Zalo shop API, access token, OAID

OA Access token: Official Account Access Token (Hạn sử dụng: 1 năm): Là mã truy cập do Admin của Officlal Account cấp cho Ứng dụng để Ứng dụng có quyền đại diện OA gọi các API nhằm mục đích hỗ trợ quản lý và chăm sóc khách hàng (người quan tâm) trên Officlal Account . Các API khi được gọi sẽ trừ vào hạn mức cho phép (số lần gọi API trong 1 khoảng thời gian) của Officlal Account .

Bạn cần có Official Account Access Token khi gọi Official Account API, Store API và Article API.

XRateLimitLimit là tổng số lệnh ứng dụng được gọi API tính theo phút

XRateLimitRemain là số lệnh gọi còn lại mà ứng dụng được gọi API tính theo phút, khi số này bằng 0 có nghĩa là ứng dụng của bạn đã đạt tới giới hạn gọi API.

URL:

Article API: Tạo bài viết https://openapi.zalo.me/v2.0/article/create?access_token=<ACCESS_TOKEN>

Shop API: 

+ danh sách sản phẩm: https://openapi.zalo.me/v2.0/store/product/getproductofoa?access_token=ACCESS_TOKEN&offset=0&limit=10 //tối đa 50

+ Lấy chi tiết sản phẩm: https://openapi.zalo.me/v2.0/store/product/getproduct?access_token=ACCESS_TOKEN&id=product_id

+ Tạo sản phẩm: https://openapi.zalo.me/v2.0/store/product/create?access_token=ACCESS_TOKEN //Một cửa hàng chỉ có thể tạo tối đa 2000 sản phẩm.

+ Cập nhật sản phẩm: https://openapi.zalo.me/v2.0/store/product/update?access_token=ACCESS_TOKEN

+ Xóa sản phẩm: https://openapi.zalo.me/v2.0/store/product/remove?access_token=ACCESS_TOKEN

+ Tìm kiếm sản phẩm của Shop: https://openapi.zalo.me/v2.0/store/product/search?access_token=ACCESS_TOKEN&offset=0&limit=10&code=123 //code: SKU sản phẩm, limit tối đa 50

Có 2 cách để lấy Official Account Access Token:

Cách 1: Sử dụng cho platform/partner xây dựng ứng dụng sử dụng cho nhiều merchant.

Bước 1: Cấu hình Official Account Callback Url trong phần setting của Official Account liên kết với Ứng dụng.

Sau khi admin của Official Account đồng ý cấp mã truy cập. Phía Zalo sẽ redirect về Official Account Callback Url (Có thể hiểu là gửi một http get request đến OA Callback Url của bạn) để bạn có thể lấy được access_token trong parameters của request. 

Bước 2: Bạn hãy gửi đường dẫn dưới đây đến Admin của Official Account để xin cấp mã truy cập Official Account đó:
https://oauth.zaloapp.com/v3/oa/permission?app_id=<APP_ID>&redirect_uri=<OFFICIAL_ACOUNT_CALLBACKURL>

Tham số Ý nghĩa
app_id Là Id của ứng dụng của bạn.
redirect_uri Là đường dẫn được cấu hình tại phần setting của Official Account đang liên kết với Ứng dụng của bạn

Trong đó:

Đường dẫn này sẽ mở ra trang cấp quyền cho ứng dụng.

Bước 3: Sau khi người dùng chọn Official Account muốn cấp quyền và nhấn “Cho phép”. Trình duyệt sẽ redirect về Official Account Callback Url của Official Account đang liên kết với Ứng dụng (Có thể hiểu là OA Callback Url của bạn sẽ nhận được một http get request) và kèm theo parameter access_token và oaId để lưu trữ và sử dụng.

Ví dụ:

Nếu OA Callback Url của bạn là: https://yourdomain.com/abc

Http get request sẽ gọi đến OA Callback Url là:

Trong đó:

Tham số Ý nghĩa
access_token Là mã truy cập bạn có thể dùng để gọi Official Account API, Shop API và Article API
oaId Id của Official Account đã cấp quyền cho Ứng dụng

Cách 2: Sử dụng tool API Exproler

*Chú ý: Để lấy được access_token bằng cách này bạn phải thỏa các điều kiện sau

  • Tài khoản của bạn phải có quyền admin của OA muốn lấy access_token.
  • Tài khoản của bạn phải có quyền admin của ứng dụng (app) dùng để lấy access_token.

Nếu chưa có OA và app của Zalo, bạn có thể tạo mới tại trang https://developers.zalo.me.

Dưới đây là các bước thực hiện:

Bước 1: Bạn hãy vào phần Công cụ & Hỗ trợ > API Explorer trên trang developer.

Bước 2: Chọn Ứng dụng:

Bước 3: Chọn Official Account:

Bước 4: Trong cửa sổ vừa hiện ra chọn ô “Đồng ý…“và chọn “Cho phép“:

Bước 5: Nhấn copy để sao chép access_token:

Khi đã có access_token bạn có thể sử dụng các api sau:

  • Official Account API: Hỗ trợ bạn quản lý và tương tác với người quan tâm. Bạn có thể gửi tin nhắn text, hình ảnh, cấu hình menu của OA…
  • Store API: Cung cấp cho bạn các công cụ để quản lý sản phẩm, đơn hàng của cửa hàng trên zalo shop.
  • Article API: Cho phép bạn tạo ra các bài viết, chia sẻ các bài viết tời người dùng.

Ref: https://developers.zalo.me/docs/api/official-account-api/phu-luc/official-account-access-token-post-4307

Update woocommerce product via google sheet API

To update woocommerce products (price, sale price, quantity…), we can use Google sheet as database & Google sheet API to automatically update woocommerce. Below is the workflow: 

Prepare the product template => update the template with real data => upload to woocommerce (manual/API): 

+ Download from woocommerce (export product data – built-in function of woocommerce)

+ Put the template product data to Google sheet

+ Update the product data in Google sheet (edit price, quantity…)

+ Upload edited data to Woocommerce: 

           . For manual upload: Download file from Goolge sheet as csv file (default file downloaded from Google sheet is encoded UTF8 csv file – supported by Woo). Note: Excel doesnt support the encoded utf 8 csv file => Dont use Excel.

           . For API work:

Ref: https://wisdmlabs.com/blog/google-apps-script-fetch-databases-to-google-spreadsheet/

Woocommerce Rest API – link data với google sheet

1. Generate Keys – tạo API key trong Woocommerce setting

To start using REST API, you first need to generate API keys.

  1. Go to WooCommerce > Settings > Advanced
  2. Go to the REST API tab and click Add key.
  3. Give the key a description for your own reference, choose a user with access to orders etc, and give the key read/write permissions.
  4. Click Generate api key.
  5. Your keys will be shown – do not close this tab yet, the secret will be hidden if you try to view the key again.

To test API in test tool (ex: https://reqbin.com/), username = consumer key, password = consumer secret 
Note: + Using https, header with authentication (username & password) can not be read.

+ If error 401 => check security measures (server firewall and/or security plugin – ex: ithemes security … to block API access)

2. Woocommerce Rest API endpoints: (orders/products)

Endpoints are located at WooCommerce > Settings > Advanced.

List all products: domain//wp-json/wc/v3/products

Ref: https://woocommerce.github.io/woocommerce-rest-api-docs/#introduction

WooCommerce GET request examples

+ GET request to view all orders
https://yourcompany.com/wp-json/wc/v3/orders/
+ GET request to view a single order
https://yourcompany.com/wp-json/wc/v3/orders/{insert order ID}
+ GET request to view all products
https://yourcompany.com/wp-json/wc/v3/products/
https://yourcompany.com/wp-json/wc/v3/products?type=variable&per_page=50     //Type = variable products & 1<per_page<100

+ Get all variations of a product: => to get all variations of all products, we need to loop through all variable product IDs.
/wp-json/wc/v3/products/<product_id>/variations

+ GET request to view a single product
https://yourcompany.com/wp-json/wc/v3/products/{insert product ID}
+ GET request to view a single product variation
https://yourcompany.com/wp-json/wc/v3/products/{insert product ID}/variations/{insert variation ID}
+ GET request to view all customers
https://yourcompany.com/wp-json/wc/v3/customers/
+ GET request to view a single customer
https://yourcompany.com/wp-json/wc/v3/customers/{insert customer ID}

Ref: https://sgwebpartners.com/how-to-use-woocommerce-api/

Routes vs Endpoints

A route is the “name” you use to access endpoints, used in the URL. A route can have multiple endpoints associated with it, and which is used depends on the HTTP verb.

For example, with the URL http://example.com/wp-json/wp/v2/posts/123:

  • The “route” is wp/v2/posts/123 – The route doesn’t include wp-json because wp-json is the base path for the API itself.
  • This route has 3 endpoints:
    • GET triggers a get_item method, returning the post data to the client.
    • PUT triggers an update_item method, taking the data to update, and returning the updated post data.
    • DELETE triggers a delete_item method, returning the now-deleted post data to the client.

3. Authentication with google scripts:

Solution from google – basic authentication

var USERNAME = 'your_username';
var PASSWORD = 'your_password';
var API_URL = 'http://<place_api_url_here>';

var authHeader = 'Basic ' + Utilities.base64Encode(USERNAME + ':' + PASSWORD);
var options = {
  headers: {Authorization: authHeader}
}
// Include 'options' object in every request
var response = UrlFetchApp.fetch(API_URL, options);

Ref: https://developers.google.com/google-ads/scripts/docs/features/third-party-apis
Ref: https://stackoverflow.com/questions/23546255/how-to-use-urlfetchapp-with-credentials-google-scripts
Ref: https://badlywired.com/2018/01/how-to-authenticate-wordpress-rest-api-from-google-sheets-scripts/

https://stackoverflow.com/questions/16027002/google-apps-script-and-external-api-authorization-failing-in-header

4. Output Woocommerce data to Google Sheet

After all 3 above steps, we need to output data to Google Sheet.

Issue 1: To protect server, Woocommerce API returns 100 result/page (Ref: Rest API pagination)

=> Solution: loop to all API URL để lấy toàn bộ các API URL  => Loop through all Url returned data to append each product/order to Google Sheet.

Issue 2: Setup the script to run on a specific time (ex: at 00:00 each day)

=> Solution: Using trigger

4.1 Woo API Pagination

Woocommerce API limit per page: maximum 100 results/page => If the result set is 500 products/order => 5 API URLs 

Ex: URL 1: yourdomain/wp-json/wc/v3/products?per_page=100&page=1 (first 100 results)

      URL 2: yourdomain/wp-json/wc/v3/products?per_page=100&page=2 (2nd 100 results)

      URL 3: yourdomain/wp-json/wc/v3/products?per_page=100&page=3 (3rd 100 results)

      URL 4: yourdomain/wp-json/wc/v3/products?per_page=100&page=4 (4th 100 results)

      URL 5: yourdomain/wp-json/wc/v3/products?per_page=100&page=5 (5th 100 results)

How to know how many pages & products/orders does the data set have:  

based on the API header below:  

  • X-WP-Total: Total returned records – Using Postman or reqbin.com to see 
  • X-WP-TotalPages: Total returned pages

Ref: Retrieve entire data from paginated API recursively 

4.2 Actual code:

Script example:

function myFunction() {
var USERNAME = 'comsumer key';
var PASSWORD = 'secret key';
var headers = {
"Accept": "application/xml",
"Content-Type": "application/xml",
"Authorization": "Basic "+ Utilities.base64Encode(USERNAME+":"+PASSWORD)
};
var options = {
"method" : "get",
"headers" : headers 
};
Logger.clear();
for (page = 1; page < 4; page++) { //see header X-WP-TotalPages to know total how many pages returned
var URL = 'Yourdomain/wp-json/wc/v3/products?per_page=20'+'&page='+page;
var response = UrlFetchApp.fetch(URL,options);
var data = JSON.parse(response); 
Logger.log(data.length);
var sheet = SpreadsheetApp.getActiveSheet();
// loop through the map and output to sheet
for (i = 0; i < data.length; i++) { 
sheet.appendRow([data[i].id,
data[i].name,
data[i].price,
data[i].stock_quantity,
data[i].stock_status,
]);
}
}
}

Ref: https://badlywired.com/2018/01/linking-wordpress-to-a-spreadsheet-using-wp-rest-api-and-google-sheets-scripts/

Ref: get all api url& fetch: https://stackoverflow.com/questions/56671010/how-can-i-iterate-through-multiple-urls-to-fetch-json-response-in-google-apps-sc

5. Using time-based script to automate script: 

+ Using time-driven trigger to wake up the main script everyday/week…

+ Clear the spreadsheet everytime the main script run to get fresh data

function startTimeTrigger() {
ScriptApp.newTrigger('main')
.timeBased()
.atHour(7)
.everDays(1)
.create();
};

6. Cell formatting in google sheet: 

Format a single column: 

var column = sheet.getRange("B2:B"); //select column B from cell B2
column.setNumberFormat("M/d/yy");

Ref: https://www.blackcj.com/blog/2015/05/18/cell-number-formatting-with-google-apps-script/  

 

Tìm giá trị thỏa mãn nhiều điều kiện trong sheet – array formula

Issue: cần tìm value thỏa mãn nhiều điều kiện (các điều kiện thuộc các dòng khác nhau) => trả lại value thuộc dòng đó.

Solution: Sử dụng Index & Match

{=INDEX(return_range, MATCH(1, (criteria1=range1) * (criteria2=range2) * (…), 0))}

Important note! This is an array formula and it must be completed with Ctrl + Shift + Enter. This will enclose your formula in {curly brackets}, which is a visual sign of an array formula in Excel. Do not try typing the braces manually, that won’t work!

Ref: https://www.ablebits.com/office-addins-blog/2019/12/11/excel-index-match-multiple-criteria-formula-examples/

Google apps script: Creates a Date Stamp if a column is edited

/**
* Creates a Date Stamp if a column is edited.
*/

//CORE VARIABLES
// The column you want to check if something is entered.
var COLUMNTOCHECK = 6;   //cot can track khi co su thay doi
// Where you want the date time stamp offset from the input location. [row, column]
var DATETIMELOCATION = [0,-4];   //cot se dien thoi gian thay doi
// Sheet you are working on
var SHEETNAME = ‘Inventory’       //ten sheet co su thay doi

function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
//checks that we’re on the correct sheet.
if( sheet.getSheetName() == SHEETNAME ) {
var selectedCell = ss.getActiveCell();
//checks the column to ensure it is on the one we want to cause the date to appear.
if( selectedCell.getColumn() == COLUMNTOCHECK) {
var dateTimeCell = selectedCell.offset(DATETIMELOCATION[0],DATETIMELOCATION[1]);
dateTimeCell.setValue(new Date());
}
}
}

Code trộn template với google apps script

Tham khảo: example trộn data từ google sheet => docs template:

cần 4 file: google sheet, google docs template, google docs output => tạo file output.

Ref: spin.atomicobject.com/2019/07/05/mail-merge-for-documents/

 

Code trộn data từ Google sheet vào template có sẵn (lưu trong google sheet):

function formSubmit(e) {
if (e.values[1] == "Gửi"){
sendEmails();
}
}
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheetByName("Data"); //Sheet "Data" chứa thông tin cần sử dụng
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, dataSheet.getLastColumn());

var templateSheet = ss.getSheetByName("Template"); //Sheet "template" chứa template mẫu 
var emailTemplate = templateSheet.getRange("B3").getValue(); //Email template ở ô B3 - sheet "template"

// Create one JavaScript object per row of data.
var objects = getRowsData(dataSheet, dataRange);

// For every row object, create a personalized email from a template and send
// it to the appropriate person.
for (var i = 0; i < objects.length; ++i) {
// Get a row object
var rowData = objects[i];

// Generate a personalized email.
// Given a template string, replace markers (for instance ${"First Name"}) with
// the corresponding value in a row object (for instance rowData.firstName).
var emailText = fillInTemplateFromObject(emailTemplate, rowData);
var emailSubject = templateSheet.getRange("B2").getValue(); //Email subject lấy từ ô B2 - sheet "Template"

MailApp.sendEmail(rowData.email, emailSubject, emailText,{
name: templateSheet.getRange("B1").getValue().toString(),
});
}
}
// Replaces markers in a template string with values define in a JavaScript data object.
// Arguments:
// - template: string containing markers, for instance ${"Column name"}
// - data: JavaScript object with values to that will replace markers. For instance
// data.columnName will replace marker ${"Column name"}
// Returns a string without markers. If no data is found to replace a marker, it is
// simply removed.
function fillInTemplateFromObject(template, data) {
var email = template;
// Search for all the variables to be replaced, for instance ${"Column name"}
var templateVars = template.match(/\$\{\"[^\"]+\"\}/g);

// Replace variables from the template with the actual values from the data object.
// If no value is available, replace with the empty string.
for (var i = 0; i < templateVars.length; ++i) {
// normalizeHeader ignores ${"} so we can call it directly here.
var variableData = data[normalizeHeader(templateVars[i])];
email = email.replace(templateVars[i], variableData || "");
}

return email;
}

//////////////////////////////////////////////////////////////////////////////////////////
//
// The code below is reused from the 'Reading Spreadsheet data using JavaScript Objects'
// tutorial.
//
//////////////////////////////////////////////////////////////////////////////////////////

// getRowsData iterates row by row in the input range and returns an array of objects.
// Each object contains all the data for a given row, indexed by its normalized column name.
// Arguments:
// - sheet: the sheet object that contains the data to be processed
// - range: the exact range of cells where the data is stored
// - columnHeadersRowIndex: specifies the row number where the column names are stored.
// This argument is optional and it defaults to the row immediately above range;
// Returns an Array of objects.
function getRowsData(sheet, range, columnHeadersRowIndex) {
columnHeadersRowIndex = columnHeadersRowIndex || range.getRowIndex() - 1;
var numColumns = range.getEndColumn() - range.getColumn() + 1;
var headersRange = sheet.getRange(columnHeadersRowIndex, range.getColumn(), 1, numColumns);
var headers = headersRange.getValues()[0];
return getObjects(range.getValues(), normalizeHeaders(headers));
}

// For every row of data in data, generates an object that contains the data. Names of
// object fields are defined in keys.
// Arguments:
// - data: JavaScript 2d array
// - keys: Array of Strings that define the property names for the objects to create
function getObjects(data, keys) {
var objects = [];
for (var i = 0; i < data.length; ++i) {
var object = {};
var hasData = false;
for (var j = 0; j < data[i].length; ++j) {
var cellData = data[i][j];
if (isCellEmpty(cellData)) {
continue;
}
object[keys[j]] = cellData;
hasData = true;
}
if (hasData) {
objects.push(object);
}
}
return objects;
}

// Returns an Array of normalized Strings.
// Arguments:
// - headers: Array of Strings to normalize
function normalizeHeaders(headers) {
var keys = [];
for (var i = 0; i < headers.length; ++i) {
var key = normalizeHeader(headers[i]);
if (key.length > 0) {
keys.push(key);
}
}
return keys;
}

// Normalizes a string, by removing all alphanumeric characters and using mixed case
// to separate words. The output will always start with a lower case letter.
// This function is designed to produce JavaScript object property names.
// Arguments:
// - header: string to normalize
// Examples:
// "First Name" -> "firstName"
// "Market Cap (millions) -> "marketCapMillions
// "1 number at the beginning is ignored" -> "numberAtTheBeginningIsIgnored"
function normalizeHeader(header) {
var key = "";
var upperCase = false;
for (var i = 0; i < header.length; ++i) {
var letter = header[i];
if (letter == " " && key.length > 0) {
upperCase = true;
continue;
}
if (!isAlnum(letter)) {
continue;
}
if (key.length == 0 && isDigit(letter)) {
continue; // first character must be a letter
}
if (upperCase) {
upperCase = false;
key += letter.toUpperCase();
} else {
key += letter.toLowerCase();
}
}
return key;
}

// Returns true if the cell where cellData was read from is empty.
// Arguments:
// - cellData: string
function isCellEmpty(cellData) {
return typeof(cellData) == "string" && cellData == "";
}

// Returns true if the character char is alphabetical, false otherwise.
function isAlnum(char) {
return char >= 'A' && char <= 'Z' ||
char >= 'a' && char <= 'z' ||
isDigit(char);
}

// Returns true if the character char is a digit, false otherwise.
function isDigit(char) {
return char >= '0' && char <= '9';
}

 

Sử dụng Google sheet làm phần mềm quản lý tồn kho

Quản lý tồn kho bằng Google sheet

Idea:

+ Đổ dữ liệu hàng hóa dựa trên ID & tên & quantity từ website => google sheet

+ Xuất đơn hàng mới (tự động từ Website API/webhook) & nhập hàng (manual/quét mã vạch) => google sheet tự tính tồn kho

+ Google Sheet tự động xuất dữ liệu tồn kho làm đầu vào cho Google merchant/ Zalo shop/ Shopee …

          => Đồng bộ tự động tất cả các kênh bán hàng.

Ưu điểm: free, cộng đồng hỗ trợ google apps script lớn – các scripts có sẵn nhiều, chỉ cần lấy về & tùy biến cho phù hợp nhu cầu.

Nhược điểm: Google sheet có các limits về tính toán => cần giữ sheet tồn kho càng đơn giản càng tốt (hạn chế link với các sheet khác => mỗi khi có thay đổi tồn kho thì xuất ra một file static và send dữ liệu đến các platform) 

Workflow: 

  1. Tạo sheet – đơn hàng xuất => nhận dữ liệu đơn hàng tự động từ Website (woo) với các chi tiết đơn hàng (product ID, variation ID, tên sp, quantity, chi tiết khách hàng)
  2. Tạo sheet – đơn hàng nhập => nhận dữ liệu nhập hàng (manual hoặc từ barcode scanner)
  3. Xây dựng sheet tồn kho:

          + Tồn kho cập nhật = Nhập + tồn – xuất (theo variation ID)  => Sử dụng SumIF & IFErrror (nếu cần) & Vlookup (nếu cần)

          + Export dữ liệu tồn kho (static data) mỗi khi có thay đổi vào 1 sheet mới: Sheet tồn kho có nhiều công thức => khi có thay đổi sẽ export ra một sheet mới (chỉ có static data – không có công thức) => làm đầu vào cho các dịch vụ khác (Google merchant) => sử dụng funtction ImportRange

* Sử dụng function ImportRange để xuất toàn bộ dữ liệu từ sheet tồn kho sang 1 sheet khác (values only)  

           + Tạo một spreadsheet để lấy dữ liệu variable products từ sheet “Tồn kho” (Google remarketing chỉ cần tồn kho còn hay không để chạy quảng cáo bám đuôi cho khách đã xem sản phẩm – không cần cụ thể theo size/variation product) => sử dụng vlookup tìm theo product ID => điền tự động dữ liệu tồn kho

           + Từ file merchant Data, link với sheet variable products mới tạo ở trên – sử dụng ImportRange => ImportRange xuất dữ liệu “Values only”

           + Lệnh ImportRange chạy tự động by default 30 mins/lần (thay đổi trong File/Spreadsheet settings/Calculation)

          Câu lệnh function IMPORTRANGE: IMPORTRANGE("https://docs.google.com/spreadsheets/d/abcd123abcd123", "sheet1!A1:C10")      

Ref: https://blog.google/products/g-suite/g-suite-pro-tips-how-sync-one-spreadsheet-another-google-sheets/

Next development: Điền template sử dụng dữ liệu từ Google Sheet – tham khảo hướng dẫn sau:

https://www.it-swarm.net/vi/google-apps-script/co-dien-truoc-mot-bieu-mau-google-bang-cach-su-dung-du-lieu-tu-bang-tinh-google-khong/1042716111/

http://nguyencongblog.com/tao-1-ung-dung-tron-va-gui-email-bang-google-app-script/

http://nguyencongblog.com/code-tron-email/

Giải thích chi tiết từ Google: https://developers.google.com/apps-script/articles/mail_merge

Google sheet limits

40,000 new rows

18,278 columns

5 million cells per workbook

50,000 characters for a single cell.

Tips to speed up Google sheet:

+ Convert formulas to static values wherever possible

Làm việc với JSON

Giới thiệu chung về JSON:

+ JSON viết tắt bởi JavaScript Object Notation
{
“type”: “laptop”,
“brand”: “Sony”,
“operating system”: “Windows 7”,
“graphic card”: “NVIDIA”
}

ví dụ trên cũng chính là biểu diễn cho một Object trong JavaScript. Trong đó, gồm có hai thành phần:

keys: type, brand, operating system, graphic card
values: laptop, Sony, Windows 7, NVIDIA

Đặc trưng của JSON: 

+ Chuỗi JSON được bao lại bởi dấu ngoặc nhọn {}

+ Key: luôn luôn phải được đóng gói trong cặp dấu ngoặc kép, không phải ngoặc đơn, cũng không được phép là biến số (variable)
+ Value: Chỉ được phép là những dữ liệu cơ bản như numbers, strings, Boolean, array, object, null, không được phép là function, date, undefined hoặc là một biểu thức tính toán. Trường hợp trong value của bạn có chứa dấu nháy kép thì hãy dùng dấu () để đặt trước nó nhé, ví dụ học “json là gì”.
+ Không được phép tồn tại dấu phẩy cuối cùng như JavaScript Object.
+ Đối với number thì không được phép có chữ số 0 ở đầu. Ngoài ra, nếu đó là chữ số thập phân thì phải có ít nhất 1 chữ số sau dấu chấm (.).

Cách sử dụng

+ JSON.stringify dùng để convert một JavaScript Object thành JSON string.
+ JSON.parse dùng để convert string biểu diễn JSON thành JavaScript Object.

Khai thác dữ liệu JSON: 

Dữ liệu trong mảng được đánh số từ 0 (zero-based): Số đánh dấu đối tượng đầu tiền là 0, sau đó là 1, 2, 3…

VD: 

{
“name”:“John”,
“age”:30,
“cars”:[ “Ford”“BMW”“Fiat” ]
}

x = myObj.cars[0]; //Kết quả là Ford. 

Tham khảo: https://www.w3schools.com/js/js_json_arrays.asp

Xem thêm về sử dụng Json khi Sync Woocommerce data với goolge sheet