Skip to content

InnerBlocks, Reusable JSXBlock Class & Generic Heading Block ​

Konsep InnerBlocks ​

InnerBlocks memungkinkan sebuah block menyarangkan (nest) block lain di dalamnya. Ini adalah kunci untuk membuat layout yang fleksibel.

Import InnerBlocks ​

js
import { InnerBlocks } from "@wordpress/block-editor";

Penggunaan di Edit Component ​

js
function EditComponent() {
  return (
    <div className="page-banner">
      <div className="page-banner__content container">
        <InnerBlocks allowedBlocks={["ourBlockTheme/genericHeading", "ourBlockTheme/genericButton"]} />
      </div>
    </div>
  );
}

Penggunaan di Save Component ​

js
function SaveComponent() {
  return (
    <div className="page-banner">
      <div className="page-banner__content container">
        <InnerBlocks.Content />
      </div>
    </div>
  );
}
KomponenFungsi
<InnerBlocks />Area editor untuk menambahkan nested blocks
allowedBlocksArray block types yang diizinkan di dalamnya
<InnerBlocks.Content />Menyimpan konten nested blocks ke database

JSXBlock: Class PHP yang Reusable ​

Daripada menulis kode registrasi block yang sama berulang-ulang, buat class PHP reusable:

php
class JSXBlock {
    function __construct($name) {
        $this->name = $name;
        add_action('init', [$this, 'onInit']);
    }
    
    function onInit() {
        wp_register_script(
            $this->name,
            get_stylesheet_directory_uri() . "/build/{$this->name}.js",
            array('wp-blocks', 'wp-editor')
        );
        
        register_block_type("ourBlockTheme/{$this->name}", array(
            'editor_script' => $this->name
        ));
    }
}

Penggunaan ​

php
// Cukup satu baris per block!
new JSXBlock("banner");
new JSXBlock("genericHeading");
new JSXBlock("genericButton");

Update package.json ​

Setiap block baru harus ditambahkan sebagai entry point:

json
{
  "scripts": {
    "start": "wp-scripts start src/index.js our-blocks/banner.js our-blocks/genericHeading.js",
    "build": "wp-scripts build src/index.js our-blocks/banner.js our-blocks/genericHeading.js"
  }
}

Generic Heading Block ​

Tujuan ​

Block heading yang bisa:

  • Diedit langsung di editor (RichText)
  • Memilih ukuran: Large (h1), Medium (h2), Small (h3)
  • Mendukung bold dan italic

Attributes ​

js
wp.blocks.registerBlockType("ourBlockTheme/genericHeading", {
  title: "Generic Heading",
  attributes: {
    text: { type: "string" },
    size: { type: "string", default: "large" }
  },
  edit: EditComponent,
  save: SaveComponent
});

Import yang Diperlukan ​

js
import { RichText, BlockControls } from "@wordpress/block-editor";
import { ToolbarGroup, ToolbarButton } from "@wordpress/components";

Edit Component ​

js
function EditComponent(props) {
  function handleTextChange(x) {
    props.setAttributes({ text: x });
  }
  
  return (
    <>
      <BlockControls>
        <ToolbarGroup>
          <ToolbarButton
            isPressed={props.attributes.size === "large"}
            onClick={() => props.setAttributes({ size: "large" })}
          >
            Large
          </ToolbarButton>
          <ToolbarButton
            isPressed={props.attributes.size === "medium"}
            onClick={() => props.setAttributes({ size: "medium" })}
          >
            Medium
          </ToolbarButton>
          <ToolbarButton
            isPressed={props.attributes.size === "small"}
            onClick={() => props.setAttributes({ size: "small" })}
          >
            Small
          </ToolbarButton>
        </ToolbarGroup>
      </BlockControls>
      
      <RichText
        allowedFormats={["core/bold", "core/italic"]}
        tagName="h1"
        className={`headline headline--${props.attributes.size}`}
        value={props.attributes.text}
        onChange={handleTextChange}
      />
    </>
  );
}

Save Component ​

js
function SaveComponent(props) {
  function createTagName() {
    switch (props.attributes.size) {
      case "large":
        return "h1";
      case "medium":
        return "h2";
      case "small":
        return "h3";
    }
  }
  
  return (
    <RichText.Content
      tagName={createTagName()}
      className={`headline headline--${props.attributes.size}`}
      value={props.attributes.text}
    />
  );
}

Komponen-Komponen Penting ​

RichText ​

PropFungsi
valueNilai teks saat ini (dari attributes)
onChangeHandler perubahan teks → setAttributes()
tagNameTag HTML output (h1, h2, p, a, dll.)
classNameClass CSS dengan template literal
allowedFormatsFormat yang diizinkan (core/bold, core/italic)

BlockControls & Toolbar ​

KomponenFungsi
BlockControlsContainer toolbar yang muncul di atas block
ToolbarGroupGrup tombol dalam toolbar
ToolbarButtonTombol individual (Large, Medium, Small)
isPressedBoolean — tombol aktif atau tidak
onClickHandler klik → setAttributes()

RichText.Content (untuk Save) ​

js
<RichText.Content
  tagName={createTagName()}   // Tag HTML dinamis
  className={...}              // Class CSS
  value={props.attributes.text} // Teks yang disimpan
/>

Masalah Block Recovery ​

Jika Anda mengubah output SaveComponent setelah block sudah disimpan di database, WordPress akan mendeteksi perbedaan antara HTML yang tersimpan dan HTML yang diharapkan. Ini menyebabkan pesan error "Attempt Block Recovery".

Ini adalah salah satu alasan mengapa nanti kita akan beralih ke PHP Render Callback — agar perubahan HTML tidak menyebabkan masalah pada post yang sudah ada.


Kesimpulan ​

KonsepPenjelasan
InnerBlocksMenyarangkan block di dalam block lain
allowedBlocksMembatasi block types yang bisa dinest
JSXBlock classClass PHP reusable untuk registrasi block
RichTextKomponen editor teks kaya (bold, italic)
BlockControlsToolbar di atas block untuk opsi (size S/M/L)
isPressedMenandai tombol toolbar yang aktif
Block RecoveryMasalah saat save output berubah setelah block tersimpan