WooCommerce REST API - Siparişlerin Filtrelenmesi

Woocommerce rest orders prepare object query kullanımı

WordPress pek çok işlevine eklenebilmemiz ve kimi durumlarda müdahale edebilmemiz için kanca (hook) olarak ifade edilen çeşitli fonksiyonlar sunar.

AA

WordPress ve WordPress'i alışveriş işlemi gerçekleştirmeye uygun hale getiren WooCommerce eklentisi temelinde REST API endpoint'leri üzerinden pek çok bilgiye JSON formatında erişebilmekteyiz. WooCommerce API Nedir? Nasıl Kullanılır? başlıklı yazıda temel bir şekilde değinmeye çalışmıştım. Yakın zamanda aldığım bir e-posta temelinde Orders ile ilgili hook(ları) incelemem gerekti. Edindiğim bilgileri aşağıda çeşitli örnekler temelinde açıklamaya çalışacağım.

Siparişler (Order)

WOO API, sipariş işlemlerine uzaktan erişebilmek adına /wp-json/wc/v3/orders/ enpoint'ini sunar.

curl -X GET https://alanadi.com/wp-json/wc/v3/orders \
    -u consumer_key:consumer_secret \
    -H "Content-Type: application/json"

Bu sayede, sipariş bilgilerini (satın alma, fatura, teslimat, ödeme yöntemi, sipariş durumu, siparişte yer alan ürünler, vb.) bir arada görebilmekeyiz. Aynı şekilde, bu bilgileri ileterek farklı bir servis üzerinden oluşurulan siparişleri de WooCommmerce içeriğine akarabiliriz.

curl -X POST https://alanadi.com/wp-json/wc/v3/orders \
    -u consumer_key:consumer_secret \
    -H "Content-Type: application/json" \
    -d '{
  "payment_method": "bacs",
  "payment_method_title": "Direct Bank Transfer",
  "set_paid": true,
  "billing": {
    "first_name": "John",
    "last_name": "Doe",
    "address_1": "969 Market",
    "address_2": "",
    "city": "San Francisco",
    "state": "CA",
    "postcode": "94103",
    "country": "US",
    "email": "john.doe@alanadi.com",
    "phone": "(555) 555-5555"
  },
  "shipping": {
    "first_name": "John",
    "last_name": "Doe",
    "address_1": "969 Market",
    "address_2": "",
    "city": "San Francisco",
    "state": "CA",
    "postcode": "94103",
    "country": "US"
  },
  "line_items": [
    {
      "product_id": 93,
      "quantity": 2
    },
    {
      "product_id": 22,
      "variation_id": 23,
      "quantity": 1
    }
  ],
  "shipping_lines": [
    {
      "method_id": "flat_rate",
      "method_title": "Flat Rate",
      "total": 10
    }
  ]
}'

/wp-json/wc/v3/orders bize siparişleri ID temelinde (ve dolayısıyla tarihsel olarak yeniden eskiye doğru) sıralar. &order=asc ile bu sıralamanın yönü değiştirilebilir.

Gelelim asıl konumuza.

Siparişlerle ilgili var olan endpoint üzerinden parametreler aracılığı ile işlemler gerçekleştirebilmek adına woocommerce_rest_orders_prepare_object_query hook'undan faydalanırız.

apply_filters( 'woocommerce_rest_orders_prepare_object_query', array $args, WP_REST_Request $request )

Örneğin, aşağıda yer alan örnek sayesinde modified_after parametresi kullanılarak siparişlerin güncellenme tarihine göre filtrelenmesi sağlanabilmektedir. Siparişlerin tarih bilgileri date_created ve date_modified ile gösterilmektedir1.

add_filter('woocommerce_rest_orders_prepare_object_query', function(array $args, \WP_REST_Request $request) {
    $modified_after = $request->get_param('modified_after');

    if (!$modified_after) return $args;

    $args['date_query'][0]['column'] = 'post_modified';
    $args['date_query'][0]['after']  = $modified_after;

    return $args;

}, 10, 2);

Peki, sadece belirli ürünleri içeren siparişleri (line_items > product_id) nasıl görebiliriz?

Bu işlemi $wpdb aracılığı gerçekleştirebiliriz2.

add_filter('woocommerce_rest_orders_prepare_object_query', function (array $args, \WP_REST_Request $request) {

  global $wpdb;

  $product = $request->get_param('product');
  if (!$product) return $args;

  $order_ids = $wpdb->get_col(
    $wpdb->prepare("
      SELECT order_id
      FROM {$wpdb->order_items}
      WHERE order_item_id IN (SELECT order_item_id FROM {$wpdb->order_itemmeta} WHERE meta_key = '_product_id' AND meta_value = %d)
      AND order_item_type = 'line_item'",
      $request['product']
    )
  );

  if(!empty($args['post__in'])) $args['post__in'] = array_unique(array_merge($args['post__in'], $order_ids));
  else $args['post__in'] = $order_ids;

  return $args;
}, 10, 2);

Dokan3 gibi çoklu satıcı eklentilerinden birini kullanıyorsanız, ilgili alışverişleri vendor (satıcı) düzeyinde filtrelemek ve/veya ilgili satıcılarla bu endpoint'leri paylaşmak isteyebilirsiniz. Bu durumda, eklentinin oluşturduğu veri tablolarındaki id ve store name alanlarını sürece dahil etmemiz gerekir4.

Peki, bu işlemi nasıl gerçekleştirebiliriz?

add_filter("woocommerce_rest_orders_prepare_object_query", function (array $args, \WP_REST_Request $request) {

  global $wpdb;

  $storeid = $request->get_param('storeid');
  $storename = $request->get_param('storename');

  if (!$storeid && !$storename) return $args;

  $getVendorName = $wpdb->get_col(
    $wpdb->prepare("
      SELECT user_id FROM {$wpdb->usermeta} 
      WHERE meta_key = 'dokan_store_name' AND meta_value = '".esc_attr($storename)."'"
    )
  );

  $post_ids = $wpdb->get_col(
    $wpdb->prepare("
      SELECT DISTINCT p1.post_id
      FROM {$wpdb->postmeta} p1
      INNER JOIN {$wpdb->postmeta} p2 ON p1.post_id = p2.post_id
      WHERE
        ( p1.meta_key = '_dokan_vendor_id' AND p1.meta_value = ".esc_attr( $storeid ?: $getVendorName[0] )." )
      "
    )
  );

  if(!empty($args['post__in'])) $args['post__in'] = array_unique(array_merge($args['post__in'], $post_ids));
  else $args['post__in'] = $post_ids;

  return $args;
}, 10, 2);

Bu ve benzeri örnekleri daha da çoğaltabiliriz. Özellikle merak ettiğiniz bir konu olursa, inceleyip örnekler arasına dahil etmeye çalışırım.