If you’re looking to create a custom image slider block in WordPress using the powerful Swiper.js library, you’re in the right place. In this tutorial, we’ll walk through how to build a fully functional, production-ready Gutenberg block that integrates Swiper.js, complete with autoplay, lazy loading, and responsive design. You will learn how to Build Slider block in WordPress seamlessly. This guide will help you understand how to Build Slider block in WordPress effectively.
What You’ll Build
Throughout this article, we will cover all the steps necessary to Build Slider block in WordPress using the latest practices and tools.
A custom Gutenberg block called Swiper Slider Block that allows users to:
- Upload multiple images
- Add captions and links
- Toggle autoplay and adjust speed
- Enjoy a responsive, touch-friendly slider powered by Swiper.js
Folder Structure Overview
Here’s how your plugin should be organized:
swiper-slider-block/
├── build/ # Compiled assets
│ ├── block.js
│ ├── editor.css
│ ├── style.css
│ └── block.json
├── icons/ # Optional SVG icons
│ ├── play.svg
│ └── pause.svg
├── swiper-slider-block.php # Main plugin file
├── readme.txt # Plugin metadata and instructions✅ Only the build/, icons/, and main PHP file are needed for production. Exclude node_modules/ and src/.
Registering the Block
In swiper-slider-block.php, register your block like this:
function swiper_slider_block_register_block() {
register_block_type(__DIR__ . '/build', [
'editor_script' => 'swiper-slider-block-editor-script',
'editor_style' => 'swiper-slider-block-editor-style',
'style' => 'swiper-slider-block-style',
]);
}
add_action('init', 'swiper_slider_block_register_block');Enqueuing Swiper.js
To ensure you can successfully Build Slider block in WordPress, make sure you have the necessary prerequisites installed.
Load Swiper from a CDN and initialize it on the frontend:
function swiper_slider_block_enqueue_assets() {
if (!is_admin()) {
wp_enqueue_style('swiper-css', 'https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css');
wp_enqueue_script('swiper-js', 'https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js', [], null, true);
wp_add_inline_script('swiper-js', "/* Swiper init code here */");
}
}
add_action('enqueue_block_assets', 'swiper_slider_block_enqueue_assets');In this section, we will dive deep into how to Build Slider block in WordPress efficiently and without any hassle.
✅ This ensures Swiper only loads on the frontend, improving editor performance.
Full Plugin Code: Swiper Slider Block
Below is the complete code for your plugin, broken into key files. You can copy and paste these into your project or use them as a reference.
<?php
/**
* Plugin Name: Swiper Slider Block
* Description: A custom Gutenberg block using Swiper.js.
* Version: 1.0
* Author: Your Name
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
function swiper_slider_block_enqueue_assets() {
if (!is_admin()) {
wp_enqueue_style('swiper-css', 'https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css');
wp_enqueue_script('swiper-js', 'https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js', [], null, true);
wp_add_inline_script('swiper-js', "
document.addEventListener('DOMContentLoaded', function () {
setTimeout(function () {
document.querySelectorAll('.mySwiper').forEach(function (el) {
var swiper = new Swiper(el, {
autoplay: el.dataset.autoplay === 'true' ? {
delay: parseInt(el.dataset.speed)
} : false,
loop: true,
slidesPerView: 1,
centeredSlides: false,
spaceBetween: 0,
lazy: {
loadPrevNext: true,
loadOnTransitionStart: true,
checkInView: true
},
preloadImages: false,
observer: true,
observeParents: true,
navigation: {
nextEl: el.querySelector('.swiper-button-next'),
prevEl: el.querySelector('.swiper-button-prev')
},
pagination: {
el: el.querySelector('.swiper-pagination'),
clickable: true
}
});
el.querySelectorAll('.swiper-toggle-image').forEach(function (img) {
img.addEventListener('click', function () {
const slide = img.closest('.swiper-slide');
const isPaused = swiper.autoplay.running;
if (isPaused) {
swiper.autoplay.stop();
slide.classList.add('show-pause');
} else {
swiper.autoplay.start();
slide.classList.add('show-play');
}
setTimeout(() => {
slide.classList.remove('show-pause');
slide.classList.remove('show-play');
}, 1000);
});
});
});
}, 100);
});
");
}
}
add_action('enqueue_block_assets', 'swiper_slider_block_enqueue_assets');
function swiper_slider_block_enqueue_editor_assets() {
wp_register_script(
'swiper-slider-block-editor-script',
plugins_url('build/block.js', __FILE__),
['wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-block-editor'],
filemtime(plugin_dir_path(__FILE__) . 'build/block.js'),
true
);
wp_register_style(
'swiper-slider-block-editor-style',
plugins_url('build/editor.css', __FILE__),
[],
filemtime(plugin_dir_path(__FILE__) . 'build/editor.css')
);
wp_register_style(
'swiper-slider-block-style',
plugins_url('build/style.css', __FILE__),
[],
filemtime(plugin_dir_path(__FILE__) . 'build/style.css')
);
}
add_action('init', 'swiper_slider_block_enqueue_editor_assets');
function swiper_slider_block_register_block() {
register_block_type(__DIR__ . '/build', [
'editor_script' => 'swiper-slider-block-editor-script',
'editor_style' => 'swiper-slider-block-editor-style',
'style' => 'swiper-slider-block-style',
]);
}
add_action('init', 'swiper_slider_block_register_block');
Make sure to follow these steps closely to Build Slider block in WordPress as intended.
Once you have set everything up, you will be ready to Build Slider block in WordPress with ease.
Next, we will summarize the key takeaways from how to Build Slider block in WordPress successfully.
And the Javascript
Edit.js:
const { createElement: el, Fragment } = wp.element;
const { RichText, MediaUpload, InspectorControls } = wp.blockEditor;
const { PanelBody, ToggleControl, RangeControl, Button } = wp.components;
export default function Edit({ attributes, setAttributes }) {
const { slides = [], autoplay, speed } = attributes;
const updateSlide = (index, field, value) => {
const newSlides = slides.map((slide, i) =>
i === index ? { ...slide, [field]: value } : slide
);
setAttributes({ slides: newSlides });
};
const removeSlide = (index) => {
const newSlides = slides.filter((_, i) => i !== index);
setAttributes({ slides: newSlides });
};
return el(
Fragment,
null,
el(
InspectorControls,
null,
el(
PanelBody,
{ title: 'Slider Settings' },
el(ToggleControl, {
label: 'Autoplay',
checked: autoplay,
onChange: (value) => setAttributes({ autoplay: value }),
}),
el(RangeControl, {
label: 'Speed (ms)',
value: speed,
onChange: (value) => setAttributes({ speed: value }),
min: 1000,
max: 10000,
step: 500,
}),
el(MediaUpload, {
onSelect: (mediaList) => {
const newSlides = (Array.isArray(mediaList) ? mediaList : [mediaList]).map(
(media) => ({
image: media.url,
text: '',
linkText: '',
linkUrl: '',
})
);
setAttributes({ slides: newSlides });
},
allowedTypes: ['image'],
multiple: true,
gallery: true,
render: (obj) =>
el(Button, { onClick: obj.open, isPrimary: true }, 'Select Images for Slider'),
})
)
),
el(
'div',
{ className: 'swiper mySwiper' },
el(
'div',
{ className: 'swiper-wrapper' },
slides.map((slide, index) =>
el(
'div',
{ className: 'swiper-slide', key: index },
slide.image &&
el(MediaUpload, {
onSelect: (media) => updateSlide(index, 'image', media.url),
allowedTypes: ['image'],
render: (obj) =>
el('img', {
key: 'img-' + index,
src: slide.image,
onClick: obj.open,
style: {
width: '100%',
height: 'auto',
borderRadius: '12px',
cursor: 'pointer',
},
}),
}),
el('div', { className: 'slide-content' }, [
el(RichText, {
tagName: 'div',
key: 'caption-' + index,
value: slide.text,
onChange: (value) => updateSlide(index, 'text', value),
className: 'swiper-caption',
}),
el('input', {
type: 'text',
key: 'linktext-' + index,
value: slide.linkText,
placeholder: 'Link text (e.g. See John Smith)',
onChange: (e) => updateSlide(index, 'linkText', e.target.value),
style: { marginTop: '8px', width: '100%' },
}),
el('input', {
type: 'url',
key: 'linkurl-' + index,
value: slide.linkUrl,
placeholder: 'https://example.com',
onChange: (e) => updateSlide(index, 'linkUrl', e.target.value),
style: { marginTop: '4px', width: '100%' },
}),
el(
Button,
{
isDestructive: true,
key: 'remove-' + index,
onClick: () => removeSlide(index),
style: { marginTop: '8px' },
},
'Remove Slide'
),
])
)
),
el(MediaUpload, {
onSelect: (media) => {
const newSlide = {
image: media.url,
text: '',
linkText: '',
linkUrl: '',
};
setAttributes({ slides: [...slides, newSlide] });
},
allowedTypes: ['image'],
render: (obj) =>
el(
Button,
{ onClick: obj.open, isSecondary: true, style: { marginTop: '16px' } },
'Add Image'
),
})
)
)
);
}Save.js
const { createElement: el } = wp.element;
const { RichText } = wp.blockEditor;
export default function Save({ attributes }) {
const { slides = [], autoplay, speed } = attributes;
return el(
'div',
{
className: 'swiper mySwiper',
'data-autoplay': autoplay,
'data-speed': speed,
},
el(
'div',
{ className: 'swiper-wrapper' },
slides.map((slide, index) =>
el(
'div',
{ className: 'swiper-slide', key: index },
[
slide.image &&
el('img', {
key: 'img-' + index,
src: slide.image,
className: 'swiper-toggle-image swiper-lazy',
loading: 'lazy',
style: {
width: '100%',
height: 'auto',
borderRadius: '12px',
cursor: 'pointer',
},
}),
el('div', {
key: 'preloader-' + index,
className: 'swiper-lazy-preloader',
}),
el(RichText.Content, {
key: 'caption-' + index,
tagName: 'div',
value: slide.text,
className: 'swiper-caption',
}),
slide.linkText &&
slide.linkUrl &&
el(
'a',
{
key: 'link-' + index,
href: slide.linkUrl,
className: 'swiper-link',
target: '_blank',
rel: 'noopener noreferrer',
},
slide.linkText
),
el('div', {
key: 'feedback-' + index,
className: 'swiper-feedback-icon',
}),
]
)
)
),
el('div', { className: 'swiper-button-prev' }),
el('div', { className: 'swiper-button-next' }),
el('div', { className: 'swiper-pagination' })
);
}Styling Your Swiper Slider Block with CSS
To make your slider look polished and responsive, you’ll want to include some custom CSS alongside Swiper’s default styles. Here’s a basic setup you can include in your editor.css and style.css files inside the build/ folder.
📁 File Locations
build/editor.css→ styles for the block editorbuild/style.css→ styles for the frontend
Base Block Styling
.swiper.mySwiper {
width: 100%;
max-width: 100%;
margin: 0 auto;
position: relative;
}
.swiper-slide {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 16px;
box-sizing: border-box;
}
.swiper-slide img {
width: 100%;
height: auto;
border-radius: 12px;
cursor: pointer;
transition: transform 0.3s ease;
}
.swiper-slide img:hover {
transform: scale(1.02);
}Caption and Link Styling
.swiper-caption {
margin-top: 12px;
font-size: 1rem;
color: #333;
}
.swiper-link {
display: inline-block;
margin-top: 8px;
font-weight: bold;
color: #0073aa;
text-decoration: none;
}
.swiper-link:hover {
text-decoration: underline;
}Navigation and Pagination
.swiper-button-next,
.swiper-button-prev {
color: #0073aa;
}
.swiper-pagination-bullet {
background: #0073aa;
opacity: 0.6;
}
.swiper-pagination-bullet-active {
opacity: 1;
}If you’re using SVG icons for play/pause feedback:
.swiper-slide.show-play::after,
.swiper-slide.show-pause::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 48px;
height: 48px;
background-size: contain;
background-repeat: no-repeat;
transform: translate(-50%, -50%);
z-index: 10;
}
.swiper-slide.show-play::after {
background-image: url('../icons/play-svgrepo-com.svg');
}
.swiper-slide.show-pause::after {
background-image: url('../icons/pause-svgrepo-com.svg');
}
✅ Make sure your icons are placed in the icons/ folder and properly referenced relative to your CSS file.
Building the Block (JSX or createElement)
Use @wordpress/create-block or your own src/ folder to build the block. Then compile it into the build/ folder using wp-scripts.
Make sure your edit.js and save.js handle:
slides.map()with uniquekeyprops- Conditional rendering of
<img>and<a>tags - Block attributes like
autoplay,speed,text,linkText, andlinkUrl
WordPress Plugin Requirements Checklist
✅ GPL-compatible license
✅ No minified files without source
✅ No tracking or obfuscated code
✅ Works independently
✅ External libraries (Swiper.js) disclosed
✅ Responsive and accessible design
✅ readme.txt with proper metadata
Deploying Your Plugin
- Zip your plugin folder (excluding
node_modules/,src/, etc.) - Upload it to
/wp-content/plugins/or submit it to WordPress.org - Activate and enjoy your custom Swiper-powered block!
Final Thoughts
You’ve now built a modern, responsive Gutenberg block using Swiper.js—perfect for portfolios, galleries, or product showcases. With a clean structure, CDN-powered performance, and WordPress compliance, your plugin is ready for production or public release.
Please use the Code above as REFERENCE. It doesn’t guarantee functionality. It might be different according to your system.
With these insights, you should now feel confident to Build Slider block in WordPress and implement it in your projects.
