Afficher les produits WooCommerce les mieux vendus

WooCommerce propose par défaut un Widget pour afficher des produits, et les trier par « meilleures ventes ».

Cependant vous l’avez peut-être remarqué : cette liste ne correspond pas à celle retrouvée dans WooCommerce > Rapports.
En effet le code utilisé par le Widget trie les produits avec la meta key total_sales qui n’est pas actualisée lors d’annulation de commandes, etc. (Voir l’issue sur Github).

Voici une petite classe qui se charge d’afficher les produits les mieux vendus (réellement), grâce à elle vous aurez les mêmes résultats en front-office que dans la section « Rapports ».

Elle se base tout simplement sur le cœur de WooCommerce en étendant la classe WC_Admin_Report :

La fonction get_best_sellers ne vous retournera que les identifiants des produits, à vous de faire la suite 😉

Vous trouverez un exemple d’utilisation à la ligne 173.

N’hésitez pas à me donner votre avis, remarques ou autre pull request 🙂

<?php

/**
 * Reports class
 *
 * @author  Marie Comet
 * @package Get WooCommerce (REALLY) Best Sales
 * @version 1.0.0
 * See example of use case a the end of the file
 */

if ( !defined( 'ABSPATH' ) ) {
    exit;
} // Exit if accessed directly

require_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-admin-report.php' );

if ( !class_exists( 'MC_WC_Reports' ) ) {

    /**
    * Extend the WC_Admin_Report WooCommerce class (used in admin)
    * See the original class if needed 
    */

    class MC_WC_Reports extends WC_Admin_Report {
        
        /**
         * Constructor
         *
         * @access public
         * @since  1.0.0
         */
        public function __construct() {

        }

        public function get_best_sellers( $range = 'ever', $args = array() ) {
            $filter_range = false;
            if ( $range != 'ever' ) {
                $range_args = isset( $args[ 'range_args' ] ) ? $args[ 'range_args' ] : array();
                $this->calculate_current_range( $range, $range_args );
            }

            $limit = isset( $args[ 'limit' ] ) ? $args[ 'limit' ] : 100;

            $order_report_data_array = array(
                'data'         => array(
                    '_product_id' => array(
                        'type'            => 'order_item_meta',
                        'order_item_type' => 'line_item',
                        'function'        => '',
                        'name'            => 'product_id'
                    ),
                    '_qty'        => array(
                        'type'            => 'order_item_meta',
                        'order_item_type' => 'line_item',
                        'function'        => 'SUM',
                        'name'            => 'order_item_qty'
                    )
                ),
                'order_by'     => 'order_item_qty DESC',
                'group_by'     => 'product_id',
                'limit'        => 15,
                'query_type'   => 'get_results',
                'filter_range' => true,
                'order_types'  => wc_get_order_types( 'order-count' ),

            );

            if ( $limit == -1 )
                unset( $order_report_data_array[ 'limit' ] );

            // create the unique transient name for this request
            $transient_name = strtolower( get_class( $this ) );
            $arguments      = $range;
            if ( !empty( $args ) ) {
                foreach ( $args as $key => $value ) {
                    $arguments .= strtolower( $key ) . $value;
                }
            }

            $transient_name = $transient_name . md5( $arguments );

            $best_sellers = get_transient( $transient_name );

            if ( !$best_sellers ) {
                // delete transient
                delete_transient( strtolower( get_class( $this ) ) );
                // get data
                $best_sellers = $this->get_order_report_data( $order_report_data_array );
                // set the transient, with expiration one hour
                set_transient( $transient_name, $best_sellers, 3600 );
            }

            return $best_sellers;
        }


        /**
         * Get the current range and calculate the start and end dates
         *
         * @param  string $current_range
         */
        public function calculate_current_range( $current_range, $args = array() ) {

            switch ( $current_range ) {

                case 'year' :
                    $this->start_date    = strtotime( date( 'Y-01-01', current_time( 'timestamp' ) ) );
                    $this->end_date      = strtotime( 'midnight', current_time( 'timestamp' ) );
                    $this->chart_groupby = 'month';
                    break;

                case 'last_month' :
                    $first_day_current_month = strtotime( date( 'Y-m-01', current_time( 'timestamp' ) ) );
                    $this->start_date        = strtotime( date( 'Y-m-01', strtotime( '-1 DAY', $first_day_current_month ) ) );
                    $this->end_date          = strtotime( date( 'Y-m-t', strtotime( '-1 DAY', $first_day_current_month ) ) );
                    $this->chart_groupby     = 'day';
                    break;

                case 'month' :
                    $this->start_date    = strtotime( date( 'Y-m-01', current_time( 'timestamp' ) ) );
                    $this->end_date      = strtotime( 'midnight', current_time( 'timestamp' ) );
                    $this->chart_groupby = 'day';
                    break;

                case 'yesterday':
                    $this->start_date    = strtotime( '-1 DAY midnight', current_time( 'timestamp' ) );
                    $this->end_date      = strtotime( 'midnight', current_time( 'timestamp' ) );
                    $this->chart_groupby = 'day';
                    break;

                case 'today':
                    $this->start_date    = strtotime( 'midnight', current_time( 'timestamp' ) );
                    $this->end_date      = strtotime( '+1 DAY midnight', current_time( 'timestamp' ) );
                    $this->chart_groupby = 'day';
                    break;

                case '7day' :
                    $this->start_date    = strtotime( '-6 days', current_time( 'timestamp' ) );
                    $this->end_date      = strtotime( 'midnight', current_time( 'timestamp' ) );
                    $this->chart_groupby = 'day';
                    break;
            }

            // Group by
            switch ( $this->chart_groupby ) {

                case 'day' :
                    $this->group_by_query = 'YEAR(posts.post_date), MONTH(posts.post_date), DAY(posts.post_date)';
                    $this->chart_interval = ceil( max( 0, ( $this->end_date - $this->start_date ) / ( 60 * 60 * 24 ) ) );
                    $this->barwidth       = 60 * 60 * 24 * 1000;
                    break;

                case 'month' :
                    $this->group_by_query = 'YEAR(posts.post_date), MONTH(posts.post_date)';
                    $this->chart_interval = 0;
                    $min_date             = $this->start_date;

                    while ( ( $min_date = strtotime( "+1 MONTH", $min_date ) ) <= $this->end_date ) {
                        $this->chart_interval++;
                    }

                    $this->barwidth = 60 * 60 * 24 * 7 * 4 * 1000;
                    break;
            }

        }
    }
}

/**
*   Exemple of use :
*
*   $reports  = new MC_WC_Reports();
*   $best_sellers = $reports->get_best_sellers( 'year', array( 'limit' => 10 );
*
*   $best_sellers_products_id = array();
*   // Put best seller product id in an array
*   foreach ( $best_sellers as $product ) {
*       $best_sellers_products_id[] = absint( $product->product_id );
*   }
*   
*   You can use this array in a classic WP_Query, don't forget to use args 'orderby' => 'post__in' to keep IDs order !
*
*/

Crédit photo : jackmac34 / Pixabay

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nom *

d01e5529ef61743acc602c031e6523ff4