Search code examples
phpwordpresswoocommercehook-woocommerceorders

Add a filter by date to My Account Orders in WooCommerce


Here is the Function, which enables me to create filter by date fields for WooCommerce orders in frontend (MY ACCOUNT). It's working, but when I choose date when there are no orders, Filter fields disappearing and there is no way to filter again I have to manually remove added parameters from URL.

I want to achieve the following: When there are no orders Filter fields must still be visible to be able to choose different date and also there must appear reset button which will reset the filters.

Here is my current code:

add_action('woocommerce_before_account_orders', 'add_form');
function add_form($has_orders)
{   
    if ($has_orders) {   
        echo 
        '</form>
        <form action="#" method="get">          
        <input type="date" name="start_date">
        <input type="date" name="end_date">
        <input type="submit" value="' . esc_attr__( 'Filter by date', 'your-text-domain' ) . '">
        </form>';       
    }
}
    
add_filter( 'woocommerce_my_account_my_orders_query', 'custom_woocommerce_my_account_my_orders_query', 10, 1);
function custom_woocommerce_my_account_my_orders_query($array) {
    $start_date='';
    $end_date='';
    if ( isset($_GET['start_date']) && isset($_GET['end_date'])){
        $start_date = $_GET['start_date'];
        $end_date = $_GET['end_date'];
    }
    $array['date_query'] = array(
        array(
            'after'  => $start_date, //start_date 2021-11-16
            'before' => $end_date, //end_date
            'inclusive' => true,
        ),
    );
    return $array;
}

Solution

  • As WooCommerce order query uses WC_Order_Query, you need something a bit different:

    add_action('woocommerce_before_account_orders', 'filter_myaccount_orders');
    function filter_myaccount_orders($has_orders){   
        if ($has_orders || isset($_GET['start_date']) || isset($_GET['end_date']) ) {
            $start_date = $end_date = ''; // Initializing;
            if ( isset($_GET['start_date']) && ! empty($_GET['start_date']) ) {
                $start_date = esc_attr($_GET['start_date']);
            }
            if ( isset($_GET['end_date']) && ! empty($_GET['end_date']) ) {
                $end_date = esc_attr($_GET['end_date']);
            }
    
            echo  '</form>
            <form action="#" method="get">          
            <input type="date" name="start_date" value="'.$start_date.'">
            <input type="date" name="end_date" value="'.$end_date.'">
            <input type="submit" value="' . esc_attr__( 'Filter by date', 'your-text-domain' ) . '">';
            if( isset($_GET['start_date']) || isset($_GET['end_date']) ) {
                $myaccount_orders_url = get_permalink( get_option('woocommerce_myaccount_page_id') ) . 'orders/';
                echo '<a class="button reset" href="'.$myaccount_orders_url.'">'.__('Reset').'</a>';
            }
            echo '</form>';       
        }
    }
    
    add_filter( 'woocommerce_my_account_my_orders_query', 'custom_my_account_orders', 10, 1 );
    function custom_my_account_orders( $args ) {
        $start_date = $end_date = '';// Initializing;
            
        if ( isset($_GET['start_date']) && ! empty($_GET['start_date']) ) {
            $start_date = esc_attr($_GET['start_date']);
        }
        if ( isset($_GET['end_date']) && ! empty($_GET['end_date']) ) {
            $end_date = esc_attr($_GET['end_date']);
        }
    
        if ( $start_date && ! $end_date ) {
            $args['date_created'] = '>='.$start_date;
        } elseif ( ! $start_date && $end_date ) {
            $args['date_created'] = '<='.$end_date;
        } elseif ( $start_date && $end_date ) {
            $args['date_created'] = $start_date.'...'.$end_date;
        }
        return $args;
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.