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 is get_template_directory_uri())
  • Because the initialization script lists splide as a dependency, enqueuing mytheme-splide-init alone also loads Splide first
  • Passing an array with in_footer as the fifth argument of wp_register_script() works in WordPress 6.3 and later. On older versions, pass true

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 splide class
  • Inside it, nest splide__track → splide__list → splide__slide in 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_key to _thumbnail_id returns only posts that have a featured image
  • Setting no_found_rows to true skips the row count used for pagination, which makes the query lighter
  • Because WP_Query runs 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 whether splide.min.js returns a 404
  • The arrows or dots look broken: splide.min.css isn't loading, or your theme's CSS (styles for ul or button) conflicts with it. If you use splide-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 than perPage, the clones stand out, so add more posts or switch to type: '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. Put splide.min.js and splide.min.css from dist in your child theme
  • Load them on wp_enqueue_scripts, and list splide as 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 with perPage and breakpoints

Related articles:

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