Mobile Swiper Slider Code
May 6, 2025 · AI Conversations
widget will have
image,text repeatwer field
—
### 🧩 Elementor Widget Code (PHP)
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class Mobile_Steps_Slider_Widget extends ElementorWidget_Base {
public function get_name() {
return 'mobile_steps_slider';
}
public function get_title() {
return __('Mobile Steps Slider', 'custom-widgets');
}
public function get_icon() {
return 'eicon-slider-device';
}
public function get_categories() {
return ['general'];
}
protected function _register_controls() {
$this->start_controls_section('steps_section', [
'label' => __('Steps Items', 'custom-widgets'),
]);
$repeater = new ElementorRepeater();
$repeater->add_control('step_image', [
'label' => __('Step Image', 'custom-widgets'),
'type' => ElementorControls_Manager::MEDIA,
'default' => [
'url' => ElementorUtils::get_placeholder_image_src(),
],
]);
$repeater->add_control('step_text', [
'label' => __('Step Text', 'custom-widgets'),
'type' => ElementorControls_Manager::TEXT,
'default' => __('Sample Step Text', 'custom-widgets'),
]);
$this->add_control('steps', [
'label' => __('Steps', 'custom-widgets'),
'type' => ElementorControls_Manager::REPEATER,
'fields' => $repeater->get_controls(),
'default' => [],
]);
$this->end_controls_section();
}
protected function render() {
$settings = $this->get_settings_for_display();
if ( empty($settings['steps']) ) {
return;
}
?>
<div class="mobile-steps-slider-wrapper">
<div class="swiper mobile-steps-swiper">
<div class="swiper-wrapper">
<?php foreach ( $settings['steps'] as $step ) : ?>
<div class="swiper-slide step-slide">
<div class="step-item">
<img src="<?php echo esc_url($step['step_image']['url']); ?>" alt="Step">
<p><?php echo esc_html($step['step_text']); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<style>
@media (max-width: 767px) {
.mobile-steps-slider-wrapper {
padding: 20px 0;
}
.step-item {
text-align: center;
}
.step-item img {
max-width: 100px;
margin: 0 auto 10px;
}
.step-item p {
font-size: 16px;
color: #333;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
if (window.innerWidth <= 767) {
new Swiper('.mobile-steps-swiper', {
loop: false,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
spaceBetween: 20,
});
}
});
</script>
<?php
}
}
—
### ✅ Dependencies
Ensure **Swiper JS** and **CSS** are loaded globally or enqueue them in your theme/plugin:
function enqueue_swiper_assets() {
wp_enqueue_style('swiper-css', 'https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css');
wp_enqueue_script('swiper-js', 'https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js', [], null, true);
}
add_action('wp_enqueue_scripts', 'enqueue_swiper_assets');
—
Would you like me to convert this into a zip-ready plugin format?
—
### ✅ Final Elementor Widget with Swiper CDN
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class Mobile_Steps_Slider_Widget extends ElementorWidget_Base {
public function get_name() {
return 'mobile_steps_slider';
}
public function get_title() {
return __('Mobile Steps Slider', 'custom-widgets');
}
public function get_icon() {
return 'eicon-slider-device';
}
public function get_categories() {
return ['general'];
}
protected function _register_controls() {
$this->start_controls_section('steps_section', [
'label' => __('Steps Items', 'custom-widgets'),
]);
$repeater = new ElementorRepeater();
$repeater->add_control('step_image', [
'label' => __('Step Image', 'custom-widgets'),
'type' => ElementorControls_Manager::MEDIA,
'default' => [
'url' => ElementorUtils::get_placeholder_image_src(),
],
]);
$repeater->add_control('step_text', [
'label' => __('Step Text', 'custom-widgets'),
'type' => ElementorControls_Manager::TEXT,
'default' => __('Sample Step Text', 'custom-widgets'),
]);
$this->add_control('steps', [
'label' => __('Steps', 'custom-widgets'),
'type' => ElementorControls_Manager::REPEATER,
'fields' => $repeater->get_controls(),
'default' => [],
]);
$this->end_controls_section();
}
protected function render() {
$settings = $this->get_settings_for_display();
if ( empty($settings['steps']) ) {
return;
}
?>
<div class="mobile-steps-slider-wrapper">
<div class="swiper mobile-steps-swiper">
<div class="swiper-wrapper">
<?php foreach ( $settings['steps'] as $step ) : ?>
<div class="swiper-slide step-slide">
<div class="step-item">
<img src="<?php echo esc_url($step['step_image']['url']); ?>" alt="Step">
<p><?php echo esc_html($step['step_text']); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<!-- Swiper CDN (JS + CSS) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
<style>
@media (max-width: 767px) {
.mobile-steps-slider-wrapper {
padding: 20px 0;
}
.step-item {
text-align: center;
padding: 10px;
}
.step-item img {
max-width: 80px;
margin: 0 auto 10px;
display: block;
}
.step-item p {
font-size: 15px;
color: #333;
margin: 0;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
if (window.innerWidth <= 767) {
new Swiper('.mobile-steps-swiper', {
loop: false,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
spaceBetween: 20,
});
}
});
</script>
<?php
}
}
—
You can now:
– Add this widget to your custom Elementor plugin.
– Upload images and step titles.
– The slider activates only on mobile (≤767px).
Would you like this as a zip plugin or should I help register this widget inside your custom plugin structure?
– Circular red background
– Icon/image centered inside the circle
– Text below
– Dashed curved connector (as close as possible in slider)
– White border ring
—
### ✅ Updated CSS inside widget (`render()` method):
Replace your “ block with this:
<style>
@media (max-width: 767px) {
.mobile-steps-slider-wrapper {
padding: 20px 0;
}
.swiper-slide.step-slide {
display: flex;
justify-content: center;
}
.step-item {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.step-item img {
width: 64px;
height: 64px;
background-color: #e9205a; /* Main red color */
border-radius: 50%;
padding: 14px;
border: 5px solid #fff;
box-shadow: 0 0 0 4px #e9205a;
object-fit: contain;
}
.step-item::after {
content: '';
position: absolute;
top: 32px;
right: -50%;
width: 100%;
height: 2px;
border-top: 2px dashed #e9205a;
z-index: -1;
}
.swiper-slide:last-child .step-item::after {
display: none;
}
.step-item p {
margin-top: 15px;
font-size: 14px;
font-weight: 500;
color: #1a1a1a;
text-align: center;
max-width: 120px;
}
}
</style>
—
### 🔁 Resulting Look on Mobile:
– Each step appears in a centered circle.
– Red/pink background with white ring border.
– Dotted line connecting to the next step (simulated with `::after`).
– Text is clean and clear underneath.
Let me know if you'd like:
– **A curved SVG path connector** like your image (requires custom SVG).
– **Different icons or shadow/glow effects.**
– This packed as a **ready-to-install Elementor plugin zip**.
<style>
.mobile-steps-slider-wrapper
{
display: none;
}
@media (max-width: 767px) {
.mobile-steps-slider-wrapper {
padding: 20px 0;
display: flex;
}
.swiper-slide.step-slide {
display: flex;
justify-content: center;
}
.step-item {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.step-item img {
width: 64px;
height: 64px;
background-color: #e9205a; /* Main red color */
border-radius: 50%;
padding: 14px;
border: 5px solid #fff;
box-shadow: 0 0 0 4px #e9205a;
object-fit: contain;
}
.step-item::after {
content: '';
position: absolute;
top: 32px;
right: -50%;
width: 100%;
height: 2px;
border-top: 2px dashed #e9205a;
z-index: -1;
}
.swiper-slide:last-child .step-item::after {
display: none;
}
.step-item p {
margin-top: 15px;
font-size: 14px;
font-weight: 500;
color: #1a1a1a;
text-align: center;
max-width: 120px;
}
}
</style>
<script>
</script>
<script>
document.addEventListener('DOMContentLoaded', function () {
new Swiper('.mobile-steps-swiper', {
slidesPerView: 1,
spaceBetween: 30,
loop: true,
breakpoints: {
0: { slidesPerView: 1 },
}
});
});
</script>
Also, you’re missing the `swiper-container` class on the main Swiper wrapper, and the slider CSS is hidden by default (`display: none`) unless the viewport is under 767px, but there’s no guarantee that Swiper sees it in time.
—
### ✅ Here's a corrected and working version:
Update the **render** function with these fixes:
1. Ensure `.swiper` is initialized only after it's visible.
2. Add a check for Elementor frontend/editor.
3. Use correct class hooks (`swiper` and `swiper-wrapper` are already correct).
4. Ensure `display: block` kicks in only after DOM is ready.
—
### ✅ Final Fixed `render()` Function:
Replace your `render()` content with this version:
protected function render() {
$settings = $this->get_settings_for_display();
if ( empty($settings['steps']) ) {
return;
}
?>
<style>
@media (max-width: 767px) {
.mobile-steps-slider-wrapper {
padding: 20px 0;
display: block;
}
.swiper-slide.step-slide {
display: flex;
justify-content: center;
}
.step-item {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.step-item img {
width: 64px;
height: 64px;
background-color: #e9205a;
border-radius: 50%;
padding: 14px;
border: 5px solid #fff;
box-shadow: 0 0 0 4px #e9205a;
object-fit: contain;
}
.step-item::after {
content: '';
position: absolute;
top: 32px;
right: -50%;
width: 100%;
height: 2px;
border-top: 2px dashed #e9205a;
z-index: -1;
}
.swiper-slide:last-child .step-item::after {
display: none;
}
.step-item p {
margin-top: 15px;
font-size: 14px;
font-weight: 500;
color: #1a1a1a;
text-align: center;
max-width: 120px;
}
}
@media (min-width: 768px) {
.mobile-steps-slider-wrapper {
display: none;
}
}
</style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
<div class="mobile-steps-slider-wrapper">
<div class="swiper mobile-steps-swiper">
<div class="swiper-wrapper">
<?php foreach ( $settings['steps'] as $step ) : ?>
<div class="swiper-slide step-slide">
<div class="step-item">
<img src="<?php echo esc_url($step['step_image']['url']); ?>" alt="Step">
<p><?php echo esc_html($step['step_text']); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
<script>
(function(){
function initSwiper() {
if (window.innerWidth <= 767) {
new Swiper('.mobile-steps-swiper', {
loop: false,
spaceBetween: 30,
slidesPerView: 1,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
});
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSwiper);
} else {
initSwiper();
}
// Also initialize in Elementor editor mode
jQuery(window).on('elementor/frontend/init', function() {
elementorFrontend.hooks.addAction('frontend/element_ready/widget', function($scope) {
if ($scope.find('.mobile-steps-swiper').length > 0) {
initSwiper();
}
});
});
})();
</script>
<?php
}
—
Let me know if you'd like a desktop version or continuous curved path between circles like in the image (can be done using SVG overlays).
– Repeater for image + text.
– Owl Carousel initialized on frontend.
– Matching design from your screenshot.
– CDN for Owl Carousel CSS/JS is embedded.
—
### ✅ Final Elementor Widget Using Owl Carousel
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class Mobile_Steps_Slider_Widget extends ElementorWidget_Base {
public function get_name() {
return 'mobile_steps_slider';
}
public function get_title() {
return __('Mobile Steps Slider', 'custom-widgets');
}
public function get_icon() {
return 'eicon-slider-device';
}
public function get_categories() {
return ['general'];
}
protected function _register_controls() {
$this->start_controls_section('steps_section', [
'label' => __('Steps Items', 'custom-widgets'),
]);
$repeater = new ElementorRepeater();
$repeater->add_control('step_image', [
'label' => __('Step Image', 'custom-widgets'),
'type' => ElementorControls_Manager::MEDIA,
'default' => ['url' => ElementorUtils::get_placeholder_image_src()],
]);
$repeater->add_control('step_text', [
'label' => __('Step Text', 'custom-widgets'),
'type' => ElementorControls_Manager::TEXT,
'default' => __('Sample Step Text', 'custom-widgets'),
]);
$this->add_control('steps', [
'label' => __('Steps', 'custom-widgets'),
'type' => ElementorControls_Manager::REPEATER,
'fields' => $repeater->get_controls(),
'default' => [],
]);
$this->end_controls_section();
}
protected function render() {
$settings = $this->get_settings_for_display();
if (empty($settings['steps'])) {
return;
}
?>
<!-- Owl Carousel CSS/JS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/owl.carousel@2.3.4/dist/assets/owl.carousel.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/owl.carousel@2.3.4/dist/assets/owl.theme.default.min.css" />
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/owl.carousel@2.3.4/dist/owl.carousel.min.js"></script>
<style>
@media (max-width: 767px) {
.mobile-steps-slider-wrapper {
padding: 20px 0;
display: block;
}
.owl-carousel .item {
text-align: center;
}
.step-item {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.step-item img {
width: 64px;
height: 64px;
background-color: #e9205a;
border-radius: 50%;
padding: 14px;
border: 5px solid #fff;
box-shadow: 0 0 0 4px #e9205a;
object-fit: contain;
}
.step-item p {
margin-top: 15px;
font-size: 14px;
font-weight: 500;
color: #1a1a1a;
max-width: 120px;
}
}
@media (min-width: 768px) {
.mobile-steps-slider-wrapper {
display: none;
}
}
</style>
<div class="mobile-steps-slider-wrapper">
<div class="owl-carousel owl-theme" id="mobile-steps-carousel">
<?php foreach ($settings['steps'] as $step) : ?>
<div class="item">
<div class="step-item">
<img src="<?php echo esc_url($step['step_image']['url']); ?>" alt="Step">
<p><?php echo esc_html($step['step_text']); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<script>
jQuery(document).ready(function($) {
if (window.innerWidth <= 767) {
$('#mobile-steps-carousel').owlCarousel({
loop: false,
margin: 20,
nav: false,
dots: true,
items: 1,
});
}
});
</script>
<?php
}
}
—
### ✅ Usage Notes:
– Add this to your custom Elementor widget plugin.
– Now uses **Owl Carousel** for better mobile compatibility.
– Only visible for screens ≤767px.
– Fully styled to match your circular red icons layout.
Would you like the desktop version shown as a horizontal flex layout instead of slider?
The style includes:
– A **solid red inner circle**
– An **outer semi-transparent pink border ring**
– **Pink dots** at top-left and bottom-left
– A **dashed line connector** to the next item
—
### ✅ Updated CSS (Use Inside Widget `render()` Function)
Replace your current “ block with this one:
<style>
@media (max-width: 767px) {
.mobile-steps-slider-wrapper {
padding: 20px 0;
display: block;
}
.owl-carousel .item {
text-align: center;
position: relative;
}
.step-item {
position: relative;
width: 120px;
height: 120px;
margin: auto;
}
.step-circle {
width: 100px;
height: 100px;
border-radius: 50%;
background-color: #e9205a;
border: 4px solid white;
box-shadow: 0 0 0 5px rgba(233, 32, 90, 0.5);
display: flex;
align-items: center;
justify-content: center;
margin: auto;
position: relative;
z-index: 1;
}
.step-circle img {
max-width: 40px;
max-height: 40px;
filter: brightness(0) invert(1); /* turns icon white */
}
.dot {
width: 10px;
height: 10px;
background-color: #e9205a;
border-radius: 50%;
position: absolute;
z-index: 2;
}
.dot.top-left {
top: -8px;
left: -8px;
}
.dot.bottom-left {
bottom: -8px;
left: -8px;
}
.dashed-line {
position: absolute;
top: 50%;
left: 100%;
width: 40px;
height: 1px;
border-top: 2px dashed #e9205a;
z-index: 0;
transform: translateY(-50%);
}
.step-item p {
margin-top: 20px;
font-size: 14px;
font-weight: 500;
color: #1a1a1a;
text-align: center;
max-width: 120px;
}
.owl-carousel .item:last-child .dashed-line {
display: none;
}
}
@media (min-width: 768px) {
.mobile-steps-slider-wrapper {
display: none;
}
}
</style>
—
### ✅ Update HTML in the `render()` function:
Replace this part:
<div class="step-item">
<img src="<?php echo esc_url($step['step_image']['url']); ?>" alt="Step">
<p><?php echo esc_html($step['step_text']); ?></p>
</div>
With this:
<div class="step-item">
<div class="dot top-left"></div>
<div class="dot bottom-left"></div>
<div class="step-circle">
<img src="<?php echo esc_url($step['step_image']['url']); ?>" alt="Step">
</div>
<div class="dashed-line"></div>
<p><?php echo esc_html($step['step_text']); ?></p>
</div>
—
### ✅ Final Touches
– Ensure uploaded images (icons) are **transparent SVG or PNG** for best results.
– The white icon is achieved with `filter: brightness(0) invert(1)`.
Would you like me to provide this as a ready-to-import Elementor widget/plugin zip file?