Membuat cadangan gambar dari WordPress ke GitHub secara otomatis

abdul fattah ikhsan
7 min readApr 1, 2021

--

Menggunakan Webhook dan GitHub API v3

Octocat shot by Abdul Fattah Ikhsan
Jelmaan Octocat — shot by Abdul Fattah Ikhsan

Sebelum memulai bahasan saya asumsikan kalian punya pengetahuan dasar mengenai:

  • WordPress
  • Node.js
  • Git
  • Konsep Restful API
  • Konsep webhook

Jika kalian masih belum mengerti tapi penasaran, Silakan lanjut.

Daftar Isi:

  1. Motivasi
  2. Menyiapkan Git repository dan Personal access token
  3. Menyiapkan API webhook di Node.js
  4. Deploy dan jalankan API webhook di Pipedream
  5. Pasang plugin wp-webhook
  6. Integrasi wp-webhook dengan target server
  7. Uji coba
  8. Penutup

Motivasi

Sebenarnya motivasi awal itu menjadikan GitHub sebagai image CDN (Content Delivery Network). Ini berguna ketika implementasi headless CMS di Wordpress. Nah, untuk mengurangi kompleksitas bahasan maka saya membuat judul ini. Karena memang intinya itu menyimpan gambar di GitHub melalui Rest API.

Dokumentasi GitHub sendiri tidak ada bahasan mengenai ini, bisa jadi, mereka tidak ingin kalian menggunakannya. Namun, pepatah mengatakan, selalu ada jalan menuju Roma. Beberapa implementasi, contohnya github-image-upload, pustaka ini memberikan solusi scrapping GitHub issues dan unggah gambar disana. Namun Saya tidak suka solusinya, saya ingin gambar tetap bisa di-track setiap perubahannya, tidak cuma penambahan saja. Secara teknis bisa, karena Git adalah version control, dan beberapa kali saya mengerjakan project itu bisa sekaligus unggah gambar melalui Git CLI.

Di implementasi yang lain, seperti potongan kode di github gist ini, bagaimana membuat commit dan push kontennya ke GitHub melalui API. Saya pun mencoba dan bisa, pertanyaannya bagaimana Saya unggah gambar. Saya tidak mau terlalu banyak ubah kodenya, yang mana itu bahasa Ruby. Akhirnya setelah saya cari di Google, Github punya pustaka dan dokumentasi resmi. Cuma kalau kalian baca dokumentasinya, pasti bingung bagaimana memulainya. terlalu abstrak penjelasannya. Tada 🎉, kalian telah menemukan tutorial ini, langsung saja tanpa harus menguras waktu trial and error.

Menyiapkan Git repository dan Personal access token

Pertama kalian buat repository di GitHub dan pastikan sudah ada Readme. Atau bisa menggunakan repository yang sudah ada. Contoh, kita membuat repository:

initialize github repository
Centang initial Readme ketika membuat repository

Kedua, kita harus menyiapkan Personal access token, Token ini adalah kredensial ketika kalian menggunakan GitHub API v3 tanpa harus menggunakan password utama.

Github settings
Pilih settings di pojok kanan atas (gambar profile)
Developer settings
Pilih developer settings di menu sebelah kiri
generate new token
Pilih generate new token
deskripsi token
Buat deskripsi yang sesuai untuk token tersebut
token scopes
Pilih scope dan permission yang diperlukan
generate token
Pilih generate token
Pilih 📋 simbol clipboard untuk copy tokennya

Ingat! token ini cuma sekali muncul saat pertama kali dibuat maka kalian harus simpan dulu di tempat yang aman ya!

Menyiapkan API webhook di Node.js

Kita menggunakan pustaka @octokit/request untuk berinteraksi dengan GitHub API v3. Pustaka lain yang akan kita gunakan adalah node-fetch. Yuk kita buat fungsi-fungsinya dulu.

  • Konversi URL sumber gambar ke base64
