Skip to content

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.php

Langkah 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 ke block.json
  • Di JSON, tidak bisa pakai ekspresi/variabel untuk default — jadi imgURL tidak 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:

  • props parameter 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 global ourThemeData
  • "wp-editor" = script yang pasti ada di editor screen
  • get_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 (dari wp_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
  • InnerBlocks perlu diimport di index.js (terpisah dari edit.js)

Tips: Clear Customizations

Jika setelah migrasi, konten block hilang atau tidak muncul:

  1. Klik WordPress icon di editor
  2. Klik 3 titik (...) pada template
  3. Pilih Clear Customizations
  4. Template akan kembali menggunakan file .html dari 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