آموزش ساخت Progress Bar ارسال رایگان در ووکامرس بدون افزونه
نوار پیشرفت ارسال رایگان ووکامرس چیست؟
نوار پیشرفت ارسال رایگان ووکامرس یک قابلیت کاربردی برای فروشگاههای اینترنتی است که به کاربر نشان میدهد چقدر دیگر باید خرید کند تا امکان ارسال رایگان برای او فعال شود.
فرض کن حداقل مبلغ ارسال رایگان در فروشگاه روی ۲ میلیون تومان تنظیم شده باشد و کاربر تا این لحظه ۱ میلیون و ۴۰۰ هزار تومان محصول به سبد خرید اضافه کرده باشد. در این حالت، این نوار به کاربر نمایش میدهد که مثلاً:
فقط ۶۰۰ هزار تومان دیگر تا ارسال رایگان باقی مانده است.
همین پیام ساده میتواند کاربر را تشویق کند یک محصول دیگر به سبد خرید اضافه کند تا به حد نصاب ارسال رایگان برسد. به همین دلیل، این قابلیت فقط یک المان ظاهری نیست؛ بلکه میتواند روی افزایش میانگین سبد خرید و در نهایت فروش بیشتر فروشگاه اثرگذار باشد.
اگر در حال یادگیری توسعه سایتهای وردپرسی هستی، پیشنهاد میکنم حتماً مباحث پایه را از بخش آموزش رایگان وردپرس دنبال کنی تا بهتر متوجه منطق چنین قابلیتهایی در ووکامرس بشوی.
این کد دقیقاً چه کاری انجام میدهد؟
این کد یک نوار پیشرفت هوشمند برای ووکامرس ایجاد میکند که وضعیت سبد خرید کاربر را بررسی میکند و بر اساس مبلغ فعلی سبد خرید، میزان فاصله تا ارسال رایگان را نمایش میدهد.
به زبان ساده، کد این مراحل را انجام میدهد:
- مبلغ فعلی سبد خرید کاربر را بررسی میکند.
- حداقل مبلغ لازم برای ارسال رایگان را از تنظیمات ووکامرس میخواند.
- اختلاف بین مبلغ سبد خرید و حداقل مبلغ ارسال رایگان را محاسبه میکند.
- درصد پیشرفت کاربر تا رسیدن به ارسال رایگان را مشخص میکند.
- یک نوار گرافیکی زیبا و قابل تعامل به کاربر نمایش میدهد.
- با تغییرات سبد خرید، مقدار نوار را بدون رفرش صفحه بهروزرسانی میکند.
- در شرایط خاص مثل خالی بودن سبد خرید یا صفحه پرداخت، نوار را مخفی میکند.
در نتیجه، کاربر در هر لحظه میداند چقدر تا دریافت ارسال رایگان فاصله دارد.
خواندن خودکار مبلغ ارسال رایگان از ووکامرس
یکی از مهمترین مزیتهای این کد این است که مبلغ ارسال رایگان بهصورت دستی داخل کد نوشته نشده است.
یعنی اگر در تنظیمات حملونقل ووکامرس، حداقل مبلغ ارسال رایگان را تغییر بدهی، این نوار هم بهصورت خودکار با همان مقدار جدید کار میکند.
این موضوع باعث میشود کد حرفهایتر، انعطافپذیرتر و قابل استفادهتر باشد.
مثلاً اگر امروز حداقل مبلغ ارسال رایگان روی این مقدار باشد:
۲,۰۰۰,۰۰۰ تومان
و بعداً آن را به این مقدار تغییر بدهی:
۳,۰۰۰,۰۰۰ تومان
دیگر نیازی نیست کد را ویرایش کنی. نوار پیشرفت بهصورت خودکار مقدار جدید را از تنظیمات ووکامرس دریافت میکند.
این رفتار برای فروشگاههای واقعی خیلی مهم است؛ چون معمولاً قوانین ارسال، کمپینها و حداقل خرید در طول زمان تغییر میکنند.
محاسبه فاصله کاربر تا ارسال رایگان
بعد از اینکه کد، مبلغ فعلی سبد خرید و حداقل مبلغ ارسال رایگان را به دست آورد، اختلاف این دو مقدار را محاسبه میکند.
فرمول سادهاش این است:
مبلغ باقیمانده = حداقل مبلغ ارسال رایگان - مبلغ فعلی سبد خرید
مزیت استفاده از کد اختصاصی به جای افزونه آماده
برای اضافه کردن چنین قابلیتی میتوان از افزونههای آماده هم استفاده کرد، اما استفاده از کد اختصاصی چند مزیت مهم دارد.
اول اینکه کد دقیقاً مطابق نیاز سایت نوشته میشود و امکانات اضافه و غیرضروری ندارد.
دوم اینکه کنترل کامل روی ظاهر، متنها، رفتارها و شرایط نمایش وجود دارد.
سوم اینکه میتوان آن را با قالب، طراحی سایت، سبد خرید و نیازهای خاص فروشگاه هماهنگ کرد.
چهارم اینکه اگر درست و بهینه نوشته شود، میتواند سبکتر از افزونههای سنگین آماده باشد.
برای توسعهدهندههای وردپرس، نوشتن چنین قابلیتهایی یک تمرین عالی برای درک بهتر هوکها، AJAX، ووکامرس و رفتارهای سمت کاربر است. اگر به یادگیری تخصصیتر این مسیر علاقه داری، صفحه آموزش وردپرس در تبریز میتواند برای شروع جدیتر مسیر طراحی سایت و توسعه وردپرس مناسب باشد.
کد آماده در رابطه با این آموزش با قابلیت کپی برداری
/* نمایش مانده به ارسال رایگان */
/**
* نوار پیشرفت ارسال رایگان ووکامرس
* نمایش فقط وقتی سبد خرید محصول دارد
* عدم نمایش در صفحه تسویه حساب
* آیکون شناور چسبان سمت راست وسط صفحه
* صفحه محصول در موبایل: پیشفرض آیکون
* صفحه محصول در دسکتاپ: پیشفرض باکس مثل سایر صفحات
* بروزرسانی AJAX بعد از افزودن محصول به سبد خرید
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* دریافت روش ارسال رایگان مناسب مشتری از ووکامرس
*/
function miladalizadeh_get_free_shipping_method_from_woocommerce() {
if (!class_exists('WooCommerce')) {
return false;
}
if (!function_exists('WC') || !WC()->cart) {
return false;
}
$packages = WC()->cart->get_shipping_packages();
/**
* اولویت اول:
* بررسی منطقه حمل و نقل مطابق آدرس یا موقعیت مشتری
*/
if (!empty($packages)) {
foreach ($packages as $package) {
$shipping_zone = WC_Shipping_Zones::get_zone_matching_package($package);
if (!$shipping_zone) {
continue;
}
$shipping_methods = $shipping_zone->get_shipping_methods(true);
foreach ($shipping_methods as $method) {
if (
isset($method->id) &&
$method->id === 'free_shipping' &&
isset($method->enabled) &&
$method->enabled === 'yes'
) {
return $method;
}
}
}
}
/**
* اولویت دوم:
* اگر هنوز منطقه مشتری مشخص نبود، اولین روش ارسال رایگان فعال از کل مناطق گرفته میشود.
*/
$shipping_zones = WC_Shipping_Zones::get_zones();
/**
* اضافه کردن منطقه پیشفرض ووکامرس:
* Locations not covered by your other zones
*/
$shipping_zones[] = array(
'zone_id' => 0,
);
foreach ($shipping_zones as $zone_data) {
if (!isset($zone_data['zone_id'])) {
continue;
}
$zone = new WC_Shipping_Zone($zone_data['zone_id']);
$shipping_methods = $zone->get_shipping_methods(true);
foreach ($shipping_methods as $method) {
if (
isset($method->id) &&
$method->id === 'free_shipping' &&
isset($method->enabled) &&
$method->enabled === 'yes'
) {
return $method;
}
}
}
return false;
}
/**
* دریافت حداقل مبلغ ارسال رایگان از تنظیمات حمل و نقل ووکامرس
*/
function miladalizadeh_get_free_shipping_minimum_amount() {
$method = miladalizadeh_get_free_shipping_method_from_woocommerce();
if (!$method) {
return 0;
}
$requires = $method->get_option('requires');
$min_amount = floatval($method->get_option('min_amount'));
/**
* فقط حالتهایی معتبر هستند که حداقل مبلغ خرید در آنها نقش دارد.
*/
$allowed_requires = array(
'min_amount',
'either',
'both',
);
if (!in_array($requires, $allowed_requires, true)) {
return 0;
}
if ($min_amount <= 0) {
return 0;
}
return apply_filters('miladalizadeh_free_shipping_minimum_amount', $min_amount, $method);
}
/**
* بررسی اینکه تخفیفها در محاسبه حداقل ارسال رایگان لحاظ شوند یا نه
*/
function miladalizadeh_free_shipping_ignore_discounts() {
$method = miladalizadeh_get_free_shipping_method_from_woocommerce();
if (!$method) {
return false;
}
/**
* اگر گزینه Apply minimum order rule before coupon discount فعال باشد،
* حداقل خرید قبل از اعمال تخفیف محاسبه میشود.
*/
$ignore_discounts = $method->get_option('ignore_discounts');
return $ignore_discounts === 'yes';
}
/**
* دریافت مبلغ فعلی سبد خرید برای محاسبه پیشرفت ارسال رایگان
*/
function miladalizadeh_get_cart_amount_for_free_shipping() {
if (!class_exists('WooCommerce') || !function_exists('WC') || !WC()->cart) {
return 0;
}
/**
* مبلغ محصولات سبد خرید بدون هزینه ارسال
*/
$cart_amount = floatval(WC()->cart->get_subtotal());
/**
* اگر ووکامرس گفته باشد تخفیفها لحاظ شوند،
* مبلغ تخفیف از مبلغ سبد کم میشود.
*/
if (!miladalizadeh_free_shipping_ignore_discounts()) {
$cart_amount = $cart_amount - floatval(WC()->cart->get_discount_total());
}
return max(0, $cart_amount);
}
/**
* بررسی خالی بودن سبد خرید
*/
function miladalizadeh_free_shipping_cart_is_empty() {
if (!class_exists('WooCommerce') || !function_exists('WC') || !WC()->cart) {
return true;
}
return WC()->cart->is_empty();
}
/**
* HTML مخفی برای زمانی که نباید چیزی نمایش داده شود
* نکته:
* این wrapper مخفی لازم است تا بعد از افزودن AJAX محصول، ووکامرس بتواند Fragment را جایگزین کند.
*/
function miladalizadeh_get_free_shipping_hidden_wrapper() {
return '<div id="miladalizadeh-free-shipping-bar-wrapper" class="miladalizadeh-fs-wrapper ma-fs-hidden" data-ma-fs-wrapper="1"></div>';
}
/**
* ساخت HTML نوار ارسال رایگان
*/
function miladalizadeh_get_free_shipping_bar_html() {
if (!class_exists('WooCommerce') || !function_exists('WC') || !WC()->cart) {
return miladalizadeh_get_free_shipping_hidden_wrapper();
}
/**
* در صفحه تسویه حساب کلاً نمایش داده نمیشود.
*/
if (function_exists('is_checkout') && is_checkout()) {
return miladalizadeh_get_free_shipping_hidden_wrapper();
}
/**
* اگر سبد خرید خالی باشد، هیچ چیزی نمایش داده نمیشود.
*/
if (miladalizadeh_free_shipping_cart_is_empty()) {
return miladalizadeh_get_free_shipping_hidden_wrapper();
}
$free_shipping_minimum = miladalizadeh_get_free_shipping_minimum_amount();
/**
* اگر ارسال رایگان با حداقل مبلغ در ووکامرس تنظیم نشده باشد، چیزی نمایش داده نمیشود.
*/
if ($free_shipping_minimum <= 0) {
return miladalizadeh_get_free_shipping_hidden_wrapper();
}
$cart_amount = miladalizadeh_get_cart_amount_for_free_shipping();
$remaining = max(0, $free_shipping_minimum - $cart_amount);
$percent = 0;
if ($free_shipping_minimum > 0) {
$percent = min(100, ($cart_amount / $free_shipping_minimum) * 100);
}
$is_completed = $remaining <= 0;
$remaining_html = wc_price($remaining);
$free_shipping_minimum_html = wc_price($free_shipping_minimum);
$cart_amount_html = wc_price($cart_amount);
if ($is_completed) {
$icon = '🎉';
$fab_text = 'ارسال رایگان شد';
$title = 'تبریک! ارسال سفارش شما رایگان شد';
$text = 'شما به حداقل مبلغ ارسال رایگان رسیدهاید. حالا میتوانید سفارشتان را با ارسال رایگان ثبت کنید.';
} else {
$icon = '🚚';
$fab_text = 'ارسال رایگان';
$title = 'ارسال رایگان خیلی نزدیکه!';
$text = 'فقط <strong>' . $remaining_html . '</strong> دیگه خرید کن تا سفارشت رایگان ارسال بشه.';
}
ob_start();
?>
<div id="miladalizadeh-free-shipping-bar-wrapper" class="miladalizadeh-fs-wrapper ma-fs-hidden" data-ma-fs-wrapper="1">
<button type="button" class="miladalizadeh-fs-fab" aria-label="نمایش وضعیت ارسال رایگان">
<span class="miladalizadeh-fs-fab-pulse"></span>
<span class="miladalizadeh-fs-fab-icon"><?php echo esc_html($icon); ?></span>
<span class="miladalizadeh-fs-fab-text"><?php echo esc_html($fab_text); ?></span>
</button>
<div id="miladalizadeh-free-shipping-bar" class="miladalizadeh-free-shipping-bar <?php echo $is_completed ? 'is-completed' : ''; ?>">
<div class="miladalizadeh-fs-inner">
<div class="miladalizadeh-fs-glow miladalizadeh-fs-glow-one"></div>
<div class="miladalizadeh-fs-glow miladalizadeh-fs-glow-two"></div>
<button type="button" class="miladalizadeh-fs-close" aria-label="بستن نوار ارسال رایگان">
×
</button>
<div class="miladalizadeh-fs-icon">
<?php echo esc_html($icon); ?>
</div>
<div class="miladalizadeh-fs-content">
<div class="miladalizadeh-fs-head">
<div class="miladalizadeh-fs-title-wrap">
<span class="miladalizadeh-fs-kicker">وضعیت ارسال رایگان</span>
<span class="miladalizadeh-fs-title">
<?php echo wp_kses_post($title); ?>
</span>
</div>
<div class="miladalizadeh-fs-badges">
<span class="miladalizadeh-fs-badge">
هدف: <?php echo wp_kses_post($free_shipping_minimum_html); ?>
</span>
<span class="miladalizadeh-fs-badge miladalizadeh-fs-badge-light">
سبد شما: <?php echo wp_kses_post($cart_amount_html); ?>
</span>
</div>
</div>
<div class="miladalizadeh-fs-text">
<?php echo wp_kses_post($text); ?>
</div>
<div class="miladalizadeh-fs-progress-area">
<div class="miladalizadeh-fs-progress">
<div class="miladalizadeh-fs-progress-fill" style="width: <?php echo esc_attr($percent); ?>%;">
<span></span>
</div>
</div>
<div class="miladalizadeh-fs-percent">
<?php echo esc_html(round($percent)); ?>%
</div>
</div>
</div>
</div>
</div>
</div>
<?php
return ob_get_clean();
}
/**
* نمایش نوار در فوتر سایت
*/
function miladalizadeh_render_free_shipping_bar() {
if (is_admin() && !wp_doing_ajax()) {
return;
}
echo miladalizadeh_get_free_shipping_bar_html();
}
add_action('wp_footer', 'miladalizadeh_render_free_shipping_bar', 25);
/**
* بروزرسانی نوار بعد از افزودن محصول به سبد خرید با AJAX
*/
function miladalizadeh_free_shipping_bar_add_to_cart_fragments($fragments) {
$fragments['#miladalizadeh-free-shipping-bar-wrapper'] = miladalizadeh_get_free_shipping_bar_html();
return $fragments;
}
add_filter('woocommerce_add_to_cart_fragments', 'miladalizadeh_free_shipping_bar_add_to_cart_fragments', 99);
/**
* بروزرسانی نوار در صفحه تسویه حساب یا تغییرات مرتبط با سفارش
*/
function miladalizadeh_free_shipping_bar_checkout_fragments($fragments) {
$fragments['#miladalizadeh-free-shipping-bar-wrapper'] = miladalizadeh_get_free_shipping_bar_html();
return $fragments;
}
add_filter('woocommerce_update_order_review_fragments', 'miladalizadeh_free_shipping_bar_checkout_fragments', 99);
/**
* استایل و اسکریپت نوار ارسال رایگان
*/
function miladalizadeh_free_shipping_bar_assets() {
if (is_admin() && !wp_doing_ajax()) {
return;
}
?>
<style>
:root {
--ma-fs-blue: #134686;
--ma-fs-red: #C90101;
--ma-fs-green: #00b894;
--ma-fs-dark: #07111f;
--ma-fs-white: #ffffff;
--ma-fs-muted: rgba(255, 255, 255, .76);
--ma-fs-border: rgba(255, 255, 255, .16);
--ma-fs-shadow: 0 20px 70px rgba(0, 0, 0, .32);
--ma-fs-radius: 24px;
}
#miladalizadeh-free-shipping-bar-wrapper,
#miladalizadeh-free-shipping-bar-wrapper * {
box-sizing: border-box;
}
#miladalizadeh-free-shipping-bar-wrapper {
position: fixed;
left: 50%;
bottom: 22px;
z-index: 999999;
width: min(960px, calc(100% - 32px));
direction: rtl;
font-family: inherit;
transform: translateX(-50%);
}
#miladalizadeh-free-shipping-bar-wrapper.ma-fs-hidden {
display: none !important;
}
#miladalizadeh-free-shipping-bar {
width: 100%;
animation: maFsSlideIn .55s cubic-bezier(.19, 1, .22, 1) both;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-inner {
position: relative;
overflow: hidden;
display: flex;
align-items: center;
gap: 16px;
padding: 16px 18px 16px 46px;
color: var(--ma-fs-white);
border: 1px solid var(--ma-fs-border);
border-radius: var(--ma-fs-radius);
background:
radial-gradient(circle at 8% 22%, rgba(201, 1, 1, .46), transparent 30%),
radial-gradient(circle at 92% 30%, rgba(19, 70, 134, .70), transparent 32%),
linear-gradient(135deg, rgba(7, 17, 31, .96), rgba(12, 33, 64, .94));
box-shadow: var(--ma-fs-shadow);
backdrop-filter: blur(18px);
-webkit-backdrop-filter: blur(18px);
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-inner::before {
content: "";
position: absolute;
inset: -2px;
pointer-events: none;
background: linear-gradient(
110deg,
transparent 0%,
rgba(255, 255, 255, .08) 28%,
rgba(255, 255, 255, .28) 43%,
rgba(255, 255, 255, .10) 58%,
transparent 78%
);
transform: translateX(115%);
animation: maFsShine 4.8s ease-in-out infinite;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-glow {
position: absolute;
pointer-events: none;
border-radius: 999px;
filter: blur(4px);
opacity: .78;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-glow-one {
width: 130px;
height: 130px;
right: -58px;
top: -68px;
background: rgba(201, 1, 1, .30);
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-glow-two {
width: 150px;
height: 150px;
left: -70px;
bottom: -78px;
background: rgba(19, 70, 134, .42);
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-close {
position: absolute;
z-index: 5;
top: 12px;
left: 12px;
width: 30px;
height: 30px;
display: grid;
place-items: center;
padding: 0;
cursor: pointer;
color: #fff;
font-size: 23px;
line-height: 1;
border: 1px solid rgba(255, 255, 255, .16);
border-radius: 999px;
background: rgba(255, 255, 255, .11);
box-shadow: none;
outline: none;
transition: transform .22s ease, background .22s ease, border-color .22s ease;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-close:hover {
transform: rotate(90deg) scale(1.05);
background: rgba(201, 1, 1, .72);
border-color: rgba(255, 255, 255, .24);
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-icon {
position: relative;
z-index: 2;
flex: 0 0 58px;
width: 58px;
height: 58px;
display: grid;
place-items: center;
font-size: 29px;
border-radius: 20px;
background: linear-gradient(145deg, rgba(255, 255, 255, .22), rgba(255, 255, 255, .06));
border: 1px solid rgba(255, 255, 255, .18);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .18),
0 12px 32px rgba(0, 0, 0, .20);
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-content {
position: relative;
z-index: 2;
width: 100%;
min-width: 0;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
margin-bottom: 8px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-title-wrap {
min-width: 0;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-kicker {
display: block;
margin-bottom: 1px;
color: rgba(255, 255, 255, .58);
font-size: 11px;
font-weight: 800;
line-height: 1.6;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-title {
display: block;
color: #fff;
font-size: 15px;
font-weight: 950;
line-height: 1.7;
letter-spacing: -.2px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-badges {
flex: 0 0 auto;
display: flex;
align-items: center;
gap: 7px;
flex-wrap: wrap;
justify-content: flex-end;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 30px;
padding: 5px 10px;
border-radius: 999px;
color: #fff;
font-size: 12px;
font-weight: 850;
white-space: nowrap;
background: rgba(255, 255, 255, .13);
border: 1px solid rgba(255, 255, 255, .16);
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-badge-light {
background: rgba(255, 255, 255, .08);
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-text {
margin-bottom: 11px;
color: var(--ma-fs-muted);
font-size: 13px;
font-weight: 650;
line-height: 1.9;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-text strong {
color: #fff;
font-weight: 950;
padding: 0 3px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-progress-area {
display: flex;
align-items: center;
gap: 10px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-progress {
position: relative;
overflow: hidden;
width: 100%;
height: 12px;
border-radius: 999px;
background: rgba(255, 255, 255, .12);
box-shadow:
inset 0 1px 3px rgba(0, 0, 0, .24),
0 1px 0 rgba(255, 255, 255, .08);
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-progress-fill {
position: relative;
overflow: hidden;
height: 100%;
min-width: 8px;
border-radius: inherit;
background: linear-gradient(90deg, var(--ma-fs-red), #ff5b43, #ffd166);
box-shadow:
0 0 18px rgba(255, 91, 67, .54),
0 0 34px rgba(255, 209, 102, .20);
transition: width .55s cubic-bezier(.19, 1, .22, 1);
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-progress-fill span {
position: absolute;
inset: 0;
background-image: linear-gradient(
45deg,
rgba(255,255,255,.28) 25%,
transparent 25%,
transparent 50%,
rgba(255,255,255,.28) 50%,
rgba(255,255,255,.28) 75%,
transparent 75%,
transparent
);
background-size: 18px 18px;
animation: maFsStripes 1.05s linear infinite;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-percent {
flex: 0 0 44px;
min-width: 44px;
color: #fff;
font-size: 12px;
font-weight: 950;
text-align: center;
}
#miladalizadeh-free-shipping-bar.is-completed .miladalizadeh-fs-inner {
background:
radial-gradient(circle at 12% 20%, rgba(0, 184, 148, .42), transparent 30%),
radial-gradient(circle at 92% 35%, rgba(19, 70, 134, .58), transparent 30%),
linear-gradient(135deg, rgba(5, 35, 28, .96), rgba(8, 17, 31, .94));
}
#miladalizadeh-free-shipping-bar.is-completed .miladalizadeh-fs-progress-fill {
background: linear-gradient(90deg, #00b894, #55efc4, #dff9fb);
box-shadow:
0 0 18px rgba(85, 239, 196, .55),
0 0 34px rgba(0, 184, 148, .24);
}
/**
* حالت آیکون شناور
* سمت راست، وسط صفحه، چسبان به لبه
*/
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab {
position: fixed;
right: 0;
top: 50%;
z-index: 999999;
display: none;
align-items: center;
gap: 8px;
min-height: 58px;
padding: 10px 12px 10px 15px;
cursor: pointer;
direction: rtl;
color: #fff;
border: 1px solid rgba(255, 255, 255, .20);
border-right: 0;
border-radius: 999px 0 0 999px;
background:
radial-gradient(circle at 88% 18%, rgba(255, 255, 255, .20), transparent 28%),
radial-gradient(circle at 22% 78%, rgba(201, 1, 1, .50), transparent 34%),
linear-gradient(135deg, rgba(19, 70, 134, .98), rgba(7, 17, 31, .98));
box-shadow:
0 18px 48px rgba(0, 0, 0, .34),
0 0 0 1px rgba(255, 255, 255, .05),
-8px 0 24px rgba(19, 70, 134, .22);
backdrop-filter: blur(18px);
-webkit-backdrop-filter: blur(18px);
outline: none;
transform: translateY(-50%);
transition: transform .25s ease, box-shadow .25s ease, padding .25s ease;
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab::before {
content: "";
position: absolute;
inset: -1px;
pointer-events: none;
border-radius: inherit;
background: linear-gradient(
135deg,
rgba(255, 255, 255, .22),
transparent 38%,
rgba(255, 255, 255, .10)
);
opacity: .75;
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab:hover {
transform: translateY(-50%) translateX(-4px) scale(1.035);
box-shadow:
0 22px 58px rgba(0, 0, 0, .38),
-10px 0 30px rgba(201, 1, 1, .18),
-12px 0 34px rgba(19, 70, 134, .24);
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab-pulse {
position: absolute;
inset: 8px;
border-radius: inherit;
border: 1px solid rgba(255, 255, 255, .24);
opacity: .45;
animation: maFsFabPulse 2.2s ease-in-out infinite;
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab-icon {
position: relative;
z-index: 2;
width: 38px;
height: 38px;
display: grid;
place-items: center;
font-size: 22px;
border-radius: 999px;
background: rgba(255, 255, 255, .15);
border: 1px solid rgba(255, 255, 255, .16);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .18),
0 10px 24px rgba(0, 0, 0, .20);
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab-text {
position: relative;
z-index: 2;
font-size: 12px;
font-weight: 950;
white-space: nowrap;
padding-left: 2px;
}
#miladalizadeh-free-shipping-bar-wrapper.is-closed {
width: auto;
left: auto;
right: 0;
top: 50%;
bottom: auto;
transform: none;
}
#miladalizadeh-free-shipping-bar-wrapper.is-closed #miladalizadeh-free-shipping-bar {
display: none;
}
#miladalizadeh-free-shipping-bar-wrapper.is-closed .miladalizadeh-fs-fab {
display: inline-flex;
animation: maFsFabIn .34s cubic-bezier(.19, 1, .22, 1) both;
}
#miladalizadeh-free-shipping-bar-wrapper:not(.is-closed) .miladalizadeh-fs-fab {
display: none;
}
#miladalizadeh-free-shipping-bar-wrapper.ma-fs-attention .miladalizadeh-fs-fab {
animation: maFsFabAttention 1.15s ease-in-out 2 both;
}
@keyframes maFsSlideIn {
from {
opacity: 0;
transform: translateY(24px) scale(.98);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes maFsFabIn {
from {
opacity: 0;
transform: translateY(-50%) translateX(28px) scale(.88);
}
to {
opacity: 1;
transform: translateY(-50%) translateX(0) scale(1);
}
}
@keyframes maFsFabAttention {
0%, 100% {
transform: translateY(-50%) translateX(0) rotate(0) scale(1);
}
12% {
transform: translateY(-50%) translateX(-7px) rotate(-4deg) scale(1.06);
}
24% {
transform: translateY(-50%) translateX(0) rotate(4deg) scale(1.08);
}
36% {
transform: translateY(-50%) translateX(-7px) rotate(-4deg) scale(1.06);
}
48% {
transform: translateY(-50%) translateX(0) rotate(4deg) scale(1.08);
}
64% {
transform: translateY(-50%) translateX(-4px) rotate(0) scale(1.04);
}
}
@keyframes maFsFabPulse {
0%, 100% {
transform: scale(1);
opacity: .35;
}
50% {
transform: scale(1.12);
opacity: .08;
}
}
@keyframes maFsShine {
0%, 55% {
transform: translateX(115%);
}
75%, 100% {
transform: translateX(-115%);
}
}
@keyframes maFsStripes {
from {
background-position: 0 0;
}
to {
background-position: 18px 0;
}
}
@media (max-width: 768px) {
#miladalizadeh-free-shipping-bar-wrapper {
width: calc(100% - 22px);
bottom: 12px;
}
#miladalizadeh-free-shipping-bar-wrapper.is-closed {
width: auto;
left: auto;
right: 0;
top: 50%;
bottom: auto;
transform: none;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-inner {
align-items: flex-start;
gap: 12px;
padding: 14px 14px 14px 44px;
border-radius: 19px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-icon {
flex-basis: 48px;
width: 48px;
height: 48px;
border-radius: 16px;
font-size: 24px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-head {
flex-direction: column;
align-items: flex-start;
gap: 7px;
margin-bottom: 7px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-badges {
justify-content: flex-start;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-title {
font-size: 14px;
line-height: 1.65;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-text {
font-size: 12.5px;
line-height: 1.85;
margin-bottom: 10px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-badge {
min-height: 27px;
font-size: 11px;
padding: 4px 9px;
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab {
min-height: 54px;
padding: 9px 11px 9px 13px;
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab-icon {
width: 35px;
height: 35px;
font-size: 21px;
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab-text {
font-size: 11.5px;
}
}
@media (max-width: 430px) {
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-inner {
gap: 10px;
padding: 13px 12px 13px 42px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-close {
top: 10px;
left: 10px;
width: 28px;
height: 28px;
font-size: 21px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-icon {
flex-basis: 42px;
width: 42px;
height: 42px;
font-size: 22px;
border-radius: 14px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-kicker {
font-size: 10.5px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-title {
font-size: 13.5px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-text {
font-size: 12px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-progress {
height: 10px;
}
#miladalizadeh-free-shipping-bar .miladalizadeh-fs-percent {
flex-basis: 38px;
min-width: 38px;
font-size: 11px;
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab-text {
display: none;
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab {
width: 54px;
min-height: 58px;
justify-content: center;
padding: 0;
border-radius: 999px 0 0 999px;
}
#miladalizadeh-free-shipping-bar-wrapper .miladalizadeh-fs-fab-icon {
width: 38px;
height: 38px;
font-size: 22px;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
var storageKey = 'ma_fs_bar_state';
function maFsIsCheckoutPage() {
return document.body.classList.contains('woocommerce-checkout') || document.body.classList.contains('checkout');
}
function maFsIsProductPage() {
return document.body.classList.contains('single-product');
}
function maFsIsMobile() {
return window.matchMedia('(max-width: 768px)').matches;
}
function maFsGetWrapper() {
return document.getElementById('miladalizadeh-free-shipping-bar-wrapper');
}
function maFsHasVisibleContent() {
var wrapper = maFsGetWrapper();
if (!wrapper) {
return false;
}
return !!wrapper.querySelector('#miladalizadeh-free-shipping-bar');
}
function maFsApplyState(state) {
var wrapper = maFsGetWrapper();
if (!wrapper) {
return;
}
/**
* اگر صفحه تسویه حساب است یا محتوای واقعی نداریم،
* هیچ چیزی نمایش داده نشود.
*/
if (maFsIsCheckoutPage() || !maFsHasVisibleContent()) {
wrapper.classList.add('ma-fs-hidden');
wrapper.classList.remove('is-closed');
return;
}
if (state === 'closed') {
wrapper.classList.add('is-closed');
} else {
wrapper.classList.remove('is-closed');
}
wrapper.classList.remove('ma-fs-hidden');
}
function maFsGetDefaultState() {
var savedState = localStorage.getItem(storageKey);
/**
* اگر کاربر قبلاً خودش بسته یا باز کرده باشد،
* همان حالت ذخیرهشده رعایت میشود.
*/
if (savedState === 'closed' || savedState === 'open') {
return savedState;
}
/**
* در صفحه محصول موبایل، پیشفرض آیکون باشد.
* در دسکتاپ صفحه محصول و سایر صفحات، پیشفرض باکس باز باشد.
*/
if (maFsIsProductPage() && maFsIsMobile()) {
return 'closed';
}
return 'open';
}
function maFsApplyDefaultState() {
maFsApplyState(maFsGetDefaultState());
}
function maFsOpenBox() {
localStorage.setItem(storageKey, 'open');
maFsApplyState('open');
}
function maFsCloseBox() {
localStorage.setItem(storageKey, 'closed');
maFsApplyState('closed');
}
function maFsAttentionIcon() {
var wrapper = maFsGetWrapper();
if (!wrapper) {
return;
}
if (!wrapper.classList.contains('is-closed')) {
return;
}
wrapper.classList.remove('ma-fs-attention');
setTimeout(function () {
wrapper.classList.add('ma-fs-attention');
}, 30);
setTimeout(function () {
wrapper.classList.remove('ma-fs-attention');
}, 2600);
}
/**
* کلیک روی ضربدر برای بستن باکس و تبدیل آن به آیکون شناور
*/
document.addEventListener('click', function (event) {
var closeButton = event.target.closest('.miladalizadeh-fs-close');
if (!closeButton) {
return;
}
event.preventDefault();
maFsCloseBox();
});
/**
* کلیک روی آیکون برای باز کردن باکس
*/
document.addEventListener('click', function (event) {
var fabButton = event.target.closest('.miladalizadeh-fs-fab');
if (!fabButton) {
return;
}
event.preventDefault();
maFsOpenBox();
});
/**
* اعمال وضعیت اولیه بعد از لود صفحه
*/
maFsApplyDefaultState();
/**
* در صورت تغییر سایز صفحه:
* اگر حالت ذخیرهشده وجود نداشته باشد، قانون پیشفرض موبایل/دسکتاپ دوباره اعمال شود.
*/
window.addEventListener('resize', function () {
clearTimeout(window.maFsResizeTimer);
window.maFsResizeTimer = setTimeout(function () {
maFsApplyDefaultState();
}, 180);
});
if (window.jQuery) {
jQuery(function ($) {
/**
* بعد از بروزرسانیهای AJAX ووکامرس،
* چون ممکن است Fragment نوار جایگزین شده باشد،
* دوباره وضعیت درست اعمال میشود.
*/
$(document.body).on(
'wc_fragments_refreshed wc_fragments_loaded updated_cart_totals updated_checkout applied_coupon removed_coupon removed_from_cart',
function () {
setTimeout(function () {
maFsApplyDefaultState();
}, 90);
}
);
/**
* بعد از افزودن محصول به سبد خرید:
* اگر قبلش سبد خالی بوده باشد، حالا Fragment جدید میآید و نوار/آیکون نمایش داده میشود.
*/
$(document.body).on('added_to_cart', function () {
setTimeout(function () {
maFsApplyDefaultState();
/**
* اگر در صفحه محصول موبایل هستیم یا کاربر قبلاً باکس را بسته،
* آیکون یک تکان جلبتوجه بگیرد.
*/
if (
maFsGetWrapper() &&
maFsGetWrapper().classList.contains('is-closed')
) {
maFsAttentionIcon();
}
}, 140);
});
});
}
});
</script>
<?php
}
add_action('wp_footer', 'miladalizadeh_free_shipping_bar_assets', 30);
راهنمای گامبهگام: چگونه این کد را به سایت وردپرسی خود اضافه کنیم؟
برای اضافه کردن این کد به وردپرس، چندین روش وجود دارد. در ادامه ایمنترین و استانداردترین روشها را با هم بررسی میکنیم:
روش اول: ویرایش از طریق مدیریت فایل هاست (روش حرفهای)
گاهی اوقات ممکن است دسترسی به ویرایشگر وردپرس (Theme File Editor) به دلایل امنیتی توسط توسعهدهنده قالب بسته شده باشد، یا شاید ترجیح میدهید به جای محیط وردپرس، مستقیماً با فایلهای سرور کار کنید. در این صورت، استفاده از File Manager هاست بهترین راهکار است.
گامهای اجرای کار در هاست (cPanel یا DirectAdmin):
- ورود به هاست: ابتدا وارد پنل مدیریت هاست خود (cPanel یا DirectAdmin) شوید.
- باز کردن فایل منیجر: روی گزینه File Manager کلیک کنید.
- مسیریابی: به پوشه ریشه سایت خود (معمولاً
public_html) بروید. سپس مسیر زیر را دنبال کنید:wp-content>themes>your-theme-name(نکته: بهجایyour-theme-nameنام پوسته فعال سایت خود را انتخاب کنید. اگر از Child Theme استفاده میکنید، حتماً وارد پوشه فرزند شوید). - ویرایش فایل: فایل
functions.phpرا پیدا کنید. روی آن راستکلیک کرده و گزینه Edit را انتخاب کنید. - جایگذاری کد: کد مورد نظر خود را به انتهای فایل اضافه کنید.
- ذخیره: دکمه Save Changes را در بالای صفحه ویرایشگر بزنید.
روش دوم : اضافه کردن کد به فایل functions.php (روش سریع)
فایل functions.php قلب تپنده قالب شماست و کدهای شخصیسازی در آن قرار میگیرند.
- وارد پیشخوان وردپرس شوید: از منوی سمت راست به مسیر نمایش > ویرایشگر پرونده پوسته (Theme File Editor) بروید.
- فایل مناسب را انتخاب کنید: از ستون سمت چپ (بخش پروندههای پوسته)، فایل توابع پوسته (functions.php) را پیدا کرده و روی آن کلیک کنید.
- قرار دادن کد: به انتهای فایل بروید، یک خط جدید ایجاد کنید و کدهای بالا را دقیقاً در انتهای فایل پیست (Paste) کنید.
- ذخیره تغییرات: روی دکمه بهروزرسانی پرونده کلیک کنید.
⚠️ یک هشدار امنیتی بسیار مهم:
پیش از ویرایش فایلهای قالب، حتماً یک نسخه پشتیبان (Backup) از فایل تهیه کنید. همچنین اگر قالب خود را آپدیت کنید، تغییراتی که در فایل
functions.phpقالب اصلی اعمال کردهاید پاک خواهند شد. برای جلوگیری از این مشکل، پیشنهاد میکنیم از پوسته فرزند (Child Theme) استفاده کنید یا به سراغ روش دوم بروید.
روش سوم: استفاده از افزونههای مدیریت کدهای سفارشی (روش ایمن و بدون خطر)
اگر نمیخواهید فایلهای قالب را به صورت دستی ویرایش کنید و نگران به هم ریختن سایت یا پاک شدن کدها در آپدیتهای بعدی قالب هستید، این روش بهترین گزینه است.
- افزونه رایگان WPcode (Insert Headers and Footers) یا Code Snippets را از مخزن وردپرس نصب و فعال کنید.
- از منوی جدیدی که در پیشخوان اضافه شده، روی Add Snippet (افزودن کد جدید) کلیک کنید.
- یک عنوان دلخواه برای آن انتخاب کنید (مثلاً: نوار اعلان بالای هدر).
- نوع کد (Code Type) را روی حالت PHP Snippet قرار دهید.
- کدهای بالا را در باکس مربوطه کپی کنید.
- وضعیت را روی Active (فعال) قرار داده و دکمه Save را بزنید.
جمعبندی
نوار پیشرفت ارسال رایگان ووکامرس یک قابلیت ساده اما بسیار کاربردی برای فروشگاههای اینترنتی است.
این کد با بررسی مبلغ سبد خرید و مقایسه آن با حداقل مبلغ ارسال رایگان، به کاربر نشان میدهد چقدر دیگر باید خرید کند تا ارسال رایگان برای او فعال شود.
ویژگی مهم این کد این است که مبلغ ارسال رایگان را بهصورت خودکار از تنظیمات ووکامرس میخواند، با AJAX بدون رفرش صفحه بهروزرسانی میشود، در صورت خالی بودن سبد خرید مخفی میماند، در صفحه تسویه حساب نمایش داده نمیشود و امکان باز و بسته شدن آن برای کاربر وجود دارد.
در نهایت، این قابلیت میتواند تجربه خرید را بهتر کند، سایت را حرفهایتر نشان دهد و کاربر را به افزایش مبلغ سبد خرید تشویق کند.
درباره میلاد علیزاده وکیلی
میلاد علیزاده هستم مدرس دوره های آموزش برنامه نویسی در شهر تبریز که فعالیت خودم رو از سال 95 در زمینه ی طراحی و میزبانی وبسایت شروع کردم. هدف من از راه اندازی این وبسایت ارائه ی آموزشی متفاوت همچنین اشتغال محور و پروژه محور هستش که هنرجو بعد از آموزش بتواند با دانش و تجربه ای کافی مستقیما وارد بازار کار شده و در زمینه ی برنامه نویسی کسب درامد کند.
نوشتههای بیشتر از میلاد علیزاده وکیلی

دیدگاهتان را بنویسید