'GET', 'callback' => array($this, 'get_product_batch'), 'permission_callback' => array($this, 'check_batch_permissions'), )); register_rest_route('a2cai/v1', '/health', array( 'methods' => 'GET', 'callback' => array($this, 'get_health'), 'permission_callback' => array($this, 'check_batch_permissions'), )); } public function get_health(WP_REST_Request $request) { global $wp_version; $health_data = array( 'status' => 'healthy', 'version' => ACAI_VERSION, 'environment' => array( 'wordpress' => $wp_version, 'woocommerce' => defined('WC_VERSION') ? WC_VERSION : null, 'php' => PHP_VERSION, ), 'timestamp' => current_time('mysql'), ); return rest_ensure_response($health_data); } public function get_product_batch(WP_REST_Request $request) { $batch_size = 500; $batch_number = $request->get_param('batch_number') ? max(1, intval($request->get_param('batch_number'))) : 1; $offset = ($batch_number - 1) * $batch_size; $args = array( 'post_type' => 'product', 'post_status' => 'publish', 'posts_per_page' => $batch_size, 'offset' => $offset, 'fields' => 'ids', // Only get post IDs for efficiency ); $products_query = new WP_Query($args); $products = array_map(function ($post_id) { $product = wc_get_product($post_id); // Main image $image_id = get_post_thumbnail_id($post_id); $image_src = wp_get_attachment_image_src($image_id, 'full'); $image_url = $image_src ? $image_src[0] : null; // Gallery images $gallery_ids = $product->get_gallery_image_ids(); $image_urls = array(); foreach ($gallery_ids as $gallery_id) { $gallery_src = wp_get_attachment_image_src($gallery_id, 'full'); if ($gallery_src) { $image_urls[] = $gallery_src[0]; } } $in_stock = $product->is_in_stock(); $is_published = $product->get_status() === 'publish'; $visible = $is_published && $product->get_catalog_visibility() !== 'hidden'; // Categories $category_ids = $product->get_category_ids(); $categories = array(); foreach ($category_ids as $cat_id) { $term = get_term($cat_id, 'product_cat'); if ($term && !is_wp_error($term)) { $categories[] = $term->name; } } $category = !empty($categories) ? implode(' > ', $categories) : null; // Rating and reviews $rating = $product->get_average_rating(); $review_count = $product->get_review_count(); // Compare at price (regular price when on sale) $regular_price = $product->get_regular_price(); $sale_price = $product->get_sale_price(); $compare_at_price = ($sale_price && $regular_price !== $sale_price) ? floatval($regular_price) : null; // Weight $weight = $product->get_weight(); $weight_unit = $weight ? get_option('woocommerce_weight_unit', 'kg') : null; return array( 'id' => strval($post_id), 'title' => $product->get_title(), 'price' => $product->get_price() ? floatval($product->get_price()) : null, 'imageUrl' => $image_url, 'inStock' => $in_stock, 'visible' => $visible, // Basic Product Metadata 'description' => $product->get_description() ?: $product->get_short_description(), 'brand' => $this->get_product_brand($product, $post_id), 'category' => $category, 'currency' => get_woocommerce_currency(), 'productUrl' => get_permalink($post_id), 'rating' => $rating ? floatval($rating) : null, 'reviewCount' => $review_count ? intval($review_count) : null, 'compareAtPrice' => $compare_at_price, 'sku' => $product->get_sku() ?: null, 'stockQuantity' => $product->get_stock_quantity(), 'imageUrls' => !empty($image_urls) ? $image_urls : null, // Packaging & Sizing - only pass weight from WooCommerce // packCount, itemSizeValue, itemSizeUnit, attributes will be AI-extracted during indexing 'weight' => $weight ? floatval($weight) : null, 'weightUnit' => $weight_unit, ); }, $products_query->posts); $total_products = $products_query->found_posts; $more_products = $total_products > $offset + count($products); return rest_ensure_response(array( 'products' => $products, 'moreBatches' => $more_products, 'totalProducts' => $total_products, 'currentBatch' => $batch_number, 'totalBatches' => ceil($total_products / $batch_size) )); } /** * Get product brand from various sources */ private function get_product_brand($product, $post_id) { // Check for brand taxonomy (used by various brand plugins) $brand_taxonomies = array('product_brand', 'pa_brand', 'brand', 'yith_product_brand'); foreach ($brand_taxonomies as $taxonomy) { if (taxonomy_exists($taxonomy)) { $terms = wc_get_product_terms($post_id, $taxonomy, array('fields' => 'names')); if (!empty($terms)) { return $terms[0]; } } } // Check for brand attribute $attributes = $product->get_attributes(); foreach ($attributes as $attribute) { $name = strtolower($attribute->get_name()); if (strpos($name, 'brand') !== false || strpos($name, 'marca') !== false) { if ($attribute->is_taxonomy()) { $terms = wc_get_product_terms($post_id, $attribute->get_name(), array('fields' => 'names')); if (!empty($terms)) { return $terms[0]; } } else { $options = $attribute->get_options(); if (!empty($options)) { return $options[0]; } } } } return null; } public function check_batch_permissions(WP_REST_Request $request) { $auth_header = $request->get_header('Authorization'); if (!$auth_header || strpos($auth_header, 'Bearer ') !== 0) { return new WP_Error('invalid_token', esc_html__('Invalid or missing bearer token', 'add-to-cart-ai'), array('status' => 401)); } $token = substr($auth_header, 7); $stored_key = get_option('a2cai_activation_key'); if (!hash_equals($stored_key, $token)) { return new WP_Error('invalid_token', esc_html__('Invalid bearer token', 'add-to-cart-ai'), array('status' => 401)); } return true; } } new ACAI_API();