Seorang klien minta fitur yang kedengarannya sederhana: modul konten yang bisa disisipkan editor mereka ke tengah artikel. Semacam kartu berisi data dinamis yang tampil konsisten di mana pun ditaruh. Saya pun melakukan apa yang saya anggap "hal modern yang benar": membangun custom Gutenberg block. block.json yang rapi, komponen edit dengan preview langsung, render callback di sisi server supaya markup-nya selalu dirender dari data terbaru. Saya daftarkan bloknya, tes di instalasi dev saya, dan hasilnya memuaskan: ketik nama bloknya di inserter, isi parameternya, jadi. Saya kirim ke produksi dengan perasaan bangga.
Beberapa jam kemudian klien membalas: "Bloknya di mana ya? Saya cari di editor tidak ketemu."
Investigasinya
Refleks pertama saya: pasti ada yang salah di deploy. Saya cek plugin-nya aktif di produksi, register_block_type jalan tanpa error, error_log bersih, cache sudah di-purge. Semua hijau. Tapi klien tetap tidak menemukan bloknya, dan dia bukan orang yang asal cari.
Akhirnya saya minta screenshot layar edit artikelnya. Dan satu gambar itu menjawab semuanya: tidak ada block inserter. Tidak ada tombol tambah blok, tidak ada panel samping ala Gutenberg. Yang ada cuma toolbar TinyMCE klasik — bold, italic, dropdown format. Situs produksinya menjalankan plugin Classic Editor, site-wide, dan dikunci tanpa opsi switch per user.
Akar masalahnya
Classic Editor tidak menyembunyikan block editor; dia menggantikannya sepenuhnya. Block inserter bukan disembunyikan di suatu menu — dia memang tidak pernah ada di layar itu. Sementara itu register_block_type tetap sukses tanpa warning apa pun di sisi server, karena mendaftarkan blok itu operasi yang sah. Blok saya terdaftar rapi di registry yang tidak akan pernah dibuka siapa pun.
Jadi bug-nya bukan di kode. Bug-nya di asumsi: saya tidak pernah mengecek editor apa yang benar-benar dipakai situs itu sebelum mulai membangun. Saya membangun UI untuk lingkungan yang saya bayangkan, bukan lingkungan yang klien punya.
Perbaikannya: shortcode plus tombol TinyMCE
Kabar baiknya: sejak awal saya menulis logika render sebagai fungsi PHP yang berdiri sendiri, bukan menempel di definisi blok. Jadi fitur intinya tidak perlu ditulis ulang sama sekali. Fungsi yang sama tinggal didaftarkan sebagai shortcode:
// The same render function that backed the block's render_callback.
add_shortcode('content_module', 'render_content_module');
function render_content_module($atts) {
$atts = shortcode_atts([
'id' => 0,
'layout' => 'default',
], $atts, 'content_module');
ob_start();
get_template_part('template-parts/content-module', null, $atts);
return ob_get_clean();
}Tapi menyuruh editor mengetik shortcode manual lengkap dengan parameternya itu resep typo. Jadi saya tambahkan tombol kecil di toolbar TinyMCE lewat dua filter:
add_filter('mce_buttons', function ($buttons) {
$buttons[] = 'content_module_button';
return $buttons;
});
add_filter('mce_external_plugins', function ($plugins) {
$plugins['content_module_button'] = get_template_directory_uri()
. '/js/content-module-button.js';
return $plugins;
});Plugin JS-nya sengaja dibuat sekecil mungkin: satu tombol, satu prompt, sisipkan shortcode:
tinymce.PluginManager.add('content_module_button', function (editor) {
editor.addButton('content_module_button', {
text: 'Content Module',
onclick: function () {
var moduleId = window.prompt('Module ID:');
if (moduleId) {
editor.insertContent(
'[content_module id="' + moduleId + '"]'
);
}
}
});
});Hasil akhirnya: fitur yang sama persis, markup front-end yang sama persis, tapi disisipkan dari toolbar yang memang ada di depan mata editornya. Klien senang, dan dia tidak pernah tahu bahwa versi pertama fitur ini hidup di editor yang tidak dia miliki.
Checklist sebelum membangun UI editor
- Cek dulu editor apa yang benar-benar dipakai situsnya. Cara paling cepat: buka langsung layar edit artikelnya. Cara programatik:
include_once ABSPATH . 'wp-admin/includes/plugin.php';
if (is_plugin_active('classic-editor/classic-editor.php')) {
// No block inserter here. Ship a shortcode instead.
}- Tulis logika render sebagai fungsi yang berdiri sendiri. Fungsi yang sama bisa jadi
render_callbackuntuk blok sekaligus callback untukadd_shortcode. Ini yang menyelamatkan saya dari menulis ulang fitur. - Ingat bahwa "modern" itu properti lingkungan, bukan properti kode. Gutenberg block adalah jawaban yang benar di situs yang menjalankan block editor. Di situs yang dikunci ke Classic Editor, dia cuma kode mati yang terdaftar rapi.
Sejak insiden ini, pertanyaan pertama saya sebelum membangun apa pun yang menyentuh pengalaman menulis bukan lagi "blok atau shortcode?", melainkan "editornya yang mana?".
