State vs Context & Penutup Chapter
Kapan Gunakan State?
Context = Local (Per Instance)
Setiap instance block punya context terpisah dan independen. Quiz #1 tidak tahu apa-apa tentang Quiz #2.
State = Global (Seluruh Halaman)
State dibagi antar semua block instances dan bahkan antar block types yang berbeda, selama mereka menggunakan namespace yang sama.
Contoh Kasus Nyata
3 instance quiz di satu halaman + 1 block "Solved Counter":
- Context: pertanyaan, jawaban, solved status → per quiz instance
- State: total quiz yang dijawab benar → global counter yang diupdate dari semua instance
Membuat Block Baru: Solved Counter
Scaffold Plugin Baru
cd /path/to/wp-content/plugins
npx @wordpress/create-block@latest solved-counter --template @wordpress/create-block/interactive-templateAktivasi plugin di WP Admin → Plugins.
render.php untuk Solved Counter
<?php
// src/render.php (solved-counter plugin)
// Inisialisasi state — namespace HARUS SAMA dengan quiz block
wp_interactivity_state("create-block", array(
"solvedCount" => 0
));
?>
<div data-wp-interactive="create-block">
<p>Questions solved:
<strong>
<span data-wp-text="state.solvedCount"></span>
</strong>
</p>
</div>Kunci: data-wp-interactive="create-block" dan wp_interactivity_state("create-block", ...) — namespace harus cocok dengan quiz block.
wp_interactivity_state() — Set Global State dari PHP
Di Quiz Block (render.php)
<?php
// src/render.php (interactivity-quiz plugin)
wp_interactivity_state("create-block", array(
"solvedCount" => 0,
"skyColor" => "blue" // contoh state tambahan
));
// ... rest of render.php
?>Namespace sebagai "Glue"
block.json → name: "create-block/interactivity-quiz"
^^^^^^^^^^^^
Ini adalah NAMESPACE
store("create-block", { ... }) ← JS store
wp_interactivity_state("create-block", ...) ← PHP state
data-wp-interactive="create-block" ← HTML directiveSemua harus pakai namespace yang sama agar terhubung.
Mengakses State dari JavaScript
Destructure State dari Store
// src/view.js (interactivity-quiz plugin)
import { store, getContext } from "@wordpress/interactivity";
const { state } = store("create-block", {
actions: {
guessAttempt: () => {
const context = getContext();
if (!context.solved) {
if (context.index === context.correctAnswer) {
context.showCongrats = true;
setTimeout(() => { context.solved = true; }, 1000);
// INCREMENT GLOBAL STATE
state.solvedCount++;
} else {
context.showSorry = true;
setTimeout(() => { context.showSorry = false; }, 2600);
}
}
},
},
callbacks: { /* ... */ },
});Baris kunci: const { state } = store("create-block", { ... }) — destructure state dari return value store().
State Merging
Beberapa Block Bisa Set State
// Di quiz plugin:
wp_interactivity_state("create-block", array(
"solvedCount" => 0,
"skyColor" => "blue"
));
// Di solved-counter plugin:
wp_interactivity_state("create-block", array(
"solvedCount" => 0,
"grassColor" => "green"
));WordPress Merge Otomatis
console.log(state);
// {
// solvedCount: 0, ← dari kedua plugin
// skyColor: "blue", ← dari quiz plugin
// grassColor: "green" ← dari counter plugin
// }State dari berbagai block digabungkan secara cerdas oleh WordPress. Tidak ada konflik selama namespace sama.
Edge Case: Counter Tanpa Quiz
Karena solved-counter juga inisialisasi solvedCount: 0, maka meskipun tidak ada quiz block di halaman → counter tetap menampilkan 0 tanpa error.
Menampilkan State di HTML
Directive data-wp-text dengan State
<!-- Gunakan "state." bukan "context." -->
<span data-wp-text="state.solvedCount"></span>| Prefix | Sumber | Scope |
|---|---|---|
context. | data-wp-context di DOM | Local per block instance |
state. | wp_interactivity_state / store | Global seluruh halaman |
Demo Alur Lengkap
Page Load → Counter: 0
↓
Jawab Quiz #1 benar → state.solvedCount++ → Counter: 1
↓
Jawab Quiz #2 benar → state.solvedCount++ → Counter: 2
↓
Jawab Quiz #3 benar → state.solvedCount++ → Counter: 3Semua update terjadi secara reaktif — counter otomatis update tanpa refresh!
State vs Context — Tabel Lengkap
| Aspek | Context | State |
|---|---|---|
| Scope | Per block instance | Global (seluruh halaman) |
| Set di PHP | wp_interactivity_data_wp_context() | wp_interactivity_state() |
| Akses di JS | getContext() | const { state } = store(...) |
| Akses di HTML | context.propertyName | state.propertyName |
| Tempat di DOM | data-wp-context attribute | Tidak ada di DOM (disimpan di JS) |
| Merging | Hierarki DOM (parent → child) | Namespace-based (semua block types) |
| Gunakan untuk | Data block spesifik | Data shared antar blocks |
| Frekuensi | ~90% kasus | ~10% kasus |
Interactivity Router (Teaser)
Belum Dirilis (Per April 2024)
WordPress sedang mengembangkan Interactivity Router — fitur terpisah yang akan membawa:
- SPA-like navigation — berpindah halaman tanpa full page reload
- URL management — update address bar saat navigasi
- Browser history — tombol back/forward berfungsi
- Mirip Next.js Link atau React Router
Fitur ini belum masuk ke core WordPress dan belum ada dokumentasi resmi. Akan dicakup di course update saat dirilis.
Ringkasan Chapter 29
Konsep Utama
| Konsep | Penjelasan |
|---|---|
| Interactivity API | Sistem resmi WP 6.5+ untuk front-end interactivity |
| Context | Local state per block instance |
| State | Global state shared antar blocks |
| Actions | Fungsi handler untuk events (click, keyup, dll.) |
| Callbacks | Fungsi yang return boolean untuk directive logic kompleks |
| Namespace | String penghubung antara HTML, JS store, dan PHP state |
Directives yang Dipelajari
| Directive | Fungsi |
|---|---|
data-wp-interactive | Aktifkan Interactivity API pada elemen (set namespace) |
data-wp-context | Set local context (JSON) |
data-wp-on--click | Event handler click |
data-wp-text | Render teks dari context/state |
data-wp-each | Loop array dari context/state |
data-wp-class--[name] | Toggle CSS class berdasarkan boolean |
data-wp-bind--hidden | Toggle attribute hidden |
Fungsi PHP
| Fungsi | Kegunaan |
|---|---|
wp_interactivity_data_wp_context($array) | Convert PHP array → data-wp-context attribute |
wp_interactivity_state($namespace, $array) | Set global state dari PHP |
Fungsi JavaScript
| Fungsi | Kegunaan |
|---|---|
store(namespace, config) | Register/akses store untuk namespace |
getContext() | Ambil context elemen DOM saat ini |