attribute_service = $attribute_service; $this->category_service = $category_service; $this->add_extra_price_filter(); } public function init() { if ( is_admin() ) { add_action( 'add_meta_boxes', [ $this, 'add_meta_boxes' ] ); add_action( 'save_post_' . static::PRODUCT_TYPE, [ $this, 'save_metabox' ] ); } } public function add_meta_boxes() { add_meta_box( '4partners_category_box', '4Partners', [ $this, 'render_metabox' ], static::PRODUCT_TYPE, 'advanced', 'high' ); } public function render_metabox( $post ) { $fixed_fields = get_post_meta( $post->ID, static::META_4PARTNERS_FIXED_FIELDS, true ); ?>
update_meta( $post_id, static::META_4PARTNERS_HASH, '' ); } clean_post_cache( $post_id ); } } } public function add_extra_price( $price, $product ) { if ( ! is_numeric( $price ) ) { return $price; } $product_id = is_a( $product, \WC_Product_Variable::class ) ? $product->get_parent_id() : $product->get_id(); $primary_category_id = get_post_meta( $product_id, static::META_4PARTNERS_PRIMARY_CATEGORY, true ); if ( empty( $primary_category_id ) ) { return $price; } $extra_price_data = get_term_meta( $primary_category_id, CategoryService::META_EXTRA_PRICE, true ); if ( empty( $extra_price_data ) ) { return $price; } $extra_price = explode( '|', $extra_price_data ); $extra_price_num = $extra_price[0]; $extra_price_type = $extra_price[1]; $extra_price_min = $extra_price[2]; if ( empty( $extra_price_num ) ) { return $price; } if ( $extra_price_type === 'percent' ) { $price_percent = $price * $extra_price_num / 100; $price += ( ! empty( $extra_price_min ) && $price_percent < $extra_price_min ) ? $extra_price_min : $price_percent; } elseif ( $extra_price_type === 'sum' ) { $price += $extra_price_num; } return round( $price, 0 ); } public function get_id_and_hash_by_external_id( $external_id ) { global $wpdb; $external_id = intval( $external_id ); return $wpdb->get_row( "SELECT t1.post_id AS 'post_id', t2.meta_value AS 'hash' FROM {$wpdb->postmeta} AS t1 JOIN {$wpdb->postmeta} AS t2 ON t1.post_id = t2.post_id AND t2.meta_key = '" . static::META_4PARTNERS_HASH . "' WHERE t1.`meta_key` = '" . static::META_4PARTNERS_ID . "' AND t1.`meta_value` = '$external_id'", ARRAY_A ); } public function make_from_post( \WP_Post $post ) { $product_builder = new ProductBuilder(); $brand = get_post_meta( $post->ID, static::META_4PARTNERS_BRAND, true ); $external_id = get_post_meta( $post->ID, static::META_4PARTNERS_ID, true ); $images = get_post_meta( $post->ID, static::META_4PARTNERS_IMAGES, true ); $product_builder->create_product( $post->post_title, $brand, $post->post_content ) ->add_post_id( $post->ID ) ->add_external_id( $external_id ); foreach ( $images as $image ) { $product_builder->add_image( $image ); } $wc_product = new \WC_Product_Variable( $post->ID ); $primary_category_id = get_post_meta( $post->ID, static::META_4PARTNERS_PRIMARY_CATEGORY, true ); $categories_id = $wc_product->get_category_ids(); $categories = []; foreach ( $categories_id as $category_id ) { $external_id = get_term_meta( $category_id, CategoryService::META_4PARTNERS_ID, true ); $categories[ $external_id ] = [ 'id' => $category_id, 'isMain' => $category_id == $primary_category_id ]; } $product_builder->add_categories( $categories ); $product_builder->add_wc_product( $wc_product ); $variations = $wc_product->get_children(); foreach ( $variations as $variation_post_id ) { $wc_variation = new \WC_Product_Variation( $variation_post_id ); $price = $wc_variation->get_price(); $quantity = $wc_variation->get_stock_quantity(); $wc_attributes = $wc_variation->get_attributes(); $attributes = []; foreach ( $wc_attributes as $taxonomy_slug => $term_slug ) { $taxonomy = get_taxonomy( $taxonomy_slug ); $term = get_term_by( 'slug', $term_slug, $taxonomy_slug ); $attributes[ $taxonomy->labels->singular_name ] = $term->name; } $variation_builder = new ProductVariationBuilder(); $variation_builder->create_variation( $price, $quantity ) ->add_post_id( $variation_post_id ) ->add_external_id( $wc_variation->get_meta( static::META_4PARTNERS_ID ) ) ->add_wc_product( $wc_variation ) ->add_attributes( $attributes ); $product_builder->add_variation( $variation_builder->get_variation() ); } return $product_builder->get_product(); } public function get_variation_meta_property_names() { return [ '_price' => 'price', '_regular_price' => 'price', '_stock' => 'quantity', ]; } public function get_meta_property_names() { return [ static::META_4PARTNERS_BRAND => 'brand', static::META_4PARTNERS_IMAGES => 'images', ]; } public function add_product( Product $product ) { if ( count( $product->variations ) > 1 ) { $new_product = new \WC_Product_Variable(); $new_product->set_manage_stock( false ); } else { $new_product = new \WC_Product_Simple(); $variations = $product->variations; $variation = array_shift( $variations ); $new_product->set_price( $variation->price ); $new_product->set_regular_price( $variation->price ); $new_product->set_stock_quantity( $variation->quantity ); $new_product->set_manage_stock( true ); $new_product->set_stock_status( '' ); $new_product->set_weight( '' ); } $product_attributes = $this->attribute_service->create_product_attributes( $product ); $new_product->set_attributes( $product_attributes ); $new_product->set_name( $product->name ); $new_product->set_sku( $product->external_id ); $new_product->set_description( $product->description ); /* * see update_meta method if ( ! empty( $product->images ) ) { if ( count( $product->images ) > 1 ) { $new_product->set_gallery_image_ids( range( 2, count( $product->images ) ) ); } //$new_product->set_gallery_image_ids( range( 1, count( $product->images ) ) ); $new_product->set_image_id( 1 ); } */ $categories = []; foreach ( $product->categories as $category_external_id => $category ) { if ( $category['isMain'] ) { $primary_category_id = $category['id']; } $categories[] = $category['id']; } $new_product->set_category_ids( $categories ); $product_id = $new_product->save(); if ( $product_id > 0 ) { $this->update_meta( $product_id, static::META_4PARTNERS_ID, $product->external_id ); $this->update_meta( $product_id, static::META_4PARTNERS_BRAND, $product->brand ); $this->update_meta( $product_id, static::META_4PARTNERS_HASH, $product->hash ); $this->update_meta( $product_id, static::META_4PARTNERS_IMAGES, $product->images ); if ( ! empty( $primary_category_id ) ) { $this->update_meta( $product_id, static::META_4PARTNERS_PRIMARY_CATEGORY, $primary_category_id ); } $product->id = $product_id; if ( count( $product->variations ) > 1 ) { foreach ( $product->variations as $variation ) { $this->add_variation( $product, $variation ); } } } return $product_id; //wp_cache_flush(); //wp_cache_delete( $product_id, 'posts' ); //wp_cache_delete( $product_id, 'post_meta' ); } public function add_variation( Product $product, ProductVariation $variation ) { $new_variation = new \WC_Product_Variation(); $new_variation->set_parent_id( $product->id ); $new_variation->set_sku( $variation->external_id ); $new_variation->set_price( $variation->price ); $new_variation->set_regular_price( $variation->price ); $new_variation->set_stock_quantity( $variation->quantity ); $new_variation->set_manage_stock( true ); $new_variation->set_weight( '' ); $new_variation->add_meta_data( static::META_4PARTNERS_ID, $variation->external_id ); $attributes = $this->extract_variation_attributes( $variation->attributes ); if ( ! empty( $attributes ) ) { $new_variation->set_attributes( $attributes ); } $post_id = $new_variation->save(); if ( ! empty( $post_id ) && $variation->images != $product->images ) { $variant_images_indexes = []; foreach ( $variation->images as $image ) { $key = array_search( $image, $product->images ); if ( $key !== false ) { $variant_images_indexes[] = $key + 1; } } if ( ! empty( $variant_images_indexes ) ) { $this->update_meta( $post_id, static::META_4PARTNERS_VARIATION_IMAGES, $variant_images_indexes ); } } return $post_id; } public function update_product( Product $current_product, Product $new_product ) { $product_meta_properties = $this->get_meta_property_names(); $variation_meta_properties = $this->get_variation_meta_property_names(); $fixed_fields = get_post_meta( $current_product->id, static::META_4PARTNERS_FIXED_FIELDS, true ); $fixed_fields = empty( $fixed_fields ) ? [] : $fixed_fields; $diff_new_to_old = $this->get_diff_prop_between_products( $new_product, $current_product ); $diff_old_to_new = $this->get_diff_prop_between_products( $current_product, $new_product ); $product_type = $current_product->wc_product->get_type(); $variable_product = new \WC_Product_Variable(); $simple_product = new \WC_Product_Simple(); if ( $product_type == $simple_product->get_type() && count( $new_product->variations ) > 1 ) { $new_product_type = $variable_product->get_type(); } if ( empty( $new_product_type ) ) { $wc_product = $current_product->wc_product; } else { $product_classname = \WC_Product_Factory::get_product_classname( $current_product->id, $new_product_type ); $wc_product = new $product_classname( $current_product->id ); } $product_attributes_was_updated = false; if ( ! empty( $diff_old_to_new['variations'] ) ) { foreach ( $diff_old_to_new['variations'] as $variation ) { if ( $variation instanceof ProductVariation ) { // delete $variation->wc_product->delete( true ); if ( ! $product_attributes_was_updated ) { $new_attributes = $this->attribute_service->create_product_attributes( $new_product ); $current_product->wc_product->set_attributes( $new_attributes ); $product_attributes_was_updated = true; } } } } if ( $new_product_type == $variable_product->get_type() ) { $wc_product->set_manage_stock( false ); } if ( ! empty( $diff_old_to_new['categories'] ) ) { $new_categories_id = []; foreach ( $new_product->categories as $category_external_id => $category ) { $new_categories_id[] = $category['id']; if ( $category['isMain'] ) { $this->update_meta( $current_product->id, static::META_4PARTNERS_PRIMARY_CATEGORY, $category['id'] ); } } $wc_product->set_category_ids( $new_categories_id ); } foreach ( $diff_new_to_old as $diff_prop_name => $new_value ) { $meta_key = array_search( $diff_prop_name, $product_meta_properties ); if ( $meta_key !== false ) { if ( $meta_key == ProductService::META_4PARTNERS_IMAGES ) { $new_value = $new_product->images; } $this->update_meta( $current_product->id, $meta_key, $new_value ); } if ( $diff_prop_name == 'description' ) { if ( ! in_array( 'content', $fixed_fields ) ) { $wc_product->set_description( $new_product->description ); } } if ( $diff_prop_name == 'name' ) { if ( ! in_array( 'name', $fixed_fields ) ) { $wc_product->set_name( $new_product->name ); } } } if ( ! empty( $diff_new_to_old['variations'] ) ) { foreach ( $diff_new_to_old['variations'] as $variation_external_id => $variation ) { if ( $variation instanceof ProductVariation ) { if ( ! $product_attributes_was_updated ) { $new_attributes = $this->attribute_service->create_product_attributes( $new_product ); $current_product->wc_product->set_attributes( $new_attributes ); $product_attributes_was_updated = true; } $this->add_variation( $current_product, $variation ); } else { $wc_variation = $current_product->variations[ $variation_external_id ]->wc_product; $wc_variation_changed = false; foreach ( $variation as $field => $value ) { $meta_keys = array_keys( $variation_meta_properties, $field ); foreach ( $meta_keys as $meta_key ) { $this->update_meta( $variation['id'], $meta_key, $value ); } } if ( ! empty( $variation['quantity'] ) ) { if ( $wc_product->get_type() == $simple_product->get_type() ) { $wc_product->set_stock_quantity( $variation['quantity'] ); } else { $wc_variation->set_stock_quantity( $variation['quantity'] ); $wc_variation_changed = true; } } if ( ! empty( $variation['price'] ) ) { if ( $wc_product->get_type() == $simple_product->get_type() ) { $wc_product->set_price( $variation['price'] ); $wc_product->set_regular_price( $variation['price'] ); } else { $wc_variation->set_price( $variation['price'] ); $wc_variation->set_regular_price( $variation['price'] ); $wc_variation_changed = true; } } if ( ! empty( $variation['attributes'] ) ) { if ( ! $product_attributes_was_updated ) { //todo: fix this $new_attributes = $this->attribute_service->create_product_attributes( $new_product ); $current_product->wc_product->set_attributes( $new_attributes ); $product_attributes_was_updated = true; } } if ( $wc_variation_changed ) { $wc_variation->save(); } } } } $wc_product->save(); } public function extract_variation_attributes( $attributes ) { $result = []; foreach ( $attributes as $attribute_label => $attribute_value ) { $attribute_data = $this->attribute_service->get_attribute_by_label( $attribute_label ); if ( ! isset( $attribute_data['terms'][ $attribute_value ] ) ) { throw new \Exception( 'Variation attribute term not found by name ' . $attribute_value ); } $result[ $attribute_data['taxonomy'] ] = $attribute_data['terms'][ $attribute_value ]; } return $result; } public function update_meta( $post_id, $meta_key, $meta_value ) { if ( $meta_key == static::META_4PARTNERS_IMAGES ) { $gallery_str = ''; $gallery_counter = 1; foreach ( $meta_value as $k => $image_url ) { $size = getimagesize( $image_url ); $image_size = $size ? [ $size[0], $size[1] ] : [ 100, 100 ]; $meta_value[ $k ] = [ $image_url, $image_size ]; if ( $gallery_counter > 1 ) { $gallery_str .= $gallery_counter . ','; } $gallery_counter ++; } if ( empty( $meta_value ) ) { delete_post_meta( $post_id, static::META_THUMBNAIL ); delete_post_meta( $post_id, static::META_GALLERY ); } else { $this->update_meta( $post_id, static::META_THUMBNAIL, 1 ); $this->update_meta( $post_id, static::META_GALLERY, trim( $gallery_str, ',' ) ); } } update_post_meta( $post_id, $meta_key, $meta_value ); } public function get_diff_prop_between_products( $product_1, $product_2 ) { $a1 = (array) $product_1; $a2 = (array) $product_2; $skip_fields = [ 'wc_product' ]; $r = array(); foreach ( $a1 as $k => $v ) { if ( array_key_exists( $k, $a2 ) ) { if ( $v instanceof ProductVariation ) { $v = (array) $v; } if ( is_array( $v ) ) { $rad = $this->get_diff_prop_between_products( $v, $a2[ $k ] ); if ( count( $rad ) ) { $r[ $k ] = $rad; } } else { if ( $v != $a2[ $k ] ) { $r[ $k ] = $k === 'id' ? $a2[ $k ] : $v; } } } elseif ( ! in_array( $k, $skip_fields ) ) { $r[ $k ] = $v; } } return $r; } private function add_extra_price_filter() { add_filter( 'woocommerce_product_get_price', [ $this, 'add_extra_price' ], 10, 2 ); add_filter( 'woocommerce_product_get_regular_price', [ $this, 'add_extra_price' ], 10, 2 ); add_filter( 'woocommerce_product_get_sale_price', [ $this, 'add_extra_price' ], 10, 2 ); add_filter( 'woocommerce_product_variation_get_price', [ $this, 'add_extra_price' ], 10, 2 ); add_filter( 'woocommerce_variation_prices_regular_price', [ $this, 'add_extra_price' ], 10, 2 ); add_filter( 'woocommerce_variation_prices_price', [ $this, 'add_extra_price' ], 10, 2 ); add_filter( 'woocommerce_variation_prices_sale_price', [ $this, 'add_extra_price' ], 10, 2 ); } }