🔌 فصل ۹: REST API ووکامرس
REST API ووکامرس به شما اجازه میدهد از هر برنامهای (موبایل، ربات تلگرام، اپلیکیشن دسکتاپ، Flutter) با فروشگاه ارتباط برقرار کنید. در این فصل تمام چم و خم آن را یاد میگیرید — مخصوصاً برای پروژههای Flutter شما.
🔑 تولید کلید API و احراز هویت
تولید کلید از پنل
- برو به
WooCommerce → Settings → Advanced → REST API - روی Add key کلیک کن
- توضیح: نام پروژه (مثل «اپ Flutter Apadana»)
- کاربر: یک کاربر با نقش Administrator یا Shop Manager
- دسترسی: Read/Write
- کلید Consumer Key و Consumer Secret را ذخیره کن
⚠️ امنیت: Consumer Secret فقط یک بار نمایش داده میشود. حتماً ذخیره کنید.
تست با curl
# لیست محصولات
curl https://shop.icsd.ir/wp-json/wc/v3/products
-u ck_xxxxxxxxxxxx:cs_xxxxxxxxxxxx
# با فیلتر
curl "https://shop.icsd.ir/wp-json/wc/v3/products?per_page=10&category=15"
-u ck_xxxxxxxxxxxx:cs_xxxxxxxxxxxx
روشهای احراز هویت
| روش | زمان استفاده | مثال |
|---|---|---|
| Basic Auth | HTTPS داخلی، server-to-server | -u ck:cs |
| OAuth 1.0a | HTTP بدون SSL (نامعمول) | مدیریت پیچیده |
| JWT | اپ موبایل/Flutter (با افزونه) | Authorization: Bearer xxx |
| Application Passwords | WP Core (نه WC) | کاربر WordPress عادی |
📦 API محصولات
Endpointهای پرکاربرد
| Method | URL | توضیح |
|---|---|---|
| GET | /wc/v3/products | لیست محصولات |
| GET | /wc/v3/products/{id} | محصول خاص |
| POST | /wc/v3/products | ساخت محصول جدید |
| PUT | /wc/v3/products/{id} | ویرایش محصول |
| DELETE | /wc/v3/products/{id} | حذف محصول |
| GET | /wc/v3/products/categories | لیست دستهها |
| GET | /wc/v3/products/{id}/variations | تنوعهای محصول متغیر |
پارامترهای فیلتر
GET /wc/v3/products?
per_page=20 # تعداد در صفحه (max=100)
&page=2 # صفحه
&search=فرش # جستجو
&category=15,16 # فیلتر دستهها
&tag=23 # فیلتر تگ
&status=publish # وضعیت
&featured=true # محصولات ویژه
&on_sale=true # تخفیفخورده
&min_price=100000 # حداقل قیمت
&max_price=500000 # حداکثر قیمت
&orderby=price # مرتبسازی
&order=asc # صعودی/نزولی
&stock_status=instock # موجود
&after=2024-01-01 # بعد از تاریخ
ساخت محصول با POST
curl -X POST https://shop.icsd.ir/wp-json/wc/v3/products
-u ck_xxx:cs_xxx
-H "Content-Type: application/json"
-d '{
"name": "فرش دستباف ۶ متری",
"type": "simple",
"regular_price": "12000000",
"sale_price": "10000000",
"description": "فرش دستباف نقشه افشار، رنگ شیری-قهوهای",
"short_description": "زیبا و بادوام",
"categories": [{"id": 15}],
"images": [
{"src": "https://example.com/carpet1.jpg"},
{"src": "https://example.com/carpet2.jpg"}
],
"stock_quantity": 1,
"manage_stock": true,
"weight": "8",
"dimensions": {"length": "300", "width": "200", "height": "1"},
"attributes": [
{"name": "اندازه", "options": ["۲ × ۳ متر"], "visible": true},
{"name": "جنس", "options": ["پشم"], "visible": true}
],
"meta_data": [
{"key": "_origin", "value": "اصفهان"},
{"key": "_pattern", "value": "افشار"}
]
}'
بهروزرسانی موجودی Bulk
curl -X POST https://shop.icsd.ir/wp-json/wc/v3/products/batch
-u ck_xxx:cs_xxx
-H "Content-Type: application/json"
-d '{
"update": [
{"id": 100, "stock_quantity": 5},
{"id": 101, "stock_quantity": 3},
{"id": 102, "stock_quantity": 10, "regular_price": "150000"}
]
}'
📋 API سفارشها
ساخت سفارش
curl -X POST https://shop.icsd.ir/wp-json/wc/v3/orders
-u ck_xxx:cs_xxx
-H "Content-Type: application/json"
-d '{
"payment_method": "icsd_zarinpal",
"payment_method_title": "زرینپال",
"set_paid": false,
"billing": {
"first_name": "محمدعلی",
"last_name": "ناظری",
"address_1": "خیابان امام",
"city": "کاشان",
"state": "اصفهان",
"postcode": "8716743",
"country": "IR",
"email": "ali@icsd.ir",
"phone": "09120000000"
},
"shipping": { ... },
"line_items": [
{"product_id": 100, "quantity": 2},
{"product_id": 101, "quantity": 1, "variation_id": 105}
],
"shipping_lines": [
{"method_id": "tipax", "method_title": "تیپاکس", "total": "50000"}
],
"meta_data": [
{"key": "_app_source", "value": "Flutter Android"}
]
}'
تغییر وضعیت سفارش
curl -X PUT https://shop.icsd.ir/wp-json/wc/v3/orders/250
-u ck_xxx:cs_xxx
-d '{"status": "completed"}'
افزودن یادداشت به سفارش
curl -X POST https://shop.icsd.ir/wp-json/wc/v3/orders/250/notes
-u ck_xxx:cs_xxx
-d '{
"note": "کد رهگیری: TPX12345",
"customer_note": true
}'
👥 API مشتریان
# ساخت مشتری
POST /wc/v3/customers
{
"email": "user@example.com",
"first_name": "علی",
"last_name": "محمدی",
"username": "ali",
"password": "Strong!Pass123",
"billing": {...},
"shipping": {...}
}
# جستجوی مشتری
GET /wc/v3/customers?email=user@example.com
GET /wc/v3/customers?role=customer&page=1
# سفارشهای یک مشتری
GET /wc/v3/orders?customer=15
🔧 ساخت Endpoint سفارشی
ووکامرس endpoint های پیشفرض دارد، اما گاهی نیاز به منطق سفارشی است:
includes/api/class-icsd-api.php
<?php
defined('ABSPATH') || exit;
class ICSD_Custom_API {
public function __construct() {
add_action('rest_api_init', [$this, 'register_routes']);
}
public function register_routes() {
// GET /wp-json/icsd/v1/featured-products
register_rest_route('icsd/v1', '/featured-products', [
'methods' => 'GET',
'callback' => [$this, 'get_featured'],
'permission_callback' => '__return_true', // عمومی
]);
// POST /wp-json/icsd/v1/cart/add
register_rest_route('icsd/v1', '/cart/add', [
'methods' => 'POST',
'callback' => [$this, 'add_to_cart'],
'permission_callback' => [$this, 'check_jwt_auth'],
'args' => [
'product_id' => ['required' => true, 'type' => 'integer'],
'quantity' => ['default' => 1, 'type' => 'integer'],
],
]);
// GET /wp-json/icsd/v1/dashboard
register_rest_route('icsd/v1', '/dashboard', [
'methods' => 'GET',
'callback' => [$this, 'get_dashboard'],
'permission_callback' => function() {
return current_user_can('manage_woocommerce');
},
]);
}
public function get_featured($request) {
$args = [
'post_type' => 'product',
'posts_per_page' => 8,
'meta_query' => [[
'key' => '_featured',
'value' => 'yes',
]],
];
$query = new WP_Query($args);
$products = [];
foreach ($query->posts as $post) {
$product = wc_get_product($post->ID);
$products[] = [
'id' => $product->get_id(),
'name' => $product->get_name(),
'price' => $product->get_price(),
'image' => wp_get_attachment_url($product->get_image_id()),
'url' => $product->get_permalink(),
'on_sale' => $product->is_on_sale(),
];
}
return rest_ensure_response($products);
}
public function add_to_cart($request) {
$product_id = $request->get_param('product_id');
$quantity = $request->get_param('quantity');
if (!WC()->cart) {
wc_load_cart();
}
$key = WC()->cart->add_to_cart($product_id, $quantity);
if (!$key) {
return new WP_Error('cart_error', 'افزودن به سبد ناموفق', ['status' => 400]);
}
return rest_ensure_response([
'success' => true,
'cart_key' => $key,
'cart_total' => WC()->cart->get_cart_contents_count(),
]);
}
public function get_dashboard($request) {
// آمار سریع برای داشبورد ادمین
$today_orders = wc_get_orders([
'date_created' => '>' . strtotime('today'),
'limit' => -1,
]);
$today_revenue = 0;
foreach ($today_orders as $order) {
if ($order->get_status() !== 'cancelled') {
$today_revenue += $order->get_total();
}
}
return rest_ensure_response([
'today_orders' => count($today_orders),
'today_revenue' => $today_revenue,
'low_stock' => count(wc_get_low_stock_products()),
]);
}
public function check_jwt_auth($request) {
// نیاز به افزونه JWT Auth یا کد اختصاصی
$auth_header = $request->get_header('authorization');
if (!$auth_header || strpos($auth_header, 'Bearer ') !== 0) {
return false;
}
$token = substr($auth_header, 7);
$user_id = $this->validate_jwt($token);
if (!$user_id) return false;
wp_set_current_user($user_id);
return true;
}
private function validate_jwt($token) {
// پیادهسازی validation با firebase/php-jwt
// برمیگرداند: user_id یا false
}
}
new ICSD_Custom_API();
📱 کلاینت Flutter کامل
برای پروژه Apadana شما — یک کلاینت تمیز:
lib/services/woocommerce_api.dart
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
class WooCommerceAPI {
final Dio _dio;
final String baseUrl;
final String consumerKey;
final String consumerSecret;
WooCommerceAPI({
required this.baseUrl,
required this.consumerKey,
required this.consumerSecret,
}) : _dio = Dio() {
_dio.options.baseUrl = '$baseUrl/wp-json/wc/v3';
_dio.options.connectTimeout = const Duration(seconds: 15);
_dio.options.receiveTimeout = const Duration(seconds: 15);
_dio.options.headers['Authorization'] =
'Basic ' + base64Encode(utf8.encode('$consumerKey:$consumerSecret'));
_dio.interceptors.add(LogInterceptor(responseBody: true));
}
// محصولات
Future<List<Product>> getProducts({
int page = 1,
int perPage = 20,
String? search,
int? categoryId,
}) async {
try {
final response = await _dio.get('/products', queryParameters: {
'page': page,
'per_page': perPage,
if (search != null) 'search': search,
if (categoryId != null) 'category': categoryId,
});
return (response.data as List)
.map((json) => Product.fromJson(json))
.toList();
} on DioException catch (e) {
throw _handleError(e);
}
}
Future<Product> getProduct(int id) async {
final response = await _dio.get('/products/$id');
return Product.fromJson(response.data);
}
// سفارش
Future<Order> createOrder(Map<String, dynamic> orderData) async {
final response = await _dio.post('/orders', data: orderData);
return Order.fromJson(response.data);
}
Future<List<Order>> getCustomerOrders(int customerId) async {
final response = await _dio.get('/orders', queryParameters: {
'customer': customerId,
'per_page': 50,
});
return (response.data as List).map((j) => Order.fromJson(j)).toList();
}
// کاتگوری
Future<List<Category>> getCategories() async {
final response = await _dio.get('/products/categories', queryParameters: {
'per_page': 100,
'hide_empty': true,
});
return (response.data as List).map((j) => Category.fromJson(j)).toList();
}
Exception _handleError(DioException e) {
if (e.response != null) {
final data = e.response!.data;
final message = data is Map ? (data['message'] ?? 'خطا') : 'خطا';
return Exception(message);
}
return Exception('عدم اتصال به سرور');
}
}
// مدل
class Product {
final int id;
final String name;
final String price;
final String? salePrice;
final List<String> images;
final bool inStock;
Product({
required this.id,
required this.name,
required this.price,
this.salePrice,
required this.images,
required this.inStock,
});
factory Product.fromJson(Map<String, dynamic> json) => Product(
id: json['id'],
name: json['name'],
price: json['price'] ?? '',
salePrice: json['sale_price'],
images: (json['images'] as List? ?? [])
.map((img) => img['src'] as String).toList(),
inStock: json['stock_status'] == 'instock',
);
}
⚡ بهینهسازی پرفورمنس API
۱. کش با Transient
add_filter('woocommerce_rest_prepare_product_object', function($response, $product, $request) {
$cache_key = 'wc_product_' . $product->get_id() . '_' . md5(serialize($request->get_params()));
$cached = get_transient($cache_key);
if ($cached) return $cached;
set_transient($cache_key, $response, 5 * MINUTE_IN_SECONDS);
return $response;
}, 10, 3);
// پاکسازی هنگام تغییر
add_action('woocommerce_update_product', function($product_id) {
global $wpdb;
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_wc_product_{$product_id}_%'");
});
۲. کاهش فیلدهای برگشتی
# فقط فیلدهای مورد نیاز
GET /wc/v3/products?_fields=id,name,price,images
۳. Pagination صحیح
// از header X-WP-Total استفاده کن
final response = await _dio.get('/products');
final total = int.parse(response.headers.value('x-wp-total') ?? '0');
final totalPages = int.parse(response.headers.value('x-wp-totalpages') ?? '0');
🔒 امنیت API
- همیشه از HTTPS استفاده کنید (SSL واجب است)
- کلیدها را در کد commit نکنید — از .env استفاده کنید
- برای کلیدهای موبایل، Read فقط (نه Write)
- Rate Limit در nginx یا Cloudflare
- IP Whitelist برای کلیدهای حساس
- لاگ کردن درخواستهای مشکوک
- Rotation منظم کلیدها (هر ۶ ماه)
Rate Limiting در ووکامرس
add_filter('rest_pre_dispatch', function($result, $server, $request) {
if (strpos($request->get_route(), '/wc/') === false) return $result;
$ip = $_SERVER['REMOTE_ADDR'];
$key = 'rate_limit_' . md5($ip);
$count = (int) get_transient($key);
if ($count >= 100) { // ۱۰۰ درخواست در دقیقه
return new WP_Error('rate_limit', 'محدودیت درخواست', ['status' => 429]);
}
set_transient($key, $count + 1, MINUTE_IN_SECONDS);
return $result;
}, 10, 3);
📝 خلاصه فصل
- تولید کلید REST API و روشهای احراز هویت
- API محصولات، سفارشها، مشتریان
- ساخت Endpoint سفارشی با register_rest_route
- کلاینت Flutter کامل برای Apadana
- بهینهسازی با کش، فیلد و Pagination
- امنیت با Rate Limit و HTTPS