1291 lines
42 KiB
PHP
1291 lines
42 KiB
PHP
<?php
|
|
/**
|
|
* @package CTXFeed\V5\Helper
|
|
*/
|
|
|
|
namespace CTXFeed\V5\Helper;
|
|
|
|
use CTXFeed\V5\Common\Helper;
|
|
use CTXFeed\V5\Product\AttributeValueByType;
|
|
use CTXFeed\V5\Query\QueryFactory;
|
|
use CTXFeed\V5\Utility\Config;
|
|
use DateTime;
|
|
use Exception;
|
|
use TRP_Settings;
|
|
use TRP_Translation_Render;
|
|
use WC_Product;
|
|
use WC_Product_Composite;
|
|
use WC_Product_External;
|
|
use WC_Product_Grouped;
|
|
use WC_Product_Variable;
|
|
use WC_Product_Variation;
|
|
use WC_Product_Variation_Data_Store_CPT;
|
|
use WP_Term;
|
|
|
|
/**
|
|
* This class contains product feed method
|
|
*/
|
|
class ProductHelper {
|
|
|
|
/**
|
|
* Advance Custom Field (ACF) Prefix
|
|
*
|
|
* @since 3.1.18
|
|
*/
|
|
const PRODUCT_ACF_FIELDS = 'acf_fields_';
|
|
|
|
/**
|
|
* Post meta prefix for dropdown item
|
|
*
|
|
* @since 3.1.18
|
|
*/
|
|
const POST_META_PREFIX = 'wf_cattr_';
|
|
|
|
/**
|
|
* Product Attribute (taxonomy & local) Prefix
|
|
*
|
|
* @since 3.1.18
|
|
*/
|
|
const PRODUCT_ATTRIBUTE_PREFIX = 'wf_attr_';
|
|
|
|
/**
|
|
* Product Taxonomy Prefix
|
|
*
|
|
* @since 3.1.18
|
|
*/
|
|
const PRODUCT_TAXONOMY_PREFIX = 'wf_taxo_';
|
|
|
|
/**
|
|
* Product Category Mapping Prefix
|
|
*
|
|
* @since 3.1.18
|
|
*/
|
|
const PRODUCT_CATEGORY_MAPPING_PREFIX = 'wf_cmapping_';
|
|
|
|
/**
|
|
* Product Dynamic Attribute Prefix
|
|
*
|
|
* @since 3.1.18
|
|
*/
|
|
const PRODUCT_DYNAMIC_ATTRIBUTE_PREFIX = 'wf_dattribute_';
|
|
|
|
/**
|
|
* WordPress Option Prefix
|
|
*
|
|
* @since 3.1.18
|
|
*/
|
|
const WP_OPTION_PREFIX = 'wf_option_';
|
|
|
|
/**
|
|
* Extra Attribute Prefix
|
|
*
|
|
* @since 3.2.20
|
|
*/
|
|
const PRODUCT_EXTRA_ATTRIBUTE_PREFIX = 'wf_extra_';
|
|
|
|
/**
|
|
* Product Attribute Mappings Prefix
|
|
*
|
|
* @since 3.3.2*
|
|
*/
|
|
const PRODUCT_ATTRIBUTE_MAPPING_PREFIX = 'wp_attr_mapping_';
|
|
|
|
/**
|
|
* Product Custom Field Prefix
|
|
*
|
|
* @since 3.1.18
|
|
*/
|
|
const PRODUCT_CUSTOM_IDENTIFIER = 'woo_feed_';
|
|
|
|
/**
|
|
* Retrieves IDs based on feed configuration and query arguments.
|
|
*
|
|
* @param Config $config Feed Configuration.
|
|
* @param array $args Query Arguments.
|
|
* @param mixed $settings Additional settings, if any. Default is null.
|
|
*
|
|
* @return array IDs retrieved based on the given configuration and arguments.
|
|
* @throws Exception If any exceptions are thrown by QueryFactory::get_ids.
|
|
*/
|
|
public static function get_ids( Config $config, array $args = [], $settings = null ) {
|
|
if ( $config === null ) {
|
|
return array();
|
|
}
|
|
|
|
return QueryFactory::get_ids( $config, $args, $settings );
|
|
}
|
|
|
|
/**
|
|
* Retrieves the product gallery items (URLs) array for a given product.
|
|
* This can contain empty array values.
|
|
*
|
|
* @param WC_Product|WC_Product_Variable|WC_Product_Variation|WC_Product_Grouped|WC_Product_External|WC_Product_Composite $product The product object.
|
|
*
|
|
* @return array<string> An array of attachment IDs.
|
|
* @since 3.2.6
|
|
*/
|
|
|
|
public static function get_product_gallery( $product ) {
|
|
$img_urls = [];
|
|
$attachment_ids = [];
|
|
|
|
if ( $product->is_type( 'variation' ) ) {
|
|
$theme = wp_get_theme(); // gets the current theme
|
|
// if ( 'Woodmart Child' == $theme->name || 'Twenty Twelve' == $theme->parent_theme ) {
|
|
// // if you're here Twenty Twelve is the active theme or is
|
|
// // the current theme's parent theme
|
|
// }
|
|
if ( class_exists( 'Woo_Variation_Gallery' ) ) {
|
|
/**
|
|
* Get Variation Additional Images for "Additional Variation Images Gallery for WooCommerce"
|
|
*
|
|
* @plugin Additional Variation Images Gallery for WooCommerce
|
|
* @link https://wordpress.org/plugins/woo-variation-gallery/
|
|
*/
|
|
$attachment_ids = \get_post_meta( $product->get_id(), 'woo_variation_gallery_images', true );
|
|
} elseif ( \class_exists( 'WooProductVariationGallery' ) ) {
|
|
/**
|
|
* Get Variation Additional Images for "Variation Images Gallery for WooCommerce"
|
|
*
|
|
* @plugin Variation Images Gallery for WooCommerce
|
|
* @link https://wordpress.org/plugins/woo-product-variation-gallery/
|
|
*/
|
|
$attachment_ids = \get_post_meta( $product->get_id(), 'rtwpvg_images', true );
|
|
} elseif ( \class_exists( 'WC_Additional_Variation_Images' ) ) {
|
|
/**
|
|
* Get Variation Additional Images for "WooCommerce Additional Variation Images"
|
|
*
|
|
* @plugin WooCommerce Additional Variation Images
|
|
* @link https://woocommerce.com/products/woocommerce-additional-variation-images/
|
|
*/
|
|
$attachment_ids = \explode( ',', \get_post_meta( $product->get_id(), '_wc_additional_variation_images', true ) );
|
|
} elseif ( \class_exists( 'WOODMART_Theme' ) ) {
|
|
/**
|
|
* Get Variation Additional Images for "WOODMART Theme -> Variation Gallery Images Feature"
|
|
*
|
|
* @theme WOODMART
|
|
* @link https://themeforest.net/item/woodmart-woocommerce-wordpress-theme/20264492
|
|
*/
|
|
$var_id = $product->get_id();
|
|
$parent_id = $product->get_parent_id();
|
|
|
|
$variation_obj = \get_post_meta( $parent_id, 'woodmart_variation_gallery_data', true );
|
|
if ( isset( $variation_obj, $variation_obj[ $var_id ] ) ) {
|
|
$attachment_ids = \explode( ',', $variation_obj[ $var_id ] );
|
|
} else {
|
|
$attachment_ids = \explode( ',', \get_post_meta( $var_id, 'wd_additional_variation_images_data', true ) );
|
|
}
|
|
} elseif ( 'Woodmart Child' == $theme->name ) {
|
|
/**
|
|
* Get Variation Additional Images for "Woodmart Child Theme -> Variation Gallery Images Feature"
|
|
*
|
|
* @theme WOODMART
|
|
* @link https://themeforest.net/item/woodmart-woocommerce-wordpress-theme/20264492
|
|
*/
|
|
$var_id = $product->get_id();
|
|
$parent_id = $product->get_parent_id();
|
|
|
|
$variation_obj = \get_post_meta( $parent_id, 'woodmart_variation_gallery_data', true );
|
|
if ( isset( $variation_obj, $variation_obj[ $var_id ] ) ) {
|
|
$attachment_ids = \explode( ',', $variation_obj[ $var_id ] );
|
|
} else {
|
|
$attachment_ids = \explode( ',', \get_post_meta( $var_id, 'wd_additional_variation_images_data', true ) );
|
|
}
|
|
} else {
|
|
/**
|
|
* If any Variation Gallery Image plugin not installed then get Variable Product Additional Image Ids .
|
|
*/
|
|
$attachment_ids = \wc_get_product( $product->get_parent_id() )->get_gallery_image_ids();
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Get Variable Product Gallery Image ids if Product is not a variation
|
|
* or variation does not have any gallery images
|
|
*
|
|
* Test case write is pending
|
|
*/
|
|
if ( empty( $attachment_ids ) ) {
|
|
$attachment_ids = $product->get_gallery_image_ids();
|
|
}
|
|
|
|
if ( $attachment_ids && \is_array( $attachment_ids ) ) {
|
|
$m_key = 1;
|
|
foreach ( $attachment_ids as $attachment_id ) {
|
|
$img_urls[ $m_key ] = Helper::woo_feed_get_formatted_url( \wp_get_attachment_url( $attachment_id ) );
|
|
$m_key ++;
|
|
}
|
|
}
|
|
|
|
return $img_urls;
|
|
}
|
|
|
|
|
|
|
|
private static function count_identifiers_in_attributes( $product, $config ) {
|
|
$count = 0;
|
|
$feed_rules = $config->get_feed_rules()['option_value']['feedrules'];
|
|
$identifiers = [
|
|
self::PRODUCT_CUSTOM_IDENTIFIER . 'identifier_gtin',
|
|
self::PRODUCT_TAXONOMY_PREFIX . 'woo-feed-brand',
|
|
self::PRODUCT_CUSTOM_IDENTIFIER . 'identifier_mpn',
|
|
];
|
|
|
|
foreach ( \array_intersect( $feed_rules['attributes'], $identifiers ) as $key => $result ) {
|
|
if ( $feed_rules['type'][ $key ] === 'attribute' && self::get_custom_field( $result, $product, $config ) !== '' ) {
|
|
$count ++;
|
|
}
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* Retrieves custom field values for a WooCommerce product.
|
|
*
|
|
* @param string $field The custom field key.
|
|
* @param WC_Product $product The WooCommerce product object.
|
|
* @param mixed $config Additional configuration or context.
|
|
*
|
|
* @return mixed The formatted value of the custom field.
|
|
*/
|
|
public static function get_custom_field( $field, $product, $config ) {
|
|
|
|
$field_name = $field;
|
|
// Adjust the meta key for variation products.
|
|
if ( strpos( $field, '_cattr') !== false ) {
|
|
$field = str_replace(AttributeValueByType::POST_META_PREFIX, "", $field );
|
|
}
|
|
|
|
if ( strpos( $field, '_var') !== false ) {
|
|
// $meta_key = $product->is_type( 'variation' ) ? $field : str_replace("_var", "",$field );
|
|
$meta_key = $field ;
|
|
}else{
|
|
$meta_key = $product->is_type( 'variation' ) ? $field . '_var' : $field;
|
|
}
|
|
|
|
// Allow filtering of the meta key.
|
|
$meta_key = apply_filters( 'woo_feed_custom_field_meta', $meta_key, $product, $config );
|
|
|
|
// Determine the new and old meta keys based on the presence of '_identifier'.
|
|
if ( \strpos( $meta_key, '_identifier' ) !== false ) {
|
|
$new_meta_key = \str_replace( '_identifier', '', $meta_key );
|
|
$old_meta_key = $meta_key;
|
|
} else {
|
|
$new_meta_key = $meta_key;
|
|
$old_meta_key = \str_replace( 'woo_feed_', 'woo_feed_identifier_', $meta_key );
|
|
}
|
|
|
|
// Retrieve the values for the new and old meta keys.
|
|
$new_meta_value = self::get_product_meta( $new_meta_key, $product, $config );
|
|
$old_meta_value = self::get_product_meta( $old_meta_key, $product, $config );
|
|
|
|
if ( strpos( $field_name, '_cattr') === false ) {
|
|
if ( empty( $new_meta_value) && $product->is_type('variation')) {
|
|
$new_meta_key = str_replace("_var", "", $new_meta_key );
|
|
$new_meta_value = self::get_product_meta( $new_meta_key, $product, $config );
|
|
}
|
|
}
|
|
|
|
// Return the formatted custom field value, preferring the new meta key.
|
|
return empty( $new_meta_value ) ? self::format_custom_field_value( $old_meta_value, $meta_key )
|
|
: self::format_custom_field_value( $new_meta_value, $meta_key );
|
|
}
|
|
|
|
/**
|
|
* Retrieves a specific meta value for a WooCommerce product. Supports handling variations and RankMath integration.
|
|
*
|
|
* @param string $meta The meta key to retrieve.
|
|
* @param WC_Product $product The WooCommerce product object.
|
|
* @param mixed $config Additional configuration or context.
|
|
*
|
|
* @return mixed The value of the specified meta key. Filters the value through 'woo_feed_filter_product_meta'.
|
|
*/
|
|
public static function get_product_meta( $meta, $product, $config ) {
|
|
$product_id = $product->get_id();
|
|
$value = \get_post_meta( $product_id, $meta, true );
|
|
|
|
// Attempt to retrieve the meta value from the parent product if it's a variation and the meta value is empty.
|
|
if ( empty( $value ) && $product->is_type( 'variation' ) ) {
|
|
$parent_id = $product->get_parent_id();
|
|
$value = \get_post_meta( $parent_id, $meta, true );
|
|
}
|
|
|
|
// Handling for RankMath integration.
|
|
if ( self::is_rank_math_active() && $meta === 'rank_math_primary_product_cat' && \is_numeric( $value ) ) {
|
|
$term = \get_term( $value );
|
|
$value = $term instanceof WP_Term ? $term->name : $value;
|
|
}
|
|
|
|
// Handle taxonomy-related meta keys.
|
|
if ( \strpos( $meta, self::PRODUCT_TAXONOMY_PREFIX ) !== false ) {
|
|
$meta_key = \str_replace( self::PRODUCT_TAXONOMY_PREFIX, '', $meta );
|
|
$value = self::get_product_taxonomy( $meta_key, $product, $config );
|
|
}
|
|
|
|
return apply_filters( 'woo_feed_filter_product_meta', $value, $product, $config );
|
|
}
|
|
|
|
/**
|
|
* Checks if Rank Math SEO plugin is active.
|
|
*
|
|
* @return bool True if Rank Math or Rank Math Pro is active, false otherwise.
|
|
*/
|
|
private static function is_rank_math_active() {
|
|
return \class_exists( 'RankMath' ) || \class_exists( 'RankMathPro' );
|
|
}
|
|
|
|
/**
|
|
* Retrieves the taxonomy terms associated with a product.
|
|
*
|
|
* @param string $taxonomy The taxonomy for which to retrieve terms.
|
|
* @param WC_Product $product The WooCommerce product object.
|
|
* @param Config $config Additional configuration or context.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function overwrite_identifier_exists( $attribute, $product, $config ) {
|
|
|
|
/**
|
|
* Please add the plugins name if any plugin needs to do extra code to get proper identifier_exists attribute value.
|
|
*
|
|
* Here is the already compatible plugin list:
|
|
* 1. EAN for WooCommerce
|
|
* 2. Custom Post Type UI
|
|
* 3. ACF
|
|
*/
|
|
|
|
$identifiers = array( 'brand', 'upc', 'sku', 'mpn', 'gtin' );
|
|
|
|
$structure = get_transient( 'ctx_feed_structure_transient' );
|
|
$have_attributes_value = [];
|
|
foreach ( $identifiers as $single_identifier ) {
|
|
$attribute_key = self::array_search_key( $single_identifier, $structure );
|
|
if ( ! is_array( $attribute_key ) ) {
|
|
continue;
|
|
}
|
|
|
|
$attributeValueByType = new AttributeValueByType( $attribute_key['attribute'], $product, $config, $attribute_key['mattribute'] );
|
|
$value = $attributeValueByType->get_value();
|
|
if ( $value ) {
|
|
$have_attributes_value[ $single_identifier ] = $value;
|
|
}
|
|
}
|
|
|
|
return count( $have_attributes_value ) > 1 ? "yes" : "no";
|
|
}
|
|
|
|
/**
|
|
* Get merchant attribute and attribute
|
|
*
|
|
* @param $needle_key
|
|
* @param $structure
|
|
*
|
|
* @return array|false
|
|
*/
|
|
private static function array_search_key( $needle_key, $structure ) {
|
|
foreach ( $structure as $key => $value ) {
|
|
if ( strpos( $key, $needle_key ) !== false ) {
|
|
|
|
return [
|
|
'attribute' => $value,
|
|
'mattribute' => $key,
|
|
];
|
|
}
|
|
if ( is_array( $value ) ) {
|
|
if ( ( $result = self::array_search_key( $needle_key, $value ) ) !== false ) {
|
|
return $result;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get Product Taxonomy.
|
|
=======
|
|
* @return string A string containing the taxonomy terms separated by the specified separator.
|
|
>>>>>>> develop
|
|
*
|
|
* Note: Test case writing is pending for this function.
|
|
*/
|
|
public static function get_product_taxonomy( $taxonomy, $product, $config ) {
|
|
$id = CommonHelper::parent_product_id( $product );
|
|
$separator = apply_filters( 'woo_feed_product_taxonomy_term_list_separator', ',', $config, $product );
|
|
$term_list = \get_the_term_list( $id, $taxonomy, '', $separator, '' );
|
|
|
|
if ( \is_object( $term_list ) && \get_class( $term_list ) === 'WP_Error' ) {
|
|
$term_list = '';
|
|
}
|
|
|
|
$getTaxonomy = CommonHelper::strip_all_tags( $term_list );
|
|
|
|
return apply_filters( 'woo_feed_filter_product_taxonomy', $getTaxonomy, $product, $config );
|
|
}
|
|
|
|
/**
|
|
* Formats the value of a custom field based on its metadata key.
|
|
*
|
|
* @param mixed $value The value of the custom field.
|
|
* @param string $meta_key The metadata key used to determine the formatting.
|
|
*
|
|
* @return mixed Formatted value if specific formatting is required, otherwise returns the original value.
|
|
*/
|
|
private static function format_custom_field_value( $value, $meta_key ) {
|
|
if ( \strpos( $meta_key, 'availability_date' ) !== false ) {
|
|
$formatted_date = \strtotime( $value );
|
|
|
|
if ( $formatted_date === false ) {
|
|
// Handle invalid date
|
|
return $value;
|
|
}
|
|
|
|
return \date( 'c', $formatted_date );
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
private static function count_identifiers_in_mattributes( $product, $config ) {
|
|
$count = 0;
|
|
$feed_rules = $config->get_feed_rules()['option_value']['feedrules'];
|
|
$identifier_keys = [ 'brand', 'upc', 'sku', 'mpn', 'gtin' ];
|
|
|
|
foreach ( \array_intersect( $feed_rules['mattributes'], $identifier_keys ) as $key => $result ) {
|
|
$count += self::evaluate_mattribute( $feed_rules, $key, $product, $config );
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
private static function evaluate_mattribute( $feed_rules, $key, $product, $config ) {
|
|
$attribute_key = $feed_rules['attributes'][ $key ];
|
|
|
|
if ( $feed_rules['type'][ $key ] === 'pattern' && $feed_rules['default'][ $key ] !== '' ) {
|
|
return 1;
|
|
}
|
|
|
|
if ( $feed_rules['type'][ $key ] === 'attribute' ) {
|
|
if ( $attribute_key === 'sku' && $product->get_sku() !== '' ) {
|
|
return 1;
|
|
}
|
|
|
|
if ( $attribute_key !== '' && \strpos( $attribute_key, self::PRODUCT_ATTRIBUTE_PREFIX ) !== false ) {
|
|
$attribute = \str_replace( self::PRODUCT_ATTRIBUTE_PREFIX, '', $attribute_key );
|
|
|
|
return self::get_product_attribute( $attribute, $product, $config ) !== '' ? 1 : 0;
|
|
}
|
|
|
|
if ( $attribute_key !== '' && \strpos( $attribute_key, self::PRODUCT_TAXONOMY_PREFIX ) !== false ) {
|
|
return self::get_product_meta( $attribute_key, $product, $config ) !== '' ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Retrieves a specified attribute from a WooCommerce product.
|
|
*
|
|
* @param string $attr The attribute slug to retrieve.
|
|
* @param WC_Product $product The WooCommerce product object.
|
|
* @param Config $config Additional configuration or context.
|
|
*
|
|
* @return string The value of the specified attribute.
|
|
* @since 2.2.3
|
|
*/
|
|
public static function get_product_attribute( $attr, $product, $config ) {
|
|
$id = $product->get_id();
|
|
|
|
if ( woo_feed_wc_version_check( 3.2 ) ) {
|
|
if ( woo_feed_wc_version_check( 3.6 ) ) {
|
|
$attr = str_replace( 'pa_', '', $attr );
|
|
}
|
|
if ( $product instanceof WC_Product ) {
|
|
$value = $product->get_attribute( $attr );
|
|
}
|
|
|
|
// if empty get attribute of parent post
|
|
if ( '' === $value && $product->is_type( 'variation' ) ) {
|
|
$product = wc_get_product( $product->get_parent_id() );
|
|
if ( $product instanceof WC_Product ) {
|
|
$value = $product->get_attribute( $attr );
|
|
}
|
|
}
|
|
|
|
$getAttribute = $value;
|
|
} else {
|
|
$getAttribute = implode( ',', wc_get_product_terms( $id, $attr, array( 'fields' => 'names' ) ) );
|
|
}
|
|
|
|
$value = self::fetch_product_attribute( $attr, $product );
|
|
|
|
// Retrieve attribute value from the parent product if it's a variation and the attribute value is empty.
|
|
|
|
if ( $product instanceof WC_Product ) {
|
|
if ('' === $value && $product->is_type('variation')) {
|
|
$parent_product = \wc_get_product($product->get_parent_id());
|
|
if ($parent_product) {
|
|
$value = self::fetch_product_attribute($attr, $parent_product);
|
|
}
|
|
}
|
|
}
|
|
|
|
return apply_filters( 'woo_feed_filter_product_attribute', $value, $attr, $product, $config );
|
|
}
|
|
|
|
/**
|
|
* Fetches the attribute value from a product.
|
|
*
|
|
* @param string $attr The attribute slug.
|
|
* @param WC_Product $product The WooCommerce product object.
|
|
*
|
|
* @return string The attribute value.
|
|
*/
|
|
private static function fetch_product_attribute( $attr, $product ) {
|
|
if ($product instanceof WC_Product) {
|
|
if (\woo_feed_wc_version_check(3.2)) {
|
|
return $product->get_attribute($attr);
|
|
}
|
|
|
|
// Fallback for WooCommerce versions below 3.2.
|
|
return \implode(',', \wc_get_product_terms($product->get_id(), $attr, array('fields' => 'names')));
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Retrieves the value of an Advanced Custom Fields (ACF) field for a given WooCommerce product.
|
|
*
|
|
* @param WC_Product $product The WooCommerce product object.
|
|
* @param string $field_key The ACF field key, with the prefix "acf_fields_".
|
|
*
|
|
* @return mixed|string The value of the ACF field, or an empty string if ACF is not available.
|
|
*
|
|
* Note: Test case writing is pending for this function.
|
|
*/
|
|
public static function get_acf_field( $product, $field_key ) {
|
|
// Remove the prefix to get the actual ACF field key.
|
|
$acf_field_key = \str_replace( 'acf_fields_', '', $field_key );
|
|
|
|
// Check if ACF is installed and active.
|
|
if ( \class_exists( 'ACF' ) ) {
|
|
// Retrieve and return the ACF field value.
|
|
return \get_field( $acf_field_key, $product->get_id() );
|
|
}
|
|
|
|
// Return an empty string if ACF is not available.
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Returns category mapping values by product ID, considering the parent product for variations.
|
|
*
|
|
* @param string $mapping_name Category Mapping Name
|
|
* @param int $product_id Product ID / Parent Product ID for variation product
|
|
*
|
|
* @return mixed
|
|
*
|
|
* This function already exists in CTXFeed\V5\Output\CategoryMapping.
|
|
* Test case is available in CTXFeed\tests\wpunit\Output\CategoryMappingTest.
|
|
*/
|
|
public static function get_category_mapping( $mapping_name, $product_id ) {
|
|
$mapping_settings = \maybe_unserialize( \get_option( $mapping_name ) );
|
|
|
|
if ( ! isset( $mapping_settings['cmapping'], $mapping_settings['gcl-cmapping'] ) ) {
|
|
return '';
|
|
}
|
|
|
|
// Define suggestive category list merchants.
|
|
$suggestive_category_list_merchants = [
|
|
'google',
|
|
'facebook',
|
|
'pinterest',
|
|
'bing',
|
|
'bing_local_inventory',
|
|
'snapchat'
|
|
];
|
|
|
|
// Determine the appropriate mapping array.
|
|
$cmapping = self::determine_mapping_array( $mapping_settings, $suggestive_category_list_merchants );
|
|
|
|
// Retrieve product categories and process them.
|
|
$categories = \get_the_terms( $product_id, 'product_cat' );
|
|
if ( \is_array( $categories ) ) {
|
|
foreach ( \array_reverse( $categories ) as $category ) {
|
|
if ( ! empty( $cmapping[ $category->term_id ] ) ) {
|
|
return $cmapping[ $category->term_id ];
|
|
}
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Determines the appropriate category mapping array.
|
|
*
|
|
* @param array $mapping_settings Configuration settings for mapping.
|
|
* @param array $merchants List of suggestive category list merchants.
|
|
*
|
|
* @return array The determined mapping array.
|
|
*/
|
|
private static function determine_mapping_array( $mapping_settings, $merchants ) {
|
|
if ( isset( $mapping_settings['gcl-cmapping'] ) && \in_array( $mapping_settings['mappingprovider'], $merchants, true ) ) {
|
|
return \is_array( $mapping_settings['gcl-cmapping'] ) ? \array_reverse( $mapping_settings['gcl-cmapping'], true ) : $mapping_settings['gcl-cmapping'];
|
|
}
|
|
|
|
return \is_array( $mapping_settings['cmapping'] ) ? \array_reverse( $mapping_settings['cmapping'], true ) : $mapping_settings['cmapping'];
|
|
}
|
|
|
|
/**
|
|
* Retrieves the mapped value for a specified attribute, considering the merchant attribute and configuration.
|
|
*
|
|
* @param WC_Product $product The product object.
|
|
* @param string $attribute The attribute to map.
|
|
* @param string $merchant_attribute The merchant attribute.
|
|
* @param mixed $config Additional configuration or context.
|
|
*
|
|
* @return string The concatenated attribute values, separated by the defined glue or a space.
|
|
*
|
|
* This function already exists in CTXFeed\V5\Output\AttributesMapping.
|
|
* Test case is available in CTXFeed\tests\wpunit\Output\AttributesMappingTest.
|
|
*/
|
|
public static function get_attribute_mapping( $product, $attribute, $merchant_attribute, $config ) {
|
|
$attributes = \get_option( $attribute );
|
|
$glue = ! empty( $attributes['glue'] ) ? $attributes['glue'] : ' ';
|
|
|
|
if ( ! isset( $attributes['mapping'] ) || ! \is_array( $attributes['mapping'] ) ) {
|
|
return '';
|
|
}
|
|
|
|
$get_attribute_value_by_type = new AttributeValueByType( $attribute, $merchant_attribute, $product, $config );
|
|
$output = self::build_attribute_output( $attributes['mapping'], $get_attribute_value_by_type, $glue );
|
|
|
|
// remove extra whitespace
|
|
$output = \preg_replace( '!\s\s+!', ' ', $output );
|
|
|
|
return apply_filters( 'woo_feed_filter_attribute_mapping', $output, $attribute, $product, $config );
|
|
}
|
|
|
|
/**
|
|
* Builds the concatenated output for the attribute mapping.
|
|
*
|
|
* @param array $mapping The attribute mapping array.
|
|
* @param AttributeValueByType $get_attribute_value_by_type The object to retrieve attribute values.
|
|
* @param string $glue The glue used for concatenation.
|
|
*
|
|
* @return string The concatenated attribute values.
|
|
*/
|
|
private static function build_attribute_output( $mapping, $get_attribute_value_by_type, $glue ) {
|
|
$output = [];
|
|
|
|
foreach ( $mapping as $map ) {
|
|
$value = $get_attribute_value_by_type->get_value( $map );
|
|
if ( ! empty( $value ) ) {
|
|
$output[] = $value;
|
|
}
|
|
}
|
|
|
|
return implode( $glue, $output );
|
|
}
|
|
|
|
/**
|
|
* Retrieves the value of a dynamic attribute for a product.
|
|
*
|
|
* @param WC_Product $product
|
|
* @param string $attribute_name
|
|
* @param string $merchant_attribute
|
|
* @param mixed $config
|
|
*
|
|
* @return mixed|string
|
|
* @since 3.2.0
|
|
*
|
|
* This function already exists in CTXFeed\V5\Output\DynamicAttributes.
|
|
* Test case is available in CTXFeed\tests\wpunit\Output\DynamicAttributesTest.
|
|
*/
|
|
public static function get_dynamic_attribute( $product, $attribute_name, $merchant_attribute, $config ) {
|
|
$get_attribute_value_by_type = new AttributeValueByType( $attribute_name, $merchant_attribute, $product, $config );
|
|
$get_value = \maybe_unserialize( \get_option( $attribute_name ) );
|
|
$wf_dattribute_code = $get_value['wfDAttributeCode'] ?? '';
|
|
$attribute = isset( $get_value['attribute'] ) ? (array) $get_value['attribute'] : array();
|
|
$condition = isset( $get_value['condition'] ) ? (array) $get_value['condition'] : array();
|
|
$compare = isset( $get_value['compare'] ) ? (array) $get_value['compare'] : array();
|
|
$type = isset( $get_value['type'] )
|
|
? (array) $get_value['type']
|
|
: array();
|
|
|
|
$prefix = isset( $get_value['prefix'] )
|
|
? (array) $get_value['prefix']
|
|
: array();
|
|
$suffix = isset( $get_value['suffix'] )
|
|
? (array) $get_value['suffix']
|
|
: array();
|
|
|
|
$value_attribute = isset( $get_value['value_attribute'] )
|
|
? (array) $get_value['value_attribute']
|
|
: array();
|
|
$value_pattern = isset( $get_value['value_pattern'] )
|
|
? (array) $get_value['value_pattern']
|
|
: array();
|
|
|
|
$default_type = $get_value['default_type'] ?? 'attribute';
|
|
$default_value_attribute = $get_value['default_value_attribute'] ?? '';
|
|
$default_value_pattern = $get_value['default_value_pattern'] ?? '';
|
|
|
|
$result = '';
|
|
|
|
// Check If Attribute Code exist
|
|
if ( $wf_dattribute_code && count( $attribute ) ) {
|
|
foreach ( $attribute as $key => $name ) {
|
|
if ( empty( $name ) ) {
|
|
continue;
|
|
}
|
|
|
|
$condition_name = $get_attribute_value_by_type->get_value( $name );
|
|
|
|
if ( 'weight' === $name ) {
|
|
$unit = ' ' . \get_option( 'woocommerce_weight_unit' );
|
|
|
|
if ( ! empty( $unit ) ) {
|
|
$condition_name = (float) \str_replace( $unit, '', $condition_name );
|
|
}
|
|
}
|
|
|
|
$condition_compare = $compare[ $key ];
|
|
$condition_operator = $condition[ $key ];
|
|
|
|
if ( ! empty( $condition_compare ) ) {
|
|
$condition_compare = \trim( $condition_compare );
|
|
}
|
|
|
|
$condition_value = '';
|
|
|
|
if ( 'pattern' === $type[ $key ] ) {
|
|
$condition_value = $value_pattern[ $key ];
|
|
} elseif ( 'attribute' === $type[ $key ] ) {
|
|
$condition_value = $get_attribute_value_by_type->get_value( $value_attribute[ $key ] );
|
|
} elseif ( 'remove' === $type[ $key ] ) {
|
|
$condition_value = '';
|
|
}
|
|
|
|
switch ( $condition_operator ) {
|
|
case '==':
|
|
if ( $condition_name === $condition_compare ) {
|
|
$result = self::price_format( $name, $condition_name, $condition_value );
|
|
|
|
if ( '' !== $result ) {
|
|
$result = $prefix[ $key ] . $result . $suffix[ $key ];
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case '!=':
|
|
if ( $condition_name !== $condition_compare ) {
|
|
$result = self::price_format( $name, $condition_name, $condition_value );
|
|
|
|
if ( '' !== $result ) {
|
|
$result = $prefix[ $key ] . $result . $suffix[ $key ];
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case '>=':
|
|
if ( $condition_name >= $condition_compare ) {
|
|
$result = self::price_format( $name, $condition_name, $condition_value );
|
|
|
|
if ( '' !== $result ) {
|
|
$result = $prefix[ $key ] . $result . $suffix[ $key ];
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case '<=':
|
|
if ( $condition_name <= $condition_compare ) {
|
|
$result = self::price_format( $name, $condition_name, $condition_value );
|
|
|
|
if ( '' !== $result ) {
|
|
$result = $prefix[ $key ] . $result . $suffix[ $key ];
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case '>':
|
|
if ( $condition_name > $condition_compare ) {
|
|
$result = self::price_format( $name, $condition_name, $condition_value );
|
|
|
|
if ( '' !== $result ) {
|
|
$result = $prefix[ $key ] . $result . $suffix[ $key ];
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case '<':
|
|
if ( $condition_name < $condition_compare ) {
|
|
$result = self::price_format( $name, $condition_name, $condition_value );
|
|
|
|
if ( '' !== $result ) {
|
|
$result = $prefix[ $key ] . $result . $suffix[ $key ];
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'contains':
|
|
if ( false !== stripos( $condition_name, $condition_compare ) ) {
|
|
$result = self::price_format( $name, $condition_name, $condition_value );
|
|
|
|
if ( '' !== $result ) {
|
|
$result = $prefix[ $key ] . $result . $suffix[ $key ];
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'nContains':
|
|
if ( stripos( $condition_name, $condition_compare ) === false ) {
|
|
$result = self::price_format( $name, $condition_name, $condition_value );
|
|
|
|
if ( '' !== $result ) {
|
|
$result = $prefix[ $key ] . $result . $suffix[ $key ];
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'between':
|
|
$compare_items = explode( ',', $condition_compare );
|
|
|
|
if (
|
|
isset( $compare_items[1] )
|
|
&& \is_numeric( $compare_items[0] )
|
|
&& \is_numeric( $compare_items[1] )
|
|
) {
|
|
if ( $condition_name >= $compare_items[0] && $condition_name <= $compare_items[1] ) {
|
|
$result = self::price_format( $name, $condition_name, $condition_value );
|
|
|
|
if ( '' !== $result ) {
|
|
$result = $prefix[ $key ] . $result . $suffix[ $key ];
|
|
}
|
|
}
|
|
} else {
|
|
$result = '';
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( '' === $result ) {
|
|
if ( 'pattern' === $default_type ) {
|
|
$result = $default_value_pattern;
|
|
} elseif ( 'attribute' === $default_type ) {
|
|
if ( ! empty( $default_value_attribute ) ) {
|
|
$result = $get_attribute_value_by_type->get_value( $default_value_attribute );
|
|
}
|
|
} elseif ( 'remove' === $default_type ) {
|
|
$result = '';
|
|
}
|
|
}
|
|
|
|
return apply_filters( 'woo_feed_after_dynamic_attribute_value', $result, $product, $attribute_name, $merchant_attribute, $config );
|
|
}
|
|
|
|
/**
|
|
* Formats a price or weight value based on the specified operation.
|
|
*
|
|
* @param string $name Attribute Name indicating whether it's a price or weight.
|
|
* @param float $conditionName The initial value to be formatted.
|
|
* @param string $result The operation and value to apply to the initial value.
|
|
*
|
|
* @return float|int|string Formatted result after applying the operation.
|
|
* @since 3.2.0
|
|
*/
|
|
public static function price_format( $name, $condition_name, $result ) {
|
|
// calc and return the output.
|
|
if ( false !== \strpos( $name, 'price' ) || false !== \strpos( $name, 'weight' ) ) {
|
|
if ( false !== \strpos( $result, '+' ) && false !== \strpos( $result, '%' ) ) {
|
|
$result = \str_replace_trim( '+', '', $result );
|
|
$result = \str_replace_trim( '%', '', $result );
|
|
|
|
if ( \is_numeric( $result ) ) {
|
|
$result = $condition_name + ( $condition_name * $result / 100 );
|
|
}
|
|
} elseif ( false !== \strpos( $result, '-' ) && false !== \strpos( $result, '%' ) ) {
|
|
$result = \str_replace_trim( '-', '', $result );
|
|
$result = \str_replace_trim( '%', '', $result );
|
|
|
|
if ( \is_numeric( $result ) ) {
|
|
// $result = ( ( $conditionName * $result ) / 100 ) - $conditionName;
|
|
$result = $condition_name - ( $condition_name * $result / 100 );
|
|
}
|
|
} elseif ( false !== \strpos( $result, '*' ) && false !== \strpos( $result, '%' ) ) {
|
|
$result = \str_replace_trim( '*', '', $result );
|
|
$result = \str_replace_trim( '%', '', $result );
|
|
|
|
if ( \is_numeric( $result ) ) {
|
|
$result = $condition_name * $result / 100;
|
|
}
|
|
} elseif ( false !== \strpos( $result, '+' ) ) {
|
|
$result = \str_replace_trim( '+', '', $result );
|
|
|
|
if ( \is_numeric( $result ) ) {
|
|
$result = $condition_name + $result;
|
|
}
|
|
} elseif ( false !== \strpos( $result, '-' ) ) {
|
|
$result = \str_replace_trim( '-', '', $result );
|
|
|
|
if ( \is_numeric( $result ) ) {
|
|
$result = $condition_name - $result;
|
|
}
|
|
} elseif ( false !== \strpos( $result, '*' ) ) {
|
|
$result = \str_replace_trim( '*', '', $result );
|
|
|
|
if ( \is_numeric( $result ) ) {
|
|
$result = $condition_name * $result;
|
|
}
|
|
} elseif ( false !== \strpos( $result, '/' ) ) {
|
|
$result = \str_replace_trim( '/', '', $result );
|
|
|
|
if ( \is_numeric( $result ) ) {
|
|
$result = $condition_name / $result;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Validates a given date string against a specified format.
|
|
*
|
|
* @param string $date The date string to validate.
|
|
* @param string $format The date format to validate against. Defaults to 'Y-m-d'.
|
|
*
|
|
* @return bool True if the date is valid and matches the format, false otherwise.
|
|
*/
|
|
public static function validate_date( $date, $format = 'Y-m-d' ) {
|
|
if ( ! \is_string( $date ) ) {
|
|
// Optional: Add error logging or handling if $date is not a string
|
|
return false;
|
|
}
|
|
|
|
$dateTime = DateTime::createFromFormat( $format, $date );
|
|
|
|
return $dateTime && $dateTime->format( $format ) === $date;
|
|
}
|
|
|
|
/**
|
|
* Retrieves a product attribute value based on its type.
|
|
*
|
|
* @param string $attribute The name of the product attribute.
|
|
* @param \WC_Product $product The product object, representing the context of the attribute.
|
|
* @param \CTXFeed\V5\Utility\Config $config Configuration settings, affecting how attribute values are processed.
|
|
* @param string|null $merchant_attribute Optional merchant-specific attribute, altering the return value based on merchant requirements.
|
|
* @param \WC_Product $parent_product The product object.
|
|
*
|
|
* @return mixed The value of the attribute, which varies depending on the attribute type and configuration settings.
|
|
*/
|
|
public static function get_attribute_value_by_type( $attribute, $product, $config, $merchant_attribute = null, $parent_product = null ) {
|
|
// Error handling: validate inputs
|
|
if ( ! $product || ! $config ) {
|
|
// Handle error or invalid input
|
|
return null;
|
|
}
|
|
|
|
// Efficient handling of AttributeValueByType instance creation could be considered here
|
|
$attribute_value = new AttributeValueByType( $attribute, $product, $config, $merchant_attribute, $parent_product );
|
|
|
|
return $attribute_value->get_value();
|
|
}
|
|
|
|
/**
|
|
* Replaces specific strings in a product attribute based on configuration rules.
|
|
*
|
|
* @param string $output The initial string to be modified.
|
|
* @param string $productAttribute The product attribute to be checked for replacements.
|
|
* @param Config $config Configuration containing the replacement rules.
|
|
*
|
|
* @return string The modified string after applying the replacement rules.
|
|
*
|
|
* @todo Write test cases for this method.
|
|
*/
|
|
public static function str_replace( $output, $product_attribute, $config ) {
|
|
|
|
// str_replace array can contain duplicate subjects, so better loop through...
|
|
foreach ( $config->get_string_replace() as $str_replace ) {
|
|
|
|
if ( ! empty( $str_replace['subject'] ) && ( $product_attribute == $str_replace['subject'] || self::PRODUCT_ATTRIBUTE_PREFIX . $product_attribute == $str_replace['subject'] ) ) {
|
|
|
|
if ( \strpos( $str_replace['search'], '/' ) === false ) {
|
|
$output = \preg_replace( \stripslashes( '/' . $str_replace['search'] . '/mi' ), $str_replace['replace'], $output );
|
|
} else {
|
|
$output = \str_replace( $str_replace['search'], $str_replace['replace'], $output );
|
|
}
|
|
}
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Adds a prefix and/or suffix to a given output string based on attribute configurations.
|
|
*
|
|
* @param string $output The string to which the prefix and suffix will be added.
|
|
* @param string $attribute The product attribute to which the prefix and suffix apply.
|
|
* @param \CTXFeed\V5\Utility\Config $config Configuration settings for determining prefix and suffix.
|
|
* @param string|null $merchant_attribute Optional merchant-specific attribute.
|
|
*
|
|
* @return string The modified output string with the appropriate prefix and/or suffix added.
|
|
*/
|
|
public static function add_prefix_suffix( $output, $attribute, $config, $merchant_attribute ) {
|
|
if ( $output == '' ) {
|
|
return $output;
|
|
}
|
|
|
|
if ( ! $config || ! \method_exists( $config, 'get_prefix_suffix' ) ) {
|
|
// Handle error or invalid configuration object
|
|
return $output;
|
|
}
|
|
|
|
$prefix_suffix = $config->get_prefix_suffix( $attribute, $merchant_attribute );
|
|
|
|
$output = ( empty( $prefix_suffix['prefix'] ) ? '' : $prefix_suffix['prefix'] ) . $output;
|
|
if ( ! empty( $prefix_suffix['suffix'] ) ) {
|
|
if ( self::should_encode_attribute( $attribute ) ) {
|
|
$output .= ( \preg_match( '/^\s/', $prefix_suffix['suffix'] ) ? '' : '' ) . $prefix_suffix['suffix'];
|
|
}else{
|
|
$output .= ( \preg_match( '/^\s/', $prefix_suffix['suffix'] ) ? '' : ' ' ) . $prefix_suffix['suffix'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Some attributes don't need any space like : link url, image url
|
|
*/
|
|
if ( self::should_encode_attribute( $attribute ) ) {
|
|
$output = \str_replace( ' ', '%20', $output );
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Determines if a prefix or suffix should be stripped from a given attribute.
|
|
*
|
|
* @param string $attribute The attribute name to check.
|
|
*
|
|
* @return bool True if the prefix and suffix should be stripped for the given attribute, false otherwise.
|
|
*/
|
|
public static function should_encode_attribute( $attribute ) {
|
|
// Validate attribute
|
|
if ( ! \is_string( $attribute ) ) {
|
|
// Handle error or invalid input
|
|
return false;
|
|
}
|
|
|
|
// Consider defining these as a class constant or static variable if reused
|
|
$attributes_to_strip = [
|
|
'link',
|
|
'canonical_link',
|
|
'mobile_link',
|
|
'image',
|
|
'images',
|
|
'images_1',
|
|
'images_2',
|
|
'images_3',
|
|
'images_4',
|
|
'images_5',
|
|
'images_6',
|
|
'images_7',
|
|
'images_8',
|
|
'images_9',
|
|
'images_10',
|
|
'image_1',
|
|
'image_2',
|
|
'image_3',
|
|
'image_4',
|
|
'image_5',
|
|
'image_6',
|
|
'image_7',
|
|
'image_8',
|
|
'image_9',
|
|
'image_10'
|
|
];
|
|
|
|
return \in_array( $attribute, $attributes_to_strip );
|
|
}
|
|
|
|
/**
|
|
* Translates an attribute using the TranslatePress plugin.
|
|
*
|
|
* @param string $attribute Name of the product attribute.
|
|
* @param mixed $attribute_value Value of the product attribute.
|
|
* @param WC_Product $product Product object.
|
|
* @param mixed $config Feed configuration settings.
|
|
*
|
|
* @return mixed Translated attribute value if TranslatePress is active and configured, else returns original value.
|
|
* @since 5.2.12
|
|
*/
|
|
public static function get_tp_translate( $attribute, $attribute_value, $product, $config ) {
|
|
if ( \is_plugin_active( 'translatepress-multilingual/index.php' ) ) {
|
|
$target_language = $config->get_feed_language( $attribute );
|
|
|
|
if ( ! empty( $target_language ) ) {
|
|
if ( \class_exists( 'TRP_Settings' ) && \class_exists( 'TRP_Translation_Render' ) ) {
|
|
$settings = ( new TRP_Settings() )->get_settings();
|
|
$trp_render = new TRP_Translation_Render( $settings );
|
|
global $TRP_LANGUAGE;
|
|
$default_language = $TRP_LANGUAGE;
|
|
$TRP_LANGUAGE = $target_language;
|
|
$attribute_value = $trp_render->translate_page( $attribute_value );
|
|
|
|
// Resetting the global language to default
|
|
$TRP_LANGUAGE = $default_language;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $attribute_value;
|
|
}
|
|
|
|
/**
|
|
* Retrieves a WooCommerce product object based on the product ID and configuration settings.
|
|
* For variable products, it returns a specific variation based on the configured variation type.
|
|
*
|
|
* @param int $product_id Product ID.
|
|
* @param Config $config Configuration settings for handling variable products.
|
|
*
|
|
* @return mixed The product object, which may be a variation for variable products.
|
|
* @throws Exception If the product is not found or an error occurs.
|
|
*/
|
|
public static function get_product_object( $product_id, $config ) {
|
|
$product = \wc_get_product( $product_id );
|
|
if ( ! $product ) {
|
|
throw new Exception( 'Product not found.' );
|
|
}
|
|
|
|
$variable_config = $config->get_variable_config();
|
|
$variation_type = $variable_config['is_variations'];
|
|
|
|
if ( $product->is_type( 'variable' ) && \in_array( $variation_type, [
|
|
'default',
|
|
'cheap',
|
|
'first',
|
|
'last',
|
|
'expensive',
|
|
'n'
|
|
], true ) ) {
|
|
$id = self::determine_variable_product( $product, $variation_type );
|
|
|
|
return $id ? \wc_get_product( $id ) : $product;
|
|
}
|
|
|
|
if ( $config->get_categories_to_include() && $product->is_type( 'variable' ) ) {
|
|
$products = [];
|
|
if ( $variation_type == 'both' ) {
|
|
array_push( $products, $product );
|
|
}
|
|
$variations = $product->get_visible_children();
|
|
|
|
foreach ( $variations as $variation_id ) {
|
|
$variation_product = wc_get_product( $variation_id );
|
|
array_push( $products, $variation_product );
|
|
}
|
|
|
|
return $products;
|
|
}
|
|
|
|
|
|
return $product;
|
|
}
|
|
|
|
/**
|
|
* Determines the ID of the variable product based on the variation type.
|
|
*
|
|
* @param WC_Product $product The variable product.
|
|
* @param string $variationType The type of variation to retrieve.
|
|
*
|
|
* @return int|null The ID of the determined product variation, or null if not found.
|
|
*/
|
|
private static function determine_variable_product( $product, $variation_type ) {
|
|
$variations = $product->get_visible_children();
|
|
$variations_price = $product->get_variation_prices();
|
|
switch ( $variation_type ) {
|
|
case 'default':
|
|
return self::get_default_product_variation( $product );
|
|
|
|
case 'first':
|
|
return ! empty( $variations ) ? \reset( $variations ) : null;
|
|
|
|
case 'last':
|
|
return ! empty( $variations ) ? \end( $variations ) : null;
|
|
|
|
case 'cheap':
|
|
return (isset($variations_price['price']) && !empty($variations_price['price'])) ? \array_keys( $variations_price['price'], \min( $variations_price['price'] ) )[0] : null;
|
|
|
|
case 'expensive':
|
|
return isset( $variations_price['price'] ) ? \array_keys( $variations_price['price'], \max( $variations_price['price'] ) )[0] : null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Finds the default variation ID for a variable product.
|
|
*
|
|
* @param WC_Product $product The variable product.
|
|
*
|
|
* @return int|false The ID of the default variation, or false if the product is not a variable product.
|
|
* @throws Exception If the product is not valid.
|
|
*/
|
|
public static function get_default_product_variation( $product ) {
|
|
if ( $product->is_type( 'variable' ) ) {
|
|
$attributes = $product->get_default_attributes();
|
|
|
|
foreach ( $attributes as $key => $value ) {
|
|
if ( \strpos( $key, 'attribute_' ) === 0 ) {
|
|
continue;
|
|
}
|
|
|
|
unset( $attributes[ $key ] );
|
|
$attributes[ \sprintf( 'attribute_%s', $key ) ] = $value;
|
|
}
|
|
|
|
return ( new WC_Product_Variation_Data_Store_CPT )->find_matching_product_variation( $product, $attributes );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the product price including tax.
|
|
*
|
|
* @param float|string $price The base price of the product.
|
|
* @param WC_Product $product The WooCommerce product object.
|
|
*
|
|
* @return float The product price including tax.
|
|
*/
|
|
public static function get_price_with_tax( $price, $product ) {
|
|
if ( CommonHelper::wc_version_check( 3.0 ) ) {
|
|
return \wc_get_price_including_tax( $product, array( 'price' => $price ) );
|
|
}
|
|
|
|
return $product->get_price_including_tax( 1, $price );
|
|
|
|
}
|
|
|
|
}
|
|
|