admin_url( 'admin-ajax.php' ), 'shop_url' => get_permalink( wc_get_page_id( 'shop' ) ), 'twincaaf_nonce' => wp_create_nonce( 'twincaaf_filter_action' ), 'i18n' => array( 'show_filters' => __( 'Show Filters', 'advanced-attribute-filters' ), 'hide_filters' => __( 'Hide Filters', 'advanced-attribute-filters' ), ), ) ); } /** * Build tax and meta queries from filters. * * @param array $filters Filter data. * @return array */ private function build_filter_queries( $filters ) { // phpcs:disable $tax_query = array(); $meta_query = array(); if (empty($filters) || ! is_array($filters)) { return array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_query_tax_query 'tax_query' => array(), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_query_meta_query 'meta_query' => array(), ); } foreach ($filters as $key => $terms) { if (empty($terms)) { continue; } $clean_key = sanitize_key($key); if (strpos($clean_key, 'filter_') === 0) { $current_taxonomy = str_replace('filter_', 'pa_', $clean_key); } elseif ('product_cat' === $clean_key) { $current_taxonomy = 'product_cat'; } else { continue; } if (! taxonomy_exists($current_taxonomy)) { continue; } $terms_array = is_array($terms) ? $terms : explode(',', $terms); $clean_terms = array_map('sanitize_title', $terms_array); if (! empty($clean_terms)) { $tax_query[] = array( 'taxonomy' => $current_taxonomy, 'field' => 'slug', 'terms' => $clean_terms, 'operator' => 'IN', ); } } if (! empty($tax_query)) { $tax_query['relation'] = 'AND'; } return array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_query_tax_query 'tax_query' => $tax_query, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_query_meta_query 'meta_query' => $meta_query, ); // phpcs:enable } /** * Filter the main query on page load based on URL parameters. * * @param \WP_Query $query The query object. * @return void */ public function filter_main_query( $query ) { if ( is_admin() || ! $query->is_main_query() ) { return; } if ( ! is_shop() && ! is_product_taxonomy() ) { return; } // phpcs:disable WordPress.Security.NonceVerification.Recommended $filters = array(); foreach ( $_GET as $key => $value ) { $clean_key = sanitize_text_field( wp_unslash( $key ) ); if ( strpos( $clean_key, 'filter_' ) === 0 ) { $filters[ $clean_key ] = sanitize_text_field( wp_unslash( $value ) ); } } // phpcs:enable if ( empty( $filters ) ) { return; } $query->set( 'woocommerce_term_action', 'none' ); $queries = $this->build_filter_queries( $filters ); if ( ! empty( $queries['tax_query'] ) ) { $query->set( 'tax_query', $queries['tax_query'] ); } $query->set( 'post_status', 'publish' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core WooCommerce filter $query->set( 'posts_per_page', apply_filters( 'loop_shop_per_page', 12 ) ); add_filter( 'woocommerce_is_filtered', '__return_true' ); add_filter( 'the_posts', function ( $posts, $q ) use ( $query ) { if ( $q === $query ) { return $posts; } return $posts; }, 999, 2 ); } /** * Sync sorting logic for main query. * * @param \WP_Query $query The query object. * @return void */ public function sync_sorting_logic( $query ) { if ( is_admin() || ! $query->is_main_query() ) { return; } if ( is_shop() || is_product_taxonomy() ) { $sorting_method = isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : get_option( 'woocommerce_default_catalog_orderby', 'menu_order' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $ordering_args = WC()->query->get_catalog_ordering_args( $sorting_method ); $query->set( 'orderby', $ordering_args['orderby'] ); $query->set( 'order', $ordering_args['order'] ); if ( isset( $ordering_args['meta_key'] ) ) { $query->set( 'meta_key', $ordering_args['meta_key'] ); } $current_orderby = $query->get( 'orderby' ); if ( is_array( $current_orderby ) ) { $current_orderby['ID'] = 'DESC'; $query->set( 'orderby', $current_orderby ); } else { $query->set( 'orderby', array( $current_orderby => $query->get( 'order' ), 'ID' => 'DESC', ) ); } } } }