D
P
0
← Semua artikel Read in English

WordPress & PHP di Produksi

Warnanya Milik `post_content`, Bukan `theme.json`: Menyunting `content.raw` Lewat REST lalu Menambal Seeder-nya

· · 6 menit baca
Warnanya Milik `post_content`, Bukan `theme.json`: Menyunting `content.raw` Lewat REST lalu Menambal Seeder-nya

Ada satu pertanyaan yang tidak saya tanyakan sebelum menyentuh apa pun: siapa yang sebenarnya memiliki nilai warna itu. Saya langsung membuka theme.json, karena di situlah warna diatur, mengganti hex aksennya di sana, lalu menganggap urusan warna sudah selesai.

Sembilan halaman tidak setuju. Tombol di semua halaman itu tetap #8B1538, hex yang harusnya sudah pensiun. Saya sempat menuduh cache, jadi saya purge object cache, purge page cache, hard refresh, buka incognito. Saya sempat menuduh spesifisitas, jadi saya buka DevTools siap menulis selektor yang lebih berat. Panel Styles justru tidak menunjuk ke stylesheet mana pun.

<a class="wp-block-button__link has-background"
   style="background-color:#8B1538">
  Lihat detail
</a>

Warnanya datang dari atribut style di elemen itu sendiri. Tidak ada berkas CSS yang bisa saya sunting untuk menghapusnya, karena warna itu memang tidak pernah tinggal di CSS.

Jadi ini bukan cerita tentang perubahan yang gagal menyebar. Ini cerita tentang saya menyunting lapisan yang salah selama berjam-jam, karena saya salah menebak siapa pemilik nilainya.

theme.json mengatur tema, warna ini duduk di konten

Blok tombol Gutenberg menyimpan warna kustom langsung di markup blok, dan markup blok itu disimpan apa adanya di kolom post_content. Jadi isi database untuk halaman-halaman tadi kurang lebih begini:

<!-- wp:button {"style":{"color":{"background":"#8B1538"}}} -->
<div class="wp-block-button">
  <a class="wp-block-button__link has-background"
     style="background-color:#8B1538">Lihat detail</a>
</div>
<!-- /wp:button -->

theme.json mendefinisikan palet dan nilai default. Otoritasnya berhenti di sana. Begitu seorang editor, atau sebuah skrip, memilih warna kustom pada sebuah blok, nilai itu berhenti menjadi referensi ke palet dan berubah menjadi literal yang dibekukan di dalam satu baris konten. Tema dan konten adalah dua pemilik yang berbeda. Tema tidak akan pernah menjangkau nilai yang sudah duduk di konten, bukan karena saya kurang teliti membaca berkasnya, tapi karena secara struktur memang tidak ada jalannya.

Untungnya pertanyaan kepemilikan tadi punya tes yang cepat, dan saya harusnya menjalankannya di menit pertama. Buka DevTools, lihat dari mana nilai itu datang. Kalau dia muncul sebagai aturan dari sebuah stylesheet, pemiliknya lapisan tema dan berkas tema adalah tempat yang benar untuk diperbaiki. Kalau dia muncul sebagai atribut style pada elemen, pemiliknya konten, dan tidak ada berkas tema yang akan menyentuhnya.

Lapisan yang memang milik tema

Perbaikan di berkas tema tetap perlu dan tetap benar, cakupannya saja jauh lebih sempit dari yang saya kira. Satu jalan sed di theme.css, theme.json, CSS layar loading, dan CSS pattern hero. Bagian itu membosankan dan berjalan lancar.

Yang hampir saya lewatkan, lapisan tema sendiri ternyata punya dua tempat simpan, dan theme.json cuma yang pertama. Begitu ada orang yang pernah menyetel warna lewat Penyunting Situs, WordPress menyimpan hasilnya di database sebagai satu post bertipe wp_global_styles, dan nilai di post itu ditumpuk di atas theme.json, bukan menggantinya. Jadi berkas tema boleh saya rapikan sampai bersih, kalau aksennya pernah disimpan dari Penyunting Situs yang menang tetap salinan di database. Isinya bisa dibaca lewat REST di /wp-json/wp/v2/global-styles/<id>, dan dibereskan dari panel Styles yang dulu menulisnya.

Setelah kedua tempat itu benar-benar bersih, tombol di sembilan halaman tadi tetap #8B1538. Persis seperti yang harusnya saya duga sejak awal, karena lapisan ini memang tidak memilikinya.

Lapisan konten: content.raw, bukan content.rendered

Yang saya butuhkan adalah membaca post_content mentah, mengganti hex-nya, lalu menyimpannya kembali, tanpa harus membuka sembilan halaman di editor satu per satu dan mengklik picker warna di setiap tombol.

