';
}
$active_tab_slug = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'add-terms';
// Default order
if (! isset($_GET['order'])) {
$_GET['order'] = 'name-asc';
}
settings_errors(__CLASS__); ?>
$taxonomy,
'name' => sanitize_text_field($term_name),
'hide_empty' => false,
]);
if (is_array($term_objects) && count($term_objects) > 1) {
$terms = array_merge($terms, $term_objects);
}
}
if (empty($terms)) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No terms with the same name found.', 'simple-tags'), 'error taxopress-notice');
return false;
}
usort($terms, function ($a, $b) use ($term_name, $retained_slug_param) {
// If a retained slug is provided, sort that term to the top
if ($retained_slug_param) {
if ($a->slug === $retained_slug_param) return -1;
if ($b->slug === $retained_slug_param) return 1;
}
// Score based on similarity to term name
similar_text($term_name, $a->slug, $similarity_a);
similar_text($term_name, $b->slug, $similarity_b);
if ($similarity_a === $similarity_b) {
// If similarity is the same, sort by length (shortest first)
return strlen($a->slug) - strlen($b->slug);
}
// Otherwise, sort by similarity (higher first)
return $similarity_b - $similarity_a;
});
// Retain the term with the highest similarity and shortest slug (first in sorted array)
$retained_term = $terms[0];
$retained_slug = $retained_term->slug;
$retained_id = $retained_term->term_id;
// Collect terms to delete
$terms_to_delete = array_filter($terms, function ($term) use ($retained_id) {
return $term->term_id !== $retained_id;
});
// Reassign objects and delete old terms (existing logic)
$terms_id = array_map(function ($term) {
return $term->term_id;
}, $terms_to_delete);
$objects_id = get_objects_in_term($terms_id, $taxonomy, ['fields' => 'ids']);
foreach ($objects_id as $object_id) {
// Check if the object already has the term assigned
$current_terms = wp_get_object_terms($object_id, $taxonomy, ['fields' => 'ids']);
if (!in_array($retained_id, $current_terms)) {
wp_set_object_terms($object_id, $retained_slug, $taxonomy, true);
}
}
foreach ($terms_to_delete as $term) {
wp_delete_term($term->term_id, $taxonomy);
}
// Clean caches
clean_object_term_cache($objects_id, $taxonomy);
clean_term_cache($terms_id, $taxonomy);
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Merged term(s) with the same name "%s". %d posts updated.', 'simple-tags'), $retained_term->name, count($objects_id)), 'updated taxopress-notice');
return [
'success' => true,
'retained_slug' => $retained_slug,
'posts_updated' => count($objects_id),
'post_ids' => $objects_id,
'terms_merged' => count($terms_to_delete) + 1,
];
} else {
if (trim(str_replace(',', '', stripslashes($new))) == '' && $merge_type !== 'same_name' ) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No new term specified!', 'simple-tags'), 'error taxopress-notice');
return false;
}
// String to array
$old_terms = explode(',', $old);
$new_terms = explode(',', $new);
$old_terms = array_map($extractTermName, $old_terms);
$new_terms = array_map($extractTermName, $new_terms);
// Remove empty element and trim
$old_terms = array_filter($old_terms, '_delete_empty_element');
$new_terms = array_filter($new_terms, '_delete_empty_element');
$common_elements = array_intersect($old_terms, $new_terms);
// If old/new tag are empty => exit !
if (empty($old_terms) || empty($new_terms)) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No new/old valid term specified!', 'simple-tags'), 'error taxopress-notice');
return false;
}
if (!empty($common_elements) && $merge_type !== 'different_name') {
add_settings_error(__CLASS__, __CLASS__, esc_html__('Term to merge and New Term must not contain same term.', 'simple-tags'), 'error taxopress-notice');
return false;
}
$counter = 0;
if (count($new_terms) == 1) { // Merge
// Set new tag
$new_tag = sanitize_text_field($new_terms[0]);
if (empty($new_tag)) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No valid new term.', 'simple-tags'), 'error taxopress-notice');
return false;
}
// Ensure the new term exists or create it
$new_term = get_term_by('name', $new_tag, $taxonomy);
if (!$new_term) {
$new_term_info = wp_insert_term($new_tag, $taxonomy);
if (is_wp_error($new_term_info)) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('Failed to create the new term.', 'simple-tags'), 'error taxopress-notice');
return false;
}
$new_term_id = $new_term_info['term_id'];
$new_term_slug = isset($new_term_info['slug']) ? $new_term_info['slug'] : sanitize_title($new_tag);
} else {
$new_term_id = $new_term->term_id;
$new_term_slug = $new_term->slug;
}
// Get terms ID from old terms names
$terms_id = array();
$found_terms = array();
foreach ((array) $old_terms as $old_tag) {
$term = get_term_by('name', addslashes(sanitize_text_field($old_tag)), $taxonomy);
if ($term) {
$terms_id[] = (int) $term->term_id;
$found_terms[] = $term->name;
}
}
if (empty($terms_id)) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No matching terms found to merge.', 'simple-tags'), 'error taxopress-notice');
return false;
}
// Get objects from terms ID
$objects_id = get_objects_in_term($terms_id, $taxonomy, ['fields' => 'ids']);
// Use a set to track unique post IDs
$unique_objects = [];
// Assign the new term to all posts associated with the old terms
foreach ((array) $objects_id as $object_id) {
// Check if the object already has the term assigned
$current_terms = wp_get_object_terms($object_id, $taxonomy, ['fields' => 'ids']);
if (!in_array($new_term_id, $current_terms)) {
wp_set_object_terms($object_id, $new_term_slug, $taxonomy, true);
}
$unique_objects[$object_id] = true; // Add to unique set
}
// Count unique posts
$counter = count($unique_objects);
// Delete old terms
foreach ((array) $terms_id as $term_id) {
wp_delete_term($term_id, $taxonomy);
}
// Test if term is also a category
/*
if ( is_term($new_tag, 'category') ) {
// Edit the slug to use the new term
self::editTermSlug( $new_tag, sanitize_title($new_tag) );
}
*/
// Clean cache
clean_object_term_cache($objects_id, $taxonomy);
clean_term_cache($terms_id, $taxonomy);
if (empty($found_terms)) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No terms were merged (terms may not exist).', 'simple-tags'), 'error taxopress-notice');
} else {
$message = sprintf(
esc_html__('Successfully merged %1$d term(s) "%2$s" to "%3$s". %4$s posts updated.', 'simple-tags'),
count($found_terms),
implode(', ', $found_terms),
rtrim($new, ','),
$counter
);
add_settings_error(__CLASS__, __CLASS__, $message, 'updated taxopress-notice');
}
} else { // Error
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Error. You need to enter a single term to merge to in new term name !', 'simple-tags'), $old), 'error taxopress-notice');
}
return [
'success' => true,
'merged_into' => $new_tag,
'posts_updated' => $counter,
'post_ids' => array_keys($unique_objects),
'terms_merged' => count($terms_id) + 1,
];
}
}
/**
* Find terms with same names but different slugs
*/
public static function getSameNameMergeSuggestions($taxonomy = 'post_tag') {
global $wpdb;
$query = $wpdb->prepare("
SELECT t.name, COUNT(*) as count, GROUP_CONCAT(CONCAT(t.name, ' (', t.slug, ')') SEPARATOR ', ') as terms
FROM {$wpdb->terms} t
INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
WHERE tt.taxonomy = %s
GROUP BY t.name
HAVING COUNT(*) > 1
ORDER BY count DESC, t.name ASC
", $taxonomy);
$results = $wpdb->get_results($query);
$show_slug = (int) SimpleTags_Plugin::get_option_value('enable_merge_terms_slug');
if (!$show_slug) {
foreach ($results as &$result) {
$result->terms = preg_replace('/\s*\([^)]+\)/', '', $result->terms);
}
}
return $results;
}
/**
* Find terms that might be candidates for merging based on similarity
*/
public static function getDifferentNameMergeSuggestions($taxonomy = 'post_tag', $limit = 50) {
global $wpdb;
$terms = get_terms([
'taxonomy' => $taxonomy,
'hide_empty' => false,
'number' => $limit * 2,
]);
$show_slug = (int) SimpleTags_Plugin::get_option_value('enable_merge_terms_slug');
$suggestions = [];
foreach ($terms as $i => $term1) {
foreach ($terms as $j => $term2) {
if ($i >= $j) continue;
$similarity_score = 0;
$reasons = [];
// 1. Levenshtein distance (for typos)
$levenshtein = levenshtein(strtolower($term1->name), strtolower($term2->name));
if ($levenshtein <= 2 && $levenshtein > 0) {
$similarity_score += 40;
$reasons[] = esc_html__('Similar spelling', 'simple-tags');
}
// 2. Soundex (phonetic similarity)
if (soundex($term1->name) === soundex($term2->name)) {
$similarity_score += 30;
$reasons[] = esc_html__('Sounds similar', 'simple-tags');
}
// 3. Common words/partial matches
$words1 = explode(' ', strtolower($term1->name));
$words2 = explode(' ', strtolower($term2->name));
$common_words = array_intersect($words1, $words2);
if (!empty($common_words)) {
$similarity_score += count($common_words) * 15;
$reasons[] = sprintf(esc_html__('Shared words: %s', 'simple-tags'), implode(', ', $common_words));
}
// 4. Prefix/suffix similarity
if (strpos($term1->name, $term2->name) !== false || strpos($term2->name, $term1->name) !== false) {
$similarity_score += 25;
$reasons[] = esc_html__('One contains the other', 'simple-tags');
}
if ($similarity_score >= 30) {
$suggested_name = '';
// Get clean term names for comparison
$term1_clean = strtolower(trim($term1->name));
$term2_clean = strtolower(trim($term2->name));
if (!empty($common_words)) {
$suggested_name = ucfirst(implode(' ', $common_words));
} else {
// Use the shorter term as base
$suggested_name = strlen($term1->name) <= strlen($term2->name) ? $term1->name : $term2->name;
}
// let's make sure suggested name is different from both original terms
$suggested_clean = strtolower(trim($suggested_name));
if ($suggested_clean === $term1_clean || $suggested_clean === $term2_clean) {
if (!empty($common_words)) {
$suggested_name = ucfirst($common_words[0]);
} else {
$popular_term = ($term1->count >= $term2->count) ? $term1 : $term2;
$suggested_name = $popular_term->name;
}
$suggested_clean = strtolower(trim($suggested_name));
}
$term1_display = $show_slug ? $term1->name . ' (' . $term1->slug . ')' : $term1->name;
$term2_display = $show_slug ? $term2->name . ' (' . $term2->slug . ')' : $term2->name;
$suggestions[] = [
'term1' => $term1_display,
'term2' => $term2_display,
'score' => $similarity_score,
'reasons' => implode(', ', $reasons),
'suggested_name' => $suggested_name
];
}
}
}
usort($suggestions, function($a, $b) {
return $b['score'] - $a['score'];
});
return array_slice($suggestions, 0, $limit);
}
/**
* AJAX handler for merge suggestions
*/
public function handle_taxopress_merge_suggestions() {
if (!current_user_can('simple_tags')) {
wp_send_json_error('Permission denied');
}
if (!wp_verify_nonce($_POST['nonce'], 'simpletags_admin')) {
wp_send_json_error('Invalid nonce');
}
$taxonomy = get_option('merge-terms_taxo', 'post_tag');
$merge_type = sanitize_text_field($_POST['merge_type']);
if ($merge_type === 'same_name') {
$suggestions = self::getSameNameMergeSuggestions($taxonomy);
wp_send_json_success([
'type' => 'same_name',
'suggestions' => $suggestions
]);
} else {
$suggestions = self::getDifferentNameMergeSuggestions($taxonomy);
wp_send_json_success([
'type' => 'different_name',
'suggestions' => $suggestions
]);
}
}
public static function taxopress_merge_terms_batch() {
$nonce = isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '';
if (empty($nonce) || !wp_verify_nonce($nonce, 'st-admin-js')) {
wp_send_json_error(['message' => __('Security check failed.', 'simple-tags')], 403);
wp_die();
}
if (!current_user_can('simple_tags')) {
wp_send_json_error(['message' => __('Permission denied.', 'simple-tags')], 403);
wp_die();
}
$taxonomy = isset($_POST['taxonomy']) ? sanitize_text_field($_POST['taxonomy']) : '';
$new_term = isset($_POST['new_term']) ? sanitize_text_field($_POST['new_term']) : '';
$merge_type = isset($_POST['merge_type']) ? sanitize_text_field($_POST['merge_type']) : 'different_name';
$old_terms_input = isset($_POST['old_terms']) ? array_map('sanitize_text_field', (array) $_POST['old_terms']) : [];
$extractTermName = function ($term) {
return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
};
$old_terms = [];
foreach ($old_terms_input as $term_name) {
$term_name_clean = $extractTermName($term_name);
$term = get_term_by('name', $term_name_clean, $taxonomy);
if ($term && !is_wp_error($term)) {
$old_terms[] = $term_name_clean;
}
}
if (empty($old_terms)) {
wp_send_json_error([
'message' => __('Please enter a valid term. Merge cancelled.', 'simple-tags')
]);
wp_die();
}
if ($merge_type === 'different_name' && !empty($new_term)) {
$old_terms = array_values(array_filter($old_terms, function($term_name) use ($new_term) {
return strtolower(trim($term_name)) !== strtolower(trim($new_term));
}));
}
// Execute the merge
$result = SimpleTags_Admin_Manage::mergeTerms($taxonomy, implode(',', $old_terms), $new_term, $merge_type);
if ($result === true || (is_array($result) && !empty($result['success']))) {
$response = ['message' => __('Merge successful', 'simple-tags')];
if (is_array($result)) {
$response = array_merge($response, $result);
}
wp_send_json_success($response);
} else {
global $wp_settings_errors;
$errors = [];
if (!empty($wp_settings_errors)) {
foreach ($wp_settings_errors as $error) {
if (!empty($error['message'])) {
$errors[] = $error['message'];
}
}
}
if (is_wp_error($result)) {
$errors[] = $result->get_error_message();
} elseif (is_array($result) && isset($result['message'])) {
$errors[] = $result['message'];
}
wp_send_json_error(['message' => implode(' ', $errors)]);
}
wp_die();
}
/**
* Method for remove tags
*
* @param string $taxonomy
* @param string $post_type
* @param string $tag
*
* @return boolean
* @author WebFactory Ltd
*/
public static function removeTerms($taxonomy = 'post_tag', $post_type = 'posts', $new = '')
{
if (trim(str_replace(',', '', stripslashes($new))) == '') {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No term specified!', 'simple-tags'), 'error taxopress-notice');
return false;
}
// String to array
$new_terms = explode(',', $new);
// Remove empty element and trim
$new_terms = array_filter($new_terms, '_delete_empty_element');
// If new tag are empty => exit !
if (empty($new_terms)) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No valid term specified!', 'simple-tags'), 'error taxopress-notice');
return false;
}
$counter = 0;
if (count($new_terms) > 0) {
foreach ((array) $new_terms as $term) {
$term = get_term_by('name', sanitize_text_field($term), $taxonomy);
if (empty($term) || !is_object($term)) {
continue;
}
$term = $term->term_id;
$args = array(
'post_type' => $post_type, // post_type
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => $taxonomy,
'field' => 'id',
'terms' => $term
)
)
);
$posts = get_posts($args);
foreach ($posts as $post) {
$remove = wp_remove_object_terms($post->ID, $term, $taxonomy);
if ($remove) {
clean_object_term_cache($post->ID, $taxonomy);
clean_term_cache($term, $taxonomy);
$counter ++;
}
}
}
if ($counter == 0) {
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('This term is not associated with any %1$s.', 'simple-tags'), SimpleTags_Admin::$post_type_name), 'error taxopress-notice');
} else {
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Removed term(s) "%1$s" from %2$s %3$s', 'simple-tags'), $new, $counter, SimpleTags_Admin::$post_type_name), 'updated taxopress-notice');
}
} else { // Error
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Error. No enough terms specified.', 'simple-tags'), $old), 'error taxopress-notice');
}
return true;
}
/**
* Method for rename tags
*
* @param string $taxonomy
* @param string $old
* @param string $new
*
* @return boolean
* @author WebFactory Ltd
*/
public static function renameTerms($taxonomy = 'post_tag', $old = '', $new = '')
{
// Helper function to extract term name (ignoring slug in brackets)
$extractTermName = function ($term) {
return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
};
if (trim(str_replace(',', '', stripslashes($new))) == '') {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No new term specified!', 'simple-tags'), 'error taxopress-notice');
return false;
}
// String to array
$old_terms = explode(',', $old);
$new_terms = explode(',', $new);
// Clean up terms by removing slugs
$old_terms = array_map($extractTermName, $old_terms);
$new_terms = array_map($extractTermName, $new_terms);
// Remove empty element and trim
$old_terms = array_filter($old_terms, '_delete_empty_element');
$new_terms = array_filter($new_terms, '_delete_empty_element');
// If old/new tag are empty => exit !
if (empty($old_terms) || empty($new_terms)) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No new/old valid term specified!', 'simple-tags'), 'error taxopress-notice');
return false;
}
$counter = 0;
if (count($old_terms) === count($new_terms)) { // Rename only
foreach ((array) $old_terms as $i => $old_tag) {
$new_name = sanitize_text_field($new_terms[ $i ]);
// Get term by name
$term = get_term_by('name', sanitize_text_field($old_tag), $taxonomy);
if (! $term) {
continue;
}
// Get objects from term ID
$objects_id = get_objects_in_term($term->term_id, $taxonomy, array( 'fields' => 'all_with_object_id' ));
// Create the new term
if (! $term_info = term_exists($new_name, $taxonomy)) {
$term_info = wp_insert_term($new_name, $taxonomy);
}
// If default category, update the ID for new term...
if ('category' == $taxonomy && $term->term_id == get_option('default_category')) {
update_option('default_category', $term_info['term_id']);
clean_term_cache($term_info['term_id'], $taxonomy);
}
// Delete old term
wp_delete_term($term->term_id, $taxonomy);
// Set objects to new term ! (Append no replace)
foreach ((array) $objects_id as $object_id) {
wp_set_object_terms($object_id, $new_name, $taxonomy, true);
}
// Clean cache
clean_object_term_cache($objects_id, $taxonomy);
clean_term_cache($term->term_id, $taxonomy);
// Increment
$counter ++;
}
if ($counter == 0) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No term renamed.', 'simple-tags'), 'updated taxopress-notice');
} else {
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Renamed term(s) "%1$s" to "%2$s"', 'simple-tags'), rtrim($old, ','), rtrim($new, ',')), 'updated taxopress-notice');
}
} else { // Error
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Error. No enough terms for rename.', 'simple-tags'), $old), 'error taxopress-notice');
}
return true;
}
/**
* Method for delete a list of terms
*
* @param string $taxonomy
* @param string $delete
*
* @return boolean
* @author WebFactory Ltd
*/
public static function deleteTermsByTermList($taxonomy = 'post_tag', $delete = '')
{
if (trim(str_replace(',', '', stripslashes($delete))) == '') {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No term specified!', 'simple-tags'), 'error taxopress-notice');
return false;
}
// In array + filter
$delete_terms = explode(',', $delete);
$delete_terms = array_filter($delete_terms, '_delete_empty_element');
// Delete tags
$counter = 0;
foreach ((array) $delete_terms as $term) {
$term = get_term_by('name', sanitize_text_field($term), $taxonomy);
$term_id = (int) $term->term_id;
if ($term_id != 0) {
wp_delete_term($term_id, $taxonomy);
clean_term_cache($term_id, $taxonomy);
$counter ++;
}
}
if ($counter == 0) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No term deleted.', 'simple-tags'), 'updated taxopress-notice');
} else {
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('%1s term(s) deleted.', 'simple-tags'), $counter), 'updated taxopress-notice');
}
return true;
}
/**
* Method for add terms for all or specified posts
*
* @param string $taxonomy
* @param string $match
* @param string $new
*
* @return boolean
* @author WebFactory Ltd
*/
public static function addMatchTerms($taxonomy = 'post_tag', $match = '', $new = '')
{
// Helper function to extract term name (ignoring slug in brackets)
$extractTermName = function ($term) {
return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
};
if (trim(str_replace(',', '', stripslashes($new))) == '') {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No new term(s) specified!', 'simple-tags'), 'error taxopress-notice');
return false;
}
$match_terms = explode(',', $match);
$new_terms = explode(',', $new);
// Clean up terms by removing slugs
$match_terms = array_map($extractTermName, $match_terms);
$new_terms = array_map($extractTermName, $new_terms);
$match_terms = array_filter($match_terms, '_delete_empty_element');
$new_terms = array_filter($new_terms, '_delete_empty_element');
$counter = 0;
if (! empty($match_terms)) { // Match and add
// Get terms ID from old match names
$terms_id = array();
foreach ((array) $match_terms as $match_term) {
$term = get_term_by('name', sanitize_text_field($match_term), $taxonomy);
$terms_id[] = (int) $term->term_id;
}
// Get object ID with terms ID
$objects_id = get_objects_in_term($terms_id, $taxonomy, array( 'fields' => 'all_with_object_id' ));
// Add new tags for specified post
foreach ((array) $objects_id as $object_id) {
wp_set_object_terms($object_id, $new_terms, $taxonomy, true); // Append terms
$counter ++;
}
// Clean cache
clean_object_term_cache($objects_id, $taxonomy);
clean_term_cache($terms_id, $taxonomy);
} else { // Add for all posts
// Page or not ?
$post_type_sql = "(post_status = 'publish' OR post_status = 'inherit') AND post_type = '".SimpleTags_Admin::$post_type."'";
// Get all posts ID
global $wpdb;
$objects_id = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE {$post_type_sql}");
// Add new tags for all posts
foreach ((array) $objects_id as $object_id) {
wp_set_object_terms($object_id, $new_terms, $taxonomy, true); // Append terms
clean_object_term_cache($object_id, $taxonomy);
clean_term_cache($new_terms, $taxonomy);
$counter ++;
}
// Clean cache
clean_object_term_cache($objects_id, $taxonomy);
}
if ($counter == 0) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No term added.', 'simple-tags'), 'updated taxopress-notice');
} else {
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Term(s) added to %1s %2s.', 'simple-tags'), $counter, SimpleTags_Admin::$post_type_name), 'updated taxopress-notice');
}
return true;
}
/**
* Delete terms when counter if inferior to a specific number
*
* @param string $taxonomy
* @param integer $number
*
* @return boolean
* @author WebFactory Ltd
*/
public static function removeRarelyUsed($taxonomy = 'post_tag', $number = 0)
{
global $wpdb;
if ((int) $number > 100) {
wp_die('Tcheater ?');
}
// Get terms with counter inferior to...
$terms_id = $wpdb->get_col($wpdb->prepare("SELECT term_id FROM $wpdb->term_taxonomy WHERE taxonomy = %s AND count < %d", $taxonomy, (int) $number));
// Delete terms
$counter = 0;
foreach ((array) $terms_id as $term_id) {
if ($term_id != 0) {
wp_delete_term($term_id, $taxonomy);
clean_term_cache($term_id, $taxonomy);
$counter ++;
}
}
if ($counter == 0) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No term deleted.', 'simple-tags'), 'updated taxopress-notice');
} else {
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('%1s term(s) deleted.', 'simple-tags'), $counter), 'updated taxopress-notice');
}
return true;
}
function handle_taxopress_check_delete_terms_ajax() {
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'st-admin-js')) {
wp_send_json_error(array('message' => __('Nonce verification failed.', 'simple-tags')));
wp_die();
}
global $wpdb;
$taxonomy = isset($_POST['taxonomy']) ? sanitize_text_field($_POST['taxonomy']) : 'post_tag';
$number = isset($_POST['number']) ? intval($_POST['number']) : 0;
if ((int) $number > 100) {
wp_die('Tcheater ?');
}
if ($number > 0) {
$terms = $wpdb->get_col($wpdb->prepare("
SELECT term_id FROM $wpdb->term_taxonomy
WHERE taxonomy = %s AND count < %d",
$taxonomy, (int) $number));
$term_count = count($terms);
if ($term_count > 0) {
wp_send_json_success(array('message' => sprintf(__('%d terms will be deleted.', 'simple-tags'), $term_count)));
} else {
wp_send_json_error(array('message' => __('No terms will be deleted.', 'simple-tags')));
}
} else {
wp_send_json_error(array('message' => __('Invalid number specified.', 'simple-tags')));
}
wp_die();
}
/**
* Method for removing terms from all or specified posts
*
* @param string $taxonomy
* @param string $match
* @param string $remove
*
* @return boolean
* @author WebFactory Ltd
*/
public static function removeMatchTerms($taxonomy = 'post_tag', $match = '', $remove = '')
{
// Helper function to extract term name (ignoring slug in brackets)
$extractTermName = function ($term) {
return trim(preg_replace('/\s*\(.*?\)$/', '', $term));
};
if (trim(str_replace(',', '', stripslashes($remove))) == '') {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No term(s) specified for removal!', 'simple-tags'), 'error taxopress-notice');
return false;
}
$match_terms = explode(',', $match);
$remove_terms = explode(',', $remove);
// Clean up terms by removing slugs
$match_terms = array_map($extractTermName, $match_terms);
$remove_terms = array_map($extractTermName, $remove_terms);
$match_terms = array_filter($match_terms, '_delete_empty_element');
$remove_terms = array_filter($remove_terms, '_delete_empty_element');
// Arrays to track if terms entered is valid
$valid_remove_terms = array();
$invalid_remove_terms = array();
foreach ((array) $remove_terms as $remove_term) {
$term = get_term_by('name', sanitize_text_field($remove_term), $taxonomy);
if ($term) {
$valid_remove_terms[] = $remove_term; // Add to valid list if the term exists
} else {
$invalid_remove_terms[] = $remove_term; // Collect invalid remove terms
}
}
if (empty($valid_remove_terms)) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('Term(s) does not exist.', 'simple-tags'), 'error taxopress-notice');
return false;
}
$counter = 0;
if (!empty($match_terms)) {
// Get terms ID from match terms
$terms_id = array();
foreach ((array) $match_terms as $match_term) {
$term = get_term_by('name', sanitize_text_field($match_term), $taxonomy);
if ($term) {
$terms_id[] = (int) $term->term_id;
}
}
// Get object ID with terms ID
$objects_id = get_objects_in_term($terms_id, $taxonomy, array('fields' => 'all_with_object_id'));
// Remove specified terms from matched posts
foreach ((array) $objects_id as $object_id) {
wp_remove_object_terms($object_id, $valid_remove_terms, $taxonomy);
$counter++;
}
clean_object_term_cache($objects_id, $taxonomy);
clean_term_cache($terms_id, $taxonomy);
} else {
// Get all posts if no match terms were provided
global $wpdb;
$post_type_sql = "(post_status = 'publish' OR post_status = 'inherit') AND post_type = '".SimpleTags_Admin::$post_type."'";
$objects_id = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE {$post_type_sql}");
// Remove valid terms for all posts
foreach ((array) $objects_id as $object_id) {
wp_remove_object_terms($object_id, $valid_remove_terms, $taxonomy);
clean_object_term_cache($object_id, $taxonomy);
clean_term_cache($valid_remove_terms, $taxonomy);
$counter++;
}
clean_object_term_cache($objects_id, $taxonomy);
}
if ($counter == 0) {
add_settings_error(__CLASS__, __CLASS__, esc_html__('No matching term found.', 'simple-tags'), 'updated taxopress-notice');
} else {
add_settings_error(__CLASS__, __CLASS__, sprintf(esc_html__('Term(s) removed from %1s %2s.', 'simple-tags'), $counter, SimpleTags_Admin::$post_type_name), 'updated taxopress-notice');
}
return true;
}
public static function handle_taxopress_autocomplete_terms() {
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'st-admin-js')) {
wp_send_json_error(['message' => __('Nonce verification failed.', 'simple-tags')]);
wp_die();
}
$taxonomy = isset($_POST['taxonomy']) ? sanitize_text_field($_POST['taxonomy']) : 'post_tag';
$term = isset($_POST['term']) ? sanitize_text_field($_POST['term']) : '';
$terms = get_terms([
'taxonomy' => $taxonomy,
'name__like' => $term,
'hide_empty' => false,
]);
$results = [];
foreach ( $terms as $term ) {
$results[] = array(
'name' => html_entity_decode(
$term->name,
ENT_QUOTES,
get_bloginfo( 'charset' )
),
'slug' => $term->slug,
);
}
wp_send_json($results);
wp_die();
}
/**
* Method for edit one or more terms slug
*
* @param string $taxonomy
* @param string $names
* @param string $slugs
*
* @return boolean
* @author WebFactory Ltd
*/
/*
public static function editTermSlug( $taxonomy = 'post_tag', $names = '', $slugs = '') {
if ( trim( str_replace(',', '', stripslashes($slugs)) ) == '' ) {
add_settings_error( __CLASS__, __CLASS__, esc_html__('No new slug(s) specified!', 'simple-tags'), 'error' );
return false;
}
$match_names = explode(',', $names);
$new_slugs = explode(',', $slugs);
$match_names = array_filter($match_names, '_delete_empty_element');
$new_slugs = array_filter($new_slugs, '_delete_empty_element');
if ( count($match_names) != count($new_slugs) ) {
add_settings_error( __CLASS__, __CLASS__, esc_html__('Terms number and slugs number isn\'t the same!', 'simple-tags'), 'error' );
return false;
} else {
$counter = 0;
foreach ( (array) $match_names as $i => $match_name ) {
// Sanitize slug + Escape
$new_slug = sanitize_title($new_slugs[$i]);
// Get term by name
$term = get_term_by('name', $match_name, $taxonomy);
if ( !$term ) {
continue;
}
// Increment
$counter++;
// Update term
wp_update_term($term->term_id, $taxonomy, array('slug' => $new_slug));
// Clean cache
clean_term_cache($term->term_id, $taxonomy);
}
}
if ( $counter == 0 ) {
add_settings_error( __CLASS__, __CLASS__, esc_html__('No slug edited.', 'simple-tags'), 'updated' );
} else {
add_settings_error( __CLASS__, __CLASS__, sprintf(esc_html__('%s slug(s) edited.', 'simple-tags'), $counter), 'updated' );
}
return true;
}
*/
/** Singleton instance */
public static function get_instance()
{
if (! isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
}
?>