query_vars['adscaleProducts'] = sanitize_key( wp_unslash( $_GET['adscaleProducts'] ) ); } // make sure endpoint request if ( ! isset( $wp->query_vars['adscaleProducts'] ) ) { return; } try { ob_start(); // Error handler self::setErrorHandler(); Helper::nocache_headers(); // Check Request (Guards) self::checkRequest(); ob_end_clean(); // Handle Request self::handleRequest(); // Default error Helper::send_response_formatted_error( self::makeErrorBody() ); } catch ( PluginApiException $ex ) { Helper::send_response_formatted_error( self::makeErrorBody( $ex->getApiErrorCode(), $ex->getMessage(), $ex->getApiErrorDetails() ) ); } catch ( \Exception $ex ) { Helper::send_response_formatted_error( self::makeErrorBody( $ex->getCode(), $ex->getMessage() ) ); } } public static function checkRequest() { parent::checkRequest(); self::initParams(); // last id from the previous page if ( ! self::checkParamAfter() ) { Helper::send_response_formatted_error( self::makeErrorBody('I001','Invalid argument value', 'after' ) ); } // Number of items per page, min if ( ! self::checkParamLimitForMin() ) { Helper::send_response_formatted_error( self::makeErrorBody('I001','Invalid argument value', 'limit' ) ); } // Number of items per page, max if ( ! self::checkParamLimitForMax() ) { Helper::send_response_formatted_error( self::makeErrorBody('I001','Invalid argument value', 'limit' ) ); } // Number of Variants, min if ( ! self::checkParamVariantsLimitForMin() ) { Helper::send_response_formatted_error( self::makeErrorBody('I001','Invalid argument value', 'variants_limit' ) ); } } public static function initParams() { self::$requestParams['after'] = Helper::get_post_body_data_value( 'after' ); self::$requestParams['limit'] = Helper::get_post_body_data_value( 'limit' ); self::$requestParams['variants_limit'] = Helper::get_post_body_data_value( 'variants_limit' ); self::$requestParams['ids'] = Helper::get_post_body_data_value( 'ids' ); // Set default params if not exists if ( null === self::$requestParams['after'] ) { self::$requestParams['after'] = 0; } if ( null === self::$requestParams['limit'] ) { self::$requestParams['limit'] = self::$defaultLimit; } if ( null === self::$requestParams['variants_limit'] ) { self::$requestParams['variants_limit'] = self::$defaultVariantsLimit; } if ( null === self::$requestParams['ids'] ) { self::$requestParams['ids'] = self::$defaultIds; } // Params Type Hinting self::$requestParams['after'] = (int) self::$requestParams['after']; self::$requestParams['limit'] = (int) self::$requestParams['limit']; self::$requestParams['variants_limit'] = (int) self::$requestParams['variants_limit']; self::$requestParams['ids'] = self::resolveIds( self::$requestParams['ids'] ); } /** * Last id from the previous page, check if is valid * * @return bool is valid */ public static function checkParamAfter() { return self::$requestParams['after'] >= 0; } /** * Check min Number of items per page * * @return bool is valid */ public static function checkParamLimitForMin() { return self::$requestParams['limit'] > 0; } /** * Check max Number of items per page * * @return bool is valid */ public static function checkParamLimitForMax() { return self::$requestParams['limit'] <= self::$maxLimit; } /** * Check min Number of Variants * * @return bool is valid */ public static function checkParamVariantsLimitForMin() { return self::$requestParams['variants_limit'] > 1; } /** * Resolve Ids * * @param mixed $ids * * @return array * */ private static function resolveIds( $ids ) { if ( is_float( $ids ) ) { Helper::send_response_formatted_error( self::makeErrorBody('I001','Invalid argument value', 'ids' ) ); } if ( is_numeric( $ids ) ) { $ids = [ (int) $ids ]; } if ( ! is_array( $ids ) ) { Helper::send_response_formatted_error( self::makeErrorBody('I001','Invalid argument value', 'ids' ) ); } $filteredIds = []; foreach ( $ids as $id ) { if ( ! is_numeric( $id ) || is_float( $id ) ) { Helper::send_response_formatted_error( self::makeErrorBody('I001','Invalid argument value', 'ids' ) ); } $filteredIds[] = (int) $id; } return $filteredIds; } /** * Handle API request * */ public static function handleRequest() { $products_data = []; $args = [ 'status' => [ 'private', 'publish' ], 'limit' => - 1, 'orderby' => 'ID', 'order' => 'ASC', 'paginate' => false, ]; // Exclude Sorts by plugin Post Types Order if (class_exists('CPTO')) { $args['ignore_custom_sort'] = true; } if ( self::$requestParams['limit'] ) { $args['limit'] = self::$requestParams['limit']; } if ( self::$requestParams['ids'] ) { $args['include'] = self::$requestParams['ids']; } add_filter( 'posts_clauses', [ self::class, 'queryFilter' ], 777, 2 ); $products_objs = wc_get_products( $args ); remove_filter( 'posts_clauses', [ self::class, 'queryFilter' ], 777 ); if ( ! is_array( $products_objs ) ) { Helper::send_response_formatted_error( self::makeErrorBody('S000','Unknown error', 'Products could not be found' ) ); } foreach ( $products_objs as $product_obj ) { /* @var \WC_Product $product_obj Product object */ $product_data = self::getProductData( $product_obj ); if ( ! $product_data ) { continue; } $products_data[] = self::getProductData( $product_obj ); } Helper::send_response_formatted_success( [ 'products' => $products_data, ] ); } /** * Filters all query clauses at once. * * @param string[] $clauses Associative array of the clauses for the query. * @param \WP_Query $query The WP_Query instance (passed by reference). * * @return string[] $clauses Filtered Array of query SQL clauses. */ public static function queryFilter( $clauses, $query ) { global $wpdb; $clauses['orderby']= "{$wpdb->posts}.ID ASC"; if ( self::$requestParams['after'] ) { $clauses['where'] .= ' AND ' . $wpdb->prepare( "{$wpdb->posts}.ID > %d", (int) self::$requestParams['after'] ); } return $clauses; } /** * Get product data * * @param \WC_Product $product * * @return array */ public static function getProductData( $product ) { try { if ( ! $product instanceof \WC_Product ) { return []; } $product_id = (int) $product->get_id(); // Get tag names $tag_names = wp_get_post_terms( $product_id, 'product_tag', [ 'fields' => 'names' ] ); // Get brand names (support common brand taxonomies) $brand_names = []; $brand_taxonomies = [ 'product_brand', 'brand', 'brands' ]; foreach ( $brand_taxonomies as $tax ) { if ( taxonomy_exists( $tax ) ) { $terms = wp_get_post_terms( $product_id, $tax, [ 'fields' => 'names' ] ); if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) { $brand_names = array_values( (array) $terms ); break; } } } $variations_data = []; $variations_objs = wc_get_products( [ 'status' => [ 'private', 'publish' ], 'type' => 'variation', 'parent' => $product_id, 'limit' => - 1, 'orderby' => [ 'ID' => 'ASC', ], 'return' => 'objects', ] ); $variations_objs_filtered = []; if ( $variations_objs && is_array( $variations_objs ) ) { foreach ( $variations_objs as $variation ) { // Hide out of stock variations if 'Hide out of stock items from the catalog' is checked. if ( ! $variation || ! $variation->exists() || ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $variation->is_in_stock() ) ) { continue; } // Recheck Class WC_Product_Variation if (!$variation instanceof \WC_Product_Variation) { continue; } // Filter 'woocommerce_hide_invisible_variations' to optionally hide invisible variations (disabled variations and variations with empty price). if ( apply_filters( 'woocommerce_hide_invisible_variations', true, $product_id, $variation ) && ! $variation->variation_is_visible() ) { continue; } $variations_objs_filtered[] = $variation; } } $variants_count_real = count( $variations_objs_filtered ); $variants_count_real = $variants_count_real ? $variants_count_real : 1; if ( $variants_count_real > self::$requestParams['variants_limit'] ) { $max_variants_num = self::$requestParams['variants_limit']; $cheapest_num = (int) floor( $max_variants_num / 2 ); $expensive_num = $max_variants_num - $cheapest_num; $variations_objs_ordered = wc_products_array_orderby( $variations_objs_filtered, 'price', 'ASC' ); $variations_objs_cheapest = array_slice( $variations_objs_ordered, 0, $cheapest_num ); $variations_objs_expensive = array_slice( $variations_objs_ordered, - $expensive_num ); $variations_objs_resolved = array_merge( $variations_objs_cheapest, $variations_objs_expensive ); } else { $variations_objs_resolved = $variations_objs_filtered; } if ( $variations_objs_resolved ) { foreach ( $variations_objs_resolved as $variation ) { $variations_data[] = self::getVariantData( $variation ); } } else { $variations_data[] = self::getVariantData( $product ); } $product_data = [ 'id' => $product_id, 'title' => $product->get_title(), 'type' => $product->get_type(), 'description' => Helper::get_sanitize_description( $product->get_description() ), 'url' => $product->get_permalink(), 'images_url' => self::getImagesUrls( $product ), 'price_html' => Helper::get_price_html( $product ), 'keywords' => null, 'categories' => array_values( (array) $product->get_category_ids() ), 'tags' => array_values( (array) $tag_names ), 'brands' => $brand_names, 'attributes' => self::getAttr($product), 'variants_count_real' => $variants_count_real, 'variants' => $variations_data, ]; if ($product->is_type('grouped')) { $children_data = []; foreach ($product->get_children() as $child_id) { $child_product = wc_get_product($child_id); if ($child_product) { $children_data[] = self::getVariantData($child_product); } } $product_data['grouped'] = $children_data; } return $product_data; } catch ( \Exception $ex ) { Helper::send_response_formatted_error( self::makeErrorBody('S000','Unknown error', $ex->getMessage() ) ); } } /** * Get variant data * * @param \WC_Product|\WC_Product_Variation $product Product instance * * @return array */ public static function getVariantData( $product ) { try { if ( $product instanceof \WC_Product_Variation ) { // Title $title = $product->get_title(); $variation_attributes = $product->get_variation_attributes(); $attrs_str_arr = []; $attrs_arr = []; foreach ( $variation_attributes as $attribute_name => $attribute ) { // taxonomy-based attributes are prefixed with `pa_`, otherwise simply `attribute_` $attribute_name = str_replace( 'attribute_', '', $attribute_name ); // Get an unprefixed(no pa_`) product attribute name $attribute_name = wc_sanitize_taxonomy_name( $attribute_name ); $attribute_slug = 0 === strpos( $attribute_name, 'pa_' ) ? substr( $attribute_name, 3 ) : $attribute_name; $name = ucwords( $attribute_slug ); if ( $name && $attribute ) { $attrs_str_arr[] = "{$name} - {$attribute}"; $attrs_arr[$attribute_slug] = $attribute; } } $attrs_str = implode( ', ', $attrs_str_arr ); $title = "{$title} ($attrs_str)"; } else { // Title $title = $product->get_title(); $attrs_arr = []; } $display_price = wc_get_price_to_display( $product ); $display_regular_price = wc_get_price_to_display( $product, [ 'price' => $product->get_regular_price() ] ); // Woo Discount Rules if (is_plugin_active('woo-discount-rules/woo-discount-rules.php')) { $discounted_price = apply_filters('advanced_woo_discount_rules_get_product_discount_price_from_custom_price', $display_regular_price, $product, 1, 0, 'discounted_price', true, false); // check if product have discounted rules if ($discounted_price !== false) { $display_price = $discounted_price; } } // iWebsite-discount if (is_plugin_active('iwebsite-discount/iwebsite-discount.php') && class_exists('Iwebsite_Categories_Discount')) { $display_price = self::getPriceRulesIWebsiteDiscount($product, $display_price); } // === NEW: Override with base price if Price Based on Country is active === if (is_plugin_active('woocommerce-product-price-based-on-countries/woocommerce-product-price-based-on-countries.php')) { $display_price = get_post_meta($product->get_id(), '_price', true); $display_regular_price = get_post_meta($product->get_id(), '_regular_price', true); } return [ 'id' => $product->get_id(), 'title' => $title, 'description' => Helper::get_sanitize_description( $product->get_description() ), 'images_url' => self::getImagesUrls( $product ), 'inventory_quantity' => $product->get_stock_quantity(), 'available_for_order_by_quantity' => $product->is_in_stock(), 'available_for_order_by_visibility' => $product->is_purchasable(), 'sku' => $product->get_sku(), 'barcode_ean13' => null, 'barcode_upc' => null, 'price_before_discount' => Helper::format_price_with_precision( $display_regular_price ), 'price' => Helper::format_price_with_precision( $display_price ), 'price_html' => Helper::get_price_html( $product ), 'attributes' =>$attrs_arr ]; } catch ( \Exception $ex ) { Helper::send_response_formatted_error( self::makeErrorBody('S000','Unknown error', $ex->getMessage() ) ); } } /** * Get the attributes for a product * * @param \WC_Product $product Product instance * * @return array */ public static function getAttr($product) { $attributeArray = []; foreach ($product->get_attributes() as $key => $attribute) { $attribute_name = str_replace('attribute_', '', $key); // Get an unprefixed(no pa_`) product attribute name $attribute_name = wc_sanitize_taxonomy_name($attribute_name); $attribute_slug = 0 === strpos($attribute_name, 'pa_') ? substr($attribute_name, 3) : $attribute_name; $attributeArray[] = [ 'options' => $attribute->get_slugs(), 'slug' => $attribute_slug, 'visible' => $attribute->get_visible(), 'variation' => $attribute->get_variation(), ]; } return $attributeArray; } /** * Get the images urls for a product or product variation * * @param \WC_Product|\WC_Product_Variation $product Product instance * * @return array */ public static function getImagesUrls( $product ) { $images_urls = []; $attachment_ids = []; // Add featured image if ( $product->get_image_id() ) { $attachment_ids[] = $product->get_image_id(); } // Add gallery images $attachment_ids = array_merge( $attachment_ids, $product->get_gallery_image_ids() ); foreach ( $attachment_ids as $attachment_id ) { $attachment_post = get_post( $attachment_id ); if ( is_null( $attachment_post ) ) { continue; } $attachment = wp_get_attachment_image_src( $attachment_id, 'full' ); if ( ! is_array( $attachment ) ) { continue; } $images_urls[] = current( $attachment ); } return $images_urls; } /** * Get Price If you have Plugin iWebsite-discount * * @param \WC_Product|\WC_Product_Variation $product Product instance * * @param float $display_price Product Price * * @return float */ public static function getPriceRulesIWebsiteDiscount($product, $display_price) { $icoun = new \Iwebsite_Categories_Discount(); $object_discount_settings = new \Iwebsite_Get_Discount_Settings('iwebsite_discount_categories', array( 'discount_active' => '', 'discount_value' => '', 'discount_measure' => '', 'discount_categories' => array(), )); $settings_option = $object_discount_settings->get_settings_option(); $settings = false; if ($settings_option) { foreach ($settings_option as $repeater) { $discount_categories = (isset($repeater['discount_categories']) && !empty($repeater['discount_categories'])) ? $repeater['discount_categories'] : false; $discount = (isset($repeater['discount_value']) && !empty($repeater['discount_value'])) ? $repeater['discount_value'] : false; $measure = (isset($repeater['discount_measure'])) ? $repeater['discount_measure'] : 'percent'; $active_sale = (isset($repeater['discount_active'])) ? $repeater['discount_active'] : false; if (!$active_sale || !$discount_categories || !$discount) { continue; } $category_id = $icoun->iwebsite_wc_helper->get_product_cat_in_discount_categories($product->get_parent_id()?:$product->get_id(), $discount_categories); if ($category_id) { $settings['discount'] = $discount; $settings['measure'] = $measure; break; } } } if (is_array($settings) && !empty($settings)) { $discount = $settings['discount']; $discount_measure = $settings['measure']; $discount_price = ($discount_measure == 'percent') ? ($display_price * $discount / 100) : $discount; $display_price = ceil($display_price - intval($discount_price)); } return $display_price; } }