skip to Main Content

First, sorry for my ignorance in this field and I will try to express myself clear.

I am trying to use wc_get_orders to get orders from Woocommerce with the following args

$args = array(
  'limit' => $rows_per_page,
  'paged' => $page,
  'paginate' => true,
  'customer' => $filter
);
$results = wc_get_orders($args);
$orders = $results->orders;

code taken from https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query#customer and modified by me.

$filter is a partial string of customer name or email. With this setup, I can only filter and receive result when $filter is full: [email protected]. I am trying to partially match %@woo% just like in MySQL with no luck.

Currently, I solve this with a raw query as follow (I understand that it is not a best practice and can break when woo commerce update their database):

global $wpdb;
$rows_per_page = intval((isset($_POST['rowsPerPage'])) ? sanitize_text_field($_POST['rowsPerPage']) : '5');
$page = intval((isset($_POST['page'])) ? sanitize_text_field($_POST['page']) : '1');
$filter = ((isset($_POST['filter'])) ? sanitize_text_field($_POST['filter']) : '') === 'undefined' ? '' : $_POST["filter"];

$skip = ($page - 1) * $rows_per_page;

$sqlCount = "
      SELECT 
      SQL_CALC_FOUND_ROWS {$wpdb->prefix}posts.ID 
   FROM 
      {$wpdb->prefix}posts 
   WHERE 
      1 = 1 
      AND wp_posts.post_type = 'shop_order' 
      AND (
      (
         {$wpdb->prefix}posts.post_status = 'wc-pending'
         OR {$wpdb->prefix}posts.post_status = 'wc-processing'
         OR {$wpdb->prefix}posts.post_status = 'wc-on-hold'
         OR {$wpdb->prefix}posts.post_status = 'wc-completed'
         OR {$wpdb->prefix}posts.post_status = 'wc-cancelled' 
         OR {$wpdb->prefix}posts.post_status = 'wc-refunded'
         OR {$wpdb->prefix}posts.post_status = 'wc-failed'
      )
      ) 
      AND {$wpdb->prefix}posts.ID IN (
         SELECT post_id AS order_id
         FROM {$wpdb->prefix}postmeta 
         WHERE meta_key 
         IN ('_billing_first_name', '_billing_email', '_billing_phone' )
         AND meta_value LIKE '%" . $filter . "%'
      )
   ORDER BY
      {$wpdb->prefix}posts.post_date DESC
";

$sql = "
      SELECT 
      SQL_CALC_FOUND_ROWS {$wpdb->prefix}posts.ID 
   FROM 
      {$wpdb->prefix}posts 
   WHERE 
      1 = 1 
      AND wp_posts.post_type = 'shop_order' 
      AND (
        (
          {$wpdb->prefix}posts.post_status = 'wc-pending' 
          OR {$wpdb->prefix}posts.post_status = 'wc-processing' 
          OR {$wpdb->prefix}posts.post_status = 'wc-on-hold' 
          OR {$wpdb->prefix}posts.post_status = 'wc-completed' 
          OR {$wpdb->prefix}posts.post_status = 'wc-cancelled' 
          OR {$wpdb->prefix}posts.post_status = 'wc-refunded' 
          OR {$wpdb->prefix}posts.post_status = 'wc-failed'
        )
      )
      AND {$wpdb->prefix}posts.ID IN (
         SELECT post_id AS order_id
         FROM {$wpdb->prefix}postmeta 
         WHERE meta_key 
         IN ('_billing_first_name', '_billing_email', '_billing_phone' )
         AND meta_value LIKE '%" . $filter . "%'
      )
   ORDER BY 
      {$wpdb->prefix}posts.post_date DESC 
   LIMIT 
      " . $skip . ", " . $rows_per_page . "       
";
$orders = $wpdb->get_results($sql);
$rowcount = count($wpdb->get_results($sqlCount));

I am not entirely happy with my raw sql setup because it may not be the best way to do such thing and I need to run 2 sql queries, one to get the paginated result, one to count the number of results returned. Is there a better way to do this?

Thank you very much.

2

Answers


  1. Chosen as BEST ANSWER

    I found out how to do this. First, this is my $args:

    $args = array(
      'limit' => $rows_per_page,
      'paged' => $page,
      'status' => $status,
      'paginate' => true,
      'meta_query' => array(
        'relation' => 'OR',
        array(
          'key'     => '_billing_first_name',
          'value'   => esc_attr($filter),
          'compare' => 'LIKE'
        ),
         array(
           'key'     => '_billing_email',
           'value'   => esc_attr($filter),
           'compare' => 'LIKE'
         ),
         array(
           'key'     => '_billing_phone',
           'value'   => esc_attr($filter),
           'compare' => 'LIKE'
         )
       )
    );
    

    To this point wc_get_orders won't work.

    $results = wc_get_orders($args);

    We need to tell Wordpress/WooCommerce to take the meta_query into consideration:

    add_filter('woocommerce_get_wp_query_args', function ($wp_query_args, $query_vars) {
       if (isset($query_vars['meta_query'])) {
          $meta_query = isset($wp_query_args['meta_query']) ? $wp_query_args['meta_query'] : [];
          $wp_query_args['meta_query'] = array_merge($meta_query, $query_vars['meta_query']);
       }
       return $wp_query_args;
    }, 10, 2);
    

    This wonderful code is from this answer: https://wordpress.stackexchange.com/a/337865


  2. /**
     * Handle a custom 'customvar' query var to get orders with the 'customvar' meta.
     * @param array $query - Args for WP_Query.
     * @param array $query_vars - Query vars from WC_Order_Query.
     * @return array modified $query
     */
    function handle_custom_query_var( $query, $query_vars ) {
        if ( ! empty( $query_vars['customvar'] ) ) {
            $query['meta_query'][] = array(
                'key' => 'customvar',
                'value' => esc_attr( $query_vars['customvar'] ),
                'compare' => 'LIKE'
            );
        }
    
        return $query;
    }
    add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'handle_custom_query_var', 10, 2 );
    

    Using LIKE inside wc_get_orders() with custom values can be done like the above code snippet. You can find more details here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search