'AI Tags',
'singular_name' => 'AI Tag',
'search_items' => 'Search AI Tags',
'popular_items' => 'Popular AI Tags',
'all_items' => 'All AI Tags',
'edit_item' => 'Edit AI Tag',
'update_item' => 'Update AI Tag',
'add_new_item' => 'Add New AI Tag',
'new_item_name' => 'New AI Tag Name',
'separate_items_with_commas' => 'Separate AI tags with commas',
'add_or_remove_items' => 'Add or remove AI tags',
'choose_from_most_used' => 'Choose from the most used AI tags',
'not_found' => 'No AI tags found.',
'menu_name' => 'AI Tags',
);
register_taxonomy(
self::TAXONOMY,
array(self::POST_TYPE),
array(
'hierarchical' => false,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'show_in_quick_edit' => true,
'show_tag(self::TAXONOMY)) { 'show_tagcloud' => true,
$query->set('post_type', array(self::POST_TYPE));
$query->set('posts_per_page', 24);
}
}
/**
* Auto-generate AI Tags on AI Tool save.
*/
public static function auto_generate_tags($post_id, $post, $update) {
if (!$post_id || !$post) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
return;
}
if ($post->post_type !== self::POST_TYPE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
if (!taxonomy_exists(self::TAXONOMY)) {
return;
}
if (in_array($post->post_status, array('auto-draft', 'trash'), true)) {
return;
}
if (self::ONLY_WHEN_EMPTY) {
$existing_terms = wp_get_object_terms($post_id, self::TAXONOMY, array(
'fields' => 'ids',
));
if (!is_wp_error($existing_terms) && !empty($existing_terms)) {
return;
}
}
$source_text = self::build_source_text($post_id, $post);
if (trim($source_text) === '') {
return;
}
$tags = self::extract_keywords($source_text, self::MAX_TAGS);
if (empty($tags)) {
return;
}
$tags = array_slice($tags, 0, self::MAX_TAGS);
if (count($tags) < self::MIN_TAGS) {
return;
}
wp_set_object_terms($post_id, $tags, self::TAXONOMY, false);
}
private static function build_source_text($post_id, $post) {
$parts = array();
if (!empty($post->post_title)) {
$parts[] = $post->post_title;
$parts[] = $post->post_title;
}
if (!empty($post->post_excerpt)) {
$parts[] = $post->post_excerpt;
}
if (!empty($post->post_content)) {
$parts[] = $post->post_content;
}
$short_description = '';
if (function_exists('get_field')) {
$short_description = get_field('short_description', $post_id);
}
if (!$short_description) {
$short_description = get_post_meta($post_id, 'short_description', true);
}
if (!empty($short_description)) {
$parts[] = $short_description;
$parts[] = $short_description;
}
/**
* Optional fields if they exist.
*/
$extra_fields = array(
'tool_features',
'tool_use_cases',
'pricing_label',
);
foreach ($extra_fields as $field_name) {
$value = '';
if (function_exists('get_field')) {
$value = get_field($field_name, $post_id);
}
if (!$value) {
$value = get_post_meta($post_id, $field_name, true);
}
if (is_array($value)) {
$value = implode(' ', array_map('strval', $value));
}
if (!empty($value)) {
$parts[] = $value;
}
}
return implode(' ', $parts);
}
private static function extract_keywords($text, $limit = 5) {
$text = html_entity_decode($text, ENT_QUOTES, get_bloginfo('charset'));
$text = wp_strip_all_tags($text);
$text = strtolower($text);
$text = preg_replace('/https?:\/\/[^\s]+/i', ' ', $text);
$text = preg_replace('/www\.[^\s]+/i', ' ', $text);
$text = str_replace(array('&', '&'), ' and ', $text);
$text = preg_replace('/[^a-z0-9\+\#\-\s]/i', ' ', $text);
$text = preg_replace('/\s+/', ' ', $text);
$text = trim($text);
if ($text === '') {
return array();
}
$stopwords = self::get_stopwords();
$raw_tokens = preg_split('/\s+/', $text);
$tokens = array();
foreach ($raw_tokens as $token) {
$token = self::clean_token($token);
if (!self::is_valid_token($token, $stopwords)) {
continue;
}
$tokens[] = $token;
}
if (empty($tokens)) {
return array();
}
$scores = array();
foreach ($tokens as $token) {
if (!isset($scores[$token])) {
$scores[$token] = 0;
}
$scores[$token] += 1;
}
$phrase_stopwords = self::get_phrase_stopwords();
$count_tokens = count($tokens);
for ($i = 0; $i < $count_tokens - 1; $i++) {
$first = $tokens[$i];
$second = $tokens[$i + 1];
if ($first === $second) {
continue;
}
$phrase = $first . ' ' . $second;
if (in_array($phrase, $phrase_stopwords, true)) {
continue;
}
if (!isset($scores[$phrase])) {
$scores[$phrase] = 0;
}
$scores[$phrase] += 3;
}
foreach ($scores as $keyword => $score) {
if (strpos($keyword, 'generator') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'editor') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'assistant') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'automation') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'marketing') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'writing') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'coding') !== false || strpos($keyword, 'code') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'image') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'video') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'audio') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'music') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'seo') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'chat') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'research') !== false) {
$scores[$keyword] += 2;
}
if (strpos($keyword, 'productivity') !== false) {
$scores[$keyword] += 2;
}
}
arsort($scores);
$final = array();
foreach ($scores as $keyword => $score) {
$keyword = trim($keyword);
if ($keyword === '') {
continue;
}
if (strpos($keyword, ' ') === false) {
$skip_single = false;
foreach ($final as $existing) {
if (stripos($existing, $keyword) !== false && strpos($existing, ' ') !== false) {
$skip_single = true;
break;
}
}
if ($skip_single) {
continue;
}
}
$formatted = self::format_tag_name($keyword);
if ($formatted === '') {
continue;
}
if (!in_array($formatted, $final, true)) {
$final[] = $formatted;
}
if (count($final) >= $limit) {
break;
}
}
return $final;
}
private static function clean_token($token) {
$token = strtolower(trim((string) $token));
$token = trim($token, "-_+.# \t\n\r\0\x0B");
$map = array(
'chatgpt' => 'chatgpt',
'gpt' => 'gpt',
'seo' => 'seo',
'api' => 'api',
'pdf' => 'pdf',
'ppt' => 'ppt',
'excel' => 'excel',
'wordpress' => 'wordpress',
'youtube' => 'youtube',
'tiktok' => 'tiktok',
'instagram' => 'instagram',
'linkedin' => 'linkedin',
'ecommerce' => 'ecommerce',
'e-commerce' => 'ecommerce',
'chatbot' => 'chatbot',
'chatbots' => 'chatbot',
);
if (isset($map[$token])) {
return $map[$token];
}
return $token;
}
private static function is_valid_token($token, $stopwords) {
if ($token === '') {
return false;
}
if (strlen($token) < 3) {
return false;
}
if (strlen($token) > 32) {
return false;
}
if (is_numeric($token)) {
return false;
}
if (in_array($token, $stopwords, true)) {
return false;
}
if (!preg_match('/[a-z]/i', $token)) {
return false;
}
return true;
}
private static function format_tag_name($keyword) {
$keyword = trim((string) $keyword);
if ($keyword === '') {
return '';
}
$parts = explode(' ', $keyword);
$formatted_parts = array();
$uppercase_words = array(
'ai',
'api',
'seo',
'pdf',
'ppt',
'gpt',
'crm',
'erp',
'ui',
'ux',
'saas',
);
foreach ($parts as $part) {
$part = trim($part);
if ($part === '') {
continue;
}
if (in_array($part, $uppercase_words, true)) {
$formatted_parts[] = strtoupper($part);
} elseif ($part === 'chatgpt') {
$formatted_parts[] = 'ChatGPT';
} elseif ($part === 'wordpress') {
$formatted_parts[] = 'WordPress';
} elseif ($part === 'youtube') {
$formatted_parts[] = 'YouTube';
} elseif ($part === 'tiktok') {
$formatted_parts[] = 'TikTok';
} elseif ($part === 'linkedin') {
$formatted_parts[] = 'LinkedIn';
} else {
$formatted_parts[] = ucfirst($part);
}
}
return implode(' ', $formatted_parts);
}
private static function get_stopwords() {
return array(
'the', 'and', 'for', 'with', 'this', 'that', 'from', 'your', 'you',
'are', 'was', 'were', 'will', 'would', 'could', 'should', 'can',
'into', 'onto', 'about', 'after', 'before', 'between', 'within',
'without', 'over', 'under', 'than', 'then', 'them', 'they', 'their',
'there', 'here', 'have', 'has', 'had', 'not', 'but', 'what', 'when',
'where', 'who', 'why', 'how', 'all', 'any', 'more', 'most', 'some',
'such', 'each', 'other', 'also', 'just', 'very', 'much', 'many',
'tool', 'tools', 'site', 'website', 'websites', 'official',
'visit', 'click', 'open', 'page', 'pages', 'platform', 'app',
'apps', 'software', 'service', 'services', 'solution', 'solutions',
'online', 'digital', 'product', 'products', 'features', 'feature',
'review', 'reviews', 'price', 'pricing', 'info', 'information',
'alternative', 'alternatives', 'free', 'paid', 'freemium',
'trial', 'best', 'top', 'new', 'latest', 'popular',
'artificial', 'intelligence', 'smart', 'powered', 'based',
'using', 'used', 'use', 'create', 'creates', 'creating',
'generate', 'generates', 'make', 'makes', 'help', 'helps',
'work', 'works', 'easy', 'fast', 'simple', 'advanced',
'users', 'user', 'business', 'businesses',
);
}
private static function get_phrase_stopwords() {
return array(
'official website',
'visit site',
'visit website',
'free tool',
'paid tool',
'best tool',
'top tool',
'ai tool',
'ai tools',
'artificial intelligence',
'tool review',
'tool reviews',
'pricing info',
'popular tool',
'latest tool',
);
}
}
AITM_AI_Tags_V100::init();
}
register_activation_hook(__FILE__, array('AITM_AI_Tags_V100', 'activate'));
register_deactivation_hook(__FILE__, array('AITM_AI_Tags_V100', 'deactivate'));
'show_in_nav_menus' => true,
'show_in_rest' => true,
'public' => true,
'query_var' => true,
'rewrite' => array(
'slug' => 'ai-tags',
'with_front' => false,
),
'capabilities' => array(
'manage_terms' => 'manage_categories',
'edit_terms' => 'manage_categories',
'delete_terms' => 'manage_categories',
'assign_terms' => 'edit_posts',
),
)
);
}
/**
* Make AI Tag archive pages show AI Tools.
*/
public static function include_ai_tools_in_ai_tag_archives($query) {
if (is_admin() || !$query->is_main_query()) {
return;
}