以前跟大家分享了【推荐一款防止WordPress文章标题重复的插件Duplicate Title Validate】 一文,不过有些站长不喜欢用插件,想要用纯代码实现,所以boke112百科就将需求发给豆包AI,让它帮忙生成相应的代码,没想到真的实现了。
前端逻辑(用户交互层)
- 使用原生JS(替代jQuery,WP 6.9更推荐)实现,避免依赖冲突
- 输入标题时防抖处理(500ms延迟),减少AJAX请求次数
- 拦截表单提交:标题重复时直接阻止发布,同时显示红色提醒
- 标题唯一时显示绿色提醒,不拦截发布操作
后端逻辑(安全验证层)
- AJAX接口:快速查询数据库,返回标题是否重复的JSON结果
- wp_insert_post_data过滤器:后端二次验证(防止前端绕过),确保即使前端验证被跳过,后端也能拦截重复标题的发布
- 仅针对publish状态的文章检查,不影响草稿保存、自动保存等正常操作
兼容性优化(适配WP 6.9)
- 移除老旧的jQuery语法,使用现代Fetch API
- 适配WP 6.9的管理端DOM结构(发布按钮ID、表单结构)
- 兼容古腾堡编辑器和经典编辑器
使用方法
将以下代码添加到当前主题的functions.php文件中并保存更新文件即可。
/**
* WordPress 6.9 实时标题重复检测
* Description::输入标题时动态检测重复,重复则实时红色提醒+阻止发布(不存草稿),唯一则绿色提醒+正常发布
* Author:豆包AI
* Version: 1.0
* Compatible: WordPress 6.9+ (支持古腾堡/经典编辑器)
*/
// 初始化:仅在文章编辑页加载功能
add_action('admin_init', 'realtime_title_checker_init');
function realtime_title_checker_init() {
$screen = get_current_screen();
// 仅在文章/页面编辑页生效
if (!isset($screen) || !in_array($screen->base, ['post', 'post-new']) || $screen->action === 'edit') {
// 注册AJAX接口
add_action('wp_ajax_realtime_check_title', 'realtime_check_title_callback');
// 加载前端脚本
add_action('admin_footer', 'realtime_title_checker_scripts');
}
}
// 前端核心脚本:实时检测+发布拦截
function realtime_title_checker_scripts() {
$nonce = wp_create_nonce('realtime_title_nonce');
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 核心变量
const titleInput = document.querySelector('#title') || document.querySelector('[name="post_title"]');
const postForm = document.getElementById('post');
const publishButton = document.querySelector('#publish, #save-post, .editor-post-publish-button, .editor-post-save-draft');
let isTitleUnique = false; // 标题是否唯一标记
let checkTimer = null; // 防抖定时器
// 1. 辅助函数:显示/移除提示
const noticeContainer = document.createElement('div');
noticeContainer.id = 'realtime-title-notice';
noticeContainer.className = 'notice inline below-h2';
titleInput?.parentNode?.appendChild(noticeContainer);
// 显示提示
function showNotice(text, isError = false) {
noticeContainer.textContent = text;
noticeContainer.className = `notice inline below-h2 ${isError ? 'notice-error' : 'notice-success'}`;
noticeContainer.style.display = 'block';
}
// 隐藏提示
function hideNotice() {
noticeContainer.style.display = 'none';
noticeContainer.textContent = '';
}
// 2. 核心函数:AJAX实时检测标题
function checkTitleUniqueness() {
const title = titleInput.value.trim();
const postId = document.getElementById('post_ID')?.value || 0;
const postType = document.getElementById('post_type')?.value || 'post';
// 标题为空:清空提示+标记为不唯一
if (!title) {
hideNotice();
isTitleUnique = false;
return;
}
// 发送AJAX请求(WP标准AJAX接口)
fetch(ajaxurl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: new URLSearchParams({
action: 'realtime_check_title',
title: title,
post_id: postId,
post_type: postType,
nonce: '<?php echo $nonce; ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// 标题唯一:绿色提示+标记可发布
isTitleUnique = true;
showNotice('✅ 标题未重复,可正常发布!', false);
// 恢复发布按钮可用状态
publishButton?.removeAttribute('disabled');
publishButton?.classList.remove('disabled');
} else {
// 标题重复:红色提示+标记不可发布
isTitleUnique = false;
showNotice(`❌ 标题重复,禁止发布!请修改标题后重试!`, true);
// 禁用发布按钮
publishButton?.setAttribute('disabled', 'disabled');
publishButton?.classList.add('disabled');
}
})
.catch(() => {
// 检查失败:红色提示+标记不可发布
isTitleUnique = false;
showNotice('⚠️ 标题检查失败,请重试!', true);
publishButton?.setAttribute('disabled', 'disabled');
publishButton?.classList.add('disabled');
});
}
// 3. 标题输入时实时检测(防抖:500ms内只触发一次)
titleInput?.addEventListener('input', function() {
clearTimeout(checkTimer);
checkTimer = setTimeout(checkTitleUniqueness, 500);
});
// 4. 拦截表单提交:彻底阻止重复标题的发布操作(不保存草稿)
postForm?.addEventListener('submit', function(e) {
// 仅拦截“发布”操作,不拦截“预览”等
const submitAction = e.submitter?.name || e.target?.querySelector('input[name="publish"]')?.name;
if (submitAction && !isTitleUnique) {
e.preventDefault(); // 阻止表单提交
e.stopImmediatePropagation(); // 停止事件冒泡
// 强制显示重复提示(如果没显示的话)
if (!noticeContainer.textContent) {
showNotice('🚫 标题重复,禁止发布!请修改标题后重试', true);
}
// 滚动到提示位置,方便用户看到
noticeContainer.scrollIntoView({ behavior: 'smooth', block: 'center' });
return false;
}
});
// 5. 初始化:页面加载时如果有标题,立即检测
if (titleInput?.value.trim()) {
checkTitleUniqueness();
}
});
</script>
<style>
/* 美化提示样式,适配WP 6.9管理端 */
#realtime-title-notice {
padding: 8px 12px;
margin: 8px 0;
border-radius: 4px;
display: none;
}
#realtime-title-notice.notice-success {
background: #f0fff4;
border-left: 4px solid #22c55e;
color: #166534;
}
#realtime-title-notice.notice-error {
background: #fef2f2;
border-left: 4px solid #ef4444;
color: #991b1b;
}
/* 禁用发布按钮样式 */
#publish.disabled, #save-post.disabled, .editor-post-publish-button.disabled {
opacity: 0.6;
cursor: not-allowed !important;
}
</style>
<?php
}
// AJAX回调:检测标题是否重复(后端核心逻辑)
function realtime_check_title_callback() {
// 安全验证
check_ajax_referer('realtime_title_nonce', 'nonce');
// 获取并清洗参数
$title = sanitize_text_field($_POST['title'] ?? '');
$post_id = intval($_POST['post_id'] ?? 0);
$post_type = sanitize_text_field($_POST['post_type'] ?? 'post');
// 标题为空:返回错误
if (empty($title)) {
wp_send_json_error('标题不能为空');
}
global $wpdb;
// 查询已发布的相同标题文章(排除当前文章)
$duplicate_id = $wpdb->get_var($wpdb->prepare(
"SELECT ID FROM $wpdb->posts
WHERE post_title = %s
AND post_type = %s
AND post_status = 'publish'
AND ID != %d
LIMIT 1",
$title,
$post_type,
$post_id
));
if ($duplicate_id) {
wp_send_json_error('检测到相同标题的已发布文章');
} else {
wp_send_json_success('标题唯一');
}
}
// 兜底:后端二次拦截(防止前端绕过)
add_filter('wp_insert_post_data', 'realtime_title_backend_block', 99, 2);
function realtime_title_backend_block($data, $postarr) {
// 仅拦截“发布”操作,忽略草稿/自动保存/修订版
if (
$data['post_status'] !== 'publish' ||
wp_is_post_revision($postarr['ID']) ||
wp_is_post_autosave($postarr['ID']) ||
empty($data['post_title'])
) {
return $data;
}
global $wpdb;
// 后端再次验证标题唯一性
$duplicate_id = $wpdb->get_var($wpdb->prepare(
"SELECT ID FROM $wpdb->posts
WHERE post_title = %s
AND post_type = %s
AND post_status = 'publish'
AND ID != %d
LIMIT 1",
$data['post_title'],
$data['post_type'],
intval($postarr['ID'])
));
// 检测到重复:直接终止发布(不保存草稿)
if ($duplicate_id) {
wp_die(
'<div style="padding: 20px; color: #991b1b; font-size: 16px;">🚫 标题重复,禁止发布!请返回修改标题后重试。</div>',
'发布失败',
['response' => 403]
);
}
return $data;
}
成功添加以上代码后,我们在WordPress后台编辑文章标题时:
1、输入已存在的标题:实时显示红色提醒,点击 “发布” 会被拦截,即是无法发布文章;
2、输入新标题(不重复的标题):实时显示绿色提醒,点击 “发布” 可正常发布(状态为 “已发布”)。















桂公网安备 45010502000016号