Skip to content

Ganti URL database WordPress pakai WP-CLI, bukan SQL mentah

Adityo Guni Waluyo

WP_HOME cuma menipu halaman baru; URL lama menempel di database. WP-CLI search-replace dengan dry-run dan skip-columns=guid solusinya.

Ringkasan

Pindahin dump WP produksi ke lokal ternyata nggak cukup cuma ganti WP_HOME dan WP_SITEURL, soal URL lama masih nempel di mana-mana, apalagi yang format serialized. Jangan asal REPLACE() via SQL, bisa merusak serialized dan kena limit panjang kolom. Paling aman pakai wp search-replace, dry-run dulu, dan skip kolom guid biar identitas postingan aman.

Minggu lalu: dump produksi di kontainer lokal

Minggu lalu saya memindahkan dump database WordPress produksi ke kontainer lokal buat debugging. Situsnya terbuka, tapi semua gambar dan tautan internal masih menunjuk domain produksi. Tebakan pertama saya: cukup ubah konstanta WP_HOME dan WP_SITEURL di wp-config.php. Ternyata itu salah besar. Konstanta tersebut memang menimpa nilai opsi siteurl, tapi tidak pernah menyentuh nilai lama yang tersimpan di database [8] — jadi hanya konten baru yang pakai alamat benar, seluruh konten lama tetap menunjuk domain produksi.

Padahal URL lama itu menempel di banyak tempat: post_content di wp_posts, wp_postmeta, opsi widget, sampai pengaturan tema. Dan sebagian di antaranya terbungkus format PHP serialized, yang menyimpan nilai bersama prefiks panjang string seperti s:22:"https://domainlama.com" [9]. Angka 22 itu adalah janji panjang byte. Ubah isinya tanpa mengubah angkanya, pembaca serialized akan tersandung data yang tidak konsisten.

Dua jebakan SQL mentah

Jalan pintas yang sering diajarkan tutorial lama adalah UPDATE ... REPLACE() langsung di database. Saya nyaris pakai jalan ini, dan untungnya ada dua hal yang membuatnya menurun dari daftar.

Pertama, REPLACE() buta terhadap struktur serialized. Dia mengganti teks URL tanpa menghitung ulang prefiks panjang, sehingga s:22 bisa saja berisi string 28 karakter. WordPress docs sendiri memperingatkan bahwa search-replace menyeluruh di database bisa memicu masalah serialisasi karena tema dan widget menyimpan nilai beserta panjang URL-nya [7].

Kedua, batas kolom. Storage VARCHAR bergantung pada panjang nilai aktual plus beberapa byte prefiks [10]; kalau URL pengganti lebih panjang dari aslinya, baris bisa gagal tersimpan tergantung mode ketat server. Untuk kolom yang panjangnya pas-pasan, ini bukan risiko teoretis.

Cara yang benar dan aturan emas GUID

WP-CLI search-replace dirancang untuk masalah ini: ia menangani data PHP serialized dengan benar dan tidak mengubah nilai primary key [6]. Alurnya selalu sama dalam pengalaman saya.

Rencana uji pertama: jalankan wp search-replace 'https://domainlama.com' 'http://wordpress.test:8080' --all-tables --dry-run --skip-columns=guid — laporan muncul tanpa satu baris pun berubah [6]. Kalau jumlah penggantian sudah masuk akal, jalankan lagi tanpa --dry-run.

Bendera --skip-columns=guid bukan gaya-gayaan. WordPress menyimpan permalink sebagai GUID dan aturannya tegas: isi kolom GUID tidak boleh diubah dalam keadaan apa pun, sebab itulah identitas permanen artikel di mata feed reader [7]. SQL mentah tidak tahu aturan ini; wp-cli membuatnya jadi bawaan.

Satu kebiasaan kecil yang menyelamatkan waktu: dry-run dulu, baca angkanya, baru eksekusi. Migrasi yang baik terasa membosankan, dan itu memang tujuannya.

Sumber

  1. WP-CLI, wp search-replace [6]
  2. WordPress docs, Changing The Site URL [7]
  3. WordPress developer docs, wp-config.php [8]
  4. PHP manual, serialize() [9]
  5. MySQL 8.0 manual, Storage Requirements (as archived 2026-09-18) [10]

Artikel terkait