'count',
'selection' => 'desc',
'orderby' => 'random',
'order' => 'asc',
'format' => 'border',
'xformat' => __('%tag_name%', 'simple-tags'),
'number' => 20,
'notagstext' => __('No tags.', 'simple-tags'),
'title' => __('
Tag Cloud
', 'simple-tags'),
'maxcolor' => '#000000',
'mincolor' => '#353535',
'largest' => 12,
'smallest' => 12,
'unit' => 'pt',
'taxonomy' => 'post_tag', // Note: saved as an option but no UI to set it
'parent_term' => '',
'display_mode' => 'parents_and_sub',
// Simple Tag other defaults
'size' => 'true',
'color' => 'true',
'exclude' => '',
'exclude_terms' => '',
'include' => '',
'term_selection_mode' => 'automatic',
'include_terms' => '',
'limit_days' => 0,
'min_usage' => 0,
'category' => 0,
'ID' => 0,
'hide_title' => 0,
'hide_output' => 0,
'post_type' => '',
'wrap_class' => '',
'link_class' => '',
'before' => '',
'after' => '',
'hide_terms' => 0,
);
// Get options
$options = SimpleTags_Plugin::get_option();
$enable_hidden_terms = SimpleTags_Plugin::get_option_value('enable_hidden_terms');
// Get values in DB
$defaults['selectionby'] = $options['cloud_selectionby'];
$defaults['selection'] = $options['cloud_selection'];
$defaults['orderby'] = $options['cloud_orderby'];
$defaults['order'] = $options['cloud_order'];
$defaults['format'] = $options['cloud_format'];
$defaults['xformat'] = $options['cloud_xformat'];
$defaults['number'] = $options['cloud_limit_qty'];
$defaults['notagstext'] = $options['cloud_notagstext'];
$defaults['title'] = $options['cloud_title'];
$defaults['maxcolor'] = $options['cloud_max_color'];
$defaults['mincolor'] = $options['cloud_min_color'];
$defaults['largest'] = $options['cloud_max_size'];
$defaults['smallest'] = $options['cloud_min_size'];
$defaults['unit'] = $options['cloud_unit'];
$defaults['taxonomy'] = $options['cloud_taxonomy'];
$defaults['parent_term'] = $options['cloud_parent_term'];
$defaults['display_mode'] = $options['cloud_display_mode'];
$adv_usage = $options['cloud_adv_usage'];
if (empty($args)) {
$args = $adv_usage;
} else {
$args = $adv_usage . "&" . $args;
}
$args = wp_parse_args($args, $defaults);
// Add compatibility tips with old field syntax
if (isset($args['cloud_sort'])) {
$args['cloud_order'] = $args['cloud_sort'];
unset($args['cloud_sort']);
}
// Translate selection order
if (isset($args['cloud_order'])) {
$args['orderby'] = self::compatOldOrder($args['cloud_order'], 'orderby');
$args['order'] = self::compatOldOrder($args['cloud_order'], 'order');
}
// Category names to ID codes
if (isset($args['category'])) {
$category = explode(",", $args['category']);
foreach ($category as $key => $name) {
$category[ $key ] = is_numeric($name) ? $name : get_cat_ID($name);
if ($category[ $key ] == 0) {
unset($category[ $key ]);
}
}
$args['category'] = implode(",", $category);
}
// Get correct taxonomy ?
$taxonomy = self::_get_current_taxonomy($args['taxonomy']);
// Get terms
$term_selection_mode = isset($args['term_selection_mode']) ? $args['term_selection_mode'] : 'automatic';
if ($term_selection_mode === 'custom') {
$terms = [];
if (!empty($args['include_terms'])) {
$include_terms_array = array_map('trim', explode(',', $args['include_terms']));
foreach ($include_terms_array as $term_name) {
if (!empty($term_name)) {
$term = get_term_by('name', $term_name, $taxonomy);
if ($term && !is_wp_error($term)) {
$terms[] = $term;
}
}
}
}
} elseif ($term_selection_mode === 'combined') {
$terms = self::getTags($args, $taxonomy);
if (!empty($args['include_terms'])) {
$include_terms_array = array_map('trim', explode(',', $args['include_terms']));
$existing_term_ids = wp_list_pluck($terms, 'term_id');
foreach ($include_terms_array as $term_name) {
if (!empty($term_name)) {
$term = get_term_by('name', $term_name, $taxonomy);
if ($term && !is_wp_error($term) && !in_array($term->term_id, $existing_term_ids)) {
$terms[] = $term;
$existing_term_ids[] = $term->term_id;
}
}
}
}
} else {
$terms = self::getTags($args, $taxonomy);
}
// Remove hidden terms if enabled
if ($enable_hidden_terms && !empty($args['hide_terms'])) {
$hidden_terms = get_transient('taxopress_hidden_terms_' . $args['taxonomy']);
if (!empty($hidden_terms) && is_array($hidden_terms)) {
$terms = array_filter($terms, function ($term) use ($hidden_terms) {
return !in_array($term->term_id, $hidden_terms);
});
}
}
extract($args); // Params to variables
// Process exclude_terms
if (! empty($exclude_terms)) {
// Convert the exclude terms string into a set (associative array) for faster lookup
$exclude_terms_set = array_flip(array_map('strtolower', array_map('trim', explode(',', $exclude_terms))));
} else {
$exclude_terms_set = array();
}
// Filter out excluded terms
if (! empty($exclude_terms_set)) {
// Use array_filter to remove terms that exist in the exclude set
$terms = array_filter($terms, function ($term) use ($exclude_terms_set) {
return ! isset($exclude_terms_set[ strtolower($term->name) ]);
});
}
// If empty use default xformat !
if (empty($xformat)) {
$xformat = $defaults['xformat'];
}
$xformat = taxopress_sanitize_text_field($xformat);
//remove title if in settings
if ((int)$hide_title > 0) {
$title = '';
}
if (empty($terms)) {
// Check if custom mode is selected with empty include_terms
if ($term_selection_mode === 'custom' && empty($args['include_terms'])) {
$message_text = __('You have selected Custom mode but the "Custom terms to display" field is empty. Please add terms to display or switch to Automatic mode.', 'simple-tags');
// Apply the same styling as terms would have
$font_size = !empty($smallest) ? $smallest : 12;
$font_color = !empty($mincolor) ? $mincolor : '#353535';
$font_unit = !empty($unit) ? $unit : 'pt';
$custom_mode_message = '' . esc_html($message_text) . '';
if ((int)$hide_output === 0) {
return SimpleTags_Client::output_content('st-tag-cloud', $format, $title, $custom_mode_message, $copyright, '', $wrap_class, $link_class);
} else {
return '';
}
}
if ((int)$hide_output === 0) {
return SimpleTags_Client::output_content('st-tag-cloud', $format, $title, $notagstext, $copyright, '', $wrap_class, $link_class);
} else {
return '';
}
}
$counts = $terms_data = array();
foreach ((array) $terms as $term) {
$counts[ $term->name ] = $term->count;
$terms_data[ $term->name ] = $term;
}
// Remove temp data from memory
$terms = array();
unset($terms);
// Use full RBG code
if (strlen($maxcolor) == 4) {
$maxcolor = $maxcolor . substr($maxcolor, 1, strlen($maxcolor));
}
if (strlen($mincolor) == 4) {
$mincolor = $mincolor . substr($mincolor, 1, strlen($mincolor));
}
// Check as smallest inferior or egal to largest
if ($smallest > $largest) {
$smallest = $largest;
}
// Scaling - Hard value for the moment
$scale_min = 0;
$scale_max = 10;
$minval = min($counts);
$maxval = max($counts);
$minout = max($scale_min, 0);
$maxout = max($scale_max, $minout);
$scale = ($maxval > $minval) ? (($maxout - $minout) / ($maxval - $minval)) : 0;
// HTML Rel (tag/no-follow)
$rel = SimpleTags_Client::get_rel_attribut();
// Remove color marquer if color = false
if ($color == 'false') {
$xformat = str_replace('%tag_color%', '', $xformat);
}
// Remove size marquer if size = false
if ($size == 'false') {
$xformat = str_replace('%tag_size%', '', $xformat);
}
// Order terms before output
// count, name, rand | asc, desc
$orderby = strtolower($orderby);
$order = strtolower($order);
if (in_array($format, ['parent/child']) && $args['display_mode'] === 'parents_and_sub') {
$terms = self::getTags($args, $taxonomy);
// Check if terms is empty or invalid
if (empty($terms)) {
return SimpleTags_Client::output_content('st-tag-cloud', $format, $title, $notagstext, $copyright, '', $wrap_class, $link_class);
}
// First, group terms by parent term
$grouped_terms = [];
foreach ($terms as $term) {
// Only group terms with a parent (excluding standalone terms)
if ($term->parent != 0) {
$parent_id = $term->parent;
if (!isset($grouped_terms[$parent_id])) {
$grouped_terms[$parent_id] = [];
}
$grouped_terms[$parent_id][] = $term;
}
}
// Then, sort each group by name
foreach ($grouped_terms as &$parent_group) {
usort($parent_group, function ($a, $b) {
return strcmp($a->name, $b->name);
});
}
// Merge all grouped terms into a single array, ensuring correct parent-child order
$terms = [];
foreach ($grouped_terms as $parent_group) {
$terms = array_merge($terms, $parent_group);
}
}
// Custom drag-and-drop order: always check first!
if ($orderby === 'taxopress_term_order') {
$custom_order = get_option('taxopress_term_order_' . $taxonomy, []);
if (!empty($custom_order)) {
$terms_by_id = [];
foreach ($terms_data as $term_name => $term_obj) {
if (is_object($term_obj) && isset($term_obj->term_id)) {
$terms_by_id[$term_obj->term_id] = $term_obj;
}
}
$ordered_terms = [];
foreach ($custom_order as $term_id) {
if (isset($terms_by_id[$term_id])) {
$ordered_terms[$terms_by_id[$term_id]->name] = $terms_by_id[$term_id]->count;
unset($terms_by_id[$term_id]);
}
}
// Add any terms not in custom order at the end
foreach ($terms_by_id as $term_obj) {
$ordered_terms[$term_obj->name] = $term_obj->count;
}
if ($order === 'desc') {
$ordered_terms = array_reverse($ordered_terms, true);
}
$counts = $ordered_terms;
}
} else {
// Default sorting logic
if ($orderby == 'count') {
asort($counts);
} elseif ($orderby == 'name') {
uksort($counts, [__CLASS__, 'uksort_by_name']);
} else { // rand
SimpleTags_Client::random_array($counts);
}
$order = strtolower($order);
if ($order == 'desc' && $orderby != 'random') {
$counts = array_reverse($counts, true);
}
}
$output = array();
//update xformat with class link class
if (!empty(trim($link_class))) {
$link_class = taxopress_format_class($link_class);
$xformat = taxopress_add_class_to_format($xformat, $link_class);
}
foreach ((array) $counts as $term_name => $count) {
if (! is_object($terms_data[ $term_name ])) {
continue;
}
$term = $terms_data[ $term_name ];
$scale_result = (int) ($scale <> 0 ? (($term->count - $minval) * $scale + $minout) : ($scale_max - $scale_min) / 2);
//$output[] = SimpleTags_Client::format_internal_tag( $xformat, $term, $rel, $scale_result, $scale_max, $scale_min, $largest, $smallest, $unit, $maxcolor, $mincolor );
$formatted = SimpleTags_Client::format_internal_tag($xformat, $term, $rel, $scale_result, $scale_max, $scale_min, $largest, $smallest, $unit, $maxcolor, $mincolor);
if ($format === 'table') {
$output[] = [
'html' => $formatted,
'count' => $term->count,
'term_name' => $term->name,
];
} else {
$output[] = $formatted;
}
}
return SimpleTags_Client::output_content('st-tag-cloud', $format, $title, $output, $copyright, '', $wrap_class, $link_class, $before, $after, $taxonomy);
}
/**
* Generate extended tag result
*
* @param string $args
*
* @return array
*/
public static function extendedTagResult($args = '', $copyright = true)
{
$defaults = array(
// Simple Tag global options defaults
'selectionby' => 'count',
'selection' => 'desc',
'orderby' => 'random',
'order' => 'asc',
'format' => 'border',
'xformat' => __('%tag_name%', 'simple-tags'),
'number' => 20,
'notagstext' => __('No tags.', 'simple-tags'),
'title' => __('Tag Cloud
', 'simple-tags'),
'maxcolor' => '#000000',
'mincolor' => '#353535',
'largest' => 12,
'smallest' => 12,
'unit' => 'pt',
'taxonomy' => 'post_tag', // Note: saved as an option but no UI to set it
'parent_term' => '',
'display_mode' => 'parents_and_sub',
// Simple Tag other defaults
'size' => 'true',
'color' => 'true',
'exclude' => '',
'include' => '',
'limit_days' => 0,
'min_usage' => 0,
'category' => 0,
'hide_terms' => 0,
);
// Get options
$options = SimpleTags_Plugin::get_option();
$enable_hidden_terms = SimpleTags_Plugin::get_option_value('enable_hidden_terms');
// Get values in DB
$defaults['selectionby'] = $options['cloud_selectionby'];
$defaults['selection'] = $options['cloud_selection'];
$defaults['orderby'] = $options['cloud_orderby'];
$defaults['order'] = $options['cloud_order'];
$defaults['format'] = $options['cloud_format'];
$defaults['xformat'] = $options['cloud_xformat'];
$defaults['number'] = $options['cloud_limit_qty'];
$defaults['notagstext'] = $options['cloud_notagstext'];
$defaults['title'] = $options['cloud_title'];
$defaults['maxcolor'] = $options['cloud_max_color'];
$defaults['mincolor'] = $options['cloud_min_color'];
$defaults['largest'] = $options['cloud_max_size'];
$defaults['smallest'] = $options['cloud_min_size'];
$defaults['unit'] = $options['cloud_unit'];
$defaults['taxonomy'] = $options['cloud_taxonomy'];
$defaults['parent_term'] = $options['cloud_parent_term'];
$defaults['display_mode'] = $options['cloud_display_mode'];
$adv_usage = $options['cloud_adv_usage'];
if (empty($args)) {
$args = $adv_usage;
} else {
$args = $adv_usage . "&" . $args;
}
$args = wp_parse_args($args, $defaults);
// Add compatibility tips with old field syntax
if (isset($args['cloud_sort'])) {
$args['cloud_order'] = $args['cloud_sort'];
unset($args['cloud_sort']);
}
// Translate selection order
if (isset($args['cloud_order'])) {
$args['orderby'] = self::compatOldOrder($args['cloud_order'], 'orderby');
$args['order'] = self::compatOldOrder($args['cloud_order'], 'order');
}
// Category names to ID codes
if (isset($args['category'])) {
$category = explode(",", $args['category']);
foreach ($category as $key => $name) {
$category[ $key ] = is_numeric($name) ? $name : get_cat_ID($name);
if ($category[ $key ] == 0) {
unset($category[ $key ]);
}
}
$args['category'] = implode(",", $category);
}
// Get correct taxonomy ?
$taxonomy = self::_get_current_taxonomy($args['taxonomy']);
// Get terms
$terms = self::getTags($args, $taxonomy);
// Remove hidden terms if enabled
if ($enable_hidden_terms && !empty($args['hide_terms'])) {
$hidden_terms = get_transient('taxopress_hidden_terms_' . $args['taxonomy']);
if (!empty($hidden_terms) && is_array($hidden_terms)) {
$terms = array_filter($terms, function ($term) use ($hidden_terms) {
return !in_array($term->term_id, $hidden_terms);
});
}
}
extract($args); // Params to variables
// If empty use default xformat !
if (empty($xformat)) {
$xformat = $defaults['xformat'];
}
if (empty($terms)) {
return [];
}
$counts = $terms_data = array();
foreach ((array) $terms as $term) {
$counts[ $term->name ] = $term->count;
$terms_data[ $term->name ] = $term;
}
// Remove temp data from memory
$terms = array();
unset($terms);
// Use full RBG code
if (strlen($maxcolor) == 4) {
$maxcolor = $maxcolor . substr($maxcolor, 1, strlen($maxcolor));
}
if (strlen($mincolor) == 4) {
$mincolor = $mincolor . substr($mincolor, 1, strlen($mincolor));
}
// Check as smallest inferior or egal to largest
if ($smallest > $largest) {
$smallest = $largest;
}
// Scaling - Hard value for the moment
$scale_min = 0;
$scale_max = 10;
$minval = min($counts);
$maxval = max($counts);
$minout = max($scale_min, 0);
$maxout = max($scale_max, $minout);
$scale = ($maxval > $minval) ? (($maxout - $minout) / ($maxval - $minval)) : 0;
// HTML Rel (tag/no-follow)
$rel = SimpleTags_Client::get_rel_attribut();
// Remove color marquer if color = false
if ($color == 'false') {
$xformat = str_replace('%tag_color%', '', $xformat);
}
// Remove size marquer if size = false
if ($size == 'false') {
$xformat = str_replace('%tag_size%', '', $xformat);
}
// Order terms before output
// count, name, rand | asc, desc
$orderby = strtolower($orderby);
if ($orderby == 'count') {
asort($counts);
} elseif ($orderby == 'name') {
uksort($counts, array( __CLASS__, 'uksort_by_name' ));
} else { // rand
SimpleTags_Client::random_array($counts);
}
$order = strtolower($order);
if ($order == 'desc' && $orderby != 'random') {
$counts = array_reverse($counts);
}
$output = array();
foreach ((array) $counts as $term_name => $count) {
if (! is_object($terms_data[ $term_name ])) {
continue;
}
$output[] = $terms_data[ $term_name ];
}
return $output;
}
/**
* Check if taxonomy exist and return it, otherwise return default post tags.
*
* @param string|array $taxonomies
* @param boolean $force_single
*
* @return array|string
* @author WebFactory Ltd
*/
public static function _get_current_taxonomy($taxonomies, $force_single = false)
{
if (is_array($taxonomies)) {
foreach ($taxonomies as $key => $value) {
if (! taxonomy_exists($value)) { // Remove from array is taxonomy not exist !
unset($taxonomies[ $key ]);
} elseif (true === $force_single) {// Force single instead array ?
return $value;
}
}
return $taxonomies;
} elseif (taxonomy_exists($taxonomies)) {
return $taxonomies;
}
return 'post_tag';
}
/**
* Extended get_tags public static function that use getTerms function
*
* @param string|array $args
* @param string|array $taxonomy
*
* @return array
*/
public static function getTags($args = '', $taxonomy = 'post_tag', $post_type = '')
{
$key = md5(maybe_serialize($args) . $taxonomy . (isset($args['parent_term']) ? $args['parent_term'] : '') . (isset($args['display_mode']) ? $args['display_mode'] : ''));
// Get cache if exist
if ($cache = wp_cache_get('st_get_tags', 'simple-tags')) {
if (isset($cache[ $key ])) {
return apply_filters('get_tags', $cache[ $key ], $args);
}
}
// Get tags
if (isset($args['taxonomy'])) {
$taxonomy = $args['taxonomy'];
}
if (isset($args['parent_term'])) {
$parent_term = $args['parent_term'];
}
if (isset($args['display_mode'])) {
$display_mode = $args['display_mode'];
}
if (isset($args['max'])) {
$max_terms = intval($args['max']);
} else {
$max_terms = 20;
}
if (isset($args['hide_terms'])) {
$hide_terms = $args['hide_terms'];
}
$term_args = [
'taxonomy' => $taxonomy,
'hide_empty' => false,
'number' => $max_terms,
];
// exclude hidden terms from being queried for display at all
if ($hide_terms && SimpleTags_Plugin::get_option_value('enable_hidden_terms')) {
$hidden_terms = get_transient('taxopress_hidden_terms_' . $taxonomy);
if (!empty($hidden_terms) && is_array($hidden_terms)) {
$term_args['exclude'] = $hidden_terms;
}
}
$is_hierarchical = is_taxonomy_hierarchical($taxonomy);
if ($is_hierarchical && isset($args['parent_term'])) {
$parent_term = $args['parent_term'];
$display_mode = isset($args['display_mode']) ? $args['display_mode'] : '';
if ($parent_term === 'all') {
if ($display_mode === 'parents_only') {
$term_args['parent'] = 0;
} elseif ($display_mode === 'sub_terms_only') {
// Get all parent terms
$parent_terms = get_terms([
'taxonomy' => $taxonomy,
'parent' => 0,
'hide_empty' => false
]);
$parent_ids = wp_list_pluck($parent_terms, 'term_id');
if (!empty($parent_ids)) {
$sub_terms = [];
foreach ($parent_ids as $parent_id) {
$terms = get_terms([
'taxonomy' => $taxonomy,
'parent' => $parent_id,
'hide_empty' => false,
'number' => $max_terms
]);
$sub_terms = array_merge($sub_terms, $terms);
if (count($sub_terms) >= $max_terms) {
break;
}
}
$term_args['include'] = wp_list_pluck($sub_terms, 'term_id');
} else {
$term_args['parent'] = -1;
}
}
} else {
// Specific parent term selected
if ($display_mode === 'parents_only') {
$term_args['include'] = [$parent_term];
} elseif ($display_mode === 'sub_terms_only') {
$term_args['parent'] = $parent_term;
} else {
// Both parent and sub-terms
$parent_terms = get_terms([
'taxonomy' => $taxonomy,
'include' => [$parent_term],
'hide_empty' => false
]);
$sub_terms = get_terms([
'taxonomy' => $taxonomy,
'parent' => $parent_term,
'hide_empty' => false,
'number' => $max_terms
]);
$all_terms = array_merge($parent_terms, $sub_terms);
$term_args['include'] = wp_list_pluck(array_slice($all_terms, 0, $max_terms), 'term_id');
}
}
}
// Ensure `max_terms` is always applied
if (!empty($term_args['include'])) {
$term_args['include'] = array_slice($term_args['include'], 0, $max_terms);
}
if (isset($args['orderby'])) {
$term_args['orderby'] = $args['orderby'];
}
if (isset($args['order'])) {
$term_args['order'] = $args['order'];
}
if (!empty($args['limit_days'])) {
$recent_posts_args = [
'post_type' => $post_type ?: 'any',
'post_status' => 'publish',
'date_query' => [
[
'after' => $args['limit_days'] . ' days ago',
'inclusive' => false,
],
],
'fields' => 'ids',
'posts_per_page' => 100,
];
$recent_posts = [];
$page = 1;
do {
$recent_posts_args['paged'] = $page;
$recent_posts_batch = get_posts($recent_posts_args);
$recent_posts = array_merge($recent_posts, $recent_posts_batch);
$page++;
} while (count($recent_posts_batch) === $recent_posts_args['posts_per_page']);
if (!empty($recent_posts)) {
$terms = get_terms([
'taxonomy' => $taxonomy,
'object_ids' => $recent_posts,
'hide_empty' => false,
'number' => $max_terms,
]);
} else {
$terms = [];
}
} else {
$terms = get_terms($term_args);
}
if (isset($args['orderby']) && strtolower($args['orderby']) === 'random' && is_array($terms)) {
shuffle($terms);
if (isset($args['order']) && strtolower($args['order']) === 'desc') {
$terms = array_reverse($terms);
}
}
if (empty($terms)) {
return [];
}
if ($hide_terms && SimpleTags_Plugin::get_option_value('enable_hidden_terms')) {
$hidden_terms = get_transient('taxopress_hidden_terms_' . $taxonomy);
if (!empty($hidden_terms) && is_array($hidden_terms)) {
$hidden_terms = array_flip($hidden_terms);
$terms = array_filter($terms, function ($term) use ($hidden_terms) {
return !isset($hidden_terms[$term->term_id]);
});
}
}
// Cache the result
$cache = [];
$cache[$key] = $terms;
wp_cache_set('st_get_tags', $cache, 'simple-tags');
$terms = apply_filters('st_get_tags', $terms, $args);
return $terms;
}
/**
* Helper public static function for keep compatibility with old options TaxoPress widgets
*
* @param string $old_value
* @param string $key
*
* @return string
* @author WebFactory Ltd
*/
public static function compatOldOrder($old_value = '', $key = '')
{
$return = array();
switch (strtolower($old_value)) { // count-asc/count-desc/name-asc/name-desc/random
case 'count-asc':
$return = array( 'orderby' => 'count', 'order' => 'ASC' );
break;
case 'rand':
case 'random':
$return = array( 'orderby' => 'random', 'order' => '' );
break;
case 'name-asc':
$return = array( 'orderby' => 'name', 'order' => 'ASC' );
break;
case 'name-desc':
$return = array( 'orderby' => 'name', 'order' => 'DESC' );
break;
case 'count-desc':
$return = array( 'orderby' => 'count', 'order' => 'DESC' );
break;
}
if (empty($return) || ! isset($return[ $key ])) {
return $old_value;
}
return $return[ $key ];
}
/**
* Extended get_terms public static function support
* - Limit category
* - Limit days
* - Selection restrict
* - Min usage
*
* @param string|array $taxonomies
* @param string $args
*
* @return array|WP_Error
*/
public static function getTerms($taxonomies, $args = '')
{
global $wpdb;
$empty_array = array();
$join_relation = false;
$single_taxonomy = false;
if (! is_array($taxonomies)) {
$single_taxonomy = true;
$taxonomies = array( $taxonomies );
}
foreach ((array) $taxonomies as $taxonomy) {
if (! taxonomy_exists($taxonomy)) {
$error = new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
return $error;
}
}
$in_taxonomies = "'" . implode("', '", $taxonomies) . "'";
$defaults = array(
'orderby' => 'name',
'order' => 'ASC',
'hide_empty' => true,
'exclude' => array(),
'exclude_tree' => array(),
'include' => array(),
'number' => '',
'fields' => 'all',
'slug' => '',
'parent' => '',
'hierarchical' => true,
'child_of' => 0,
'get' => '',
'name__like' => '',
'pad_counts' => false,
'offset' => '',
'search' => '',
// TaxoPress added
'limit_days' => 0,
'category' => 0,
'min_usage' => 0,
'st_name__like' => '',
'post_type' => false
);
$args = wp_parse_args($args, $defaults);
// Translate selection order
$args['orderby'] = self::compatOldOrder($args['selectionby'], 'orderby');
$args['order'] = self::compatOldOrder($args['selection'], 'order');
$args['number'] = absint($args['number']);
$args['offset'] = absint($args['offset']);
$args['limit_days'] = absint($args['limit_days']);
$args['min_usage'] = absint($args['min_usage']);
if (
! $single_taxonomy || ! is_taxonomy_hierarchical($taxonomies[0]) ||
'' !== $args['parent']
) {
$args['child_of'] = 0;
$args['hierarchical'] = false;
$args['pad_counts'] = false;
}
if ('all' == $args['get']) {
$args['child_of'] = 0;
$args['hide_empty'] = 0;
$args['hierarchical'] = false;
$args['pad_counts'] = false;
}
extract($args, EXTR_SKIP);
if ($child_of) {
$hierarchy = _get_term_hierarchy($taxonomies[0]);
if (! isset($hierarchy[ $child_of ])) {
return $empty_array;
}
}
if ($parent) {
$hierarchy = _get_term_hierarchy($taxonomies[0]);
if (! isset($hierarchy[ $parent ])) {
return $empty_array;
}
}
// $args can be whatever, only use the args defined in defaults to compute the key
$filter_key = (has_filter('list_terms_exclusions')) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
$key = md5(serialize(compact(array_keys($defaults))) . serialize($taxonomies) . $filter_key);
$last_changed = wp_cache_get('last_changed', 's-terms');
if (! $last_changed) {
$last_changed = time();
wp_cache_set('last_changed', $last_changed, 's-terms');
}
$cache_key = "get_terms:$key:$last_changed";
$cache = wp_cache_get($cache_key, 's-terms');
if (false !== $cache) {
$cache = apply_filters('get_terms', $cache, $taxonomies, $args);
return $cache;
}
$_orderby = strtolower($orderby);
if ('count' == $_orderby) {
$orderby = 'tt.count';
}
if ('random' == $_orderby) {
$orderby = 'RAND()';
} elseif ('name' == $_orderby) {
$orderby = 't.name';
} elseif ('slug' == $_orderby) {
$orderby = 't.slug';
} elseif ('term_group' == $_orderby) {
$orderby = 't.term_group';
} elseif (empty($_orderby) || 'id' == $_orderby) {
$orderby = 't.term_id';
}
$orderby = apply_filters('get_terms_orderby', $orderby, $args);
if (! empty($orderby)) {
$orderby = "ORDER BY $orderby";
} else {
$order = '';
}
$where = '';
$inclusions = '';
if (! empty($include)) {
$exclude = '';
$exclude_tree = '';
$interms = wp_parse_id_list($include);
foreach ($interms as $interm) {
if (empty($inclusions)) {
$inclusions = ' AND ( t.term_id = ' . intval($interm) . ' ';
} else {
$inclusions .= ' OR t.term_id = ' . intval($interm) . ' ';
}
}
}
if (! empty($inclusions)) {
$inclusions .= ')';
}
$where .= $inclusions;
$exclusions = '';
$excluded_terms = array(); // Collect all terms to exclude
if (! empty($exclude_tree)) {
$excluded_trunks = wp_parse_id_list($exclude_tree);
foreach ($excluded_trunks as $extrunk) {
$excluded_children = (array) get_terms(array(
'taxonomy' => $taxonomies[0],
'child_of' => intval($extrunk),
'fields' => 'ids',
));
$excluded_children[] = $extrunk;
foreach ($excluded_children as $exterm) {
if (empty($exclusions)) {
$exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
} else {
$exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
}
}
// Also collect terms for batch exclusion
$excluded_terms = array_merge($excluded_terms, $excluded_children);
}
}
if (! empty($exclude)) {
$exterms = wp_parse_id_list($exclude);
foreach ($exterms as $exterm) {
if (empty($exclusions)) {
$exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
} else {
$exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
}
}
// Also collect terms for batch exclusion
$excluded_terms = array_merge($excluded_terms, $exterms);
}
// Batch exclusion logic with 'NOT IN'
$excluded_terms = array_unique($excluded_terms);
if (! empty($excluded_terms)) {
$excluded_terms_sql = implode(',', array_map('intval', $excluded_terms));
// Batch exclusion will be combined with original exclusion logic
$exclusions .= " AND t.term_id NOT IN ($excluded_terms_sql)";
}
if (! empty($exclusions)) {
$exclusions .= ')';
}
$exclusions = apply_filters('list_terms_exclusions', $exclusions, $args);
$where .= $exclusions;
// ST Features : Restrict category
if (!empty($category)) {
if (! is_array($taxonomies)) {
$taxonomies = array( $taxonomies );
}
$incategories = wp_parse_id_list($category);
$taxonomies = "'" . implode("', '", $taxonomies) . "'";
$incategories = "'" . implode("', '", $incategories) . "'";
$where .= " AND tr.object_id IN ( ";
$where .= "SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN $wpdb->posts as p ON tr.object_id=p.ID WHERE tt.term_id IN ($incategories) AND p.post_status='publish'";
$where .= " ) ";
$join_relation = true;
unset($incategories, $category);
}
// ST Features : Limit posts date
if ((int)$limit_days > 0) {
if ($post_type) {
$post_type = "AND post_type = '$post_type'";
} else {
$post_type = '';
}
$where .= " AND tr.object_id IN ( ";
$where .= "SELECT DISTINCT ID FROM $wpdb->posts AS p WHERE p.post_date_gmt > '" . gmdate('Y-m-d H:i:s', time() - $limit_days * 86400) . "' $post_type";
$where .= " ) ";
$join_relation = true;
unset($limit_days);
} else {
if ($post_type) {
$where .= " AND tr.object_id IN ( ";
$where .= "SELECT DISTINCT ID FROM $wpdb->posts AS p WHERE post_type = '$post_type'";
$where .= " ) ";
$join_relation = true;
}
}
if (! empty($slug)) {
$slug = sanitize_title($slug);
$where .= " AND t.slug = '$slug'";
}
if (! empty($name__like)) {
$where .= " AND t.name LIKE '{$name__like}%'";
}
if ('' !== $parent) {
$parent = (int) $parent;
$where .= " AND tt.parent = '$parent'";
}
// ST Features : Another way to search
if (strpos($st_name__like, ' ') !== false) {
$st_terms_formatted = array();
$st_terms = preg_split('/[\s,]+/', $st_name_like);
foreach ((array) $st_terms as $st_term) {
if (empty($st_term)) {
continue;
}
$st_terms_formatted[] = "t.name LIKE '%" . $wpdb->esc_like($st_term) . "%'";
}
$where .= " AND ( " . explode(' OR ', $st_terms_formatted) . " ) ";
unset($st_term, $st_terms_formatted, $st_terms);
} elseif (! empty($st_name__like)) {
$where .= " AND t.name LIKE '%{$st_name__like}%'";
}
if (in_array($taxonomies[0], ['post_tag', 'category'])) {
//TODO - count not working for attachment and/or CPT ?
// ST Features : Add min usage
if ($hide_empty && ! $hierarchical) {
if ($min_usage == 0) {
$where .= ' AND tt.count > 0';
} else {
$where .= $wpdb->prepare(' AND tt.count >= %d', $min_usage);
}
}
}
if (! empty($search)) {
$search = $wpdb->esc_like($search);
$where .= " AND (t.name LIKE '%$search%')";
}
$selects = array();
switch ($fields) {
case 'all':
$selects = array( 't.*', 'tt.*' );
break;
case 'ids':
case 'id=>parent':
$selects = array( 't.term_id', 'tt.parent', 'tt.count' );
break;
case 'names':
$selects = array( 't.term_id', 'tt.parent', 'tt.count', 't.name' );
break;
case 'count':
$orderby = '';
$order = '';
$selects = array( 'COUNT(*)' );
}
$select_this = implode(', ', apply_filters('get_terms_fields', $selects, $args));
// Add inner to relation table ?
$join_relation = $join_relation == false ? '' : "INNER JOIN $wpdb->term_relationships AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id";
// Query parts are individually escaped above, $taxonomies are individually checked if they exists
// don't limit the query results when we have to descend the family tree
if (! empty($number) && ! $hierarchical && empty($child_of) && '' == $parent) {
if ($offset) {
$query = $wpdb->prepare(
"SELECT DISTINCT $select_this
FROM $wpdb->terms AS t
INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
$join_relation
WHERE 1 = %d AND tt.taxonomy IN ($in_taxonomies)
$where
$orderby $order
LIMIT %d, %d",
1,
$offset,
$number
);
} else {
$query = $wpdb->prepare(
"SELECT DISTINCT $select_this
FROM $wpdb->terms AS t
INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
$join_relation
WHERE 1 = %d AND tt.taxonomy IN ($in_taxonomies)
$where
$orderby $order
LIMIT %d",
1,
$number
);
}
} else {
$query = $wpdb->prepare(
"SELECT DISTINCT $select_this
FROM $wpdb->terms AS t
INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
$join_relation
WHERE 1 = %d AND tt.taxonomy IN ($in_taxonomies)
$where
$orderby $order",
1
);
}
// GROUP BY t.term_id
if ('count' == $fields) {
$term_count = $wpdb->get_var($query);
return $term_count;
}
$terms = $wpdb->get_results($query);
if ('all' == $fields) {
update_term_cache($terms);
}
if (empty($terms)) {
wp_cache_add($cache_key, array(), 's-terms');
$terms = apply_filters('get_terms', array(), $taxonomies, $args);
return $terms;
}
if ($child_of) {
$children = _get_term_hierarchy($taxonomies[0]);
if (! empty($children)) {
$terms = &_get_term_children($child_of, $terms, $taxonomies[0]);
}
}
// Update term counts to include children.
if ($pad_counts && 'all' == $fields) {
_pad_term_counts($terms, $taxonomies[0]);
}
// Make sure we show empty categories that have children.
if ($hierarchical && $hide_empty && is_array($terms)) {
foreach ($terms as $k => $term) {
if (! $term->count) {
$children = _get_term_children($term->term_id, $terms, $taxonomies[0]);
if (is_array($children)) {
foreach ($children as $child) {
if ($child->count) {
continue 2;
}
}
}
// It really is empty
unset($terms[ $k ]);
}
}
}
reset($terms);
$_terms = array();
if ('id=>parent' == $fields) {
while ($term = array_shift($terms)) {
$_terms[ $term->term_id ] = $term->parent;
}
$terms = $_terms;
} elseif ('ids' == $fields) {
while ($term = array_shift($terms)) {
$_terms[] = $term->term_id;
}
$terms = $_terms;
} elseif ('names' == $fields) {
while ($term = array_shift($terms)) {
$_terms[] = $term->name;
}
$terms = $_terms;
}
if (0 < $number && intval(@count($terms)) > $number) {
$terms = array_slice($terms, $offset, $number);
}
wp_cache_add($cache_key, $terms, 's-terms');
$terms = apply_filters('get_terms', $terms, $taxonomies, $args);
return $terms;
}
}