2026年11月12日
2026年11月12日
Add a Splide Slider to WordPress: Theme Setup and a Post Slider
This article is a localized edition of the Japanese original. Read the Japanese original
Splide is a JavaScript slider (carousel) library with no dependencies such as jQuery. It is MIT-licensed, and you turn markup into a slider just by loading its files and adding a few specific classes to your HTML.
This article shows how to build Splide into a theme (a child theme) without a plugin and display your latest posts in a slider. As of October 2026, the latest Splide release is 4.1.4 (published November 2022), and the code here assumes that version.
What you will build
- A slider on the front page that shows up to six recent posts that have a featured image
- Three slides at a time on desktop, two on tablets, and one on phones
- Slides advance automatically at a set interval and pause when you hover over them
If you edit the parent theme directly, your changes are lost when the theme updates. Put the files below in a child theme. To create one, see How to create a WordPress child theme correctly.
The file layout looks like this:
wp-content/themes/your-child-theme/
├── functions.php
├── front-page.php ← template that shows the slider (classic theme)
├── template-parts/
│ └── splide-posts.php ← the slider HTML
└── assets/
├── splide/
│ ├── splide.min.js
│ └── splide.min.css
└── js/
└── splide-init.js ← initialization script
Step 1: Get the Splide files
Splide's distribution files are in the dist folder of the npm package @splidejs/splide. You need two of them: dist/js/splide.min.js and dist/css/splide.min.css.
If you can use npm, install the package in a working folder and copy the files into your child theme.
# Install in a working folder (pin the version)
npm install @splidejs/splide@4.1.4
# Copy the distribution files into the child theme
mkdir -p wp-content/themes/your-child-theme/assets/splide
cp node_modules/@splidejs/splide/dist/js/splide.min.js wp-content/themes/your-child-theme/assets/splide/
cp node_modules/@splidejs/splide/dist/css/splide.min.css wp-content/themes/your-child-theme/assets/splide/
The package name is @splidejs/splide. The splide package that npm install splide installs is a different package (an empty security placeholder), so watch out.
If you don't use npm, you can save the files from jsDelivr instead. In production, use URLs that pin the version.
https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/js/splide.min.js
https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/css/splide.min.css
dist/css also contains splide-core.min.css, which leaves out the styling for arrows and pagination. Use it if you plan to design everything yourself.
Step 2: Load the script and CSS in functions.php
In WordPress, you don't write <script> tags by hand for JavaScript and CSS; you register and load them on the wp_enqueue_scripts hook. Add the following code to your child theme's functions.php.
<?php
add_action( 'wp_enqueue_scripts', function () {
$uri = get_stylesheet_directory_uri();
// Register Splide itself
wp_register_style( 'splide', $uri . '/assets/splide/splide.min.css', array(), '4.1.4' );
wp_register_script( 'splide', $uri . '/assets/splide/splide.min.js', array(), '4.1.4', array( 'in_footer' => true ) );
// Initialization script (loaded after Splide)
wp_register_script( 'mytheme-splide-init', $uri . '/assets/js/splide-init.js', array( 'splide' ), '1.0.0', array( 'in_footer' => true ) );
// Load only on the front page, where the slider lives
if ( is_front_page() ) {
wp_enqueue_style( 'splide' );
wp_enqueue_script( 'mytheme-splide-init' );
}
} );
get_stylesheet_directory_uri()returns the URL of the child theme folder (the parent theme folder isget_template_directory_uri())- Because the initialization script lists
splideas a dependency, enqueuingmytheme-splide-initalone also loads Splide first - Passing an array with
in_footeras the fifth argument ofwp_register_script()works in WordPress 6.3 and later. On older versions, passtrue
The basics of loading scripts are also covered in How to load JS and CSS with wp_enqueue_scripts in WordPress.
Step 3: Build the slider HTML
Splide turns HTML with the following structure into a slider:
- The outermost element has the
splideclass - Inside it, nest
splide__track→splide__list→splide__slidein that order
If the outermost element is a section, give the slider a name for screen readers with aria-label (recommended in Splide's official guide).
Create a template part that lists recent posts as template-parts/splide-posts.php.
<?php
// Get up to six recent posts that have a featured image
$slider_query = new WP_Query(
array(
'post_type' => 'post',
'posts_per_page' => 6,
'ignore_sticky_posts' => true,
'no_found_rows' => true,
'meta_key' => '_thumbnail_id',
)
);
if ( ! $slider_query->have_posts() ) {
return;
}
?>
<section class="splide js-post-slider" aria-label="Latest posts">
<div class="splide__track">
<ul class="splide__list">
<?php while ( $slider_query->have_posts() ) : $slider_query->the_post(); ?>
<li class="splide__slide">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail( 'medium_large' ); ?>
<span class="slide-title"><?php the_title(); ?></span>
</a>
</li>
<?php endwhile; ?>
</ul>
</div>
</section>
<?php
wp_reset_postdata();
- Setting
meta_keyto_thumbnail_idreturns only posts that have a featured image - Setting
no_found_rowstotrueskips the row count used for pagination, which makes the query lighter - Because
WP_Queryruns outside the main loop,wp_reset_postdata()restores the global post data at the end
In a classic theme, add this one line where you want the slider (in this example, the child theme's front-page.php):
<?php get_template_part( 'template-parts/splide-posts' ); ?>
For more ways to filter posts with WP_Query, see How to get posts with WP_Query in WordPress.
Step 4: Start the slider with an initialization script
Create assets/js/splide-init.js to start Splide. Calling new Splide( element, options ).mount() brings the slider to life.
document.addEventListener( 'DOMContentLoaded', function () {
document.querySelectorAll( '.js-post-slider' ).forEach( function ( el ) {
new Splide( el, {
type: 'loop', // after the last slide, go back to the first (loop)
perPage: 3, // number of slides shown at once
perMove: 1, // number of slides moved per action
gap: '1.5rem', // space between slides
speed: 500, // transition duration (ms)
autoplay: true, // advance automatically
interval: 5000, // autoplay interval (ms)
pauseOnHover: true, // pause while the mouse is over the slider
breakpoints: {
1024: { perPage: 2 },
640: { perPage: 1, gap: '1rem' },
},
} ).mount();
} );
} );
With the default setting (mediaQuery: 'max'), each breakpoints entry applies when the screen width is at or below that value. In this example, the slider shows two slides at 1024px and below, and one slide at 640px and below.
To give images a consistent size, add CSS like the following to your child theme's style.css or similar.
.js-post-slider img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.js-post-slider .slide-title {
display: block;
margin-top: 0.5rem;
}
Commonly used options
| Option | Default | What it does |
|---|---|---|
type |
'slide' |
'slide' (normal), 'loop' (loop), 'fade' (fade; one slide at a time) |
perPage |
1 |
Number of slides shown at once |
perMove |
None | Number of slides moved per action. If not set, the slider moves by perPage slides |
gap |
None | Space between slides (such as '1rem', or a number in pixels) |
speed |
400 |
Transition duration (ms) |
rewind |
false |
With 'slide', lets the slider rewind from the last slide to the first |
autoplay |
false |
Advance automatically |
interval |
5000 |
Autoplay interval (ms) |
pauseOnHover |
true |
Pause autoplay while the mouse is over the slider |
arrows |
true |
Show previous/next arrows |
pagination |
true |
Show pagination dots |
lazyLoad |
false |
Lazy-load images ('nearby' or 'sequential') |
breakpoints |
None | Change options by screen width |
The full list is on the Options page of the official Splide site. Options such as perPageMove, which appeared in an earlier version of this article, do not exist, so check option names against the official list.
Change the labels read by screen readers
The arrow and pagination buttons carry English labels for screen readers (for example, Next slide). To use your own wording, or your site's language, replace them with the i18n option.
new Splide( el, {
i18n: {
prev: 'Previous post',
next: 'Next post',
first: 'Go to the first post',
last: 'Go to the last post',
slideX: 'Go to post %s',
pageX: 'Go to page %s',
play: 'Start the slideshow',
pause: 'Pause the slideshow',
},
} ).mount();
Using it with a block theme
Block themes such as Twenty Twenty-Five have no PHP templates like front-page.php, so there is nowhere to put the get_template_part() call from Step 3. In that case, you can register the template part as a shortcode and call it from the "Shortcode" block in the Site Editor. Keep the registration part of the Step 2 code (wp_register_style() and wp_register_script()) as is.
<?php
function mytheme_post_slider_shortcode() {
// Load the assets only when the shortcode is used
wp_enqueue_style( 'splide' );
wp_enqueue_script( 'mytheme-splide-init' );
ob_start();
get_template_part( 'template-parts/splide-posts' );
return ob_get_clean();
}
add_shortcode( 'post_slider', 'mytheme_post_slider_shortcode' );
In the Shortcode block, enter post_slider wrapped in square brackets. With this method, the CSS loads at the end of the page, so you may briefly see the slider before its styling is applied. If that bothers you, load the CSS early with the is_front_page() condition from Step 2.
When it doesn’t work
- The slides stay stacked vertically: Splide's JavaScript isn't loading, or initialization is failing. Check the browser developer tools "Console" for errors such as
Splide is not defined, and check "Network" to see whethersplide.min.jsreturns a 404 - The arrows or dots look broken:
splide.min.cssisn't loading, or your theme's CSS (styles forulorbutton) conflicts with it. If you usesplide-core.min.css, you need to provide your own styling for the arrows and other controls - The same slide appears repeatedly in loop mode:
type: 'loop'displays clones of the slides. When there are fewer posts thanperPage, the clones stand out, so add more posts or switch totype: 'slide' - It doesn't work on pages other than the front page: Because of the
is_front_page()condition in Step 2, the files aren't loaded on other pages. Change the condition to match the pages where you show the slider
Summary
- Splide's npm package name is
@splidejs/splide. Putsplide.min.jsandsplide.min.cssfromdistin your child theme - Load them on
wp_enqueue_scripts, and listsplideas a dependency of the initialization script - Output HTML with the structure
splide→splide__track→splide__list→splide__slide - Start the slider with
new Splide( element, options ).mount(), and adjust the number of visible slides withperPageandbreakpoints
Related articles:
- How to load JS and CSS with wp_enqueue_scripts in WordPress
- How to get posts with WP_Query in WordPress
- How to build a slider with Swiper.js in WordPress
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)