REST API bawaan WordPress bisa melakukan itu, dengan satu syarat yang gampang terlewat. Secara default endpoint post mengembalikan content.rendered, yaitu HTML hasil render. Di bentuk itu komentar blok yang membawa atribut sudah dilucuti, jadi menyimpannya kembali sama saja dengan mengganti markup blok dengan HTML datar dan menghancurkan struktur bloknya. Yang saya perlukan adalah content.raw, bentuk mentah yang masih memuat komentar blok beserta atribut JSON-nya.

Dan raw hanya muncul kalau saya meminta context=edit, sementara context=edit hanya diizinkan untuk pengguna yang boleh menyunting post itu. Cara termudah memenuhi kedua syarat itu sekaligus adalah menjalankannya dari tab admin yang sudah login, jadi cookie autentikasinya sudah ada dan saya tinggal ikut menyertakan nonce.

// dijalankan di konsol browser, di dalam wp-admin, sudah login
const OLD = "#8B1538";
const NEW = "#9E1B21";
const IDS = [12, 18, 23, 31, 44, 52, 57, 63, 71];
 
for (const id of IDS) {
  const res = await fetch(`/wp-json/wp/v2/pages/${id}?context=edit`, {
    credentials: "same-origin",
    headers: { "X-WP-Nonce": wpApiSettings.nonce },
  });
 
  const page = await res.json();
  const raw = page.content.raw;
  if (!raw.includes(OLD)) {
    console.log(id, "bersih, dilewati");
    continue;
  }
 
  await fetch(`/wp-json/wp/v2/pages/${id}`, {
    method: "POST",
    credentials: "same-origin",
    headers: {
      "Content-Type": "application/json",
      "X-WP-Nonce": wpApiSettings.nonce,
    },
    body: JSON.stringify({ content: raw.split(OLD).join(NEW) }),
  });
 
  console.log(id, "diganti");
}

Beberapa catatan dari proses ini. wpApiSettings.nonce tersedia di halaman admin yang meng-enqueue skrip wp-api-request; kalau di layar yang Anda buka variabel itu undefined, wp.apiFetch juga ada di admin dan dia mengurus nonce sendiri, jadi Anda bisa memakainya sebagai gantinya. Saya sengaja memakai split().join() alih-alih regex supaya tidak perlu memikirkan escaping, dan saya sengaja melewati halaman yang sudah bersih supaya modified tidak berubah tanpa alasan. Kalau situsnya cukup besar, jalankan dulu versi yang hanya console.log tanpa POST sama sekali, dan baca hasilnya sebelum menulis apa pun.

Pemilik ketiga: skrip yang mencetak halaman itu

Setelah database bersih dan situsnya akhirnya benar, ada satu pertanyaan yang belum terjawab. Kenapa sembilan halaman ini punya warna kustom, padahal saya tidak pernah menyetelnya satu per satu di editor?

Jawabannya ada di seed-content.php, skrip yang dulu saya pakai untuk membangkitkan halaman-halaman itu. Skrip itu menyusun markup blok sebagai string, lengkap dengan hex-nya, dan hex yang dia tulis masih hex lama. Artinya baris database yang barusan saya perbaiki bukan asal dari nilai itu. Baris itu cuma hasil cetakan, dan mesin cetaknya masih memegang nilai lama.

Jadi saya buka skrip itu dan mengganti setiap hex lama di string markup blok yang dia hasilkan. Ini langkah yang tidak memberi hasil terlihat pada hari itu juga, dan justru karena itu paling gampang dilupakan. Selama seeder masih memegang hex lama, satu perintah re-seed cukup untuk mengembalikan seluruh masalahnya, dan saya akan mengulang debugging yang sama dua minggu lagi sambil merasa gila.

Pelajaran

Sebelum mengubah sebuah nilai, tanyakan lapisan mana yang memilikinya. Di WordPress urutannya cukup jelas: theme.json memegang palet dan default, wp_global_styles memegang apa pun yang pernah disimpan dari Penyunting Situs, dan post_content memegang nilai yang sudah tertulis ke dalam blok. Yang terakhir itu yang menang, dan cuma dia yang tidak punya jalur dari berkas tema. DevTools memberi tahu Anda sedang berhadapan dengan yang mana: aturan dari stylesheet berarti tema, atribut style pada blok berarti konten. Untuk yang di konten, jalurnya REST dengan context=edit, supaya yang Anda tulis ulang itu content.raw dan bukan hasil render yang komentar bloknya sudah hilang.

Lalu pertanyaan kepemilikan itu punya satu tingkat lagi yang jauh lebih gampang terlewat. Konten yang dibangkitkan oleh skrip selalu punya dua pemilik: baris database yang ada sekarang, dan generator yang mencetaknya. Memperbaiki baris database saja terasa seperti selesai, karena situsnya langsung terlihat benar, padahal yang Anda perbaiki baru keluarannya. Sebelum menyatakan beres, tanyakan apa yang terjadi kalau konten ini di-seed ulang besok pagi. Kalau jawabannya nilai lama kembali, Anda belum memperbaiki apa pun, Anda baru menundanya.