I was publishing an article earlier that included a before-and-after image with a slider overlay. While there are numerous plugins available that perform this function, I prefer not to use third-party plugins due to the additional overhead, including limited features and advertisements for upgrades. I like to keep my WordPress instance as lean as possible, so I created a plugin that utilizes WordPress and jQuery to display the before-and-after images.
Before and After Image Slider
Here’s a working demo of the slider:
Here’s the shortcode that produced it:
[before_after before="https://cdn.martech.zone/wp-content/uploads/2025/04/black-white.jpg" after="https://cdn.martech.zone/wp-content/uploads/2025/04/full-color.jpg" width="600"]
How to Install the Before and After Slider Plugin
Follow these steps to install and activate the plugin on your WordPress site:
- Create a new folder in the
wp-content/plugins/
directory and name itbefore-after-slider
. - Create a new file inside that folder and name it
before-after-slider.php
. - Copy and paste the following code into the
before-after-slider.php
file. - Save the file and activate the plugin from the WordPress admin dashboard.
When the page loads:
- If the shortcode is detected, the jQuery script and CSS are injected into the page header.
- The script initializes the slider behavior, setting the handle in the middle (50%) initially.
- Users interact with the handle to reveal more or less of the before or after image dynamically.
post_content, 'before_after' ) ) {
wp_enqueue_script( 'jquery' ); // jQuery is already included in WordPress
wp_add_inline_script( 'jquery', '
jQuery(document).ready(function($) {
$(".ba-slider").each(function() {
var $slider = $(this),
$before = $slider.find(".ba-before"),
$after = $slider.find(".ba-after"),
$handle = $slider.find(".ba-handle");
// Initialize slider position
var initialPercent = 50;
$before.css("clip-path", "inset(0 " + (100 - initialPercent) + "% 0 0)");
$after.css("clip-path", "inset(0 0 0 " + initialPercent + "%)");
$handle.css("left", initialPercent + "%");
// Handle drag and click
$slider.on("mousedown touchstart", function(e) {
e.preventDefault();
var moveHandler = function(moveEvent) {
moveEvent.preventDefault();
var clientX = moveEvent.type.includes("touch") ? moveEvent.originalEvent.touches[0].clientX : moveEvent.clientX,
offsetX = clientX - $slider.offset().left,
percent = Math.max(0, Math.min(100, (offsetX / $slider.width()) * 100));
// Update clip-path for both images
$before.css("clip-path", "inset(0 " + (100 - percent) + "% 0 0)");
$after.css("clip-path", "inset(0 0 0 " + percent + "%)");
$handle.css("left", percent + "%");
};
$(document).on("mousemove touchmove", moveHandler);
$(document).on("mouseup touchend", function() {
$(document).off("mousemove touchmove", moveHandler);
});
});
});
});
' );
// Inline CSS to minimize requests
wp_add_inline_style( 'wp-block-library', '
.ba-slider { position: relative; width: 100%; max-width: 100%; overflow: hidden; }
.ba-slider img { position: absolute; top: 0; left: 0; width: 100%; height: auto; object-fit: cover; object-position: center; }
.ba-before, .ba-after { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
.ba-before img, .ba-after img { width: 100%; height: 100%; }
.ba-handle { position: absolute; top: 0; width: 4px; height: 100%; background: #fff; cursor: ew-resize; box-shadow: 0 0 5px rgba(0,0,0,0.3); z-index: 10; }
.ba-handle::before { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 20px; height: 20px; background: #fff; border-radius: 50%; box-shadow: 0 0 5px rgba(0,0,0,0.3); }
' );
}
}
add_action( 'wp_enqueue_scripts', 'ba_slider_scripts' );
// Shortcode function
function ba_slider_shortcode( $atts ) {
$atts = shortcode_atts( array(
'before' => '',
'after' => '',
'width' => '600',
'height' => '',
), $atts, 'before_after' );
// Sanitize inputs
$before = esc_url( $atts['before'] );
$after = esc_url( $atts['after'] );
$width = esc_attr( $atts['width'] );
$height = $atts['height'] ? 'height: ' . esc_attr( $atts['height'] ) . 'px;' : 'aspect-ratio: 16 / 9;';
if ( ! $before || ! $after ) {
return 'Error: Both before and after images are required.
';
}
// Generate HTML, wrapped in wp-block-image and figure for centering
$output="";
$output .= '';
$output .= ' ';
$output .= ' ';
$output .= '';
return $output;
}
add_shortcode( 'before_after', 'ba_slider_shortcode' );
The first portion of the plugin ensures security and proper environment by exiting immediately if the code is accessed outside of WordPress (if (!defined('ABSPATH')) exit;
).
JavaScript and CSS Loading: The plugin conditionally enqueues JavaScript and CSS only if the current page or post contains the before_after
shortcode. This optimization avoids unnecessarily loading scripts sitewide.
- It hooks into WordPress’s
wp_enqueue_scripts
action to add both:- JavaScript, which uses jQuery to initialize the before/after slider. It:
- Positions the before and after images side-by-side using CSS
clip-path
to reveal or hide parts of each image. - Adds event listeners for mouse and touch events, allowing the visitor to drag a handle horizontally to adjust the visible portions of the before and after images in real-time.
- Updates the handle’s position and dynamically adjusts the visibility of each image based on pointer movement.
- Positions the before and after images side-by-side using CSS
- Inline CSS, which:
- Style the slider container and images to stack correctly with absolute positioning.
- Designs the draggable handle, including a vertical white line and a circular indicator, for improved user experience (UX).
- JavaScript, which uses jQuery to initialize the before/after slider. It:
Shortcode Functionality: The main shortcode function ba_slider_shortcode()
:
- Accepts and sanitizes four optional attributes:
before
(URL of the “before” image),after
(URL of the “after” image),width
(pixel width of the slider),height
(pixel height or defaults to a 16:9 aspect ratio if none is provided).
- Verifies that both
before
andafter
images are supplied; otherwise, it displays an error message. - Constructs the slider HTML structure:
- Wraps the slider in a WordPress
wp-block-image
div and afigure
element for alignment. - Includes the two images and the draggable handle inside a
div
with classba-slider
. - Applies the user-specified width and height/aspect ratio styling inline.
- Wraps the slider in a WordPress