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

Vous avez des questions ?
Contactez-moi :
Me contacter

Laisser un commentaire

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

Nom *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

ipsum mattis vulputate, leo. pulvinar porta. felis id, tempus risus fringilla ipsum