Admin Options, Block Preview & block.json
Gambaran Umum
Video ini membahas cara menambahkan opsi admin di sidebar (InspectorControls) dan toolbar (BlockControls), menggunakan ColorPicker + third-party color picker, menambahkan block preview dan description, serta migrasi ke file block.json dengan apiVersion 2.
1. InspectorControls — Panel Sidebar Kanan
Import dari masing-masing package:
import { InspectorControls, BlockControls, AlignmentToolbar } from "@wordpress/block-editor"
import { PanelBody, PanelRow } from "@wordpress/components"Struktur di JSX
function OurQuizEdit(props) {
return (
<div>
{/* Panel sidebar kanan */}
<InspectorControls>
<PanelBody title="Background Color" initialOpen={true}>
<PanelRow>
{/* Color picker di sini */}
</PanelRow>
</PanelBody>
</InspectorControls>
{/* Inline toolbar atas block */}
<BlockControls>
<AlignmentToolbar
value={props.attributes.theAlignment}
onChange={(x) => props.setAttributes({ theAlignment: x })}
/>
</BlockControls>
{/* Konten block utama */}
<div style={{
backgroundColor: props.attributes.bgColor,
textAlign: props.attributes.theAlignment
}}>
{/* ... form fields, answers, dll */}
</div>
</div>
);
}Penjelasan Components
| Component | Lokasi | Fungsi |
|---|---|---|
InspectorControls | Sidebar kanan (Settings panel) | Container untuk opsi block |
PanelBody | Dalam InspectorControls | Collapsible section |
PanelRow | Dalam PanelBody | Satu baris opsi |
BlockControls | Toolbar atas block | Inline toolbar |
AlignmentToolbar | Dalam BlockControls | Left/center/right alignment |
2. ColorPicker — WordPress Default
import { ColorPicker } from "@wordpress/components"<PanelBody title="Background Color" initialOpen={true}>
<PanelRow>
<ColorPicker
color={props.attributes.bgColor}
onChangeComplete={(x) => props.setAttributes({ bgColor: x.hex })}
/>
</PanelRow>
</PanelBody>Perhatian: onChangeComplete bukan onChange
// ❌ SALAH — onChange memberikan real-time setiap pixel drag
onChange={(x) => props.setAttributes({ bgColor: x.hex })}
// ✅ BENAR — onChangeComplete hanya fire setelah user selesai memilih
onChangeComplete={(x) => props.setAttributes({ bgColor: x.hex })}
x.hexmengekstrak string hex color (contoh:"#ff0000").
3. Third-Party Color Picker (react-color)
Install
npm install react-colorImport ChromePicker
import { ChromePicker } from "react-color"Gunakan di JSX
<PanelBody title="Background Color" initialOpen={true}>
<PanelRow>
<ChromePicker
color={props.attributes.bgColor}
onChangeComplete={(x) => props.setAttributes({ bgColor: x.hex })}
disableAlpha={true}
/>
</PanelRow>
</PanelBody>Perbedaan Default vs react-color
| Fitur | WP ColorPicker | ChromePicker |
|---|---|---|
| Install | Tidak perlu | npm install react-color |
| Bundle size | 0 (built-in) | Tambah ~beberapa KB |
| Look | WP native | Chrome DevTools style |
| Alpha/opacity | Ya | Bisa di-disable |
4. Attributes Baru
registerBlockType("ourplugin/are-you-paying-attention", {
attributes: {
question: { type: "string" },
answers: { type: "array", default: [""] },
correctAnswer: { type: "string", default: undefined },
bgColor: { type: "string", default: "#EBEBEB" }, // ★ Baru
theAlignment: { type: "string", default: "left" } // ★ Baru
},
// ...
})5. Frontend Style Props
Penting: Akses Props Berbeda di Frontend
// Admin (index.js) — lewat props.attributes
style={{ backgroundColor: props.attributes.bgColor }}
// Frontend (frontend.js) — langsung di props (tidak ada .attributes)
style={{
backgroundColor: props.bgColor,
textAlign: props.theAlignment
}}Karena di frontend kita spread data langsung:
<Quiz {...data} />.
6. Block Preview & Description
Example Property — Preview di Block Inserter
registerBlockType("ourplugin/are-you-paying-attention", {
// ...
example: {
attributes: {
question: "What is my name?",
answers: ["Meowsalot", "Barksalot", "Purrsloud", "Brad"],
correctAnswer: "3",
bgColor: "#CFE8F1",
theAlignment: "center"
}
},
// ...
})Ketika user hover di list block inserter, preview muncul di panel kanan. Tanpa
example, tidak ada preview.
Description Property
registerBlockType("ourplugin/are-you-paying-attention", {
title: "Are You Paying Attention?",
description: "Give your audience a chance to prove their comprehension.",
// ...
})Teks description muncul di sidebar kanan ketika block di-select.
7. Migrasi ke block.json
Sebelum (Manual Registration)
// PHP
function onInit() {
wp_register_script('ournewblocktype', plugin_dir_url(__FILE__) . 'build/index.js', array('wp-blocks', 'wp-editor'));
wp_register_style('ournewblocktype', plugin_dir_url(__FILE__) . 'build/index.css');
register_block_type('ourplugin/are-you-paying-attention', array(
'editor_script' => 'ournewblocktype',
'editor_style' => 'ournewblocktype',
'render_callback' => 'theHTML'
));
}
add_action('init', 'onInit');Sesudah (block.json)
block.json:
{
"apiVersion": 2,
"name": "ourplugin/are-you-paying-attention",
"title": "Are You Paying Attention?",
"category": "common",
"description": "Give your audience a chance to prove their comprehension.",
"editorScript": "file:./build/index.js",
"editorStyle": "file:./build/index.css"
}PHP (lebih sederhana):
function onInit() {
register_block_type(__DIR__, array(
'render_callback' => 'theHTML'
));
}
add_action('init', 'onInit');
__DIR__mengarah ke folder yang mengandung block.json. WordPress otomatis membaca file tersebut.
8. apiVersion 2 & useBlockProps
Import useBlockProps
import { useBlockProps, InspectorControls, BlockControls, AlignmentToolbar } from "@wordpress/block-editor"Gunakan di Edit Function
function OurQuizEdit(props) {
const blockProps = useBlockProps({
className: "paying-attention-edit-block",
style: { backgroundColor: props.attributes.bgColor }
})
return (
<div {...blockProps}>
<InspectorControls>
{/* ... */}
</InspectorControls>
<BlockControls>
{/* ... */}
</BlockControls>
{/* konten block ... */}
</div>
)
}Apa yang useBlockProps Lakukan?
- Menambahkan class dan ID yang diperlukan WordPress untuk mengidentifikasi block
- Menambahkan atribut data-block
- Menambahkan style dan className yang kamu berikan
- Wajib untuk apiVersion 2 — block tidak berfungsi tanpa ini
Spread Operator
<div {...blockProps}>Ini menyebarkan semua properti yang dikembalikan
useBlockProps()ke elemen div.
9. Properties block.json untuk Asset Loading
{
"editorScript": "file:./build/index.js",
"editorStyle": "file:./build/index.css",
"style": "file:./build/style-index.css",
"script": "file:./build/frontend.js",
"viewScript": "file:./build/frontend.js"
}| Property | Dimuat Di | Keterangan |
|---|---|---|
editorScript | Editor saja | JavaScript untuk admin/editor |
editorStyle | Editor saja | CSS untuk admin/editor |
style | Editor + Frontend | CSS yang berlaku di keduanya |
script | Editor + Frontend | JS yang berlaku di keduanya |
viewScript | Frontend saja | JS hanya untuk pengunjung |
⚠️ Masalah viewScript + render_callback
viewScript TIDAK bekerja jika kamu menggunakan render_callback (dynamic block)Ini adalah keterbatasan WordPress.
viewScriptotomatis dimuat hanya untuk static blocks yang menyimpan HTML di database.
Workaround: script + DOMContentLoaded
Jika kamu terpaksa menggunakan script (dimuat di editor+frontend):
// frontend.js
document.addEventListener("DOMContentLoaded", function() {
// Kode hanya berjalan setelah DOM siap
const divsToUpdate = document.querySelectorAll(".paying-attention-update-me")
// ...
})Wrapper
DOMContentLoadedmemastikan kode tidak berjalan sebelum HTML ada di halaman.
10. Rekomendasi Brad
Brad tidak menggunakan viewScript/script di block.json untuk frontend JS. Ia tetap memuat secara manual di PHP:
function theHTML($attributes) {
if (!is_admin()) {
wp_enqueue_script(
'attentionFrontend',
plugin_dir_url(__FILE__) . 'build/frontend.js',
array('wp-element'),
'1.0',
true
);
wp_enqueue_style(
'attentionFrontendStyles',
plugin_dir_url(__FILE__) . 'build/frontend.css'
);
}
ob_start(); ?>
<div class="paying-attention-update-me">
<pre style="display: none;"><?php echo wp_json_encode($attributes) ?></pre>
</div>
<?php return ob_get_clean();
}Alasan
- Kontrol penuh kapan dan bagaimana JS dimuat
- Tidak kena bug viewScript + render_callback
- Conditional loading — hanya load jika block benar-benar ada di halaman
- block.json hanya untuk editorScript dan editorStyle
Ringkasan File Structure Final
are-you-paying-attention/
├── block.json ← Block registration metadata
├── are-you-paying-attention.php ← PHP plugin file
├── node_modules/ ← Dependencies
├── package.json ← Build scripts (build + start)
├── src/
│ ├── index.js ← Editor/admin React component
│ ├── index.scss ← Editor styles
│ ├── frontend.js ← Frontend React component
│ └── frontend.scss ← Frontend styles
└── build/
├── index.js ← Compiled editor JS
├── index.css ← Compiled editor CSS
├── frontend.js ← Compiled frontend JS
└── frontend.css ← Compiled frontend CSS