Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

woocommerce - Average Sale price of a product

I'm trying to create a shortcode for a single product page that shows the average sale price of the current product. So the shortcode will be in a description of a product page. This value should work both with simple and variable products. I'm able to get average value for simple product but only when there is one item in order and I'm not able to solve this with variable products.


function avg_sales_price () {

    global $product;
    if ( is_a($product, 'WC_Product') ) {
        $product_id = $product->get_id();
        $orders = wc_get_orders( array(
            'numberposts' => -1,
            'post_type' => 'shop_order',
        ) );

        foreach ( $orders as $order ) {
            if ( count( $order->get_items() ) > 0 ) {
                foreach ( $order->get_items() as $item_id => $item )
                $productid = $item->get_variation_id() ? $item->get_variation_id() : $item->get_product_id();
                if ( $productid == $product_id) {
                    $product_price_in_orders += $item->get_total();
                }
            }
        }


        $count_orders = 0;
        foreach ( $orders as $order ) {
            $has_product = false;
            foreach ( $order->get_items() as $item_values )
                if ( $item_values['product_id'] == $product_id )
                    $has_product = true;

            if ( $has_product )
                $count_orders++;
        }

        $avg_sales_price = round( $product_price_in_orders / $count_orders );
        
        echo '<div class="sales-price-number">
            <span class="sales-price-text">Average Sale Price </span>
            <span class="sales-price-value">' . esc_html( get_woocommerce_currency_symbol() . $avg_sales_price ). ' </span>
        </div>';
    }
}

Any ideas how to get this work? Thanks.

question from:https://stackoverflow.com/questions/65906316/average-sale-price-of-a-product

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

To get orders based on current product you shouldn't have to query all orders every time. It takes up too many resources especially if the orders are many.

From Get all Orders IDs from a product ID in Woocommerce answer code you can use the function get_orders_ids_by_product_id() to get all orders from a specific product Id (where you will have to set the desired order statuses).

Then you can use this other function to calculate the average price of each product (simple or variation) based on the product id.

// calculate the average price based on the product id using the query within the "get_orders_ids_by_product_id()" function
function calculates_average_price_based_on_product_id( $product_id ) {
    $orders = get_orders_ids_by_product_id( $product_id );
    $count = count( $orders );
    if ( $count <= 0 ) {
        return; // set the return value in case there are no orders for this product
    }
    $prices = 0;
    foreach ( $orders as $order_id ) {
        $order = wc_get_order( $order_id );
        if ( $order ) {
            foreach ( $order->get_items() as $item ) {
                $product = $item->get_product();
                if ( $product_id == $product->get_id() ) {
                    $qty = $item->get_quantity();
                    $total = $item->get_total();
                    $prices += $total / $qty;
                }
            }
        }
    }
    return $prices / $count;
}

HOW DOES IT WORK

  • If the product is variable:
    • Calculate the average price ONLY between the product variations that have been purchased
    • If no variation has been purchased, it calculates the average price between the net prices currently set
  • If the product is simple:
    • Calculate the average price based on the selling prices across all orders containing this product
    • If the product has never been purchased, it displays the currently set net price

SHORTCODE

Finally here is the shortcode which will show the average price based on the product of the current page. If the product is variable, the average price between all variations will be calculated and shown.

The [average_price_product] shortcode will only work on the product page.

// create a shortcode showing the average price of the product
add_shortcode( 'average_price_product', 'shortcode_average_price_product' );
function shortcode_average_price_product() {
    global $product;
    // initialize prices
    $avg_price = 0;
    $current_avg_price = 0;
    // initializes the number of variations that have been purchased at least once
    $count = 0;
    // if the product is variable it calculates the average price of all the variations
    if ( $product->is_type( 'variable' ) ) {
        $variation_ids = $product->get_children();
        // gets the total number of variations
        $total_variations = count( $variation_ids );
        foreach ( $variation_ids as $variation_id ) {
            $variation = wc_get_product( $variation_id );
            // gets the average price of each single variation
            $avg_price_variation = calculates_average_price_based_on_product_id( $variation_id );
            // if the average price of the current product variation is greater than zero, it updates the price and count
            if ( $avg_price_variation > 0 ) {
                $avg_price += $avg_price_variation;
                $count++; 
            }
            // sum the current price of each single variation (in case no variation has ever been purchased)
            $current_avg_price += $variation->get_price();
        }
        // if no variation has been purchased, I display the average price between the current net prices
        if ( $avg_price == 0 ) {
            $avg_price = $current_avg_price / $total_variations;
        } else {
            $avg_price /= $count;
        }
    // if the product is simple
    } else {
        // gets the average price of the product
        $avg_price = calculates_average_price_based_on_product_id( $product->get_id() );
        // if the simple product has never been ordered, I will display the current price
        if ( $avg_price == 0 ) {
            $avg_price = $product->get_price();
        }
    }
    // creates the HTML content to display on the product page
    $html = '<div class="sales-price-number"><span class="sales-price-text">Average Sale Price </span><span class="sales-price-value">' . wc_price( $avg_price ) . ' </span></div>';
    return $html;
}

HOOK

As an alternative to the shortcode you can add the average price on the product page using the woocommerce_before_add_to_cart_form hook, with the following function:

// shows the average price on the product page
add_action( 'woocommerce_before_add_to_cart_form', 'shows_average_price_on_the_product_page', 10 );
function shows_average_price_on_the_product_page() {
    global $product;
    // initialize prices
    $avg_price = 0;
    $current_avg_price = 0;
    // initializes the number of variations that have been purchased at least once
    $count = 0;
    // if the product is variable it calculates the average price of all the variations
    if ( $product->is_type( 'variable' ) ) {
        $variation_ids = $product->get_children();
        // gets the total number of variations
        $total_variations = count( $variation_ids );
        foreach ( $variation_ids as $variation_id ) {
            $variation = wc_get_product( $variation_id );
            // gets the average price of each single variation
            $avg_price_variation = calculates_average_price_based_on_product_id( $variation_id );
            // if the average price of the current product variation is greater than zero, it updates the price and count
            if ( $avg_price_variation > 0 ) {
                $avg_price += $avg_price_variation;
                $count++; 
            }
            // sum the current price of each single variation (in case no variation has ever been purchased)
            $current_avg_price += $variation->get_price();
        }
        // if no variation has been purchased, I display the average price between the current net prices
        if ( $avg_price == 0 ) {
            $avg_price = $current_avg_price / $total_variations;
        } else {
            $avg_price /= $count;
        }
    // if the product is simple
    } else {
        // gets the average price of the product
        $avg_price = calculates_average_price_based_on_product_id( $product->get_id() );
        // if the simple product has never been ordered, I will display the current price
        if ( $avg_price == 0 ) {
            $avg_price = $product->get_price();
        }
    }
    // creates the HTML content to display on the product page
    $html = '<div class="sales-price-number"><span class="sales-price-text">Average Sale Price </span><span class="sales-price-value">' . wc_price( $avg_price ) . ' </span></div>';
    echo $html;
}

The code has been tested and works. Add it to your active theme's functions.php.

Advice

Although the code above works correctly this is not the best way to get the average price of the product.

You could create and update a custom meta for each product whenever the status of each order changes, for example, to "wc-completed".

You will only need a counter of the number of orders for that product and the average price calculated based on the last completed order.

When a new order goes to the completed status you will update the respective fields.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...