~/icsd.ir — bash
SYSTEM_ONLINE

🧱 فصل ۱۰: Blocks Cart و Checkout

از ووکامرس ۸ به بعد، فرم سبد و پرداخت کلاسیک با Blocks جایگزین شد. این تغییر بزرگ بر مبنای React و Store API است و نیاز به رویکرد جدیدی برای سفارشی‌سازی دارد.

🤔 چرا Blocks Cart/Checkout؟

تیم ووکامرس Cart/Checkout را با Blocks بازنویسی کرد به دلایل:

  • سرعت ۲ تا ۳ برابر بیشتر – مخصوصاً در موبایل
  • UX مدرن – مشابه استانداردهای ۲۰۲۴
  • نرخ تبدیل بهتر – فرآیند تک‌صفحه‌ای
  • قابلیت توسعه با React – برای توسعه‌دهنده‌ها
  • سازگاری با Site Editor – تم‌های Block-based
💡 نکته: Classic Cart/Checkout هنوز موجود است، اما تیم ووکامرس به‌مرور پشتیبانی را کم می‌کند.

🆚 تفاوت Classic با Blocks

ویژگی Classic Blocks
Shortcode [woocommerce_checkout] <!-- wp:woocommerce/checkout -->
تکنولوژی PHP + jQuery React
API WC API Store API
سفارشی‌سازی فیلد woocommerce_checkout_fields filter woocommerce_blocks_loaded + extend_schema
درگاه پرداخت کلاس PHP + form fields کلاس PHP + JS payment method
چندصفحه‌ای دارد تک‌صفحه‌ای
RTL پشتیبانی کامل کامل (نسخه‌های اخیر)

🔄 آشنایی با Store API

Store API (نسخه پابلیک) دیتای cart/checkout را به React می‌رساند:

# دریافت محتوای سبد فعلی
GET /wp-json/wc/store/v1/cart

# افزودن به سبد
POST /wp-json/wc/store/v1/cart/add-item
{ "id": 100, "quantity": 1 }

# حذف از سبد
POST /wp-json/wc/store/v1/cart/remove-item
{ "key": "abc123..." }

# اعمال کوپن
POST /wp-json/wc/store/v1/cart/apply-coupon
{ "code": "WELCOME10" }

# Checkout (ثبت سفارش)
POST /wp-json/wc/store/v1/checkout
{
  "billing_address": {...},
  "shipping_address": {...},
  "payment_method": "icsd_zarinpal"
}

⚠️ تفاوت با /wc/v3/: Store API برای فرانت‌اند و session-based است. نیازی به authentication ندارد (با cookie کار می‌کند).

🔧 extend_schema – افزودن فیلد سفارشی

برای اضافه کردن داده به Cart/Checkout block، از extend_schema استفاده می‌کنیم:

includes/blocks-extension.php
<?php
use AutomatticWooCommerceBlocksPackage;
use AutomatticWooCommerceStoreApiStoreApi;
use AutomatticWooCommerceStoreApiSchemasV1CheckoutSchema;
use AutomatticWooCommerceStoreApiSchemasV1CartSchema;