let fetch = require('node-fetch');
async function getImageAsBase64(imageUrl) {
let result = await fetch(imageUrl);
let data = await result.buffer();
return data.toString('base64');
}
  • Inisialisasi @octokit/request dengan default settings
let { request } = require("@octokit/request");
let requestWithAuth = request.defaults({
headers: {
authorization: 'token ' + process.env.GITHUB_TOKEN,
},
});
  • Mengambil commit-an terakhir dari target repo dan branch utama (main)
async function getLastCommitSha() {
let result = await requestWithAuth('GET /repos/{owner}/{repo}/git/matching-refs/{ref}', {
owner: process.env.GITHUB_USERNAME,
repo: process.env.GITHUB_REPO,
ref: process.env.GITHUB_REF,
});
return result.data.length ? result.data[0].object.sha : '';
}
  • Mengunggah gambar base64 ke Git blob (objek binari)
async function createBlob(base64Image) {
const result = await requestWithAuth('POST /repos/{owner}/{repo}/git/blobs', {
owner: process.env.GITHUB_USERNAME,
repo: process.env.GITHUB_REPO,
content: base64Image,
encoding: 'base64',
});
return result.data;
}
  • Membuat commit baru
async function createCommit(fileName, data, lastCommitSha) {
let tree = await requestWithAuth('POST /repos/{owner}/{repo}/git/trees', {
owner: process.env.GITHUB_USERNAME,
repo: process.env.GITHUB_REPO,
tree: [
{
path: 'public/' + fileName,
mode: '100644', // mode untuk file blob
type: 'blob',
sha: data.sha,
},
],
base_tree: lastCommitSha,
});
let result = await requestWithAuth('POST /repos/{owner}/{repo}/git/commits', {
owner: process.env.GITHUB_USERNAME,
repo: process.env.GITHUB_REPO,
message: 'add new image ' + fileName,
tree: tree.data.sha,
parents: [lastCommitSha],
});
return result.data;
}
  • Push commit baru tadi ke repository GitHub kalian
async function pushCommit(data) {
let result = await requestWithAuth('PATCH /repos/{owner}/{repo}/git/refs/{ref}', {
owner: process.env.GITHUB_USERNAME,
repo: process.env.GITHUB_REPO,
ref: process.env.GITHUB_REF,
sha: data.sha,
});
return result.data;
}
  • Cek validitas URL gambar
let { URL } = require('url');
function isValidURL(targetUrl) {
try {
let url = new URL(targetUrl);
return url.protocol === 'http:' || url.protocol === 'https:';
}
catch (error) {
return false;
}
}

Catatan: Disini kalian menggunakan environment variables. Saya akan jelaskan setiap variablenya.

  1. GITHUB_TOKEN adalah personal access token yang tadi kalian buat.
  2. GITHUB_USERNAME adalah nama username kalian di github
  3. GITHUB_REPO adalah nama repository kalian yang dijadikan target
  4. GITHUB_REF adalah referensi gabungan berformat heads/<nama_branch>. Diawali katakunci heads/ dan nama branch kalian. Branch utama biasanya adalah main. maka formatnya jadi heads/main.

Deploy dan jalankan API server di Pipedream

Nah, kode-kode diatas mau kalian taruh mana? lokal komputer kalian? tidak-tidak, kita sudah di era cloud computing dan serverless. Kalian langsung implementasikan di pipedream. Saya ga perlu jelaskan panjang lebar. kalian bisa langsung cek aja webnya dan daftar. Langkah-langkahnya sebagai berikut:

pipedream workflow
Buat workflow baru
pipedream title
Ubah judul workflow
pipedream trigger
Pilih HTTP API
Pilih tombol + di bawah untuk menambahkan step trigger

gambar diatas memiliki URL https://xxxxxxx.m.pipedream.net ini adalah endpoint Rest API. Kalian akan daftarkan ini di wordpress webhook kalian.

pipedream step
Pilih Run Node.js code
Taruh kode-kode diatas ke dalam fungsi trigger pada baris ke 2 seperti di gambar

