Permintaannya berbunyi "change the font to", lalu nama font brand. Permintaan itu datang dari marketing manager di pihak klien, sampai ke saya lewat kontak yang menjadi jalur permintaan revisi situs ini, dan tiba pada 1 September bersama dua permintaan lain. Salah satunya meminta dua nama kota di homepage ditulis kapital. Saya tidak ikut membangun situs ini, dan tugas saya di sana sebatas revisi. Fondasinya WordPress dengan tema Hello Elementor plus child theme, dan halamannya dibangun di Elementor.
Begitu permintaan itu saya telusuri, maknanya berbalik. Font yang diminta sudah terpasang sejak Maret 2023 dan sudah dipakai di CSS. Lima judul kota di homepage bahkan sudah memakai font-family:"Brand Title", Sans-serif. Yang rusak hanya protokol pemanggilannya, dan gara-gara itu font brand tidak pernah tampil di mana pun. Jadi permintaan tadi sebenarnya bukan "ganti font", melainkan "fontnya tidak muncul". (Semua nama font di tulisan ini saya ganti dengan nama netral seperti Brand Title.)
@font-face dari Custom Fonts, semuanya http://
Deklarasi fontnya dicetak inline oleh Elementor Pro Custom Fonts, di dalam <style id="elementor-pro-custom-fonts-inline-css">. Tiga keluarga terdaftar di sana, Brand Display Bold, Brand Title, dan Brand Alt, dan semua src-nya menunjuk http:// sementara halamannya https://. Dalam versi yang disederhanakan, dengan nama dan domain netral, bentuknya seperti ini:
<!-- disederhanakan: nama keluarga dan domain diganti -->
<style id="elementor-pro-custom-fonts-inline-css">
@font-face {
font-family: "Brand Title";
src: url("http://example.com/fonts/brand-title.woff2");
}
</style>Halaman https:// yang meminta font lewat http:// memicu mixed content, dan browser memblokir permintaannya. Akibatnya setiap teks yang meminta font brand jatuh ke Sans-serif generik. Berkas fontnya sendiri sehat. Saya minta satu per satu lewat https:// dan semuanya membalas 200. Masalahnya murni di protokol yang tertulis di src.
Cakupannya seluruh situs, bukan homepage saja. Setiap halaman membawa 14 URL http:// di dalam @font-face, dan halaman yang lebih ringan membawa 9. Tidak ada satu halaman pun yang menampilkan tipografi brand.
Pemanggilan font lewat http:// ini sebenarnya sudah ada di catatan status saya per 27 Agustus. Di sana ia tercatat sebagai cacat lama yang belum pernah dilaporkan, dengan 28 error konsol di setiap halaman yang semuanya font. Bahwa cacat lama itu membuat font brand mati di seluruh situs, dan bahwa itulah yang sebenarnya dikeluhkan klien, baru ketahuan 1 September, saat permintaan ganti font tadi saya telusuri.
23 URL ditulis ulang, tanpa unggah ulang
Perbaikannya tidak butuh pembelian maupun berkas baru. URL fontnya cukup ditulis ulang jadi https:// lewat Elementor > Custom Fonts. Di layar edit post elementor_font, URL berkas font ternyata input teks biasa, jadi tinggal diubah lalu Update, tanpa perlu mengunggah ulang berkasnya. Dari sebelas Custom Font, sepuluh perlu diperbaiki dengan total 23 URL dari http:// ke https://. Hanya satu font yang sudah bersih sejak awal.
Untuk mengubahnya secara borongan, form #post di layar edit diambil lewat fetch, nilainya ditambal, lalu dikirim balik sebagai FormData ditambah publish=Update. Serialisasinya sama persis dengan yang dikirim browser, jadi tidak ada field yang hilang. Versi yang disederhanakan, dijalankan dari tab wp-admin yang sudah login:
// Disederhanakan. editUrl: layar edit satu post elementor_font,
// misalnya "/wp-admin/post.php?post=ID&action=edit".
const html = await (await fetch(editUrl)).text();
const form = new DOMParser()
.parseFromString(html, "text/html")
.querySelector("#post");
const body = new FormData();
for (const [key, value] of new FormData(form)) {
// tambal hanya nilai yang masih diawali http://
body.append(key, typeof value === "string"
? value.replace(/^http:\/\//, "https://")
: value);
}
body.append("publish", "Update");
await fetch("/wp-admin/post.php", { method: "POST", body });Post font sudah benar, halamannya belum
Memperbaiki post font saja ternyata tidak cukup. Elementor menyimpan salinan @font-face di berkas CSS miliknya sendiri, uploads/elementor/css/post-*.css, dan berkas itu tetap memuat http:// sesudah post fontnya benar. Langkah yang wajib sesudahnya adalah Elementor > Tools > Clear Files & Data.
Bedanya terbaca jelas di document.fonts. Sebelum Clear Files & Data, Brand Title berstatus error. Sesudahnya loaded, dan konsol bersih. Untuk melihat status semua face sekaligus, satu baris di konsol sudah cukup:
// Contoh umum: status setiap FontFace yang dikenal halaman
[...document.fonts].map((f) => `${f.family} ${f.weight} ${f.status}`);Situs ini ada di belakang Cloudflare, dan setiap perubahan perlu purge yang saya kerjakan sendiri. Sesudah purge, verifikasinya saya lakukan pada 1 September di URL polos tanpa cache-buster, dan cf-cache-status di semuanya MISS, jadi semuanya benar-benar diambil ulang dari origin. Homepage memuat 14 URL font https:// dan nol http://, dan berkas CSS kit serta berkas CSS homepage juga nol http://.
Satu temuan lain sempat salah saya catat, yaitu bahwa logo situs ikut kena mixed content. Koreksinya saya buat 2 September. Diperiksa ulang, nol tag <img> atau <source> di seluruh situs yang memakai http://. Dua kemunculan URL logo lewat http:// ternyata ada di dalam JSON-LD Rank Math, pada @id dan url sebuah ImageObject, dan URL http-nya sendiri 301 ke https. Dampaknya hanya kebersihan data terstruktur dan satu lompatan redirect, bukan kerusakan tampilan maupun keamanan, jadi bagian itu sengaja saya biarkan.
Kapitalisasi yang beres sendiri
Permintaan kapitalisasi tadi ternyata beres sendiri begitu font hidup. Huruf kecil di Brand Title digambar sebagai kapital penuh, jadi nama kota yang tersimpan sebagai Title Case tampil kapital semua.
Di titik ini saya sempat menyimpulkan sebaliknya. Tabel cmap berkas BrandTitle-Base.ttf saya periksa langsung, dan 0 dari 26 huruf kecil memakai glyph huruf besar. Dari situ saya simpulkan font ini punya huruf kecil sendiri, bukan font yang hanya kapital. Sebagai dasar kesimpulan, itu salah. Tabel cmap hanya memetakan kode karakter ke glyph ID, dan glyph ID yang berbeda tidak berarti bentuknya berbeda. Yang menentukan tampilan adalah render, bukan tabel cmap.
Teks tersimpan di enam judul kota di homepage tetap saya ubah jadi kapital, supaya teks cadangannya tetap benar kalau font gagal dimuat lagi. Verifikasi di URL polos tanggal 1 September tadi mencatat keenam nama kota di homepage sudah kapital semua.
Batch kedua dan nama keluarga yang tidak pernah didaftarkan
Pada 2 September kontak saya meneruskan dua email dari marketing manager klien, ditambah permintaan membetulkan menu header. Sebagian besar keluhan di dalamnya sudah terjawab oleh perbaikan 1 September, karena screenshotnya diambil sebelum perbaikan itu. Saya buktikan di elemen yang persis dikirim: H1 di satu halaman venue sekarang tampil dengan font brand, dan judul animasi di halaman lain juga sudah benar. Kontak saya juga menyebut "revisions all are gone", dan itu keliru. Homepage masih menyimpan 54 revisi, dua halaman kota masing-masing 24 dan 48, dan halaman yang tidak disentuh masih menyimpan revisi Oktober dan November 2025. Tidak ada yang terhapus oleh Clear Files & Data.
Hari itu juga muncul cacat font yang kedua. Tipografi global Elementor di berkas CSS kit menunjuk keluarga "Brand Display" untuk ketiga variabelnya, primary, secondary, dan accent. Padahal yang punya @font-face hanya varian bernama lengkap: Brand Display Bold, Brand Display Medium Face, Brand Display Light Face, dan Brand Display Bold Face. Browser mencocokkan nama keluarga secara utuh, bukan sebagai awalan, jadi "Brand Display" tidak menunjuk @font-face mana pun, dan apa pun yang mewarisi tipografi global jatuh ke sans-serif generik.
Dampaknya ternyata jauh lebih kecil dari kelihatannya, dan saya sempat salah melaporkan skalanya dua kali. Aturan tipografi global Elementor spesifisitasnya rendah, .elementor-widget-heading .elementor-heading-title di 0-2-0, sementara aturan per elemen di 0-4-0 menimpanya hampir di mana-mana dengan font yang memang tersaji. Sensus font terkomputasi di satu halaman venue mencatat Brand Display Bold di 73 elemen, Brand Alt 30, Brand Display Medium Face 22, dan Brand Display tanpa akhiran hanya 13, semuanya teks footer 14px.
Kesalahan pertama saya adalah angka "232 aturan CSS". Angka itu datang dari grep "Brand Display" yang ikut mencocokkan Brand Display Bold dan Brand Display Medium Face, dua font yang sehat. Hitungan sebenarnya 8 sampai 32 per halaman, dan pencariannya harus memakai lookahead negatif:
# nama keluarga diganti nama netral
grep -oP 'Brand Display(?! (Bold|Medium|Light|Face))'Kesalahan kedua, saya sempat menyebutnya kegagalan judul se-situs. Salah, yang kena hanya footer. Jangkauan footernya sendiri memang luas: templat-templat footer situs ini membawa lima aturan Brand Display tanpa akhiran yang sama, sehingga cacatnya mengenai 99 dari 113 halaman plus seluruh 182 post.
Membetulkan kit tidak menyembuhkan footer
Tipografi global saya perbaiki di kit pada 2 September. system_typography di sana punya empat entri, dan primary, secondary, serta accent diubah dari Brand Display ke Brand Display Bold. Semua 24 kunci per entri disalin utuh, jadi bobot dan ukurannya tidak berubah. Entri text dibiarkan kosong karena memang mewarisi tema.
Yang benar-benar menyembuhkan cacatnya justru perbaikan 40 widget di delapan templat footer. Footer memakai font-family:"Brand Display" yang di-hardcode per widget, sehingga tidak ikut berubah waktu kit diperbaiki. Polanya seragam di semua templat: tiga widget icon-list pada kunci icon_typography_font_family dan dua widget heading pada typography_font_family. Lima widget per templat dikali delapan templat, itulah 40 widget tadi.
Widget yang rusak ditemukan tanpa menebak: telusuri semua container di editor, lalu ambil setiap kunci yang cocok /font_family$/ dan bernilai persis Brand Display. Logikanya, dalam versi yang disederhanakan:
// Disederhanakan: root mewakili pohon container di editor,
// setiap node punya settings (kunci dan nilai) dan children.
const hits = [];
const stack = [root];
while (stack.length) {
const node = stack.pop();
for (const [key, value] of Object.entries(node.settings ?? {})) {
if (/font_family$/.test(key) && value === "Brand Display") {
hits.push({ id: node.id, key });
}
}
stack.push(...(node.children ?? []));
}Sesudah itu Clear Files & Data lagi, sama wajibnya dengan perbaikan pertama. Hasilnya terverifikasi: rujukan ke Brand Display tanpa akhiran tinggal nol di seluruh situs, dan sensus di halaman venue yang sama menunjukkan 13 elemen footer pindah dari fallback ke Brand Display Bold. Jumlahnya naik persis dari 73 ke 86, sesuai 73 ditambah 13.
Huruf depan yang tampil tipis
Begitu perbaikan itu hidup, saya langsung melihat keanehan baru: huruf depan tiap kata tampil tipis, sementara sisanya tebal. Saya sempat menjelaskannya sebagai small caps. Itu salah, persoalannya ketebalan, bukan ukuran.
Mekanismenya baru terbukti setelah fontnya saya render di empat bobot, 400, 500, 600, dan 700, lalu hasilnya saya potret. Keluarga Brand Display Bold terdiri dari beberapa @font-face. Di bobot 400 dan 500, browser memilih face yang hanya memuat glyph huruf besar, bentuknya serif tipis. Huruf kecil tidak ada di face itu, jadi browser mengambilnya dari face saudara dalam keluarga yang sama, yang tebal. Teksnya tersimpan dalam Title Case, sehingga huruf pertama setiap kata datang dari face tipis dan sisanya dari face tebal. Di bobot 600 dan 700 hasilnya seragam, karena face yang terpilih memuat kedua kelas huruf. Itu juga menjelaskan kenapa judul VENUES, INFORMATION, dan CONTACT rapi sejak awal: ketiganya memang 22px dengan bobot 600.
Perbaikan yang saya pilih adalah menaikkan bobot 500 jadi 600 pada lima widget di kedelapan footer, di kunci icon_typography_font_weight dan typography_font_weight. Kunci bobotnya diturunkan dari kunci family: untuk setiap kunci *_font_family yang bernilai Brand Display Bold, akhirannya diganti jadi _font_weight, lalu hanya yang bernilai 500 yang diubah, supaya widget lain tidak ikut tersentuh. Tampilannya terverifikasi seragam sesudahnya.
Verifikasi akhirnya di URL polos, dan kali ini tidak perlu purge Cloudflare lagi, karena HTML di URL polos sudah menunjuk berkas CSS versi yang sama dengan origin. Empat berkas CSS footer yang saya periksa nol font-weight:500 dan delapan font-weight:600, dan rujukan ke Brand Display tanpa akhiran tetap nol. Hari itu cache Elementor dibersihkan dua kali.
Render dulu, baru simpulkan
Pelajaran umum dari kasus ini: jangan menyimpulkan penyebab tampilan dari nama font atau dari cmap. Dua kali saya salah di situs ini dengan cara yang sama. Render sungguhan lalu potret, itu satu-satunya bukti yang sahih.
Sisanya lebih praktis. Kalau klien minta "ganti font" ke font yang namanya sudah ada di CSS, periksa dulu apakah font itu pernah benar-benar tampil, misalnya lewat statusnya di document.fonts. Di Elementor, membetulkan src di Custom Fonts belum selesai sebelum salinan @font-face di uploads/elementor/css dibuang lewat Clear Files & Data. Kalau mencari nama keluarga yang juga menjadi awalan nama keluarga lain, pakai lookahead negatif, karena tanpa itu hitungannya ikut menelan keluarga yang sehat. Dan tidak setiap http:// di HTML adalah mixed content. URL di dalam JSON-LD, misalnya, tidak pernah diminta browser sebagai subresource.