add_action('woocommerce_blocks_loaded', function() {
    
    // ۱. اضافه کردن فیلد به Cart endpoint
    woocommerce_store_api_register_endpoint_data([
        'endpoint'        => CartSchema::IDENTIFIER,
        'namespace'       => 'icsd-extras',
        'data_callback'   => function() {
            return [
                'gift_message' => WC()->session->get('gift_message', ''),
                'is_gift'      => (bool) WC()->session->get('is_gift', false),
            ];
        },
        'schema_callback' => function() {
            return [
                'gift_message' => [
                    'type'        => 'string',
                    'description' => 'پیام هدیه',
                ],
                'is_gift'      => [
                    'type'        => 'boolean',
                    'description' => 'آیا این سفارش هدیه است؟',
                ],
            ];
        },
    ]);
    
    // ۲. اضافه کردن فیلد به Checkout
    woocommerce_store_api_register_endpoint_data([
        'endpoint'        => CheckoutSchema::IDENTIFIER,
        'namespace'       => 'icsd-extras',
        'data_callback'   => function() {
            return [
                'delivery_date' => '',
                'national_id'   => '',
            ];
        },
        'schema_callback' => function() {
            return [
                'delivery_date' => [
                    'type'        => ['string', 'null'],
                    'description' => 'تاریخ تحویل دلخواه',
                ],
                'national_id' => [
                    'type'        => 'string',
                    'description' => 'کد ملی برای فاکتور رسمی',
                ],
            ];
        },
        'schema_type'     => ARRAY_A,
    ]);
    
    // ۳. هنگام ثبت سفارش، فیلدها را ذخیره کن
    add_action('woocommerce_store_api_checkout_update_order_from_request', function($order, $request) {
        $extras = $request['extensions']['icsd-extras'] ?? [];
        
        if (!empty($extras['delivery_date'])) {
            $order->update_meta_data('_delivery_date', sanitize_text_field($extras['delivery_date']));
        }
        if (!empty($extras['national_id'])) {
            $order->update_meta_data('_billing_national_id', sanitize_text_field($extras['national_id']));
        }
        
        $order->save();
    }, 10, 2);
});

🎨 ساخت Block در Checkout

برای نمایش UI سفارشی در صفحه Checkout، باید یک Block JavaScript بسازیم:

ساختار افزونه

icsd-checkout-extras/
├── icsd-checkout-extras.php
├── package.json
├── webpack.config.js
├── src/
│   ├── index.js
│   ├── block.js
│   └── style.scss
└── build/   (خروجی webpack)

package.json
{
  "name": "icsd-checkout-extras",
  "version": "1.0.0",
  "scripts": {
    "build": "wp-scripts build",
    "start": "wp-scripts start"
  },
  "devDependencies": {
    "@woocommerce/dependency-extraction-webpack-plugin": "^3.0.0",
    "@wordpress/scripts": "^27.0.0"
  }
}

src/block.js
import { __ } from '@wordpress/i18n';
import { useState, useEffect } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data';

const Block = ({ checkoutExtensionData }) => {
    const [deliveryDate, setDeliveryDate] = useState('');
    const [nationalId, setNationalId] = useState('');
    
    const { setExtensionData } = checkoutExtensionData;
    
    useEffect(() => {
        setExtensionData('icsd-extras', 'delivery_date', deliveryDate);
        setExtensionData('icsd-extras', 'national_id', nationalId);
    }, [deliveryDate, nationalId, setExtensionData]);
    
    return (
        

{__('اطلاعات تکمیلی', 'icsd')}

setDeliveryDate(e.target.value)} min={new Date(Date.now() + 2*86400*1000).toISOString().split('T')[0]} />

setNationalId(e.target.value.replace(/D/g, ''))} required /> {__('برای صدور فاکتور رسمی', 'icsd')}

); }; export default Block;

src/index.js
import { registerCheckoutBlock } from '@woocommerce/blocks-checkout';
import Block from './block';
import metadata from './block.json';
import './style.scss';

const options = {
    metadata: {
        ...metadata,
        parent: ['woocommerce/checkout-fields-block'],
    },
    component: Block,
};

registerCheckoutBlock(options);

icsd-checkout-extras.php
<?php
/**
 * Plugin Name: ICSD Checkout Extras (Blocks)
 */

defined('ABSPATH') || exit;

// بارگذاری extension
require_once __DIR__ . '/includes/blocks-extension.php';

// ثبت block
add_action('init', function() {
    register_block_type(__DIR__ . '/build');
});

// ثبت aset برای frontend
add_action('woocommerce_blocks_checkout_block_registration', function($integration_registry) {
    require_once __DIR__ . '/includes/class-checkout-extras-integration.php';
    $integration_registry->register(new ICSD_Checkout_Extras_Integration());
});

💳 یکپارچه‌سازی درگاه با Blocks

درگاه‌های پرداخت سنتی (که در فصل ۴ ساختیم) باید به Blocks معرفی شوند:

includes/class-zarinpal-blocks-support.php
<?php
use AutomatticWooCommerceBlocksPaymentsIntegrationsAbstractPaymentMethodType;

