Content Marketing

WordPress: How To Build a Shortcode Plugin For A Simple Before and After Image Slider

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

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:

  1. Create a new folder in the wp-content/plugins/ directory and name it before-after-slider.
  2. Create a new file inside that folder and name it before-after-slider.php.
  3. Copy and paste the following code into the before-after-slider.php file.
  4. 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="' . $before . '" alt="Before" /></div>';
    $output .= '<div class="ba-after"><img src="' . $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.

Appreciate this content?

Sign up for our weekly newsletter, which delivers our latest posts every Monday morning.

We don’t spam! Read our privacy policy for more info.

Douglas Karr

Douglas Karr is CMO of OpenINSIGHTS and the founder of the Martech Zone. Douglas has helped dozens of successful MarTech startups, has assisted in the due diligence of over $5 bil in Martech acquisitions and investments, and continues to assist companies in implementing and automating their sales and marketing strategies. Douglas is an internationally recognized digital transformation and MarTech expert and speaker. Douglas is also a published author of a Dummie's guide and a business leadership book.

Related Articles

Back to top button
Close

Adblock Detected

We rely on ads and sponsorships to keep Martech Zone free. Please consider disabling your ad blocker—or support us with an affordable, ad-free annual membership ($10 US):

Sign Up For An Annual Membership