er_by_clause = ''; $sql_query->clear_sql_clause( array( 'order_by' ) ); if ( isset( $query_args['orderby'] ) ) { $order_by_clause = $this->normalize_order_by( $query_args['orderby'] ); $sql_query->add_sql_clause( 'order_by', $order_by_clause ); } // Return ORDER BY clause to allow adding the sort field(s) to query via a JOIN. return $order_by_clause; } /** * Add order by order SQL clause. * * @param array $query_args Parameters supplied by the user. * @param SqlQuery $sql_query Query object. */ protected function add_orderby_order_clause( $query_args, &$sql_query ) { if ( isset( $query_args['order'] ) ) { $sql_query->add_sql_clause( 'order_by', $query_args['order'] ); } else { $sql_query->add_sql_clause( 'order_by', 'DESC' ); } } /** * Returns customer subquery to be used in WHERE SQL query, based on query arguments from the user. * * @param array $query_args Parameters supplied by the user. * @return string */ protected function get_customer_subquery( $query_args ) { global $wpdb; $customer_filter = ''; if ( isset( $query_args['customer_type'] ) ) { if ( 'new' === strtolower( $query_args['customer_type'] ) ) { $customer_filter = " {$wpdb->prefix}wc_order_stats.returning_customer = 0"; } elseif ( 'returning' === strtolower( $query_args['customer_type'] ) ) { $customer_filter = " {$wpdb->prefix}wc_order_stats.returning_customer = 1"; } } return $customer_filter; } /** * Returns product attribute subquery elements used in JOIN and WHERE clauses, * based on query arguments from the user. * * @param array $query_args Parameters supplied by the user. * @return array */ protected function get_attribute_subqueries( $query_args ) { global $wpdb; $sql_clauses = array( 'join' => array(), 'where' => array(), ); $match_operator = $this->get_match_operator( $query_args ); $join_table = $wpdb->prefix . 'wc_order_product_lookup'; $post_meta_comparators = array( '=' => 'attribute_is', '!=' => 'attribute_is_not', ); foreach ( $post_meta_comparators as $comparator => $arg ) { if ( ! isset( $query_args[ $arg ] ) || ! is_array( $query_args[ $arg ] ) ) { continue; } foreach ( $query_args[ $arg ] as $attribute_term ) { // We expect tuples. if ( ! is_array( $attribute_term ) || 2 !== count( $attribute_term ) ) { continue; } // If the tuple is numeric, assume these are IDs. if ( is_numeric( $attribute_term[0] ) && is_numeric( $attribute_term[1] ) ) { $attribute_id = intval( $attribute_term[0] ); $term_id = intval( $attribute_term[1] ); // Invalid IDs. if ( 0 === $attribute_id || 0 === $term_id ) { continue; } // @todo: Use wc_get_attribute() instead ? $attr_taxonomy = wc_attribute_taxonomy_name_by_id( $attribute_id ); // Invalid attribute ID. if ( empty( $attr_taxonomy ) ) { continue; } $attr_term = get_term_by( 'id', $term_id, $attr_taxonomy ); // Invalid term ID. if ( false === $attr_term ) { continue; } $meta_key = wc_variation_attribute_name( $attr_taxonomy ); $meta_value = $attr_term->slug; } else { // Assume these are a custom attribute slug/value pair. $meta_key = 'attribute_' . esc_sql( $attribute_term[0] ); $meta_value = esc_sql( $attribute_term[1] ); } $join_alias = 'wpm1'; // If we're matching all filters (AND), we'll need multiple JOINs on postmeta. // If not, just one. if ( 'AND' === $match_operator || empty( $sql_clauses['join'] ) ) { $join_idx = count( $sql_clauses['join'] ) + 1; $join_alias = 'wpm' . $join_idx; $sql_clauses['join'][] = "JOIN {$wpdb->postmeta} as {$join_alias} ON {$join_alias}.post_id = {$join_table}.variation_id"; } // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $sql_clauses['where'][] = $wpdb->prepare( "( {$join_alias}.meta_key = %s AND {$join_alias}.meta_value {$comparator} %s )", $meta_key, $meta_value ); } } return $sql_clauses; } /** * Returns logic operator for WHERE subclause based on 'match' query argument. * * @param array $query_args Parameters supplied by the user. * @return string */ protected function get_match_operator( $query_args ) { $operator = 'AND'; if ( ! isset( $query_args['match'] ) ) { return $operator; } if ( 'all' === strtolower( $query_args['match'] ) ) { $operator = 'AND'; } elseif ( 'any' === strtolower( $query_args['match'] ) ) { $operator = 'OR'; } return $operator; } /** * Returns filtered comma separated ids, based on query arguments from the user. * * @param array $query_args Parameters supplied by the user. * @param string $field Query field to filter. * @param string $separator Field separator. * @return string */ protected function get_filtered_ids( $query_args, $field, $separator = ',' ) { $ids_str = ''; $ids = isset( $query_args[ $field ] ) && is_array( $query_args[ $field ] ) ? $query_args[ $field ] : array(); /** * Filter the IDs before retrieving report data. * * Allows filtering of the objects included or excluded from reports. * * @param array $ids List of object Ids. * @param array $query_args The original arguments for the request. * @param string $field The object type. * @param string $context The data store context. */ $ids = apply_filters( 'woocommerce_analytics_' . $field, $ids, $query_args, $field, $this->context ); if ( ! empty( $ids ) ) { $ids_str = implode( $separator, $ids ); } return $ids_str; } /** * Assign report columns once full table name has been assigned. */ protected function assign_report_columns() {} }