Slideshow Block (3-Layer Nesting & Glide.js)
Arsitektur 3 Layer
Slideshow menggunakan tiga lapisan block yang saling bersarang:
┌─────────────────────────────────────────┐
│ Slideshow (parent terluar) │
│ ┌───────────────────────────────────┐ │
│ │ Slide 1 (= banner block) │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ Generic Heading │ │ │
│ │ │ Generic Button │ │ │
│ │ └─────────────────────────────┘ │ │
│ └───────────────────────────────────┘ │
│ ┌───────────────────────────────────┐ │
│ │ Slide 2 (= banner block) │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ Generic Heading │ │ │
│ │ │ Generic Button │ │ │
│ │ └─────────────────────────────┘ │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘| Layer | Block | Fungsi |
|---|---|---|
| 1 (terluar) | Slideshow | Container semua slide + navigasi dots |
| 2 (tengah) | Slide | Background image per slide (copy dari Banner) |
| 3 (terdalam) | Heading + Button | Konten teks dan link di setiap slide |
Setup di functions.php
php
// Slideshow = JSX block dengan PHP render callback
new JSXBlock("slideshow", true);
// Slide = JSX block dengan PHP render callback (copy dari banner)
new JSXBlock("slide", true);1. Slideshow Block (Parent)
our-blocks/slideshow.js
js
import { InnerBlocks } from "@wordpress/block-editor";
wp.blocks.registerBlockType("ourBlockTheme/slideshow", {
title: "Slideshow",
edit: EditComponent,
save: SaveComponent
});
function EditComponent() {
return (
<div style={{
backgroundColor: "#333",
padding: "35px"
}}>
<p style={{
textAlign: "center",
fontSize: "20px",
color: "#fff"
}}>
Slideshow
</p>
<InnerBlocks allowedBlocks={["ourBlockTheme/slide"]} />
</div>
);
}
function SaveComponent() {
return <InnerBlocks.Content />;
}Catatan: Styling di edit component hanya untuk visual di editor — memberi background gelap agar slide terlihat bersarang di dalam slideshow.
2. Slide Block (Anak = Copy dari Banner)
our-blocks/slide.js
File ini adalah duplikat dari banner.js — hanya nama block yang berbeda:
js
// Sama persis dengan banner.js, hanya ubah:
wp.blocks.registerBlockType("ourBlockTheme/slide", {
title: "Slide",
// ... attributes sama (imageID, imgURL)
// ... edit component sama (MediaUpload, InnerBlocks)
// ... save component sama (InnerBlocks.Content)
});Block slide sudah diprogram untuk hanya mengizinkan heading dan button di dalamnya (sama seperti banner).
3. PHP Render Callbacks
our-blocks/slideshow.php
HTML wrapper untuk Glide.js slideshow library:
php
<div class="hero-slider">
<div data-glide-el="track" class="glide__track">
<div class="glide__slides">
<?php echo $content; ?>
</div>
</div>
<div class="slider__bullets glide__bullets" data-glide-el="controls[nav]">
</div>
</div>
echo $content— di sini semua slide akan di-output (nested InnerBlocks).
our-blocks/slide.php
php
<?php
if (!empty($attributes['themeimage'])) {
$attributes['imgURL'] = get_theme_file_uri('/images/' . $attributes['themeimage']);
}
if (!isset($attributes['imgURL'])) {
$attributes['imgURL'] = get_theme_file_uri('/images/library-hero.jpg');
}
?>
<div class="hero-slider__slide"
style="background-image: url('<?php echo esc_url($attributes['imgURL']); ?>');">
<div class="hero-slider__interior container">
<div class="hero-slider__overlay t-center">
<?php echo $content; ?>
</div>
</div>
</div>Update Edit Component untuk Slide
Agar tampilan editor sama dengan frontend:
js
function EditComponent(props) {
// ... useEffect dan imports sama
return (
<>
<InspectorControls>
{/* ... MediaUpload */}
</InspectorControls>
<div className="hero-slider__slide"
style={{backgroundImage: `url('${props.attributes.imgURL}')`}}>
<div className="hero-slider__interior container">
<div className="hero-slider__overlay t-center">
<InnerBlocks allowedBlocks={[
"ourBlockTheme/genericHeading",
"ourBlockTheme/genericButton"
]} />
</div>
</div>
</div>
</>
);
}Fix: Multiple Slideshows per Halaman
Masalah
JavaScript Glide.js awalnya hanya mencari satu instance slideshow. Jika ada lebih dari satu slideshow di satu halaman, terjadi error:
- Jumlah dots salah (digabung)
- Slideshow kedua tidak berfungsi
Solusi: querySelectorAll + forEach
File src/modules/HeroSlider.js:
js
class HeroSlider {
constructor() {
// ❌ Sebelum (hanya satu instance)
// const el = document.querySelector('.hero-slider');
// if (el) { ... new Glide(el).mount(); }
// ✅ Sesudah (multiple instances)
const allSlideshows = document.querySelectorAll(".hero-slider");
allSlideshows.forEach(function(currentSlideshow) {
// Hitung jumlah slides SPESIFIK untuk slideshow ini
const count = currentSlideshow.querySelectorAll(".hero-slider__slide").length;
if (count) {
// Buat dots navigation
const dotContainer = currentSlideshow.querySelector(".slider__bullets");
for (let i = 0; i < count; i++) {
dotContainer.insertAdjacentHTML(
"beforeend",
`<button class="slider__bullet glide__bullet" data-glide-dir="=${i}"></button>`
);
}
// Initialize Glide untuk slideshow INI (bukan global)
new Glide(currentSlideshow, {
type: "carousel",
perView: 1,
autoplay: 3000
}).mount();
}
});
}
}
export default HeroSlider;Kunci Perubahan
| Sebelum | Sesudah |
|---|---|
document.querySelector('.hero-slider') | document.querySelectorAll('.hero-slider') |
| Satu instance | forEach — loop semua instances |
document.querySelector (child) | currentSlideshow.querySelector (scoped) |
new Glide('.hero-slider') | new Glide(currentSlideshow) |
Alur Kerja Lengkap
1. Buat JSXBlock("slideshow", true) dan JSXBlock("slide", true)
2. slideshow.js → hanya InnerBlocks (allowedBlocks: slide)
3. slide.js → copy dari banner.js (ganti nama saja)
4. slideshow.php → HTML wrapper Glide.js + echo $content
5. slide.php → div dengan background image + echo $content
6. Fix HeroSlider.js → querySelectorAll + forEach
7. Tambahkan kedua file ke package.json entry pointsPackage.json Update
json
{
"scripts": {
"start": "wp-scripts start src/index.js our-blocks/banner.js our-blocks/genericHeading.js our-blocks/genericButton.js our-blocks/slideshow.js our-blocks/slide.js"
}
}Kesimpulan
| Konsep | Penjelasan |
|---|---|
| 3-layer nesting | Slideshow > Slide > Heading + Button |
| Slide = Banner copy | Sama persis, hanya nama berbeda |
allowedBlocks | Slideshow hanya izinkan Slide |
| Glide.js | Library JavaScript untuk slideshow |
querySelectorAll + forEach | Fix untuk multiple slideshows per halaman |
| Scoped querySelector | currentSlideshow.querySelector bukan document.querySelector |
isset() dan empty() | Cek atribut PHP yang mungkin tidak ada |