define( 'WP_DEBUG', true ); sudah ada di wp-config.php, mode debug pasti aktif. Letaknya di mana dianggap tidak penting, toh masih satu file. Kenyataannya, posisi baris itu sangat menentukan. Kalau definisinya ditulis di bawah baris yang memuat wp-settings.php, WordPress sudah selesai menyiapkan dirinya sebelum baris itu sempat dibaca. Hasilnya, debug.log tidak pernah muncul dan error tetap tersembunyi.
Pola ini sering terlihat di tiket support. Pengguna menyalin potongan kode dari tutorial, menempelkannya di baris paling bawah wp-config.php karena terasa paling aman, lalu bingung kenapa folder wp-content tetap kosong. Padahal sumber masalahnya ada di urutan eksekusi, bukan di kodenya.
Kenapa posisi baris di wp-config.php menentukan hasilnya
ABSPATH, lalu require_once ABSPATH . 'wp-settings.php';. Di atasnya biasanya ada komentar penanda semacam "That's all, stop editing!". Teksnya sedikit berbeda antar versi, tapi maksudnya sama.
Baris require_once itulah titik baliknya. Begitu wp-settings.php dimuat, WordPress mulai bootstrap, yaitu proses menyiapkan seluruh lingkungannya. Ada dua fungsi di dalamnya yang berkaitan langsung dengan debug.
Fungsi pertama adalah wp_initial_constants(). Fungsi ini mengecek konstanta penting dan memberi nilai default untuk yang belum didefinisikan. Polanya kira-kira "kalau WP_DEBUG belum ada, set ke false". Hal yang sama berlaku untuk WP_DEBUG_LOG dan WP_DEBUG_DISPLAY.
Fungsi kedua adalah wp_debug_mode(). Fungsi ini membaca nilai konstanta tadi lalu menerapkannya ke PHP: mengatur level error_reporting, menyalakan atau mematikan display_errors, dan kalau WP_DEBUG_LOG aktif, mengarahkan error_log PHP ke wp-content/debug.log.
Semua itu terjadi di dalam require_once. Selama wp-settings.php berjalan, WordPress juga memuat plugin, tema, dan seluruh core. Untuk request web biasa, sebagian besar pekerjaan sudah selesai sebelum eksekusi kembali ke baris berikutnya di wp-config.php. Jadi define() yang ditaruh di bawahnya datang terlambat. Keputusan soal debug sudah diambil memakai nilai default false.
Yang terjadi pada define() yang datang terlambat
wp_initial_constants() sudah mendefinisikan WP_DEBUG sebagai false, panggilan define( 'WP_DEBUG', true ); berikutnya tidak mengubah apa pun. PHP menolaknya dan mengeluarkan pesan bahwa konstanta sudah didefinisikan. Di PHP 8 pesannya berupa Warning, di versi lama berupa Notice.
Ironisnya, pesan itu sendiri biasanya tidak terlihat. Mode debug tidak aktif, jadi pesan tidak tampil di layar dan tidak masuk debug.log. Paling-paling pesan itu tercatat di error log PHP milik server, tergantung pengaturan hosting. Inilah yang membuat masalahnya terasa "diam": tidak ada error, tidak ada file log, dan tidak ada tanda bahwa baris tadi diabaikan.
Ada variasi kedua yang efeknya sama dan justru lebih sering terjadi. wp-config.php bawaan biasanya sudah berisi define( 'WP_DEBUG', false ); di bagian tengah file. Lalu seseorang menambahkan define( 'WP_DEBUG', true ); di tempat lain tanpa menghapus yang lama. Di sini aturannya sederhana: definisi pertama yang dieksekusi yang menang. Kalau baris false ada di atas, baris true di bawahnya tidak berpengaruh, bahkan kalau keduanya sama-sama berada di atas wp-settings.php.
Satu hal lagi yang sering bikin bingung. Walaupun urutannya sudah benar, debug.log tidak langsung muncul. File itu baru dibuat saat ada sesuatu yang perlu dicatat, misalnya notice, warning, atau error dari PHP. Kalau situs sedang bersih, wajar kalau filenya belum ada. Kemungkinan lain, user PHP tidak punya izin tulis ke folder wp-content, sehingga file tidak pernah bisa dibuat. Jadi sebelum menyimpulkan apa pun, pastikan dulu urutan barisnya benar.
Cara memastikan urutannya dari terminal
BASH
grep -nE 'WP_DEBUG|wp-settings' wp-config.phpTEXT
82:define( 'WP_DEBUG', false );
96:require_once ABSPATH . 'wp-settings.php';
98:define( 'WP_DEBUG', true );
99:define( 'WP_DEBUG_LOG', true );WP_DEBUG harus punya nomor lebih kecil daripada baris wp-settings.php, dan nama konstanta yang sama tidak boleh muncul lebih dari sekali. Contoh di atas punya dua masalah sekaligus: ada definisi false di baris 82 yang akan menang, dan definisi true di baris 98 sudah terlambat.
Hati-hati kalau kamu memakai WP-CLI untuk verifikasi, misalnya lewat wp eval untuk mencetak nilai WP_DEBUG. WP-CLI memuat wp-config.php dengan caranya sendiri. Baris wp-settings.php dipisahkan lalu dimuat terpisah, sehingga define yang letaknya di bawah baris itu bisa tetap terbaca di konteks CLI. Akibatnya, WP-CLI bisa melaporkan true padahal request dari browser tetap memakai false. Untuk kasus ini, grep di atas lebih jujur karena langsung menunjukkan urutan di file. Setelah itu, buktikan lewat request web sungguhan dan lihat apakah debug.log mulai terisi saat halaman yang bermasalah dibuka.
Kalau di file tidak ada definisi ganda tapi hasilnya masih aneh, cek juga apakah ada file lain yang ikut di-include di wp-config.php. Beberapa setup memisahkan konfigurasi per environment ke file terpisah. Ada juga panel hosting atau tool manajemen yang menyisipkan baris sendiri. Prinsip urutannya tetap sama: yang dieksekusi lebih dulu yang menang.
Pola yang aman untuk dipakai di production
require_once.
PHP
// Satu-satunya blok debug di file ini. Hapus definisi WP_DEBUG lain di atasnya.
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
/* That's all, stop editing! Happy publishing. */
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
require_once ABSPATH . 'wp-settings.php';WP_DEBUG_DISPLAY diset false supaya error tidak tampil ke pengunjung. Pesan error sering berisi path server, nama tabel, atau potongan query, dan informasi seperti ini tidak perlu terlihat publik. Error tetap tercatat di log. Baris ini_set dipakai sebagai lapisan tambahan, karena beberapa konfigurasi server menyalakan display_errors dari sisi php.ini.
Perhatikan juga lokasi log-nya. Secara default, debug.log berada di wp-content. Folder ini ada di dalam document root, sehingga file log bisa saja dibuka langsung dari browser kalau web server tidak memblokirnya. Ada dua cara menutup celah itu. Cara pertama, isi WP_DEBUG_LOG dengan path file di luar folder publik sebagai pengganti true. WordPress versi baru mendukung ini, tapi cek dulu versi yang terpasang. Cara kedua, blokir akses ke file tersebut di level web server. Caranya berbeda antara Apache atau LiteSpeed yang membaca .htaccess dan Nginx yang memakai blok location, jadi sesuaikan dengan stack yang dipakai.
Rule of thumb yang aku pegang: mode debug di production adalah alat sementara, bukan pengaturan permanen. Nyalakan secukupnya, reproduksi masalahnya, baca log-nya, lalu matikan lagi. Jangan lupa hapus atau rotasi debug.log. Di situs yang ramai dan penuh notice dari plugin, file ini bisa membesar cukup cepat dan diam-diam memakan kuota disk.
Jadi, kalau debug.log tidak kunjung muncul, jangan buru-buru menyalahkan plugin atau izin folder. Buka wp-config.php dan cek urutannya dulu. Pastikan setiap konstanta debug hanya didefinisikan sekali, letaknya di atas require_once ABSPATH . 'wp-settings.php';, dan buktikan hasilnya lewat request web, bukan hanya lewat WP-CLI. Biasanya pengecekan ini cuma butuh satu perintah grep dan hasilnya langsung terlihat.