Kemudian di baris terakhir (sebelum kurawal tutup ya) kalian tambahkan kode seperti ini:

let message = '';
try {
if (event.body.post?.post_status === 'publish') {
let postThumbnail = event.body.post_thumbnail; // string or false
if (isValidURL(postThumbnail)) {
let fileName = new URL(postThumbnail).pathname.slice(28);
let base64Image = await getImageAsBase64(postThumbnail);
let blobData = await createBlob(base64Image);
let lastCommit = await getLastCommitSha();
let commit = await createCommit(fileName, blobData, lastCommit);
let result = await pushCommit(commit);
message = JSON.stringify(result);
}
}
message = 'success';
} catch (error) {
console.error(error);
message = error.message;
}

return message;

Jika kalian perhatikan kode diatas, fungsi commit dan push ke GitHub akan jalan ketika event body mempunyai pos dengan status publish dan post_thumbnail valid.

Selanjutnya, Kalian siapkan environment variables di Pipedream.

pipedream environment variable setup
Pilih tombol new environment variable
Buat masing-masing variable. contohnya disini GITHUB_TOKEN dulu

Selesai. kalian bisa coba-coba menambahkan step trigger lain seperti send email atau end workflow. Gimana? gampangkan!. Terakhir klik save dan deploy

pipedream deploy
Pilih deploy

Kalian bisa test dulu apakah kode kalian tidak bermasalah dan bisa jalan.

pipedream send event
Pilih send test event

Maka akan muncul seperti ini

pipedream event success
Pesan sukses

Pasang plugin wp-webhooks

wp-webhooks plugin page
sumber: https://wordpress.org/plugins/wp-webhooks/

Setelah terpasang di WordPress kalian. Buka wp-webhooks settings.

wp-webhook settings
Pilih settings
wp-webhook debug settings
Aktifkan mode debug
wp-webhook send data on post update
Aktifkan send data on post update

Terakhir klik Save all.

Integrasi wp-webhook dengan target server

Pilih send data
tambah webhook url
Isi nama webhook dan webhook URL dengan URL dari pipedream kemudian klik add
webhook settings
Pilih settings pada kolom action sebelah kanan
webhook settings panel
Aktifkan trigger from backend only dan on selected post types dan klik save settings

Kalian pilih Pos saja agar webhook tidak terkirim dua kali.

Uji Coba

Kalian bisa mencoba langsung dengan cara membuat pos baru di WordPress dan menambahkan gambar unggulan. Kemudian langsung klik terbitkan. wp webhook akan berjalan otomatis dan trigger pipedream URL.

pipedream receive event from wp-webhook
Disini saya kasih contoh pipedream sudah ter-trigger tapi dapat error credential karena belum ada token

Bagaimana menampilkan gambar dari GitHub? mudah, formatnya

https://github.com/<github_username>/blob/<github_branch>/<nama_folder>/<nama_file>?raw=true

atau jika bukan di dalam folder maka formatnya

https://github.com/<github_username>/blob/<github_branch>/<nama_file>?raw=true

Penutup

Saya berikan tautan Pipedream workflow-nya, Sebagai referensi saat kalian mempraktekkan.

Jika kalian perhatikan, hanya gambar unggulan yang bisa dicadangkan. Adapun gambar di dalam pos tidak, inilah keterbatasan dari implementasi kita. Keterbatasan lain, kode ini hanya bisa 1 gambar dalam 1 kali commit dan push. Namun secara keseluruhan, konsep sudah cukup jelas Saya kira.

Saya cukupkan tulisan kali ini. Terima kasih sudah membaca tulisan ini sampai selesai, Tulisan ini saya dedikasikan untuk Indonesia lebih baik. Semoga bermanfaat dan yuk lanjut kodingnya!

Apabila ada pertanyaan atau ingin kolaborasi bisa kontak langsung di telegram.

--

--

abdul fattah ikhsan
abdul fattah ikhsan

Written by abdul fattah ikhsan

If I am immortal, I will spend my time to learn everything in the universe.

No responses yet