কেন এটা দরকার?
Browser থেকে সরাসরি WordPress API call করলে CORS error আসে — বেশিরভাগ WordPress hosting এটা block করে।
Google Apps Script একটি server-side proxy হিসেবে কাজ করে, তাই CORS problem থাকে না।
সম্পূর্ণ বিনামূল্যে — Google account থাকলেই হবে।
Setup সময়: মাত্র 5 মিনিট ।
2 নিচের Code Copy করে Paste করুন
Default Code.gs ফাইলের সব content মুছে নিচের code paste করুন:
Copy
// ═══════════════════════════════════════════════════════════════════════
// AffiliateEngine — WordPress Full REST API Proxy v3.0
// Handles: Category Fetch (GET) + Article Publish (POST via text/plain)
// Deploy : Web App → Execute as Me → Who has access: Anyone
// v3.0 FIX: text/plain + base64 GET support to avoid browser CORS preflight
// ═══════════════════════════════════════════════════════════════════════
// ── doGet: Category Fetch + base64 encoded proxy requests ────────────
function doGet (e) {
var params = e.parameter;
// ── base64 encoded proxy request (Strategy B from browser) ────────────
if (params.action === 'proxy' && params.payload) {
try {
var decoded = Utilities.newBlob(Utilities.base64Decode(params.payload)).getDataAsString();
var payload = JSON.parse(decoded);
return handleProxyRequest(payload);
} catch (err) {
return makeJSON({error: 'Bad payload: ' + err.toString(), __status: 400 });
}
}
// ── Standard category fetch ────────────────────────────────────────────
var siteUrl = params.site || '' ;
var endpoint = params.endpoint || '/wp/v2/categories?per_page=100' ;
var user = params.user || '' ;
var pass = params.pass || '' ;
if (!siteUrl) return makeJSON({error: 'Missing site parameter' });
try {
siteUrl = siteUrl.replace(/\/+$/ , '' );
var options = buildOptions('get' , user, pass, null );
var apiUrl = siteUrl + '/wp-json' + endpoint;
var response = UrlFetchApp.fetch(apiUrl, options);
var code = response.getResponseCode();
var body = response.getContentText();
if (code !== 200 ) {
var epBase = endpoint.split('?' )[0 ];
var epQs = endpoint.split('?' )[1 ] || '' ;
var ep2 = '/?rest_route=' + encodeURIComponent(epBase) + (epQs ? '&' + epQs : '' );
var r2 = UrlFetchApp.fetch(siteUrl + ep2, options);
if (r2.getResponseCode() === 200 ) body = r2.getContentText();
}
return ContentService.createTextOutput(body).setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return makeJSON({error: err.toString()});
}
}
// ── doPost: Article Publish (text/plain or application/json body) ─────
function doPost (e) {
try {
var raw = e.postData ? e.postData.contents : '' ;
if (!raw) return makeJSON({error: 'Empty body' , __status: 400 });
var payload = JSON.parse(raw); // works for both text/plain and application/json
return handleProxyRequest(payload);
} catch (err) {
return makeJSON({error: err.toString(), __status: 500 });
}
}
// ── handleProxyRequest: core logic (shared by doPost + doGet base64) ──
function handleProxyRequest (payload) {
try {
var siteUrl = (payload.site || '' ).replace(/\/+$/ , '' );
var endpoint = payload.endpoint || '/wp/v2/posts' ;
var method = (payload.method || 'POST' ).toLowerCase();
var user = payload.user || '' ;
var pass = payload.pass || '' ;
var body = payload.body || {};
if (!siteUrl) return makeJSON({error: 'Missing site' , __status: 400 });
var options = buildOptions(method, user, pass, JSON.stringify(body));
// Try /wp-json/ first
var apiUrl = siteUrl + '/wp-json' + endpoint;
var response = UrlFetchApp.fetch(apiUrl, options);
var rCode = response.getResponseCode();
var rBody = response.getContentText();
// Fallback to /?rest_route= if needed
if (rCode !== 200 && rCode !== 201 && rCode !== 204 ) {
var apiUrl2 = siteUrl + '/?rest_route=' + encodeURIComponent(endpoint);
var resp2 = UrlFetchApp.fetch(apiUrl2, options);
if (resp2.getResponseCode() === 200 || resp2.getResponseCode() === 201 ) {
rCode = resp2.getResponseCode(); rBody = resp2.getContentText();
}
}
var parsed = {};
try { parsed = JSON.parse(rBody); } catch (x) { parsed = {raw: rBody}; }
parsed.__status = rCode;
return ContentService.createTextOutput(JSON.stringify(parsed)).setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return makeJSON({error: err.toString(), __status: 500 });
}
}
// ── buildOptions: UrlFetchApp options builder ─────────────────────────
function buildOptions (method, user, pass, bodyStr) {
var opts = { method: method, muteHttpExceptions: true , followRedirects: true ,
headers: {'Content-Type' : 'application/json' } };
if (user && pass)
opts.headers['Authorization' ] = 'Basic ' + Utilities.base64Encode(user + ':' + pass);
if (bodyStr && method !== 'get' ) opts.payload = bodyStr;
return opts;
}
// ── makeJSON / makeResponse: helpers ─────────────────────────────────
function makeJSON (obj) {
return ContentService.createTextOutput(JSON.stringify(obj)).setMimeType(ContentService.MimeType.JSON);
}
function makeResponse (obj) { return makeJSON(obj); }