2013-08-09 16:11:15 +00:00
< ? php
/**
2015-11-03 13:53:50 +00:00
* WooCommerce Terms
2013-08-09 16:11:15 +00:00
*
* Functions for handling terms / term meta .
*
2018-03-08 21:06:53 +00:00
* @ package WooCommerce / Functions
* @ version 2.1 . 0
2013-08-09 16:11:15 +00:00
*/
2018-03-08 21:06:53 +00:00
defined ( 'ABSPATH' ) || exit ;
2013-08-09 16:11:15 +00:00
2019-01-25 20:39:55 +00:00
/**
* Change get terms defaults for attributes to order by the sorting setting , or default to menu_order for sortable taxonomies .
*
* @ since 3.6 . 0 Sorting options are now set as the default automatically , so you no longer have to request to orderby menu_order .
*
* @ param array $defaults An array of default get_terms () arguments .
* @ param array $taxonomies An array of taxonomies .
* @ return array
*/
function wc_change_get_terms_defaults ( $defaults , $taxonomies ) {
if ( is_array ( $taxonomies ) && 1 < count ( $taxonomies ) ) {
return $defaults ;
}
$taxonomy = is_array ( $taxonomies ) ? $taxonomies [ 0 ] : $taxonomies ;
$orderby = 'name' ;
if ( taxonomy_is_product_attribute ( $taxonomy ) ) {
$orderby = wc_attribute_orderby ( $taxonomy );
} elseif ( in_array ( $taxonomy , apply_filters ( 'woocommerce_sortable_taxonomies' , array ( 'product_cat' ) ), true ) ) {
$orderby = 'menu_order' ;
}
2019-04-24 09:39:00 +00:00
// Change defaults. Invalid values will be changed later @see wc_change_pre_get_terms.
// These are in place so we know if a specific order was requested.
2019-01-25 20:39:55 +00:00
switch ( $orderby ) {
case 'menu_order' :
case 'name_num' :
case 'parent' :
2019-04-24 09:39:00 +00:00
$defaults [ 'orderby' ] = $orderby ;
2019-01-25 20:39:55 +00:00
break ;
}
return $defaults ;
}
add_filter ( 'get_terms_defaults' , 'wc_change_get_terms_defaults' , 10 , 2 );
/**
* Adds support to get_terms for menu_order argument .
*
* @ since 3.6 . 0
* @ param WP_Term_Query $terms_query Instance of WP_Term_Query .
*/
function wc_change_pre_get_terms ( $terms_query ) {
$args = & $terms_query -> query_vars ;
2019-04-24 09:39:00 +00:00
// Put back valid orderby values.
if ( 'menu_order' === $args [ 'orderby' ] ) {
$args [ 'orderby' ] = 'name' ;
$args [ 'force_menu_order_sort' ] = true ;
}
if ( 'name_num' === $args [ 'orderby' ] ) {
$args [ 'orderby' ] = 'name' ;
$args [ 'force_numeric_name' ] = true ;
}
2019-04-02 10:56:47 +00:00
// When COUNTING, disable custom sorting.
if ( 'count' === $args [ 'fields' ] ) {
return ;
}
2019-04-24 09:39:00 +00:00
// Support menu_order arg used in previous versions.
2019-01-25 20:39:55 +00:00
if ( ! empty ( $args [ 'menu_order' ] ) ) {
$args [ 'order' ] = 'DESC' === strtoupper ( $args [ 'menu_order' ] ) ? 'DESC' : 'ASC' ;
$args [ 'force_menu_order_sort' ] = true ;
}
2019-04-02 10:56:47 +00:00
if ( ! empty ( $args [ 'force_menu_order_sort' ] ) ) {
$args [ 'orderby' ] = 'meta_value_num' ;
$args [ 'meta_key' ] = 'order' ; // phpcs:ignore
$terms_query -> meta_query -> parse_query_vars ( $args );
}
2019-01-25 20:39:55 +00:00
}
add_action ( 'pre_get_terms' , 'wc_change_pre_get_terms' , 10 , 1 );
/**
* Adjust term query to handle custom sorting parameters .
*
* @ param array $clauses Clauses .
* @ param array $taxonomies Taxonomies .
* @ param array $args Arguments .
* @ return array
*/
function wc_terms_clauses ( $clauses , $taxonomies , $args ) {
global $wpdb ;
// No need to filter when counting.
2019-03-30 00:39:50 +00:00
if ( strpos ( $clauses [ 'fields' ], 'COUNT(*)' ) !== false ) {
2019-01-25 20:39:55 +00:00
return $clauses ;
}
// Force numeric sort if using name_num custom sorting param.
if ( ! empty ( $args [ 'force_numeric_name' ] ) ) {
$clauses [ 'orderby' ] = str_replace ( 'ORDER BY t.name' , 'ORDER BY t.name+0' , $clauses [ 'orderby' ] );
}
// For sorting, force left join in case order meta is missing.
if ( ! empty ( $args [ 'force_menu_order_sort' ] ) ) {
2019-02-01 13:59:09 +00:00
$clauses [ 'join' ] = str_replace ( " INNER JOIN { $wpdb -> termmeta } ON ( t.term_id = { $wpdb -> termmeta } .term_id ) " , " LEFT JOIN { $wpdb -> termmeta } ON ( t.term_id = { $wpdb -> termmeta } .term_id AND { $wpdb -> termmeta } .meta_key='order') " , $clauses [ 'join' ] );
2019-04-23 10:14:50 +00:00
$clauses [ 'where' ] = str_replace ( " { $wpdb -> termmeta } .meta_key = 'order' " , " ( { $wpdb -> termmeta } .meta_key = 'order' OR { $wpdb -> termmeta } .meta_key IS NULL ) " , $clauses [ 'where' ] );
2019-02-01 13:59:09 +00:00
$clauses [ 'orderby' ] = 'DESC' === $args [ 'order' ] ? str_replace ( 'meta_value+0' , 'meta_value+0 DESC, t.name' , $clauses [ 'orderby' ] ) : str_replace ( 'meta_value+0' , 'meta_value+0 ASC, t.name' , $clauses [ 'orderby' ] );
2019-01-25 20:39:55 +00:00
}
return $clauses ;
}
add_filter ( 'terms_clauses' , 'wc_terms_clauses' , 99 , 3 );
2016-11-17 19:00:56 +00:00
/**
* Helper to get cached object terms and filter by field using wp_list_pluck () .
* Works as a cached alternative for wp_get_post_terms () and wp_get_object_terms () .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-11-17 19:00:56 +00:00
* @ param int $object_id Object ID .
* @ param string $taxonomy Taxonomy slug .
* @ param string $field Field name .
* @ param string $index_key Index key name .
* @ return array
*/
function wc_get_object_terms ( $object_id , $taxonomy , $field = null , $index_key = null ) {
2017-04-05 11:06:37 +00:00
// Test if terms exists. get_the_terms() return false when it finds no terms.
$terms = get_the_terms ( $object_id , $taxonomy );
2018-06-23 11:53:50 +00:00
if ( ! $terms || is_wp_error ( $terms ) ) {
2018-05-15 09:44:32 +00:00
return array ();
2016-11-17 19:00:56 +00:00
}
2018-06-23 11:53:50 +00:00
return is_null ( $field ) ? $terms : wp_list_pluck ( $terms , $field , $index_key );
2016-11-17 19:00:56 +00:00
}
/**
* Cached version of wp_get_post_terms () .
* This is a private function ( internal use ONLY ) .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-11-17 19:00:56 +00:00
* @ param int $product_id Product ID .
* @ param string $taxonomy Taxonomy slug .
* @ param array $args Query arguments .
* @ return array
*/
function _wc_get_cached_product_terms ( $product_id , $taxonomy , $args = array () ) {
2018-03-08 21:06:53 +00:00
$cache_key = 'wc_' . $taxonomy . md5 ( wp_json_encode ( $args ) );
2017-10-25 12:27:18 +00:00
$cache_group = WC_Cache_Helper :: get_cache_prefix ( 'product_' . $product_id ) . $product_id ;
$terms = wp_cache_get ( $cache_key , $cache_group );
2016-11-17 19:00:56 +00:00
if ( false !== $terms ) {
return $terms ;
}
$terms = wp_get_post_terms ( $product_id , $taxonomy , $args );
2017-10-25 12:27:18 +00:00
wp_cache_add ( $cache_key , $terms , $cache_group );
2016-11-17 19:00:56 +00:00
return $terms ;
}
2013-09-13 11:07:54 +00:00
/**
2019-01-25 20:39:55 +00:00
* Wrapper used to get terms for a product .
2014-09-20 19:11:49 +00:00
*
2016-11-17 19:00:56 +00:00
* @ param int $product_id Product ID .
* @ param string $taxonomy Taxonomy slug .
* @ param array $args Query arguments .
2013-11-25 13:30:20 +00:00
* @ return array
2013-09-13 11:07:54 +00:00
*/
function wc_get_product_terms ( $product_id , $taxonomy , $args = array () ) {
2014-05-12 13:31:25 +00:00
if ( ! taxonomy_exists ( $taxonomy ) ) {
2013-11-25 13:30:20 +00:00
return array ();
2014-05-12 13:31:25 +00:00
}
2013-11-25 13:30:20 +00:00
2019-01-25 20:39:55 +00:00
return apply_filters ( 'woocommerce_get_product_terms' , _wc_get_cached_product_terms ( $product_id , $taxonomy , $args ), $product_id , $taxonomy , $args );
2013-09-13 11:07:54 +00:00
}
2014-11-27 14:48:58 +00:00
/**
2015-11-03 13:31:20 +00:00
* Sort by name ( numeric ) .
2018-03-08 21:06:53 +00:00
*
* @ param WP_Post $a First item to compare .
* @ param WP_Post $b Second item to compare .
2014-11-27 14:48:58 +00:00
* @ return int
*/
function _wc_get_product_terms_name_num_usort_callback ( $a , $b ) {
2017-05-25 15:24:42 +00:00
$a_name = ( float ) $a -> name ;
$b_name = ( float ) $b -> name ;
2017-04-09 11:45:46 +00:00
2017-05-25 15:24:42 +00:00
if ( abs ( $a_name - $b_name ) < 0.001 ) {
2014-11-27 14:48:58 +00:00
return 0 ;
}
2017-05-25 15:24:42 +00:00
2017-04-11 05:19:24 +00:00
return ( $a_name < $b_name ) ? - 1 : 1 ;
2014-11-27 14:48:58 +00:00
}
2016-12-15 14:09:01 +00:00
2013-09-13 11:07:54 +00:00
/**
2015-11-03 13:31:20 +00:00
* Sort by parent .
2018-03-08 21:06:53 +00:00
*
* @ param WP_Post $a First item to compare .
* @ param WP_Post $b Second item to compare .
2013-11-25 13:30:20 +00:00
* @ return int
2013-09-13 11:07:54 +00:00
*/
function _wc_get_product_terms_parent_usort_callback ( $a , $b ) {
2014-05-17 04:12:34 +00:00
if ( $a -> parent === $b -> parent ) {
2013-09-13 11:07:54 +00:00
return 0 ;
2014-05-12 13:31:25 +00:00
}
2013-09-13 11:07:54 +00:00
return ( $a -> parent < $b -> parent ) ? 1 : - 1 ;
}
2013-08-09 16:11:15 +00:00
/**
2015-11-03 13:31:20 +00:00
* WooCommerce Dropdown categories .
2013-08-09 16:11:15 +00:00
*
2017-08-25 11:49:51 +00:00
* @ param array $args Args to control display of dropdown .
2013-08-09 16:11:15 +00:00
*/
2017-08-25 11:49:51 +00:00
function wc_product_dropdown_categories ( $args = array () ) {
2014-05-28 10:28:20 +00:00
global $wp_query ;
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
$args = wp_parse_args (
2019-01-25 20:39:55 +00:00
$args ,
array (
2018-03-08 21:06:53 +00:00
'pad_counts' => 1 ,
'show_count' => 1 ,
'hierarchical' => 1 ,
'hide_empty' => 1 ,
'show_uncategorized' => 1 ,
'orderby' => 'name' ,
'selected' => isset ( $wp_query -> query_vars [ 'product_cat' ] ) ? $wp_query -> query_vars [ 'product_cat' ] : '' ,
'show_option_none' => __ ( 'Select a category' , 'woocommerce' ),
'option_none_value' => '' ,
'value_field' => 'slug' ,
'taxonomy' => 'product_cat' ,
'name' => 'product_cat' ,
'class' => 'dropdown_product_cat' ,
)
);
2013-08-09 16:11:15 +00:00
2016-09-07 22:32:24 +00:00
if ( 'order' === $args [ 'orderby' ] ) {
2019-01-25 20:39:55 +00:00
$args [ 'orderby' ] = 'meta_value_num' ;
$args [ 'meta_key' ] = 'order' ; // phpcs:ignore
2014-02-28 15:27:20 +00:00
}
2013-08-09 16:11:15 +00:00
2017-08-25 11:49:51 +00:00
wp_dropdown_categories ( $args );
2013-08-09 16:11:15 +00:00
}
/**
2017-08-25 11:52:49 +00:00
* Custom walker for Product Categories .
*
* Previously used by wc_product_dropdown_categories , but wp_dropdown_categories has been fixed in core .
2013-08-09 16:11:15 +00:00
*
2013-11-27 18:20:31 +00:00
* @ return mixed
2013-08-09 16:11:15 +00:00
*/
2013-11-25 13:30:20 +00:00
function wc_walk_category_dropdown_tree () {
2016-08-10 12:00:20 +00:00
$args = func_get_args ();
2017-02-16 11:46:01 +00:00
if ( ! class_exists ( 'WC_Product_Cat_Dropdown_Walker' , false ) ) {
2018-03-09 19:31:00 +00:00
include_once WC () -> plugin_path () . '/includes/walkers/class-wc-product-cat-dropdown-walker.php' ;
2014-05-28 10:28:20 +00:00
}
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
// The user's options are the third parameter.
2016-09-02 01:51:31 +00:00
if ( empty ( $args [ 2 ][ 'walker' ] ) || ! is_a ( $args [ 2 ][ 'walker' ], 'Walker' ) ) {
2018-03-08 21:06:53 +00:00
$walker = new WC_Product_Cat_Dropdown_Walker ();
2014-05-28 10:28:20 +00:00
} else {
2013-08-09 16:11:15 +00:00
$walker = $args [ 2 ][ 'walker' ];
2014-05-28 10:28:20 +00:00
}
2013-08-09 16:11:15 +00:00
2014-05-28 10:28:20 +00:00
return call_user_func_array ( array ( & $walker , 'walk' ), $args );
2013-08-09 16:11:15 +00:00
}
/**
2018-03-08 21:06:53 +00:00
* Migrate data from WC term meta to WP term meta .
2015-11-06 15:33:02 +00:00
*
* When the database is updated to support term meta , migrate WC term meta data across .
* We do this when the new version is >= 34370 , and the old version is < 34370 ( 34370 is when term meta table was added ) .
*
2018-03-08 21:06:53 +00:00
* @ param string $wp_db_version The new $wp_db_version .
* @ param string $wp_current_db_version The old ( current ) $wp_db_version .
2015-11-06 15:33:02 +00:00
*/
function wc_taxonomy_metadata_migrate_data ( $wp_db_version , $wp_current_db_version ) {
if ( $wp_db_version >= 34370 && $wp_current_db_version < 34370 ) {
global $wpdb ;
if ( $wpdb -> query ( " INSERT INTO { $wpdb -> termmeta } ( term_id, meta_key, meta_value ) SELECT woocommerce_term_id, meta_key, meta_value FROM { $wpdb -> prefix } woocommerce_termmeta; " ) ) {
$wpdb -> query ( " DROP TABLE IF EXISTS { $wpdb -> prefix } woocommerce_termmeta " );
}
}
}
2015-11-06 15:35:25 +00:00
add_action ( 'wp_upgrade' , 'wc_taxonomy_metadata_migrate_data' , 10 , 2 );
2015-11-06 15:33:02 +00:00
2013-08-09 16:11:15 +00:00
/**
2018-03-08 21:06:53 +00:00
* Move a term before the a given element of its hierarchy level .
2013-08-09 16:11:15 +00:00
*
2018-03-08 21:06:53 +00:00
* @ param int $the_term Term ID .
* @ param int $next_id The id of the next sibling element in save hierarchy level .
* @ param string $taxonomy Taxnomy .
* @ param int $index Term index ( default : 0 ) .
* @ param mixed $terms List of terms . ( default : null ) .
2013-08-09 16:11:15 +00:00
* @ return int
*/
2013-11-25 13:30:20 +00:00
function wc_reorder_terms ( $the_term , $next_id , $taxonomy , $index = 0 , $terms = null ) {
2017-05-09 18:20:36 +00:00
if ( ! $terms ) {
2019-01-25 20:39:55 +00:00
$terms = get_terms ( $taxonomy , 'hide_empty=0&parent=0&menu_order=ASC' );
2017-05-09 18:20:36 +00:00
}
if ( empty ( $terms ) ) {
return $index ;
}
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
$id = intval ( $the_term -> term_id );
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
$term_in_level = false ; // Flag: is our term to order in this level of terms.
2013-08-09 16:11:15 +00:00
2015-11-06 15:33:02 +00:00
foreach ( $terms as $term ) {
2018-03-08 21:06:53 +00:00
$term_id = intval ( $term -> term_id );
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
if ( $term_id === $id ) { // Our term to order, we skip.
2013-08-09 16:11:15 +00:00
$term_in_level = true ;
2018-03-08 21:06:53 +00:00
continue ; // Our term to order, we skip.
2013-08-09 16:11:15 +00:00
}
2018-03-08 21:06:53 +00:00
// the nextid of our term to order, lets move our term here.
if ( null !== $next_id && $term_id === $next_id ) {
2016-03-04 10:53:48 +00:00
$index ++ ;
2016-09-02 01:51:31 +00:00
$index = wc_set_term_order ( $id , $index , $taxonomy , true );
2013-08-09 16:11:15 +00:00
}
2018-03-08 21:06:53 +00:00
// Set order.
2016-03-04 10:53:48 +00:00
$index ++ ;
2018-03-08 21:06:53 +00:00
$index = wc_set_term_order ( $term_id , $index , $taxonomy );
2013-08-09 16:11:15 +00:00
2017-05-09 18:20:36 +00:00
/**
* After a term has had it ' s order set .
*/
do_action ( 'woocommerce_after_set_term_order' , $term , $index , $taxonomy );
2018-03-08 21:06:53 +00:00
// If that term has children we walk through them.
2019-01-25 20:39:55 +00:00
$children = get_terms ( $taxonomy , " parent= { $term_id } &hide_empty=0&menu_order=ASC " );
2015-11-06 15:33:02 +00:00
if ( ! empty ( $children ) ) {
2013-12-05 16:07:44 +00:00
$index = wc_reorder_terms ( $the_term , $next_id , $taxonomy , $index , $children );
2013-08-09 16:11:15 +00:00
}
}
2018-03-08 21:06:53 +00:00
// No nextid meaning our term is in last position.
2015-11-06 15:33:02 +00:00
if ( $term_in_level && null === $next_id ) {
$index = wc_set_term_order ( $id , $index + 1 , $taxonomy , true );
}
2013-08-09 16:11:15 +00:00
return $index ;
}
/**
2015-11-03 13:31:20 +00:00
* Set the sort order of a term .
2013-08-09 16:11:15 +00:00
*
2018-03-08 21:06:53 +00:00
* @ param int $term_id Term ID .
* @ param int $index Index .
* @ param string $taxonomy Taxonomy .
* @ param bool $recursive Recursive ( default : false ) .
2013-08-09 16:11:15 +00:00
* @ return int
*/
2013-11-25 13:30:20 +00:00
function wc_set_term_order ( $term_id , $index , $taxonomy , $recursive = false ) {
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
$term_id = ( int ) $term_id ;
$index = ( int ) $index ;
2013-08-09 16:11:15 +00:00
2019-01-25 20:47:54 +00:00
update_term_meta ( $term_id , 'order' , $index );
2013-08-09 16:11:15 +00:00
2017-05-09 18:20:36 +00:00
if ( ! $recursive ) {
return $index ;
}
2013-08-09 16:11:15 +00:00
2019-01-25 20:39:55 +00:00
$children = get_terms ( $taxonomy , " parent= $term_id &hide_empty=0&menu_order=ASC " );
2013-08-09 16:11:15 +00:00
foreach ( $children as $term ) {
2016-03-04 10:53:48 +00:00
$index ++ ;
2016-09-02 01:51:31 +00:00
$index = wc_set_term_order ( $term -> term_id , $index , $taxonomy , true );
2013-08-09 16:11:15 +00:00
}
clean_term_cache ( $term_id , $taxonomy );
return $index ;
}
/**
* Function for recounting product terms , ignoring hidden products .
2017-02-16 12:57:48 +00:00
*
2018-03-08 21:06:53 +00:00
* @ param array $terms List of terms .
2018-10-02 15:03:17 +00:00
* @ param object $taxonomy Taxonomy .
2018-03-08 21:06:53 +00:00
* @ param bool $callback Callback .
* @ param bool $terms_are_term_taxonomy_ids If terms are from term_taxonomy_id column .
2013-08-09 16:11:15 +00:00
*/
2013-11-25 13:30:20 +00:00
function _wc_term_recount ( $terms , $taxonomy , $callback = true , $terms_are_term_taxonomy_ids = true ) {
2017-02-16 12:57:48 +00:00
global $wpdb ;
2013-08-09 16:11:15 +00:00
2017-02-16 12:57:48 +00:00
// Standard callback.
2014-03-17 14:38:09 +00:00
if ( $callback ) {
2013-08-09 16:11:15 +00:00
_update_post_term_count ( $terms , $taxonomy );
2014-03-17 14:38:09 +00:00
}
2013-08-09 16:11:15 +00:00
2017-04-25 12:05:21 +00:00
$exclude_term_ids = array ();
2017-05-08 18:09:55 +00:00
$product_visibility_term_ids = wc_get_product_visibility_term_ids ();
2016-12-08 17:01:39 +00:00
if ( $product_visibility_term_ids [ 'exclude-from-catalog' ] ) {
2017-04-25 12:05:21 +00:00
$exclude_term_ids [] = $product_visibility_term_ids [ 'exclude-from-catalog' ];
2016-12-08 10:56:45 +00:00
}
2016-12-08 17:01:39 +00:00
if ( 'yes' === get_option ( 'woocommerce_hide_out_of_stock_items' ) && $product_visibility_term_ids [ 'outofstock' ] ) {
2017-04-25 12:05:21 +00:00
$exclude_term_ids [] = $product_visibility_term_ids [ 'outofstock' ];
}
2017-05-08 18:09:55 +00:00
$query = array (
'fields' => "
SELECT COUNT ( DISTINCT ID ) FROM { $wpdb -> posts } p
" ,
'join' => '' ,
'where' => "
WHERE 1 = 1
AND p . post_status = 'publish'
AND p . post_type = 'product'
2017-05-05 20:38:25 +00:00
2017-05-08 18:09:55 +00:00
" ,
);
if ( count ( $exclude_term_ids ) ) {
2018-03-08 21:06:53 +00:00
$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' ;
2016-12-08 10:56:45 +00:00
}
2017-02-16 12:57:48 +00:00
// Pre-process term taxonomy ids.
2014-03-17 14:38:09 +00:00
if ( ! $terms_are_term_taxonomy_ids ) {
2017-02-16 12:57:48 +00:00
// We passed in an array of TERMS in format id=>parent.
2014-03-17 14:38:09 +00:00
$terms = array_filter ( ( array ) array_keys ( $terms ) );
} else {
2017-02-16 12:57:48 +00:00
// If we have term taxonomy IDs we need to get the term ID.
2014-03-17 14:38:09 +00:00
$term_taxonomy_ids = $terms ;
$terms = array ();
foreach ( $term_taxonomy_ids as $term_taxonomy_id ) {
$term = get_term_by ( 'term_taxonomy_id' , $term_taxonomy_id , $taxonomy -> name );
$terms [] = $term -> term_id ;
}
}
2013-08-09 16:11:15 +00:00
2017-02-16 12:57:48 +00:00
// Exit if we have no terms to count.
2016-06-06 18:39:23 +00:00
if ( empty ( $terms ) ) {
2014-03-17 14:38:09 +00:00
return ;
}
2013-08-09 16:11:15 +00:00
2017-02-16 12:57:48 +00:00
// Ancestors need counting.
2014-03-17 14:38:09 +00:00
if ( is_taxonomy_hierarchical ( $taxonomy -> name ) ) {
2013-10-22 15:20:40 +00:00
foreach ( $terms as $term_id ) {
2013-10-29 11:29:17 +00:00
$terms = array_merge ( $terms , get_ancestors ( $term_id , $taxonomy -> name ) );
2013-08-09 16:11:15 +00:00
}
}
2017-02-16 12:57:48 +00:00
// Unique terms only.
2013-10-22 15:20:40 +00:00
$terms = array_unique ( $terms );
2013-08-09 16:11:15 +00:00
2017-02-16 12:57:48 +00:00
// Count the terms.
2014-03-17 14:38:09 +00:00
foreach ( $terms as $term_id ) {
$terms_to_count = array ( absint ( $term_id ) );
2013-08-09 16:11:15 +00:00
2014-03-17 14:38:09 +00:00
if ( is_taxonomy_hierarchical ( $taxonomy -> name ) ) {
2018-03-08 21:06:53 +00:00
// 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 ) ) {
2014-03-17 14:38:09 +00:00
$terms_to_count = array_unique ( array_map ( 'absint' , array_merge ( $terms_to_count , $children ) ) );
2013-10-22 15:20:40 +00:00
}
2014-03-17 14:38:09 +00:00
}
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
// Generate term query.
2017-05-08 18:09:55 +00:00
$term_query = $query ;
2018-03-08 21:06:53 +00:00
$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' ;
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
// Get the count.
$count = $wpdb -> get_var ( implode ( ' ' , $term_query ) ); // WPCS: unprepared SQL ok.
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
// Update the count.
2019-01-25 20:47:54 +00:00
update_term_meta ( $term_id , 'product_count_' . $taxonomy -> name , absint ( $count ) );
2013-08-09 16:11:15 +00:00
}
2014-06-19 10:38:57 +00:00
delete_transient ( 'wc_term_counts' );
2013-08-09 16:11:15 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* Recount terms after the stock amount changes .
2015-07-16 19:55:48 +00:00
*
2018-03-08 21:06:53 +00:00
* @ param int $product_id Product ID .
2013-08-09 16:11:15 +00:00
*/
2013-11-25 13:30:20 +00:00
function wc_recount_after_stock_change ( $product_id ) {
2016-12-08 10:56:45 +00:00
if ( 'yes' !== get_option ( 'woocommerce_hide_out_of_stock_items' ) ) {
2013-10-22 15:20:40 +00:00
return ;
2016-12-08 10:56:45 +00:00
}
2013-08-09 16:11:15 +00:00
$product_terms = get_the_terms ( $product_id , 'product_cat' );
if ( $product_terms ) {
2014-11-19 19:01:06 +00:00
$product_cats = array ();
foreach ( $product_terms as $term ) {
2013-08-09 16:11:15 +00:00
$product_cats [ $term -> term_id ] = $term -> parent ;
2014-11-19 19:01:06 +00:00
}
2013-08-09 16:11:15 +00:00
2013-11-25 13:30:20 +00:00
_wc_term_recount ( $product_cats , get_taxonomy ( 'product_cat' ), false , false );
2013-08-09 16:11:15 +00:00
}
$product_terms = get_the_terms ( $product_id , 'product_tag' );
if ( $product_terms ) {
2014-11-19 19:01:06 +00:00
$product_tags = array ();
foreach ( $product_terms as $term ) {
2013-08-09 16:11:15 +00:00
$product_tags [ $term -> term_id ] = $term -> parent ;
2014-11-19 19:01:06 +00:00
}
2013-08-09 16:11:15 +00:00
2013-11-25 13:30:20 +00:00
_wc_term_recount ( $product_tags , get_taxonomy ( 'product_tag' ), false , false );
2013-08-09 16:11:15 +00:00
}
}
2013-11-25 13:30:20 +00:00
add_action ( 'woocommerce_product_set_stock_status' , 'wc_recount_after_stock_change' );
2013-08-09 16:11:15 +00:00
/**
2015-11-03 13:31:20 +00:00
* Overrides the original term count for product categories and tags with the product count .
2013-08-09 16:11:15 +00:00
* that takes catalog visibility into account .
*
2018-03-08 21:06:53 +00:00
* @ param array $terms List of terms .
* @ param string | array $taxonomies Single taxonomy or list of taxonomies .
2013-08-09 16:11:15 +00:00
* @ return array
*/
2014-11-20 00:43:09 +00:00
function wc_change_term_counts ( $terms , $taxonomies ) {
2014-03-17 16:52:06 +00:00
if ( is_admin () || is_ajax () ) {
2013-08-09 16:11:15 +00:00
return $terms ;
2014-03-17 16:52:06 +00:00
}
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
if ( ! isset ( $taxonomies [ 0 ] ) || ! in_array ( $taxonomies [ 0 ], apply_filters ( 'woocommerce_change_term_counts' , array ( 'product_cat' , 'product_tag' ) ), true ) ) {
2013-08-09 16:11:15 +00:00
return $terms ;
2014-03-17 16:52:06 +00:00
}
2013-08-09 16:11:15 +00:00
2018-03-08 21:06:53 +00:00
$o_term_counts = get_transient ( 'wc_term_counts' );
$term_counts = $o_term_counts ;
2013-08-09 16:11:15 +00:00
foreach ( $terms as & $term ) {
2014-03-17 16:52:06 +00:00
if ( is_object ( $term ) ) {
2019-01-25 20:47:54 +00:00
$term_counts [ $term -> term_id ] = isset ( $term_counts [ $term -> term_id ] ) ? $term_counts [ $term -> term_id ] : get_term_meta ( $term -> term_id , 'product_count_' . $taxonomies [ 0 ], true );
2013-08-09 16:11:15 +00:00
2016-09-07 22:32:24 +00:00
if ( '' !== $term_counts [ $term -> term_id ] ) {
2014-03-17 16:52:06 +00:00
$term -> count = absint ( $term_counts [ $term -> term_id ] );
}
}
2013-08-09 16:11:15 +00:00
}
2018-03-08 21:06:53 +00:00
// Update transient.
if ( $term_counts !== $o_term_counts ) {
2015-02-24 12:02:56 +00:00
set_transient ( 'wc_term_counts' , $term_counts , DAY_IN_SECONDS * 30 );
2014-03-17 16:52:06 +00:00
}
2013-08-09 16:11:15 +00:00
return $terms ;
}
2014-11-20 00:43:09 +00:00
add_filter ( 'get_terms' , 'wc_change_term_counts' , 10 , 2 );
2015-11-14 16:25:09 +00:00
/**
* Return products in a given term , and cache value .
*
* To keep in sync , product_count will be cleared on " set_object_terms " .
*
2018-03-08 21:06:53 +00:00
* @ param int $term_id Term ID .
* @ param string $taxonomy Taxonomy .
2015-11-14 16:25:09 +00:00
* @ return array
*/
function wc_get_term_product_ids ( $term_id , $taxonomy ) {
2019-01-25 20:47:54 +00:00
$product_ids = get_term_meta ( $term_id , 'product_ids' , true );
2015-11-14 16:25:09 +00:00
if ( false === $product_ids || ! is_array ( $product_ids ) ) {
$product_ids = get_objects_in_term ( $term_id , $taxonomy );
2019-01-25 20:47:54 +00:00
update_term_meta ( $term_id , 'product_ids' , $product_ids );
2015-11-14 16:25:09 +00:00
}
return $product_ids ;
}
/**
* When a post is updated and terms recounted ( called by _update_post_term_count ), clear the ids .
2018-03-08 21:06:53 +00:00
*
2015-11-14 16:25:09 +00:00
* @ 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 ) {
2019-01-25 20:47:54 +00:00
delete_term_meta ( $term_id , 'product_ids' );
2015-11-14 16:25:09 +00:00
}
foreach ( $tt_ids as $term_id ) {
2019-01-25 20:47:54 +00:00
delete_term_meta ( $term_id , 'product_ids' );
2015-11-14 16:25:09 +00:00
}
}
add_action ( 'set_object_terms' , 'wc_clear_term_product_ids' , 10 , 6 );
2016-12-08 17:01:39 +00:00
/**
* Get full list of product visibilty term ids .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-12-08 17:01:39 +00:00
* @ return int []
*/
function wc_get_product_visibility_term_ids () {
2017-06-06 12:10:56 +00:00
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 ();
}
2018-03-08 21:06:53 +00:00
return array_map (
2019-01-25 20:39:55 +00:00
'absint' ,
wp_parse_args (
2018-03-08 21:06:53 +00:00
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 ,
)
2016-12-08 17:01:39 +00:00
)
2018-03-08 21:06:53 +00:00
);
2016-12-08 17:01:39 +00:00
}