'GET', 'callback' => [__CLASS__, 'list_coupons'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); // Get single coupon register_rest_route('woonoow/v1', '/coupons/(?P\d+)', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_coupon'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); // Create coupon register_rest_route('woonoow/v1', '/coupons', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'create_coupon'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); // Update coupon register_rest_route('woonoow/v1', '/coupons/(?P\d+)', [ 'methods' => 'PUT', 'callback' => [__CLASS__, 'update_coupon'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); // Delete coupon register_rest_route('woonoow/v1', '/coupons/(?P\d+)', [ 'methods' => 'DELETE', 'callback' => [__CLASS__, 'delete_coupon'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); } /** * GET /woonoow/v1/coupons * List all coupons with pagination and filtering */ public static function list_coupons(WP_REST_Request $request): WP_REST_Response { $page = max(1, (int) $request->get_param('page') ?: 1); $per_page = max(1, min(100, (int) $request->get_param('per_page') ?: 20)); $search = sanitize_text_field($request->get_param('search') ?: ''); $discount_type = sanitize_text_field($request->get_param('discount_type') ?: ''); $args = [ 'post_type' => 'shop_coupon', 'post_status' => 'publish', 'posts_per_page' => $per_page, 'paged' => $page, 'orderby' => 'date', 'order' => 'DESC', ]; // Search by code if ($search) { $args['s'] = $search; } // Filter by discount type if ($discount_type) { $args['meta_query'] = [ [ 'key' => 'discount_type', 'value' => $discount_type, 'compare' => '=', ], ]; } $query = new \WP_Query($args); $coupons = []; foreach ($query->posts as $post) { $coupon = new WC_Coupon($post->ID); $coupons[] = self::format_coupon($coupon); } return new WP_REST_Response([ 'coupons' => $coupons, 'total' => $query->found_posts, 'page' => $page, 'per_page' => $per_page, 'total_pages' => $query->max_num_pages, ], 200); } /** * GET /woonoow/v1/coupons/{id} * Get single coupon */ public static function get_coupon(WP_REST_Request $request): WP_REST_Response { $id = (int) $request->get_param('id'); $coupon = new WC_Coupon($id); if (!$coupon->get_id()) { return new WP_REST_Response([ 'error' => 'not_found', 'message' => __('Coupon not found', 'woonoow'), ], 404); } return new WP_REST_Response(self::format_coupon($coupon, true), 200); } /** * POST /woonoow/v1/coupons * Create new coupon */ public static function create_coupon(WP_REST_Request $request): WP_REST_Response { $data = $request->get_json_params(); // Validate required fields if (empty($data['code'])) { return new WP_REST_Response([ 'error' => 'missing_code', 'message' => __('Coupon code is required', 'woonoow'), ], 400); } // Check if code already exists $existing = get_page_by_title($data['code'], OBJECT, 'shop_coupon'); if ($existing) { return new WP_REST_Response([ 'error' => 'code_exists', 'message' => __('Coupon code already exists', 'woonoow'), ], 400); } try { $coupon = new WC_Coupon(); self::update_coupon_data($coupon, $data); $coupon->save(); return new WP_REST_Response(self::format_coupon($coupon, true), 201); } catch (\Exception $e) { return new WP_REST_Response([ 'error' => 'create_failed', 'message' => __('Failed to create coupon', 'woonoow'), ], 500); } } /** * PUT /woonoow/v1/coupons/{id} * Update coupon */ public static function update_coupon(WP_REST_Request $request): WP_REST_Response { $id = (int) $request->get_param('id'); $data = $request->get_json_params(); $coupon = new WC_Coupon($id); if (!$coupon->get_id()) { return new WP_REST_Response([ 'error' => 'not_found', 'message' => __('Coupon not found', 'woonoow'), ], 404); } try { self::update_coupon_data($coupon, $data); $coupon->save(); return new WP_REST_Response(self::format_coupon($coupon, true), 200); } catch (\Exception $e) { return new WP_REST_Response([ 'error' => 'update_failed', 'message' => __('Failed to update coupon', 'woonoow'), ], 500); } } /** * DELETE /woonoow/v1/coupons/{id} * Delete coupon */ public static function delete_coupon(WP_REST_Request $request): WP_REST_Response { $id = (int) $request->get_param('id'); $force = $request->get_param('force') === 'true'; $coupon = new WC_Coupon($id); if (!$coupon->get_id()) { return new WP_REST_Response([ 'error' => 'not_found', 'message' => __('Coupon not found', 'woonoow'), ], 404); } $result = wp_delete_post($id, $force); if (!$result) { return new WP_REST_Response([ 'error' => 'delete_failed', 'message' => __('Failed to delete coupon', 'woonoow'), ], 500); } return new WP_REST_Response([ 'success' => true, 'id' => $id, ], 200); } /** * Format coupon for API response * * @param WC_Coupon $coupon * @param bool $full Include full details * @return array */ private static function format_coupon(WC_Coupon $coupon, bool $full = false): array { $data = [ 'id' => $coupon->get_id(), 'code' => $coupon->get_code(), 'amount' => (float) $coupon->get_amount(), 'discount_type' => $coupon->get_discount_type(), 'description' => $coupon->get_description(), 'usage_count' => $coupon->get_usage_count(), 'usage_limit' => $coupon->get_usage_limit() ?: null, 'date_expires' => $coupon->get_date_expires() ? $coupon->get_date_expires()->date('Y-m-d') : null, ]; if ($full) { $data = array_merge($data, [ 'individual_use' => $coupon->get_individual_use(), 'product_ids' => $coupon->get_product_ids(), 'excluded_product_ids' => $coupon->get_excluded_product_ids(), 'usage_limit_per_user' => $coupon->get_usage_limit_per_user() ?: null, 'limit_usage_to_x_items' => $coupon->get_limit_usage_to_x_items() ?: null, 'free_shipping' => $coupon->get_free_shipping(), 'product_categories' => $coupon->get_product_categories(), 'excluded_product_categories' => $coupon->get_excluded_product_categories(), 'exclude_sale_items' => $coupon->get_exclude_sale_items(), 'minimum_amount' => $coupon->get_minimum_amount() ? (float) $coupon->get_minimum_amount() : null, 'maximum_amount' => $coupon->get_maximum_amount() ? (float) $coupon->get_maximum_amount() : null, 'email_restrictions' => $coupon->get_email_restrictions(), ]); } return $data; } /** * Update coupon data from request * * @param WC_Coupon $coupon * @param array $data */ private static function update_coupon_data(WC_Coupon $coupon, array $data) { if (isset($data['code'])) { $coupon->set_code(sanitize_text_field($data['code'])); } if (isset($data['amount'])) { $coupon->set_amount((float) $data['amount']); } if (isset($data['discount_type'])) { $coupon->set_discount_type(sanitize_text_field($data['discount_type'])); } if (isset($data['description'])) { $coupon->set_description(wp_kses_post($data['description'])); } if (isset($data['date_expires'])) { $coupon->set_date_expires($data['date_expires'] ? $data['date_expires'] : null); } if (isset($data['individual_use'])) { $coupon->set_individual_use((bool) $data['individual_use']); } if (isset($data['product_ids'])) { $coupon->set_product_ids(array_map('intval', (array) $data['product_ids'])); } if (isset($data['excluded_product_ids'])) { $coupon->set_excluded_product_ids(array_map('intval', (array) $data['excluded_product_ids'])); } if (isset($data['usage_limit'])) { $coupon->set_usage_limit($data['usage_limit'] ? (int) $data['usage_limit'] : null); } if (isset($data['usage_limit_per_user'])) { $coupon->set_usage_limit_per_user($data['usage_limit_per_user'] ? (int) $data['usage_limit_per_user'] : null); } if (isset($data['limit_usage_to_x_items'])) { $coupon->set_limit_usage_to_x_items($data['limit_usage_to_x_items'] ? (int) $data['limit_usage_to_x_items'] : null); } if (isset($data['free_shipping'])) { $coupon->set_free_shipping((bool) $data['free_shipping']); } if (isset($data['product_categories'])) { $coupon->set_product_categories(array_map('intval', (array) $data['product_categories'])); } if (isset($data['excluded_product_categories'])) { $coupon->set_excluded_product_categories(array_map('intval', (array) $data['excluded_product_categories'])); } if (isset($data['exclude_sale_items'])) { $coupon->set_exclude_sale_items((bool) $data['exclude_sale_items']); } if (isset($data['minimum_amount'])) { $coupon->set_minimum_amount($data['minimum_amount'] ? (float) $data['minimum_amount'] : ''); } if (isset($data['maximum_amount'])) { $coupon->set_maximum_amount($data['maximum_amount'] ? (float) $data['maximum_amount'] : ''); } if (isset($data['email_restrictions'])) { $coupon->set_email_restrictions(array_map('sanitize_email', (array) $data['email_restrictions'])); } } }