'product', 'post_status' => $args['status'] ?? 'publish', 'posts_per_page' => (int)($args['per_page'] ?? 20), 'paged' => (int)($args['page'] ?? 1)]; if (!empty($args['search'])) $qArgs['s'] = $args['search']; $query = new \WP_Query($qArgs); $products = []; foreach ($query->posts as $p) { $product = wc_get_product($p->ID); $products[] = ['id' => $p->ID, 'name' => $p->post_title, 'status' => $p->post_status, 'price' => $product ? $product->get_price() : null, 'sku' => $product ? $product->get_sku() : null, 'stock' => $product ? $product->get_stock_quantity() : null, 'type' => $product ? $product->get_type() : 'simple']; } return ['products' => $products, 'total' => $query->found_posts]; } public static function getProduct(array $args): array { $product = wc_get_product((int)$args['product_id']); if (!$product) return ['error' => "Product not found: {$args['product_id']}"]; return ['id' => $product->get_id(), 'name' => $product->get_name(), 'type' => $product->get_type(), 'status' => $product->get_status(), 'sku' => $product->get_sku(), 'regular_price' => $product->get_regular_price(), 'sale_price' => $product->get_sale_price(), 'price' => $product->get_price(), 'stock_quantity' => $product->get_stock_quantity(), 'manage_stock' => $product->get_manage_stock(), 'description' => $product->get_description(), 'short_description' => $product->get_short_description(), 'categories' => wp_get_post_terms($product->get_id(), 'product_cat', ['fields' => 'names'])]; } public static function createProduct(array $args): array { $product = new \WC_Product_Simple(); $product->set_name($args['name']); $product->set_regular_price($args['regular_price']); $product->set_status($args['status'] ?? 'draft'); if (!empty($args['description'])) $product->set_description($args['description']); if (!empty($args['sku'])) $product->set_sku($args['sku']); if (isset($args['stock_quantity'])) { $product->set_manage_stock(true); $product->set_stock_quantity((int)$args['stock_quantity']); } $id = $product->save(); return ['id' => $id, 'name' => $args['name']]; } public static function updateProduct(array $args): array { $product = wc_get_product((int)$args['product_id']); if (!$product) return ['error' => "Product not found: {$args['product_id']}"]; if (isset($args['name'])) $product->set_name($args['name']); if (isset($args['regular_price'])) $product->set_regular_price($args['regular_price']); if (isset($args['sale_price'])) $product->set_sale_price($args['sale_price']); if (isset($args['status'])) $product->set_status($args['status']); if (isset($args['description'])) $product->set_description($args['description']); if (isset($args['stock_quantity'])) { $product->set_manage_stock(true); $product->set_stock_quantity((int)$args['stock_quantity']); } $product->save(); return ['id' => $product->get_id(), 'updated' => true]; } // ========================================================= // ORDERS // ========================================================= public static function listOrders(array $args): array { $qArgs = ['limit' => (int)($args['per_page'] ?? 20), 'paged' => (int)($args['page'] ?? 1), 'status' => $args['status'] ?? 'any']; if (!empty($args['customer_id'])) $qArgs['customer_id'] = (int)$args['customer_id']; $orders = wc_get_orders($qArgs); return ['orders' => array_map(fn($o) => ['id' => $o->get_id(), 'status' => $o->get_status(), 'total' => $o->get_total(), 'currency' => $o->get_currency(), 'customer_id' => $o->get_customer_id(), 'date' => $o->get_date_created()->date('Y-m-d H:i:s'), 'items_count' => $o->get_item_count()], $orders)]; } public static function getOrder(array $args): array { $order = wc_get_order((int)$args['order_id']); if (!$order) return ['error' => "Order not found: {$args['order_id']}"]; $items = []; foreach ($order->get_items() as $item) { $items[] = ['product_id' => $item->get_product_id(), 'name' => $item->get_name(), 'qty' => $item->get_quantity(), 'total' => $item->get_total()]; } return ['id' => $order->get_id(), 'status' => $order->get_status(), 'total' => $order->get_total(), 'subtotal' => $order->get_subtotal(), 'currency' => $order->get_currency(), 'customer_id' => $order->get_customer_id(), 'billing' => $order->get_address('billing'), 'shipping' => $order->get_address('shipping'), 'items' => $items, 'date' => $order->get_date_created()->date('Y-m-d H:i:s'), 'note' => $order->get_customer_note()]; } public static function updateOrderStatus(array $args): array { $order = wc_get_order((int)$args['order_id']); if (!$order) return ['error' => "Order not found: {$args['order_id']}"]; $order->update_status($args['status']); return ['id' => $order->get_id(), 'status' => $args['status'], 'updated' => true]; } // ========================================================= // CUSTOMERS // ========================================================= public static function listCustomers(array $args): array { $qArgs = ['role' => 'customer', 'number' => (int)($args['per_page'] ?? 20), 'paged' => (int)($args['page'] ?? 1)]; if (!empty($args['search'])) $qArgs['search'] = '*' . $args['search'] . '*'; $query = new \WP_User_Query($qArgs); $customers = []; foreach ($query->get_results() as $u) { $customer = new \WC_Customer($u->ID); $customers[] = ['id' => $u->ID, 'name' => $u->display_name, 'email' => $u->user_email, 'orders_count' => $customer->get_order_count(), 'total_spent' => $customer->get_total_spent()]; } return ['customers' => $customers, 'total' => $query->get_total()]; } // Alias for MCP tool name wc_get_customers public static function getCustomers(array $args): array { return self::listCustomers($args); } // ========================================================= // STORE STATS // ========================================================= public static function getStoreStats(array $args): array { $period = $args['period'] ?? 'month'; $after = match($period) { 'day' => date('Y-m-d', strtotime('-1 day')), 'week' => date('Y-m-d', strtotime('-7 days')), 'year' => date('Y-m-d', strtotime('-1 year')), default => date('Y-m-01'), }; $orders = wc_get_orders(['status' => ['completed', 'processing'], 'date_after' => $after, 'limit' => -1]); $revenue = array_sum(array_map(fn($o) => (float)$o->get_total(), $orders)); return ['period' => $period, 'revenue' => $revenue, 'currency' => get_woocommerce_currency(), 'orders_count' => count($orders), 'products_count' => wp_count_posts('product')->publish ?? 0]; } // ========================================================= // COUPONS // ========================================================= public static function getCoupons(array $args): array { $per_page = (int)($args['per_page'] ?? 20); $page = (int)($args['page'] ?? 1); $qArgs = ['post_type' => 'shop_coupon', 'post_status' => $args['status'] ?? 'publish', 'posts_per_page' => $per_page, 'paged' => $page]; if (!empty($args['code'])) $qArgs['title'] = $args['code']; $query = new \WP_Query($qArgs); $coupons = []; foreach ($query->posts as $p) { $coupon = new \WC_Coupon($p->ID); $coupons[] = self::formatCoupon($coupon); } return ['coupons' => $coupons, 'total' => $query->found_posts]; } public static function getCoupon(array $args): array { $id = $args['coupon_id'] ?? null; if ($id) { $coupon = new \WC_Coupon((int)$id); } elseif (!empty($args['code'])) { $coupon = new \WC_Coupon($args['code']); } else { return ['error' => 'Provide coupon_id or code']; } if (!$coupon->get_id()) return ['error' => 'Coupon not found']; return self::formatCoupon($coupon); } public static function createCoupon(array $args): array { if (empty($args['code'])) return ['error' => 'code is required']; $coupon = new \WC_Coupon(); $coupon->set_code(strtolower($args['code'])); $coupon->set_discount_type($args['discount_type'] ?? 'percent'); $coupon->set_amount($args['amount'] ?? 0); if (!empty($args['description'])) $coupon->set_description($args['description']); if (isset($args['usage_limit'])) $coupon->set_usage_limit((int)$args['usage_limit']); if (isset($args['usage_limit_per_user'])) $coupon->set_usage_limit_per_user((int)$args['usage_limit_per_user']); if (!empty($args['expiry_date'])) $coupon->set_date_expires(strtotime($args['expiry_date'])); if (isset($args['minimum_amount'])) $coupon->set_minimum_amount($args['minimum_amount']); if (isset($args['maximum_amount'])) $coupon->set_maximum_amount($args['maximum_amount']); if (isset($args['free_shipping'])) $coupon->set_free_shipping((bool)$args['free_shipping']); $id = $coupon->save(); return ['coupon_id' => $id, 'code' => $coupon->get_code(), 'created' => true]; } public static function updateCoupon(array $args): array { if (empty($args['coupon_id'])) return ['error' => 'coupon_id is required']; $coupon = new \WC_Coupon((int)$args['coupon_id']); if (!$coupon->get_id()) return ['error' => 'Coupon not found']; if (isset($args['code'])) $coupon->set_code(strtolower($args['code'])); if (isset($args['discount_type'])) $coupon->set_discount_type($args['discount_type']); if (isset($args['amount'])) $coupon->set_amount($args['amount']); if (isset($args['description'])) $coupon->set_description($args['description']); if (isset($args['usage_limit'])) $coupon->set_usage_limit((int)$args['usage_limit']); if (isset($args['expiry_date'])) $coupon->set_date_expires(strtotime($args['expiry_date'])); if (isset($args['minimum_amount'])) $coupon->set_minimum_amount($args['minimum_amount']); if (isset($args['maximum_amount'])) $coupon->set_maximum_amount($args['maximum_amount']); if (isset($args['free_shipping'])) $coupon->set_free_shipping((bool)$args['free_shipping']); $coupon->save(); return ['coupon_id' => $coupon->get_id(), 'updated' => true]; } public static function deleteCoupon(array $args): array { if (empty($args['coupon_id'])) return ['error' => 'coupon_id is required']; $coupon = new \WC_Coupon((int)$args['coupon_id']); if (!$coupon->get_id()) return ['error' => 'Coupon not found']; $force = (bool)($args['force'] ?? false); $result = $force ? wp_delete_post($coupon->get_id(), true) : wp_trash_post($coupon->get_id()); return ['coupon_id' => $args['coupon_id'], 'deleted' => (bool)$result, 'force' => $force]; } public static function getCouponCount(array $args): array { $counts = wp_count_posts('shop_coupon'); return ['published' => (int)($counts->publish ?? 0), 'draft' => (int)($counts->draft ?? 0), 'trash' => (int)($counts->trash ?? 0)]; } public static function emptyCouponTrash(array $args): array { global $wpdb; $ids = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type='shop_coupon' AND post_status='trash'"); $deleted = 0; foreach ($ids as $id) { if (wp_delete_post((int)$id, true)) $deleted++; } return ['deleted' => $deleted]; } private static function formatCoupon(\WC_Coupon $c): array { return ['id' => $c->get_id(), 'code' => $c->get_code(), 'discount_type' => $c->get_discount_type(), 'amount' => $c->get_amount(), 'usage_count' => $c->get_usage_count(), 'usage_limit' => $c->get_usage_limit(), 'expiry_date' => $c->get_date_expires() ? $c->get_date_expires()->date('Y-m-d') : null, 'free_shipping' => $c->get_free_shipping(), 'minimum_amount' => $c->get_minimum_amount(), 'maximum_amount' => $c->get_maximum_amount()]; } // ========================================================= // PRODUCT ATTRIBUTES // ========================================================= public static function getProductAttributes(array $args): array { $taxonomies = wc_get_attribute_taxonomies(); return ['attributes' => array_map(fn($a) => ['id' => $a->attribute_id, 'name' => $a->attribute_label, 'slug' => 'pa_' . $a->attribute_name, 'type' => $a->attribute_type, 'order_by' => $a->attribute_orderby], $taxonomies)]; } public static function createProductAttribute(array $args): array { if (empty($args['name'])) return ['error' => 'name is required']; $slug = $args['slug'] ?? sanitize_title($args['name']); $data = ['attribute_label' => $args['name'], 'attribute_name' => $slug, 'attribute_type' => $args['type'] ?? 'select', 'attribute_orderby' => $args['order_by'] ?? 'menu_order', 'attribute_public' => (int)($args['is_visible'] ?? 1)]; $id = wc_create_attribute($data); if (is_wp_error($id)) return ['error' => $id->get_error_message()]; return ['id' => $id, 'slug' => 'pa_' . $slug, 'name' => $args['name'], 'created' => true]; } public static function getAttributeTerms(array $args): array { if (empty($args['attribute_id']) && empty($args['attribute_slug'])) return ['error' => 'attribute_id or attribute_slug required']; if (!empty($args['attribute_id'])) { $attr = wc_get_attribute((int)$args['attribute_id']); if (!$attr) return ['error' => 'Attribute not found']; $taxonomy = 'pa_' . $attr->slug; } else { $taxonomy = strpos($args['attribute_slug'], 'pa_') === 0 ? $args['attribute_slug'] : 'pa_' . $args['attribute_slug']; } $terms = get_terms(['taxonomy' => $taxonomy, 'hide_empty' => false]); if (is_wp_error($terms)) return ['error' => $terms->get_error_message()]; return ['terms' => array_map(fn($t) => ['id' => $t->term_id, 'name' => $t->name, 'slug' => $t->slug, 'count' => $t->count], $terms)]; } public static function setProductAttributes(array $args): array { if (empty($args['product_id'])) return ['error' => 'product_id is required']; $product = wc_get_product((int)$args['product_id']); if (!$product) return ['error' => "Product not found: {$args['product_id']}"]; $attributes = []; foreach ((array)($args['attributes'] ?? []) as $attr_data) { $taxonomy = 'pa_' . ltrim($attr_data['slug'] ?? $attr_data['name'] ?? '', 'pa_'); $attr = new \WC_Product_Attribute(); $attr->set_name($taxonomy); $attr->set_options(array_map('intval', $attr_data['term_ids'] ?? [])); $attr->set_position($attr_data['position'] ?? 0); $attr->set_visible((bool)($attr_data['is_visible'] ?? true)); $attr->set_variation((bool)($attr_data['is_variation'] ?? false)); $attributes[] = $attr; } $product->set_attributes($attributes); $product->save(); return ['product_id' => $product->get_id(), 'attributes_set' => count($attributes)]; } // ========================================================= // PRODUCT VARIATIONS // ========================================================= public static function getProductVariations(array $args): array { if (empty($args['product_id'])) return ['error' => 'product_id is required']; $product = wc_get_product((int)$args['product_id']); if (!$product || $product->get_type() !== 'variable') return ['error' => 'Variable product not found']; $variations = []; foreach ($product->get_children() as $var_id) { $variation = wc_get_product($var_id); if (!$variation) continue; $variations[] = self::formatVariation($variation); } return ['product_id' => $product->get_id(), 'variations' => $variations]; } public static function getVariation(array $args): array { if (empty($args['variation_id'])) return ['error' => 'variation_id is required']; $variation = wc_get_product((int)$args['variation_id']); if (!$variation || $variation->get_type() !== 'variation') return ['error' => 'Variation not found']; return self::formatVariation($variation); } public static function createVariation(array $args): array { if (empty($args['product_id'])) return ['error' => 'product_id is required']; $parent = wc_get_product((int)$args['product_id']); if (!$parent) return ['error' => "Product not found: {$args['product_id']}"]; $variation = new \WC_Product_Variation(); $variation->set_parent_id($parent->get_id()); $variation->set_status($args['status'] ?? 'publish'); if (isset($args['regular_price'])) $variation->set_regular_price($args['regular_price']); if (isset($args['sale_price'])) $variation->set_sale_price($args['sale_price']); if (isset($args['sku'])) $variation->set_sku($args['sku']); if (isset($args['stock_quantity'])) { $variation->set_manage_stock(true); $variation->set_stock_quantity((int)$args['stock_quantity']); } if (!empty($args['attributes'])) { $attrs = []; foreach ($args['attributes'] as $key => $val) { $attrs['attribute_pa_' . ltrim($key, 'pa_')] = sanitize_title($val); } $variation->set_attributes($attrs); } $id = $variation->save(); return ['variation_id' => $id, 'product_id' => $parent->get_id(), 'created' => true]; } public static function updateVariation(array $args): array { if (empty($args['variation_id'])) return ['error' => 'variation_id is required']; $variation = wc_get_product((int)$args['variation_id']); if (!$variation || $variation->get_type() !== 'variation') return ['error' => 'Variation not found']; if (isset($args['regular_price'])) $variation->set_regular_price($args['regular_price']); if (isset($args['sale_price'])) $variation->set_sale_price($args['sale_price']); if (isset($args['status'])) $variation->set_status($args['status']); if (isset($args['sku'])) $variation->set_sku($args['sku']); if (isset($args['stock_quantity'])) { $variation->set_manage_stock(true); $variation->set_stock_quantity((int)$args['stock_quantity']); } $variation->save(); return ['variation_id' => $variation->get_id(), 'updated' => true]; } public static function deleteVariation(array $args): array { if (empty($args['variation_id'])) return ['error' => 'variation_id is required']; $variation = wc_get_product((int)$args['variation_id']); if (!$variation || $variation->get_type() !== 'variation') return ['error' => 'Variation not found']; $result = wp_delete_post($variation->get_id(), true); return ['variation_id' => $args['variation_id'], 'deleted' => (bool)$result]; } public static function batchUpdateVariations(array $args): array { if (empty($args['product_id'])) return ['error' => 'product_id is required']; $results = ['created' => [], 'updated' => [], 'deleted' => []]; foreach ((array)($args['create'] ?? []) as $data) { $data['product_id'] = $args['product_id']; $results['created'][] = self::createVariation($data); } foreach ((array)($args['update'] ?? []) as $data) { $results['updated'][] = self::updateVariation($data); } foreach ((array)($args['delete'] ?? []) as $vid) { $results['deleted'][] = self::deleteVariation(['variation_id' => $vid]); } return $results; } private static function formatVariation(\WC_Product_Variation $v): array { return ['id' => $v->get_id(), 'parent_id' => $v->get_parent_id(), 'sku' => $v->get_sku(), 'status' => $v->get_status(), 'price' => $v->get_price(), 'regular_price' => $v->get_regular_price(), 'sale_price' => $v->get_sale_price(), 'stock_quantity' => $v->get_stock_quantity(), 'attributes' => $v->get_variation_attributes()]; } }