文章最后更新时间:

有一下三种方式能实现,只需要用一个代码就行
放置位置:
* /wp-content/themes/zibll/func.php
* 子比主题 安全版 标题自动标签
* 精简无报错、防500、兼容所有WP版本
/**
* 子比主题 安全版 标题自动标签
* 精简无报错、防500、兼容所有WP版本
*/
if (!defined('ABSPATH')) exit;
// 配置项,自己按需改
function zib_auto_tag_config(){
return [
'open' => true, // 总开关
'max_num' => 5, // 最多几个标签
'auto_create' => false, // 不自动新建标签(更安全)
'stop_word' => ['的','了','和','与','教程','方法','分享','怎么','如何']
];
}
// 保存文章自动打标签
add_action('save_post', function($post_id){
$cfg = zib_auto_tag_config();
if(!$cfg['open']) return;
// 安全判断,避免死循环、自动保存、草稿
if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if(wp_is_post_revision($post_id)) return;
$post = get_post($post_id);
if(!$post || $post->post_type !== 'post') return;
if(empty($post->post_title)) return;
// 获取已有标签
$old_tags = wp_get_post_tags($post_id, ['fields'=>'names']);
$title = $post->post_title;
// 读取网站所有已有标签
$all_tags = get_tags(['number'=>0, 'hide_empty'=>false]);
$match = [];
foreach($all_tags as $tag){
if(count($match) >= $cfg['max_num']) break;
// 标题包含标签名 就匹配
if(str_contains($title, $tag->name)){
$match[] = $tag->name;
}
}
// 合并原有标签+自动标签,不覆盖
$new_tags = array_unique(array_merge($old_tags, $match));
wp_set_post_tags($post_id, $new_tags);
}, 20);
* 子比Zibll 增强版 标题自动标签
* 特性:长词优先、同义词映射、停用词过滤、防崩溃、防死循环
<?php
/**
* 子比Zibll 增强版 标题自动标签
* 特性:长词优先、同义词映射、停用词过滤、防崩溃、防死循环
*/
if (!defined('ABSPATH')) exit;
// ========== 自定义配置区 ==========
function zib_auto_tag_config()
{
return [
'enable' => true,
'max_tag' => 6,
'auto_create' => false,
'append_mode' => true,
// 同义词映射
'map' => [
'建站' => '网站搭建',
'源码' => '程序源码',
'美化' => '主题美化'
],
// 过滤无用词
'stop_words' => ['的','了','和','与','及','教程','技巧','分享','详解','怎么','如何']
];
}
// 获取全部标签 按字数倒序(长词优先)
function zib_get_all_tags_sort()
{
$tags = get_tags(['number' => 0, 'hide_empty' => false]);
usort($tags, function ($a, $b) {
return mb_strlen($b->name) - mb_strlen($a->name);
});
return $tags;
}
// 核心自动匹配
add_action('save_post', function ($post_id) {
$cfg = zib_auto_tag_config();
if (!$cfg['enable']) return;
// 安全拦截
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) return;
$post = get_post($post_id);
if (!$post || $post->post_type !== 'post' || empty($post->post_title)) return;
$title = $post->post_title;
$match_tags = [];
// 1. 同义词强制匹配
foreach ($cfg['map'] as $key => $tag) {
if (str_contains($title, $key) && !in_array($tag, $match_tags)) {
$match_tags[] = $tag;
}
}
// 2. 长词优先匹配全站标签
$all_tags = zib_get_all_tags_sort();
foreach ($all_tags as $tag) {
if (count($match_tags) >= $cfg['max_tag']) break;
$name = $tag->name;
if (in_array($name, $cfg['stop_words'])) continue;
if (str_contains($title, $name) && !in_array($name, $match_tags)) {
$match_tags[] = $name;
}
}
// 合并原有标签
if ($cfg['append_mode']) {
$old = wp_get_post_tags($post_id, ['fields' => 'names']);
$match_tags = array_unique(array_merge($old, $match_tags));
}
wp_set_post_tags($post_id, $match_tags);
}, 20);
Zibll 自动标签匹配(标题 -> 标签)
*
* 放置位置:
* /wp-content/themes/zibll/func.php
<?php
/**
* Zibll 自动标签匹配(标题 -> 标签)
*
* 放置位置:
* /wp-content/themes/zibll/func.php
*
* 功能:
* 1) 保存文章时,自动从标题识别关键词并关联 post_tag 标签
* 2) 长词优先匹配,减少短词误匹配
* 3) 支持手动同义词映射(manual_map)
* 4) 可选“找不到就自动创建标签”(默认关闭)
* 5) 带缓存和防重入锁,性能和稳定性更好
*/
if (!defined('ABSPATH')) {
exit;
}
if (!function_exists('zibll_title_tag_config')) {
/**
* 统一配置入口(你主要改这里)
*/
function zibll_title_tag_config()
{
return array(
// 总开关
'enabled' => true,
// 生效的文章类型,默认只处理普通文章 post
'post_types' => array('post'),
// 标签写入模式:
// true = 与文章现有标签合并
// false = 使用自动识别结果覆盖原标签
'append_mode' => true,
// 每篇最多自动关联多少个标签
'max_tags_per_post' => 8,
// 关键词最短长度(中文/英文均生效)
'min_keyword_len' => 2,
// 当关键词没有对应标签时,是否自动创建新标签
'auto_create_tag' => false,
// 手动映射:标题命中左侧关键词时,强制绑定右侧标签
// '标题关键词' => '已有标签名'
'manual_map' => array(
// 'chatgpt' => 'ChatGPT',
// 'wordpress' => 'WordPress',
// '建站' => 'WordPress',
),
// 停用词:这些词不会作为关键词候选
'stopwords' => array(
'的', '了', '和', '与', '及', '在', '是', '就', '都', '很', '也', '把', '被',
'你', '我', '他', '她', '它', '我们', '你们', '他们',
'一个', '一些', '一种', '这个', '那个', '这些', '那些',
'怎么', '如何', '为什么', '教程', '指南', '方法', '技巧', '分享',
),
);
}
}
if (!function_exists('zibll_tt_strlen')) {
/**
* UTF-8 安全长度
*/
function zibll_tt_strlen($text)
{
if (function_exists('mb_strlen')) {
return (int) mb_strlen((string) $text, 'UTF-8');
}
return (int) strlen((string) $text);
}
}
if (!function_exists('zibll_tt_substr')) {
/**
* UTF-8 安全截取
*/
function zibll_tt_substr($text, $start, $length = null)
{
$text = (string) $text;
if (function_exists('mb_substr')) {
if ($length === null) {
return (string) mb_substr($text, (int) $start, null, 'UTF-8');
}
return (string) mb_substr($text, (int) $start, (int) $length, 'UTF-8');
}
if ($length === null) {
return (string) substr($text, (int) $start);
}
return (string) substr($text, (int) $start, (int) $length);
}
}
if (!function_exists('zibll_tt_strtolower')) {
/**
* UTF-8 安全转小写(让英文匹配不区分大小写)
*/
function zibll_tt_strtolower($text)
{
$text = (string) $text;
if (function_exists('mb_strtolower')) {
return (string) mb_strtolower($text, 'UTF-8');
}
return (string) strtolower($text);
}
}
if (!function_exists('zibll_tt_stripos')) {
/**
* UTF-8 安全不区分大小写查找
*/
function zibll_tt_stripos($haystack, $needle)
{
$haystack = (string) $haystack;
$needle = (string) $needle;
if ($needle === '') {
return false;
}
if (function_exists('mb_stripos')) {
return mb_stripos($haystack, $needle, 0, 'UTF-8');
}
return stripos($haystack, $needle);
}
}
if (!function_exists('zibll_tt_normalize')) {
/**
* 文本归一化:
* - 去 HTML
* - 全部小写
* - 去掉标点(保留字母/数字/中文/空格/下划线/中划线)
* - 压缩连续空格
* - 可选去空格(用于连续子串匹配)
*/
function zibll_tt_normalize($text, $remove_space = false)
{
$text = html_entity_decode((string) $text, ENT_QUOTES, 'UTF-8');
$text = wp_strip_all_tags($text);
$text = zibll_tt_strtolower($text);
$text = preg_replace('/[^\p{L}\p{N}\p{Han}\s\-_]+/u', ' ', $text);
$text = preg_replace('/\s+/u', ' ', trim($text));
if ($remove_space) {
$text = str_replace(' ', '', $text);
}
return (string) $text;
}
}
if (!function_exists('zibll_tt_flush_tag_index')) {
/**
* 清理标签索引缓存
* 在标签新增/编辑/删除时触发,确保匹配库实时更新
*/
function zibll_tt_flush_tag_index($term_id = 0, $tt_id = 0, $taxonomy = '')
{
if ($taxonomy && 'post_tag' !== $taxonomy) {
return;
}
delete_transient('zibll_title_tag_index_v1');
}
}
add_action('created_term', 'zibll_tt_flush_tag_index', 10, 3);
add_action('edited_term', 'zibll_tt_flush_tag_index', 10, 3);
add_action('delete_term', 'zibll_tt_flush_tag_index', 10, 3);
if (!function_exists('zibll_tt_get_tag_index')) {
/**
* 构建“标签关键词索引”
*
* 来源:
* - 标签 name
* - 标签 slug
* - 别名 meta:zib_tag_alias / tag_alias(可选)
*
* 关键点:
* - 关键词按长度降序,先匹配长词,降低误命中
* - 双层缓存:请求内 static + transient(12h)
*/
function zibll_tt_get_tag_index($force = false)
{
static $runtime_cache = null;
if (!$force && is_array($runtime_cache)) {
return $runtime_cache;
}
if (!$force) {
$cached = get_transient('zibll_title_tag_index_v1');
if (is_array($cached)) {
$runtime_cache = $cached;
return $runtime_cache;
}
}
$terms = get_terms(array(
'taxonomy' => 'post_tag',
'hide_empty' => false,
));
if (is_wp_error($terms) || empty($terms)) {
$runtime_cache = array();
return $runtime_cache;
}
$index = array();
foreach ($terms as $term) {
$keys = array(
(string) $term->name,
(string) $term->slug,
);
$alias = get_term_meta((int) $term->term_id, 'zib_tag_alias', true);
if (!$alias) {
$alias = get_term_meta((int) $term->term_id, 'tag_alias', true);
}
if (!empty($alias)) {
$alias_parts = preg_split('/[,,|\/\s]+/u', (string) $alias, -1, PREG_SPLIT_NO_EMPTY);
if (!empty($alias_parts)) {
$keys = array_merge($keys, $alias_parts);
}
}
$keys = array_unique(array_filter(array_map('trim', $keys)));
foreach ($keys as $key) {
$keyword = zibll_tt_normalize($key, true);
if ('' === $keyword || zibll_tt_strlen($keyword) < 2) {
continue;
}
$index[] = array(
'term_id' => (int) $term->term_id,
'keyword' => $keyword,
'len' => zibll_tt_strlen($keyword),
);
}
}
usort($index, function ($a, $b) {
if ((int) $a['len'] === (int) $b['len']) {
return (int) $a['term_id'] - (int) $b['term_id'];
}
return ((int) $a['len'] > (int) $b['len']) ? -1 : 1;
});
$runtime_cache = array_values($index);
set_transient('zibll_title_tag_index_v1', $runtime_cache, 12 * HOUR_IN_SECONDS);
return $runtime_cache;
}
}
if (!function_exists('zibll_tt_resolve_tag_id')) {
/**
* 把“标签名或关键词”解析成 term_id
*
* 顺序:
* 1) 按 name 查
* 2) 按 slug 查
* 3) 允许自动创建时,直接插入新标签
*/
function zibll_tt_resolve_tag_id($tag_name, $allow_create = false)
{
$tag_name = trim((string) $tag_name);
if ('' === $tag_name) {
return 0;
}
$term = get_term_by('name', $tag_name, 'post_tag');
if (!$term || is_wp_error($term)) {
$term = get_term_by('slug', sanitize_title($tag_name), 'post_tag');
}
if ($term && !is_wp_error($term)) {
return (int) $term->term_id;
}
if (!$allow_create) {
return 0;
}
$created = wp_insert_term($tag_name, 'post_tag');
if (is_wp_error($created) || empty($created['term_id'])) {
return 0;
}
zibll_tt_flush_tag_index();
return (int) $created['term_id'];
}
}
if (!function_exists('zibll_tt_extract_keywords')) {
/**
* 从标题提取候选关键词
*
* 逻辑:
* 1) 按空格/中划线/下划线拆分
* 2) 过滤停用词与短词
* 3) 对纯中文片段做 2~4 字 N-Gram 切分,提高中文命中率
*/
function zibll_tt_extract_keywords($title, $config)
{
$title = zibll_tt_normalize($title, false);
if ('' === $title) {
return array();
}
$min_len = max(2, (int) $config['min_keyword_len']);
$stopwords = array_flip((array) $config['stopwords']);
$parts = preg_split('/[\s\-_]+/u', $title, -1, PREG_SPLIT_NO_EMPTY);
$keywords = array();
foreach ((array) $parts as $part) {
$part = trim((string) $part);
if ('' === $part || isset($stopwords[$part])) {
continue;
}
if (zibll_tt_strlen($part) >= $min_len) {
$keywords[$part] = true;
}
if (preg_match('/^[\p{Han}]+$/u', $part)) {
$len = zibll_tt_strlen($part);
$max_n = min(4, $len);
for ($n = 2; $n <= $max_n; $n++) {
for ($i = 0; $i <= ($len - $n); $i++) {
$sub = zibll_tt_substr($part, $i, $n);
if ('' === $sub || isset($stopwords[$sub])) {
continue;
}
$keywords[$sub] = true;
}
}
}
}
return array_keys($keywords);
}
}
if (!function_exists('zibll_tt_match_tags_from_title')) {
/**
* 从标题匹配标签(分三层)
*
* 第一层:标签索引直接命中(长词优先)
* 第二层:manual_map 强制映射
* 第三层:关键词回退匹配(必要时可自动创建标签)
*/
function zibll_tt_match_tags_from_title($title, $config)
{
$matched = array();
$max_count = max(1, (int) $config['max_tags_per_post']);
$title_key = zibll_tt_normalize($title, true);
if ('' === $title_key) {
return array();
}
$index = zibll_tt_get_tag_index();
foreach ((array) $index as $row) {
if (count($matched) >= $max_count) {
break;
}
if (zibll_tt_stripos($title_key, $row['keyword']) !== false) {
$matched[(int) $row['term_id']] = true;
}
}
if (!empty($config['manual_map']) && is_array($config['manual_map'])) {
foreach ($config['manual_map'] as $keyword => $tag_name) {
if (count($matched) >= $max_count) {
break;
}
$map_key = zibll_tt_normalize($keyword, true);
if ('' === $map_key || zibll_tt_stripos($title_key, $map_key) === false) {
continue;
}
$term_id = zibll_tt_resolve_tag_id($tag_name, !empty($config['auto_create_tag']));
if ($term_id) {
$matched[$term_id] = true;
}
}
}
if (count($matched) < $max_count) {
$keywords = zibll_tt_extract_keywords($title, $config);
foreach ((array) $keywords as $keyword) {
if (count($matched) >= $max_count) {
break;
}
$term_id = zibll_tt_resolve_tag_id($keyword, !empty($config['auto_create_tag']));
if ($term_id) {
$matched[$term_id] = true;
}
}
}
return array_map('intval', array_keys($matched));
}
}
if (!function_exists('zibll_tt_auto_set_post_tags')) {
/**
* 保存文章时自动写入标签
*
* 防护项:
* - 跳过 autosave/revision
* - 跳过无权限保存
* - 跳过不在配置内的 post_type
* - 运行锁防重入,避免循环触发
*/
function zibll_tt_auto_set_post_tags($post_id, $post, $update)
{
$config = zibll_title_tag_config();
if (empty($config['enabled'])) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
return;
}
if (!$post || empty($post->post_type)) {
$post = get_post($post_id);
}
if (!$post || empty($post->post_title)) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
if (in_array($post->post_status, array('auto-draft', 'trash'), true)) {
return;
}
$post_types = !empty($config['post_types']) ? (array) $config['post_types'] : array('post');
if (!in_array($post->post_type, $post_types, true)) {
return;
}
static $running = array();
if (isset($running[$post_id])) {
return;
}
$running[$post_id] = true;
try {
$matched_ids = zibll_tt_match_tags_from_title($post->post_title, $config);
if (empty($matched_ids)) {
return;
}
$existing_ids = wp_get_post_terms($post_id, 'post_tag', array('fields' => 'ids'));
if (is_wp_error($existing_ids) || !is_array($existing_ids)) {
$existing_ids = array();
}
if (!empty($config['append_mode'])) {
$final_ids = array_values(array_unique(array_merge(array_map('intval', $existing_ids), $matched_ids)));
} else {
$final_ids = $matched_ids;
}
// 排序后比较,避免仅因顺序不同而重复写入数据库
$old_ids = array_map('intval', $existing_ids);
sort($old_ids);
sort($final_ids);
if ($old_ids !== $final_ids) {
wp_set_post_terms($post_id, $final_ids, 'post_tag', false);
}
} finally {
// 确保始终释放锁(即使中间出现异常)
unset($running[$post_id]);
}
}
}
// 保存文章时执行自动标签匹配
add_action('save_post', 'zibll_tt_auto_set_post_tags', 30, 3);
© 版权声明
© 版权声明 All Rights Reserved
THE END







暂无评论内容