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 .
*
* @ author WooThemes
* @ category Core
* @ package WooCommerce / Functions
* @ version 2.1 . 0
*/
2014-09-20 19:11:49 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ; // Exit if accessed directly
}
2013-08-09 16:11:15 +00:00
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 );
if ( $terms && ! is_wp_error ( $terms ) ) {
2016-11-17 19:00:56 +00:00
if ( ! is_null ( $field ) ) {
$terms = wp_list_pluck ( $terms , $field , $index_key );
}
2016-11-21 14:16:55 +00:00
} else {
$terms = array ();
2016-11-17 19:00:56 +00:00
}
return $terms ;
}
/**
* 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 () ) {
2017-10-25 12:27:18 +00:00
$cache_key = 'wc_' . $taxonomy . md5 ( json_encode ( $args ) );
$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 ;
}
// @codingStandardsIgnoreStart
$terms = wp_get_post_terms ( $product_id , $taxonomy , $args );
// @codingStandardsIgnoreEnd
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
/**
2014-02-07 11:43:34 +00:00
* Wrapper for wp_get_post_terms which supports ordering by parent .
*
2015-11-03 13:31:20 +00:00
* NOTE : At this point in time , ordering by menu_order for example isn ' t possible with this function . wp_get_post_terms has no .
* filters which we can utilise to modify it ' s query . https :// core . trac . wordpress . org / ticket / 19094.
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
2014-02-07 11:38:57 +00:00
if ( empty ( $args [ 'orderby' ] ) && taxonomy_is_product_attribute ( $taxonomy ) ) {
$args [ 'orderby' ] = wc_attribute_orderby ( $taxonomy );
2013-11-25 13:30:20 +00:00
}
2016-11-17 19:00:56 +00:00
// Support ordering by parent.
2014-11-27 14:48:58 +00:00
if ( ! empty ( $args [ 'orderby' ] ) && in_array ( $args [ 'orderby' ], array ( 'name_num' , 'parent' ) ) ) {
$fields = isset ( $args [ 'fields' ] ) ? $args [ 'fields' ] : 'all' ;
$orderby = $args [ 'orderby' ];
2013-11-25 13:30:20 +00:00
2016-11-17 19:00:56 +00:00
// Unset for wp_get_post_terms.
2013-11-25 13:30:20 +00:00
unset ( $args [ 'orderby' ] );
unset ( $args [ 'fields' ] );
2013-09-13 11:07:54 +00:00
2016-11-17 19:00:56 +00:00
$terms = _wc_get_cached_product_terms ( $product_id , $taxonomy , $args );
2013-09-13 11:07:54 +00:00
2014-11-27 14:48:58 +00:00
switch ( $orderby ) {
case 'name_num' :
usort ( $terms , '_wc_get_product_terms_name_num_usort_callback' );
break ;
case 'parent' :
usort ( $terms , '_wc_get_product_terms_parent_usort_callback' );
break ;
}
2013-09-13 11:07:54 +00:00
2013-11-25 13:30:20 +00:00
switch ( $fields ) {
case 'names' :
$terms = wp_list_pluck ( $terms , 'name' );
2014-02-12 11:47:56 +00:00
break ;
2013-11-25 13:30:20 +00:00
case 'ids' :
$terms = wp_list_pluck ( $terms , 'term_id' );
2014-02-12 11:47:56 +00:00
break ;
2013-11-25 13:30:20 +00:00
case 'slugs' :
$terms = wp_list_pluck ( $terms , 'slug' );
2014-02-12 11:47:56 +00:00
break ;
2013-11-25 13:30:20 +00:00
}
2016-09-07 22:32:24 +00:00
} elseif ( ! empty ( $args [ 'orderby' ] ) && 'menu_order' === $args [ 'orderby' ] ) {
2016-11-17 19:00:56 +00:00
// wp_get_post_terms doesn't let us use custom sort order.
2017-01-11 18:14:28 +00:00
$args [ 'include' ] = wc_get_object_terms ( $product_id , $taxonomy , 'term_id' );
2014-09-20 19:11:49 +00:00
2014-06-03 10:58:08 +00:00
if ( empty ( $args [ 'include' ] ) ) {
$terms = array ();
} else {
2016-11-17 19:00:56 +00:00
// This isn't needed for get_terms.
2014-06-03 10:58:08 +00:00
unset ( $args [ 'orderby' ] );
2014-05-12 13:31:25 +00:00
2016-11-17 19:00:56 +00:00
// Set args for get_terms.
2014-06-03 10:58:08 +00:00
$args [ 'menu_order' ] = isset ( $args [ 'order' ] ) ? $args [ 'order' ] : 'ASC' ;
$args [ 'hide_empty' ] = isset ( $args [ 'hide_empty' ] ) ? $args [ 'hide_empty' ] : 0 ;
$args [ 'fields' ] = isset ( $args [ 'fields' ] ) ? $args [ 'fields' ] : 'names' ;
2014-06-02 15:14:51 +00:00
2016-11-17 19:00:56 +00:00
// Ensure slugs is valid for get_terms - slugs isn't supported.
2016-09-07 22:32:24 +00:00
$args [ 'fields' ] = ( 'slugs' === $args [ 'fields' ] ) ? 'id=>slug' : $args [ 'fields' ];
2014-06-03 10:58:08 +00:00
$terms = get_terms ( $taxonomy , $args );
}
2014-02-12 11:47:56 +00:00
} else {
2016-11-17 19:00:56 +00:00
$terms = _wc_get_cached_product_terms ( $product_id , $taxonomy , $args );
2013-11-25 13:30:20 +00:00
}
2015-06-08 13:41:11 +00:00
return apply_filters ( 'woocommerce_get_product_terms' , $terms , $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 ) .
2014-11-27 14:48:58 +00:00
* @ param WP_POST object $a
* @ param WP_POST object $b
* @ 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 .
2013-11-25 13:30:20 +00:00
* @ param WP_POST object $a
* @ param WP_POST object $b
* @ 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
* @ return string
*/
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
2017-08-25 11:49:51 +00:00
$args = wp_parse_args ( $args , array (
2013-08-20 12:32:38 +00:00
'pad_counts' => 1 ,
2015-08-25 09:48:27 +00:00
'show_count' => 1 ,
2013-08-20 12:32:38 +00:00
'hierarchical' => 1 ,
'hide_empty' => 1 ,
'show_uncategorized' => 1 ,
'orderby' => 'name' ,
2017-08-25 11:49:51 +00:00
'selected' => isset ( $wp_query -> query_vars [ 'product_cat' ] ) ? $wp_query -> query_vars [ 'product_cat' ] : '' ,
2016-08-27 01:46:45 +00:00
'menu_order' => false ,
2017-08-25 11:49:51 +00:00
'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' ] ) {
2014-02-28 15:27:20 +00:00
$args [ 'menu_order' ] = 'asc' ;
$args [ 'orderby' ] = 'name' ;
}
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 ) ) {
2013-11-25 14:01:32 +00:00
include_once ( WC () -> plugin_path () . '/includes/walkers/class-product-cat-dropdown-walker.php' );
2014-05-28 10:28:20 +00:00
}
2013-08-09 16:11:15 +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' ) ) {
2013-08-09 16:11:15 +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
}
2015-03-05 11:27:58 +00:00
/**
* When a term is split , ensure meta data maintained .
* @ param int $old_term_id
* @ param int $new_term_id
* @ param string $term_taxonomy_id
* @ param string $taxonomy
*/
function wc_taxonomy_metadata_update_content_for_split_terms ( $old_term_id , $new_term_id , $term_taxonomy_id , $taxonomy ) {
global $wpdb ;
2015-11-06 15:33:02 +00:00
if ( get_option ( 'db_version' ) < 34370 ) {
if ( 'product_cat' === $taxonomy || taxonomy_is_product_attribute ( $taxonomy ) ) {
2017-02-13 12:58:42 +00:00
$old_meta_data = $wpdb -> get_results ( $wpdb -> prepare ( " SELECT meta_key, meta_value FROM { $wpdb -> prefix } woocommerce_termmeta WHERE woocommerce_term_id = %d; " , $old_term_id ) );
2015-11-06 15:33:02 +00:00
// Copy across to split term
if ( $old_meta_data ) {
foreach ( $old_meta_data as $meta_data ) {
$wpdb -> insert (
" { $wpdb -> prefix } woocommerce_termmeta " ,
array (
'woocommerce_term_id' => $new_term_id ,
'meta_key' => $meta_data -> meta_key ,
2016-08-27 01:46:45 +00:00
'meta_value' => $meta_data -> meta_value ,
2015-11-06 15:33:02 +00:00
)
);
}
2015-03-05 11:27:58 +00:00
}
}
}
}
add_action ( 'split_shared_term' , 'wc_taxonomy_metadata_update_content_for_split_terms' , 10 , 4 );
2013-08-09 16:11:15 +00:00
/**
2015-11-06 15:33:02 +00:00
* Migrate data from WC term meta to WP term meta
*
* 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 ) .
*
* @ param string $wp_db_version The new $wp_db_version .
* @ param string $wp_current_db_version The old ( current ) $wp_db_version .
*/
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
/**
* WooCommerce Term Meta API
*
* WC tables for storing term meta are @ deprecated from WordPress 4.4 since 4.4 has its own table .
* This function serves as a wrapper , using the new table if present , or falling back to the WC table .
*
2013-08-09 16:11:15 +00:00
* @ param mixed $term_id
2014-09-07 23:37:55 +00:00
* @ param string $meta_key
2013-08-09 16:11:15 +00:00
* @ param mixed $meta_value
* @ param string $prev_value ( default : '' )
* @ return bool
*/
function update_woocommerce_term_meta ( $term_id , $meta_key , $meta_value , $prev_value = '' ) {
2016-03-02 18:24:49 +00:00
return function_exists ( 'update_term_meta' ) ? update_term_meta ( $term_id , $meta_key , $meta_value , $prev_value ) : update_metadata ( 'woocommerce_term' , $term_id , $meta_key , $meta_value , $prev_value );
2013-08-09 16:11:15 +00:00
}
/**
2015-11-06 15:33:02 +00:00
* WooCommerce Term Meta API
*
* WC tables for storing term meta are @ deprecated from WordPress 4.4 since 4.4 has its own table .
* This function serves as a wrapper , using the new table if present , or falling back to the WC table .
*
2013-08-09 16:11:15 +00:00
* @ param mixed $term_id
* @ param mixed $meta_key
* @ param mixed $meta_value
* @ param bool $unique ( default : false )
* @ return bool
*/
2016-08-27 04:47:24 +00:00
function add_woocommerce_term_meta ( $term_id , $meta_key , $meta_value , $unique = false ) {
2016-03-02 18:24:49 +00:00
return function_exists ( 'add_term_meta' ) ? add_term_meta ( $term_id , $meta_key , $meta_value , $unique ) : add_metadata ( 'woocommerce_term' , $term_id , $meta_key , $meta_value , $unique );
2013-08-09 16:11:15 +00:00
}
/**
2015-11-06 15:33:02 +00:00
* WooCommerce Term Meta API
*
* WC tables for storing term meta are @ deprecated from WordPress 4.4 since 4.4 has its own table .
* This function serves as a wrapper , using the new table if present , or falling back to the WC table .
*
2013-08-09 16:11:15 +00:00
* @ param mixed $term_id
2016-06-06 16:50:18 +00:00
* @ param string $meta_key
2013-08-09 16:11:15 +00:00
* @ param string $meta_value ( default : '' )
2015-11-06 15:33:02 +00:00
* @ param bool $deprecated ( default : false )
2013-08-09 16:11:15 +00:00
* @ return bool
*/
2015-11-06 15:33:02 +00:00
function delete_woocommerce_term_meta ( $term_id , $meta_key , $meta_value = '' , $deprecated = false ) {
2016-03-02 18:24:49 +00:00
return function_exists ( 'delete_term_meta' ) ? delete_term_meta ( $term_id , $meta_key , $meta_value ) : delete_metadata ( 'woocommerce_term' , $term_id , $meta_key , $meta_value );
2013-08-09 16:11:15 +00:00
}
/**
2015-11-06 15:33:02 +00:00
* WooCommerce Term Meta API
*
* WC tables for storing term meta are @ deprecated from WordPress 4.4 since 4.4 has its own table .
* This function serves as a wrapper , using the new table if present , or falling back to the WC table .
*
2013-08-09 16:11:15 +00:00
* @ param mixed $term_id
2014-09-07 23:37:55 +00:00
* @ param string $key
2013-08-09 16:11:15 +00:00
* @ param bool $single ( default : true )
* @ return mixed
*/
function get_woocommerce_term_meta ( $term_id , $key , $single = true ) {
2016-03-02 18:24:49 +00:00
return function_exists ( 'get_term_meta' ) ? get_term_meta ( $term_id , $key , $single ) : get_metadata ( 'woocommerce_term' , $term_id , $key , $single );
2013-08-09 16:11:15 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* Move a term before the a given element of its hierarchy level .
2013-08-09 16:11:15 +00:00
*
* @ param int $the_term
* @ param int $next_id the id of the next sibling element in save hierarchy level
* @ param string $taxonomy
* @ param int $index ( default : 0 )
* @ param mixed $terms ( default : null )
* @ 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 ) {
$terms = get_terms ( $taxonomy , 'menu_order=ASC&hide_empty=0&parent=0' );
}
if ( empty ( $terms ) ) {
return $index ;
}
2013-08-09 16:11:15 +00:00
$id = $the_term -> term_id ;
$term_in_level = false ; // flag: is our term to order in this level of terms
2015-11-06 15:33:02 +00:00
foreach ( $terms as $term ) {
2013-08-09 16:11:15 +00:00
2015-11-06 15:33:02 +00:00
if ( $term -> term_id == $id ) { // our term to order, we skip
2013-08-09 16:11:15 +00:00
$term_in_level = true ;
continue ; // our term to order, we skip
}
// the nextid of our term to order, lets move our term here
2016-08-27 04:38:29 +00:00
if ( null !== $next_id && $term -> 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
}
// set order
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 );
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 );
2013-08-09 16:11:15 +00:00
// if that term has children we walk through them
2016-09-02 01:51:31 +00:00
$children = get_terms ( $taxonomy , " parent= { $term -> term_id } &menu_order=ASC&hide_empty=0 " );
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
}
}
// 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
*
* @ param int $term_id
* @ param int $index
* @ param string $taxonomy
* @ param bool $recursive ( default : false )
* @ 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
$term_id = ( int ) $term_id ;
$index = ( int ) $index ;
// Meta name
2017-05-09 18:20:36 +00:00
if ( taxonomy_is_product_attribute ( $taxonomy ) ) {
2016-08-27 06:14:06 +00:00
$meta_name = 'order_' . esc_attr ( $taxonomy );
2017-05-09 18:20:36 +00:00
} else {
2013-08-09 16:11:15 +00:00
$meta_name = 'order' ;
2017-05-09 18:20:36 +00:00
}
2013-08-09 16:11:15 +00:00
update_woocommerce_term_meta ( $term_id , $meta_name , $index );
2017-05-09 18:20:36 +00:00
if ( ! $recursive ) {
return $index ;
}
2013-08-09 16:11:15 +00:00
2016-09-02 01:51:31 +00:00
$children = get_terms ( $taxonomy , " parent= $term_id &menu_order=ASC&hide_empty=0 " );
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 ;
}
/**
2015-11-03 13:31:20 +00:00
* Add term ordering to get_terms .
2013-08-09 16:11:15 +00:00
*
* It enables the support a 'menu_order' parameter to get_terms for the product_cat taxonomy .
2015-11-03 13:31:20 +00:00
* By default it is 'ASC' . It accepts 'DESC' too .
2013-08-09 16:11:15 +00:00
*
2015-11-03 13:31:20 +00:00
* To disable it , set it ot false ( or 0 ) .
2013-08-09 16:11:15 +00:00
*
* @ param array $clauses
* @ param array $taxonomies
* @ param array $args
* @ return array
*/
2013-11-25 13:30:20 +00:00
function wc_terms_clauses ( $clauses , $taxonomies , $args ) {
2014-06-08 20:33:11 +00:00
global $wpdb ;
2013-08-09 16:11:15 +00:00
2016-05-11 22:33:55 +00:00
// No sorting when menu_order is false.
2016-12-15 14:09:01 +00:00
if ( isset ( $args [ 'menu_order' ] ) && ( false === $args [ 'menu_order' ] || 'false' === $args [ 'menu_order' ] ) ) {
2014-02-07 11:38:57 +00:00
return $clauses ;
}
2013-08-09 16:11:15 +00:00
2016-05-11 22:33:55 +00:00
// No sorting when orderby is non default.
2016-09-07 22:32:24 +00:00
if ( isset ( $args [ 'orderby' ] ) && 'name' !== $args [ 'orderby' ] ) {
2014-02-07 11:38:57 +00:00
return $clauses ;
}
2013-08-09 16:11:15 +00:00
2016-05-11 22:33:55 +00:00
// No sorting in admin when sorting by a column.
2014-02-07 11:38:57 +00:00
if ( is_admin () && isset ( $_GET [ 'orderby' ] ) ) {
return $clauses ;
}
2013-08-09 16:11:15 +00:00
2016-06-21 12:19:49 +00:00
// No need to filter counts
if ( strpos ( 'COUNT(*)' , $clauses [ 'fields' ] ) !== false ) {
return $clauses ;
}
2017-01-03 18:43:48 +00:00
// WordPress should give us the taxonomies asked when calling the get_terms function. Only apply to categories and pa_ attributes.
2013-08-09 16:11:15 +00:00
$found = false ;
2017-06-01 12:33:30 +00:00
2013-08-09 16:11:15 +00:00
foreach ( ( array ) $taxonomies as $taxonomy ) {
if ( taxonomy_is_product_attribute ( $taxonomy ) || in_array ( $taxonomy , apply_filters ( 'woocommerce_sortable_taxonomies' , array ( 'product_cat' ) ) ) ) {
$found = true ;
break ;
}
}
2017-06-01 12:33:30 +00:00
2014-02-07 11:38:57 +00:00
if ( ! $found ) {
return $clauses ;
}
2013-08-09 16:11:15 +00:00
2016-05-11 22:33:55 +00:00
// Meta name.
2013-08-09 16:11:15 +00:00
if ( ! empty ( $taxonomies [ 0 ] ) && taxonomy_is_product_attribute ( $taxonomies [ 0 ] ) ) {
2015-11-06 15:33:02 +00:00
$meta_name = 'order_' . esc_attr ( $taxonomies [ 0 ] );
2013-08-09 16:11:15 +00:00
} else {
$meta_name = 'order' ;
}
2016-05-11 22:33:55 +00:00
// Query fields.
2017-05-19 14:27:57 +00:00
$clauses [ 'fields' ] = $clauses [ 'fields' ] . ', tm.meta_value' ;
2013-08-09 16:11:15 +00:00
2016-05-11 22:33:55 +00:00
// Query join.
2015-11-06 15:33:02 +00:00
if ( get_option ( 'db_version' ) < 34370 ) {
$clauses [ 'join' ] .= " LEFT JOIN { $wpdb -> woocommerce_termmeta } AS tm ON (t.term_id = tm.woocommerce_term_id AND tm.meta_key = ' " . esc_sql ( $meta_name ) . " ') " ;
} else {
$clauses [ 'join' ] .= " LEFT JOIN { $wpdb -> termmeta } AS tm ON (t.term_id = tm.term_id AND tm.meta_key = ' " . esc_sql ( $meta_name ) . " ') " ;
}
2013-08-09 16:11:15 +00:00
2016-05-11 22:33:55 +00:00
// Default to ASC.
if ( ! isset ( $args [ 'menu_order' ] ) || ! in_array ( strtoupper ( $args [ 'menu_order' ] ), array ( 'ASC' , 'DESC' ) ) ) {
2014-02-07 11:38:57 +00:00
$args [ 'menu_order' ] = 'ASC' ;
}
2013-08-09 16:11:15 +00:00
2016-03-04 10:53:48 +00:00
$order = " ORDER BY tm.meta_value+0 " . $args [ 'menu_order' ];
2013-08-09 16:11:15 +00:00
2015-11-06 15:33:02 +00:00
if ( $clauses [ 'orderby' ] ) {
2016-03-04 10:53:48 +00:00
$clauses [ 'orderby' ] = str_replace ( 'ORDER BY' , $order . ',' , $clauses [ 'orderby' ] );
2015-11-06 15:33:02 +00:00
} else {
2013-08-09 16:11:15 +00:00
$clauses [ 'orderby' ] = $order ;
2015-11-06 15:33:02 +00:00
}
2013-08-09 16:11:15 +00:00
2017-06-01 12:33:30 +00:00
// Grouping.
if ( strstr ( $clauses [ 'fields' ], 'tr.object_id' ) ) {
$clauses [ 'orderby' ] = ' GROUP BY t.term_id, tr.object_id ' . $clauses [ 'orderby' ];
} else {
$clauses [ 'orderby' ] = ' GROUP BY t.term_id ' . $clauses [ 'orderby' ];
}
2013-08-09 16:11:15 +00:00
return $clauses ;
}
2016-05-11 22:33:55 +00:00
2017-06-01 12:33:30 +00:00
add_filter ( 'terms_clauses' , 'wc_terms_clauses' , 99 , 3 );
2013-08-09 16:11:15 +00:00
/**
* Function for recounting product terms , ignoring hidden products .
2017-02-16 12:57:48 +00:00
*
* @ param array $terms
* @ param string $taxonomy
* @ param bool $callback
* @ param bool $terms_are_term_taxonomy_ids
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 ) ) {
$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 ) ) {
// We need to get the $term's hierarchy so we can count its children too
if ( ( $children = get_term_children ( $term_id , $taxonomy -> name ) ) && ! is_wp_error ( $children ) ) {
$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
2014-03-17 14:38:09 +00:00
// Generate term query
2017-05-08 18:09:55 +00:00
$term_query = $query ;
2017-05-09 18:17:24 +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
2014-03-17 14:38:09 +00:00
// Get the count
2017-05-08 18:09:55 +00:00
$count = $wpdb -> get_var ( implode ( ' ' , $term_query ) );
2013-08-09 16:11:15 +00:00
2014-03-17 14:38:09 +00:00
// Update the count
update_woocommerce_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
*
* @ param int $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 .
*
* @ param array $terms
2014-11-20 00:43:09 +00:00
* @ param string | array $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
2014-03-17 16:52:06 +00:00
if ( ! isset ( $taxonomies [ 0 ] ) || ! in_array ( $taxonomies [ 0 ], apply_filters ( 'woocommerce_change_term_counts' , array ( 'product_cat' , 'product_tag' ) ) ) ) {
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
$term_counts = $o_term_counts = get_transient ( 'wc_term_counts' );
foreach ( $terms as & $term ) {
2014-03-17 16:52:06 +00:00
if ( is_object ( $term ) ) {
$term_counts [ $term -> term_id ] = isset ( $term_counts [ $term -> term_id ] ) ? $term_counts [ $term -> term_id ] : get_woocommerce_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
}
// Update transient
2014-03-17 16:52:06 +00:00
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 " .
*
* @ param int $term_id
* @ param string $taxonomy
* @ return array
*/
function wc_get_term_product_ids ( $term_id , $taxonomy ) {
$product_ids = get_woocommerce_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_woocommerce_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_woocommerce_term_meta ( $term_id , 'product_ids' );
}
foreach ( $tt_ids as $term_id ) {
delete_woocommerce_term_meta ( $term_id , 'product_ids' );
}
}
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 ();
}
2016-12-08 17:01:39 +00:00
return 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 ,
2016-12-09 15:43:25 +00:00
'rated-1' => 0 ,
'rated-2' => 0 ,
'rated-3' => 0 ,
'rated-4' => 0 ,
'rated-5' => 0 ,
2016-12-08 17:01:39 +00:00
)
) );
}