//--------Dynamic Auto-Tagging: Extracts top 6 keywords from post content------------------------------------------
add_action('save_post_post', 'plimoth_dynamic_auto_tags', 20, 3);
function plimoth_dynamic_auto_tags($post_id, $post, $update) {
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) return;
// Combine title and content, strip HTML tags
$text = strip_tags($post->post_title . ' ' . $post->post_content);
// Early exit if empty
if (trim($text) === '') return;
// List of stop words to ignore
$stop_words = [
'the', 'and', 'with', 'from', 'that', 'this', 'have', 'after',
'will', 'also', 'they', 'your', 'their', 'about', 'which', 'such',
'some', 'other', 'than', 'then', 'them', 'these', 'those', 'may',
'might', 'been', 'being', 'over', 'under', 'above', 'below', 'during',
'before', 'because', 'where', 'when', 'while', 'who', 'whom', 'whose',
'how', 'why', 'what', 'can', 'could', 'should', 'would', 'shall'
];
// Convert to lowercase safely using multibyte support
$text = mb_strtolower($text, 'UTF-8');
// Replace non-word characters with spaces, keeping letters, numbers, and diacritics intact
// Using Unicode property escapes (\p{L} for letters, \p{N} for numbers)
$text = preg_replace('/[^\p{L}\p{N}]+/u', ' ', $text);
// Split into words by whitespace
$words = preg_split('/\s+/', $text, -1, PREG_SPLIT_NO_EMPTY);
// Filter out short words (less than 4 characters) and stop words
$filtered = [];
foreach ($words as $word) {
// Use mb_strlen to accurately count characters in words like "Plymouth"
if (mb_strlen($word, 'UTF-8') >= 4 && !in_array($word, $stop_words, true)) {
$filtered[] = $word;
}
}
// Count word frequencies
$counts = array_count_values($filtered);
arsort($counts);
// Get top 6 keywords
$top_six = array_slice(array_keys($counts), 0, 6);
// Set tags if available
if (!empty($top_six)) {
wp_set_post_tags($post_id, $top_six, true);
}
}