.post_status = 'publish' AND p.post_type = 'product' ", ); if ( count( $exclude_term_ids ) ) { $query['join'] .= " LEFT JOIN ( SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ( " . implode( ',', array_map( 'absint', $exclude_term_ids ) ) . ' ) ) AS exclude_join ON exclude_join.object_id = p.ID'; $query['where'] .= ' AND exclude_join.object_id IS NULL'; } // Ancestors need counting. if ( is_taxonomy_hierarchical( $taxonomy->name ) ) { foreach ( $term_ids as $term_id ) { $term_ids = array_merge( $term_ids, get_ancestors( $term_id, $taxonomy->name ) ); } $term_ids = array_unique( $term_ids ); } // Count the terms. foreach ( $term_ids as $term_id ) { $terms_to_count = array( absint( $term_id ) ); if ( is_taxonomy_hierarchical( $taxonomy->name ) ) { // We need to get the $term's hierarchy so we can count its children too. $children = get_term_children( $term_id, $taxonomy->name ); if ( $children && ! is_wp_error( $children ) ) { $terms_to_count = array_unique( array_map( 'absint', array_merge( $terms_to_count, $children ) ) ); } } // Generate term query. $term_query = $query; $term_query['join'] .= " INNER JOIN ( SELECT object_id FROM {$wpdb->term_relationships} INNER JOIN {$wpdb->term_taxonomy} using( term_taxonomy_id ) WHERE term_id IN ( " . implode( ',', array_map( 'absint', $terms_to_count ) ) . ' ) ) AS include_join ON include_join.object_id = p.ID'; // Get the count. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $count = absint( $wpdb->get_var( implode( ' ', $term_query ) ) ); $term_id = absint( $term_id ); /** * Filter the product count for a term before it is saved. * * @since 10.9.0 * * @param int $count The product count for the term. * @param int $term_id The term ID. * @param WP_Taxonomy $taxonomy The taxonomy object. */ $count = apply_filters( 'woocommerce_term_recount_product_count', $count, $term_id, $taxonomy ); // Update the count. update_term_meta( $term_id, 'product_count_' . $taxonomy->name, absint( $count ) ); } delete_transient( 'wc_term_counts' ); } /** * Recount terms after the stock amount changes. * * @param int $product_id Product ID. */ function wc_recount_after_stock_change( $product_id ) { if ( 'yes' !== get_option( 'woocommerce_hide_out_of_stock_items' ) ) { return; } if ( wp_defer_term_counting() ) { // When deferring term counts, we're using the built in handling of `wp_update_term_count()` to deal with the deferring // and, though, this will cause both the standard and stock based counts to be rerun, it is still more efficient // in cases where deferred term counting was warranted. $product_terms = get_the_terms( $product_id, 'product_cat' ); if ( is_array( $product_terms ) ) { wp_update_term_count( array_column( $product_terms, 'term_taxonomy_id' ), 'product_cat' ); } $product_terms = get_the_terms( $product_id, 'product_tag' ); if ( is_array( $product_terms ) ) { wp_update_term_count( array_column( $product_terms, 'term_taxonomy_id' ), 'product_tag' ); } } else { _wc_recount_terms_by_product( $product_id ); } } add_action( 'woocommerce_product_set_stock_status', 'wc_recount_after_stock_change' ); /** * Overrides the original term count for product categories and tags with the product count. * that takes catalog visibility into account. * * @param array $terms List of terms. * @param string|array $taxonomies Single taxonomy or list of taxonomies. * @return array */ function wc_change_term_counts( $terms, $taxonomies ) { if ( is_admin() || wp_doing_ajax() ) { return $terms; } /** * Filter which product taxonomies should have their term counts overridden to take catalog visibility into account. * * @since 2.1.0 * * @param array $valid_taxonomies List of taxonomy slugs. */ $valid_taxonomies = apply_filters( 'woocommerce_change_term_counts', array( 'product_cat', 'product_tag', 'product_brand' ) ); $current_taxonomies = array_intersect( (array) $taxonomies, $valid_taxonomies ); if ( empty( $current_taxonomies ) ) { return $terms; } $o_term_counts = get_transient( 'wc_term_counts' ); $term_counts = false === $o_term_counts ? array() : $o_term_counts; foreach ( $terms as &$term ) { if ( $term instanceof WP_Term && in_array( $term->taxonomy, $current_taxonomies, true ) ) { $key = $term->term_id . '_' . $term->taxonomy; if ( ! isset( $term_counts[ $key ] ) ) { $count = get_term_meta( $term->term_id, 'product_count_' . $term->taxonomy, true ); $count = '' !== $count ? absint( $count ) : 0; $term_counts[ $key ] = $count; } $term->count = $term_counts[ $key ]; } } // Update transient. if ( $term_counts !== $o_term_counts ) { set_transient( 'wc_term_counts', $term_counts, MONTH_IN_SECONDS ); } return $terms; } add_filter( 'get_terms', 'wc_change_term_counts', 10, 2 ); /** * Return products in a given term, and cache value. * * To keep in sync, product_count will be cleared on "set_object_terms". * * @param int $term_id Term ID. * @param string $taxonomy Taxonomy. * @return array */ function wc_get_term_product_ids( $term_id, $taxonomy ) { $product_ids = get_term_meta( $term_id, 'product_ids', true ); if ( false === $product_ids || ! is_array( $product_ids ) ) { $product_ids = get_objects_in_term( $term_id, $taxonomy ); update_term_meta( $term_id, 'product_ids', $product_ids ); } return $product_ids; } /** * When a post is updated and terms recounted (called by _update_post_term_count), clear the ids. * * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. */ function wc_clear_term_product_ids( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) { foreach ( $old_tt_ids as $term_id ) { delete_term_meta( $term_id, 'product_ids' ); } foreach ( $tt_ids as $term_id ) { delete_term_meta( $term_id, 'product_ids' ); } } add_action( 'set_object_terms', 'wc_clear_term_product_ids', 10, 6 ); /** * Get full list of product visibility term ids. * * @since 3.0.0 * @return int[] */ function wc_get_product_visibility_term_ids() { if ( ! taxonomy_exists( 'product_visibility' ) ) { wc_doing_it_wrong( __FUNCTION__, 'wc_get_product_visibility_term_ids should not be called before taxonomies are registered (woocommerce_after_register_post_type action).', '3.1' ); return array(); } static $term_ids_by_blog = array(); $blog_id = get_current_blog_id(); if ( isset( $term_ids_by_blog[ $blog_id ] ) && ! class_exists( 'WC_Unit_Tests_Bootstrap' ) ) { return $term_ids_by_blog[ $blog_id ]; } $term_ids_by_blog[ $blog_id ] = array_map( 'absint', wp_parse_args( wp_list_pluck( get_terms( array( 'taxonomy' => 'product_visibility', 'hide_empty' => false, ) ), 'term_taxonomy_id', 'name' ), array( 'exclude-from-catalog' => 0, 'exclude-from-search' => 0, 'featured' => 0, 'outofstock' => 0, 'rated-1' => 0, 'rated-2' => 0, 'rated-3' => 0, 'rated-4' => 0, 'rated-5' => 0, ) ) ); return $term_ids_by_blog[ $blog_id ]; } /** * Recounts all terms for product categories and product tags. * * @since 5.2 * * @param bool $include_callback True to update the standard term counts in addition to the product-specific counts, * which will cause a lot more queries to run. * * @return void */ function wc_recount_all_terms( bool $include_callback = true ) { $product_cats = get_terms( array( 'taxonomy' => 'product_cat', 'hide_empty' => false, 'fields' => 'id=>parent', ) ); _wc_term_recount( $product_cats, get_taxonomy( 'product_cat' ), $include_callback, false ); $product_tags = get_terms( array( 'taxonomy' => 'product_tag', 'hide_empty' => false, 'fields' => 'id=>parent', ) ); _wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), $include_callback, false ); } /** * Recounts terms by product. * * @since 5.2 * @param int $product_id The ID of the product. * @return void */ function _wc_recount_terms_by_product( $product_id = '' ) { if ( empty( $product_id ) ) { return; } $product_terms = get_the_terms( $product_id, 'product_cat' ); if ( $product_terms ) { $product_cats = array(); foreach ( $product_terms as $term ) { $product_cats[ $term->term_id ] = $term->parent; } _wc_term_recount( $product_cats, get_taxonomy( 'product_cat' ), false, false ); } $product_terms = get_the_terms( $product_id, 'product_tag' ); if ( $product_terms ) { $product_tags = array(); foreach ( $product_terms as $term ) { $product_tags[ $term->term_id ] = $term->parent; } _wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), false, false ); } } Comments on: The Benefits of Navigation Devices https://dotmobileinspections.com/2024/03/11/the-benefits-of-navigation-devices/ DOT Mobile Inspections Services Sun, 18 Jan 2026 03:30:40 +0000 hourly 1