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:
[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″]
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 it before-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.
<?php
/**
* Plugin Name: Before and After Shortcode
* Plugin URI: https://dknewmedia.com
* Description: A simple shortcode to add a before and after slider over an image.
* Version: 1.0
* Author: Douglas Karr
* Author URI: https://dknewmedia.com
* License: GPL-2.0+
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined(‘ABSPATH’)) {
exit; // Exit if accessed directly.
}
function ba_slider_scripts() {
global $post;
if ( is_a( $post, ‘WP_Post’ ) && has_shortcode( $post->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 ‘<p>Error: Both before and after images are required.</p>’;
}
// Generate HTML, wrapped in wp-block-image and figure for centering
$output = ‘<div class=”wp-block-image”>’;
$output .= ‘<figure class=”aligncenter size-full”>’;
$output .= ‘<div class=”ba-slider” style=”width: ‘ . $width . ‘px; max-width: 100%; ‘ . $height . ‘”>’;
$output .= ‘<div class=”ba-before”><img src=”https://martech.zone’ . $before . ‘” alt=”Before” /></div>’;
$output .= ‘<div class=”ba-after”><img src=”https://martech.zone’ . $after . ‘” alt=”After” /></div>’;
$output .= ‘<div class=”ba-handle”></div>’;
$output .= ‘</div>’;
$output .= ‘</figure>’;
$output .= ‘</div>’;
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.
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).
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 and after 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 a figure element for alignment.
Includes the two images and the draggable handle inside a div with class ba-slider.
Applies the user-specified width and height/aspect ratio styling inline.
©2025 DK New Media, LLC, All rights reserved | Disclosure
Originally Published on Martech Zone: WordPress: How To Build a Shortcode Plugin For A Simple Before and After Image Slider