final class ZarinPal_Blocks_Support extends AbstractPaymentMethodType {
    
    protected $name = 'icsd_zarinpal';
    
    public function initialize() {
        $this->settings = get_option('woocommerce_icsd_zarinpal_settings', []);
    }
    
    public function is_active() {
        return !empty($this->settings['enabled']) && 'yes' === $this->settings['enabled'];
    }
    
    public function get_payment_method_script_handles() {
        wp_register_script(
            'wc-zarinpal-blocks',
            plugins_url('build/zarinpal-block.js', __DIR__),
            ['wc-blocks-registry', 'wp-element', 'wp-i18n'],
            '1.0.0',
            true
        );
        return ['wc-zarinpal-blocks'];
    }
    
    public function get_payment_method_data() {
        return [
            'title'       => $this->settings['title'] ?? 'زرین‌پال',
            'description' => $this->settings['description'] ?? '',
            'supports'    => ['products', 'refunds'],
            'icon'        => plugins_url('assets/zarinpal-icon.png', __DIR__),
        ];
    }
}

// ثبت
add_action('woocommerce_blocks_payment_method_type_registration', function($registry) {
    $registry->register(new ZarinPal_Blocks_Support());
});

src/zarinpal-block.js
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
import { getSetting } from '@woocommerce/settings';
import { __ } from '@wordpress/i18n';

const settings = getSetting('icsd_zarinpal_data', {});

const Label = ({ components }) => {
    const { PaymentMethodLabel } = components;
    return (
        
    );
};

const Content = () => {
    return (
        

{settings.description}

{__('با کلیک روی دکمه پرداخت، به درگاه امن زرین‌پال منتقل می‌شوید.', 'icsd')}

); }; registerPaymentMethod({ name: 'icsd_zarinpal', label:

🔄 مایگریشن از Classic به Blocks

مرحله ۱: تست در محیط Staging

  1. یک کپی از سایت در staging بساز
  2. صفحه Cart را باز کن، محتوا را به Blocks تغییر بده
  3. صفحه Checkout همینطور
  4. تست کامل: خرید، کوپن، ارسال، پرداخت

مرحله ۲: تغییر صفحات

// در صفحه Cart، شورت‌کد را با block جایگزین کن:
// قبل:
[woocommerce_cart]

// بعد:
<!-- wp:woocommerce/cart -->
<div class="wp-block-woocommerce-cart">...</div>
<!-- /wp:woocommerce/cart -->

مرحله ۳: مایگریشن کدهای سفارشی

Classic Blocks معادل
woocommerce_checkout_fields filter extend_schema + Block
woocommerce_review_order_before_payment Block در slot مناسب
wc_add_notice() setValidationErrors() در React
woocommerce_after_order_notes Block در checkout-fields-block
⚠️ توجه: برخی افزونه‌های قدیمی هنوز با Blocks سازگار نیستند. قبل از مایگریشن، سازگاری همه افزونه‌ها را تست کنید.

مرحله ۴: نمایش بنر یادآوری برای کاربرانی که Classic می‌بینند

// در صورت تشخیص Classic Cart، بنر بزن
add_action('woocommerce_before_cart', function() {
    if (!has_block('woocommerce/cart')) {
        echo '<div class="alert alert-info">
            🆕 سبد جدید سریع‌تر و راحت‌تر است. به‌زودی فعال می‌شود.
        </div>';
    }
});

📝 خلاصه فصل

  • تفاوت Classic و Blocks Cart/Checkout
  • Store API برای ارتباط React با backend
  • extend_schema برای افزودن داده به cart/checkout
  • ساخت Block در صفحه Checkout با React
  • یکپارچه‌سازی درگاه پرداخت با AbstractPaymentMethodType
  • مایگریشن از Classic به Blocks
📚 مرجع رسمی: https://github.com/woocommerce/woocommerce-blocks/tree/trunk/docs

نمایش سایت

رنگ سایت
حالت نمایش
اندازهٔ متن
خوانایی

این تنظیمات فقط روی مرورگر شما ذخیره می‌شود.