Migrasi Banner Block ke Pendekatan Modern
Gambaran Umum
Banner block adalah block kompleks pertama yang dimigrasi — punya background image, InnerBlocks, InspectorControls, MediaUpload, dan save function. Pelajaran ini menunjukkan cara memindahkan semua fitur tersebut ke block.json + render.php + edit.js.
Langkah 1: Persiapan
Hapus class lama di functions.php
php
// Hapus atau comment out:
// new JSXBlock("banner", true, ['fallbackimage' => get_theme_file_uri('/images/library-hero.jpg')]);
// Hapus seluruh class PlaceholderBlock (sudah tidak diperlukan)Daftarkan block modern
php
function ourNewBlocks() {
register_block_type_from_metadata(__DIR__ . "/build/footer");
register_block_type_from_metadata(__DIR__ . "/build/header");
register_block_type_from_metadata(__DIR__ . "/build/eventsandblogs");
register_block_type_from_metadata(__DIR__ . "/build/banner"); // ← tambah
}
add_action("init", "ourNewBlocks");Langkah 2: Buat Folder & File
Duplikasi folder src/header/ → rename jadi banner/
Struktur:
src/banner/
├── block.json
├── edit.js
├── index.js
└── render.phpLangkah 3: block.json dengan Attributes & Supports
Berbeda dari placeholder block, banner block butuh attributes dan supports di block.json:
json
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "ourblocktheme/banner",
"title": "Banner",
"supports": {
"align": ["full"]
},
"attributes": {
"align": {
"type": "string",
"default": "full"
},
"imgID": {
"type": "number"
},
"imgURL": {
"type": "string"
}
},
"editorScript": "file:./index.js",
"render": "file:./render.php"
}Penting:
- Attributes yang sebelumnya di JavaScript
registerBlockType()sekarang pindah keblock.json - Di JSON, tidak bisa pakai ekspresi/variabel untuk
default— jadiimgURLtidak punya default di sini - Fallback image akan diatur lewat cara lain (lihat langkah 6)
Langkah 4: render.php
Copy dari our-blocks/banner.php:
php
<div class="page-banner">
<div class="page-banner__bg-image"
style="background-image: url(<?php echo esc_url($attributes['imgURL']); ?>)">
</div>
<div class="page-banner__content container">
<div class="page-banner__content-interior">
<?php echo $content; ?>
</div>
</div>
</div>Langkah 5: edit.js (Kompleks)
Pindahkan semua JSX dari banner.js lama ke edit.js baru:
js
import { InspectorControls, MediaUpload, MediaUploadCheck, InnerBlocks, useBlockProps } from "@wordpress/block-editor";
import { PanelBody, PanelRow } from "@wordpress/components";
import { useEffect } from "@wordpress/element";
import apiFetch from "@wordpress/api-fetch";
export default function Edit(props) {
const blockProps = useBlockProps();
// Fallback image (lihat Langkah 6)
useEffect(() => {
if (!props.attributes.imgURL) {
props.setAttributes({
imgURL: `${ourThemeData.themePath}/images/library-hero.jpg`
});
}
}, []);
// Fetch image URL dari media ID
useEffect(() => {
if (props.attributes.imgID) {
async function go() {
const response = await apiFetch({
path: `/wp/v2/media/${props.attributes.imgID}`,
method: "GET",
});
props.setAttributes({
imgURL: response.media_details.sizes.pageBanner?.source_url
?? response.media_details.sizes.full.source_url,
});
}
go();
}
}, [props.attributes.imgID]);
function onFileSelect(x) {
props.setAttributes({ imgID: x.id });
}
return (
<div {...blockProps}>
<InspectorControls>
<PanelBody title="Background" initialOpen={true}>
<PanelRow>
<MediaUploadCheck>
<MediaUpload
onSelect={onFileSelect}
value={props.attributes.imgID}
render={({ open }) => (
<button className="button button-large" onClick={open}>
Choose Background Image
</button>
)}
/>
</MediaUploadCheck>
</PanelRow>
</PanelBody>
</InspectorControls>
<div className="page-banner">
<div
className="page-banner__bg-image"
style={{ backgroundImage: `url('${props.attributes.imgURL}')` }}
></div>
<div className="page-banner__content container">
<div className="page-banner__content-interior">
<InnerBlocks allowedBlocks={[
"ourblocktheme/genericheading",
"ourblocktheme/genericbutton"
]} />
</div>
</div>
</div>
</div>
);
}Poin Penting:
propsparameter wajib ada di parentheses fungsi Edit (berbeda dari placeholder block sederhana)- Semua JSX dibungkus dalam
<div {...blockProps}>wrapper useBlockProps()diperlukan untuk API Version 3
Langkah 6: Fallback Background Image
Karena block.json tidak bisa punya ekspresi JavaScript sebagai default value, gunakan wp_localize_script:
Di functions.php:
php
function ourNewBlocks() {
wp_localize_script("wp-editor", "ourThemeData", array(
"themePath" => get_stylesheet_directory_uri()
));
register_block_type_from_metadata(__DIR__ . "/build/footer");
register_block_type_from_metadata(__DIR__ . "/build/header");
register_block_type_from_metadata(__DIR__ . "/build/banner");
// ...
}
add_action("init", "ourNewBlocks");Penjelasan:
wp_localize_script("wp-editor", "ourThemeData", ...)→ membuat variabel JavaScript globalourThemeData"wp-editor"= script yang pasti ada di editor screenget_stylesheet_directory_uri()= URL absolut ke folder theme aktif
Di edit.js:
js
useEffect(() => {
if (!props.attributes.imgURL) {
props.setAttributes({
imgURL: `${ourThemeData.themePath}/images/library-hero.jpg`
});
}
}, []);ourThemeData.themePath= URL theme folder (dariwp_localize_script)- Hanya diset saat component pertama kali render DAN belum ada image
Langkah 7: Save Function (index.js)
js
import { registerBlockType } from "@wordpress/blocks";
import { InnerBlocks } from "@wordpress/block-editor";
import metadata from "./block.json";
import Edit from "./edit";
registerBlockType(metadata.name, {
edit: Edit,
save: () => {
return <InnerBlocks.Content />;
},
});- Save function tetap sederhana: hanya
<InnerBlocks.Content /> - Semua rendering front-end dilakukan oleh
render.php InnerBlocksperlu diimport diindex.js(terpisah dariedit.js)
Tips: Clear Customizations
Jika setelah migrasi, konten block hilang atau tidak muncul:
- Klik WordPress icon di editor
- Klik 3 titik (...) pada template
- Pilih Clear Customizations
- Template akan kembali menggunakan file
.htmldari hard drive (bukan database)
Ringkasan Alur
1. block.json → nama, title, supports, attributes, pointer ke file
2. render.php → HTML front-end (copy dari file PHP lama)
3. edit.js → JSX editor experience + useBlockProps wrapper
4. index.js → registerBlockType + save function (InnerBlocks.Content)
5. functions.php → register_block_type_from_metadata + wp_localize_script