标题起的有点大,不过这真的是重度强迫症患者的一剂良药。

即使禁用自动保存和修订版本,新建文章时也会产生无用的 auto-draft 记录。之前网上的办法都是采用修改 WordPress 原文件的方法屏蔽自建 auto-draft 记录,但是似乎目前没有适合 3.5 之后版本的办法,而且每次升级都需要修改原文件,既麻烦又不安全。

其实直接操作数据库更简单,原理为:如果新建文章或上传图片就获取数据库中最后一条有用记录(post_type 为 publish、draft 或 private 的行或 post_type 为 inherit 且类型为 attachment 的行)的 ID,并把之后的无用行(post_type 为 auto-draft 的行和 post_type 为 inherit 且类型为 revision 的行)删除掉,再重设自增。这样无论如何新建文章,数据库中最多有且仅有一条 auto-draft 记录(WordPress 刚刚创建的行,保存之后 post_type 变为 publish、draft 或 private),这样文章 ID 就能连续了。

function keep_id_continuous(){
	global $wpdb;
	$lastID = $wpdb->get_var("SELECT ID FROM $wpdb->posts WHERE post_status = 'publish' OR post_status = 'draft' OR post_status = 'private' OR ( post_status = 'inherit' AND post_type = 'attachment' ) ORDER BY ID DESC LIMIT 1");
	$wpdb->query("DELETE FROM $wpdb->posts WHERE ( post_status = 'auto-draft' OR ( post_status = 'inherit' AND post_type = 'revision' ) ) AND ID > $lastID");
	$wpdb->query("ALTER TABLE $wpdb->posts AUTO_INCREMENT = 1");
}
// 将函数钩在新建文章、上传媒体和自定义菜单之前。
add_filter( 'load-post-new.php', 'keep_id_continuous' );
add_filter( 'load-media-new.php', 'keep_id_continuous' );
add_filter( 'load-nav-menus.php', 'keep_id_continuous' );
// 禁用自动保存,所以编辑长文章前请注意手动保存。
add_action( 'admin_print_scripts', create_function( '$a', "wp_deregister_script('autosave');" ) );
// 禁用修订版本
remove_action( 'pre_post_update' , 'wp_save_post_revision' );

只要将上面的代码插入到主题functions.php中就可以了,支持 WordPress 3.0~3.8 的任何版本,而且未来升级也不会影响功能,基本算是一劳永逸。以上的代码考虑了使用媒体库和自定义菜单的可能,如果需要文章 ID 完全连续,就不要使用 WordPress 内置的媒体库功能和自定义菜单功能

此段代码已经过我的长时间测试,应该是没有问题的,但是由于代码涉及到DELETE这条极其危险的 MySQL 语句,所以我仍然建议你在使用这段代码之前先做个数据库备份,然后再测试。

  1. Not working at all!! Tested in WordPress 4.0.

    I wanna that what's *load-media-new.php*, *load-post-new.php* and *load-nav-menus.php*?
    These files don't exist at all! :oops:
    (根据要求, 特在此输入一些汉字)
    (PS: 这个评论功能做的还是不错的)

    • @zjhzxhz
      在我这里是有效的。
      那三个不是文件,只是一个钩子名称,分别是新建媒体、新建文章(页面)和新建菜单。

    • @zjhzxhz
      补充: 好像失效的部分是在上传附件的地方. 上传附件之后不会删除之前的 inherit 等类型的 Post, 例如在发布新文章时, 会创建多个 ID, 例如 10(publish), 11(inherit). 上传附件的 ID 为 12. 在上传附件时, add_filter('load-media-new.php') 这句话没有工作. 同时所有 load-*.php 的文件我也没有在 WordPress 中找到.

    • @zjhzxhz
      如果你在文章页面内上传,是无法生效的,那个钩子只针对媒体页面。
      那些不是文件,只是个钩子名称。

    • @小虾
      你确定是在 4.0 版本测试的吗?
      你试着按我如下叙述复现这个 Bug:
      1. 发布一篇文章, 日期定为上个月 (不插入图片)
      2. 这篇文章会占用 2 个 ID, 一个 publish 和一个 inherit
      3. 插入图片, 插入图片时, 那个 inherit 的 ID 不会被删除.

      你试试看, 是这样吗?

    • @zjhzxhz
      我上面已经说了,你在文章页面内上传,是无法生效的!
      所有清理只在进入上述三种页面时才工作!

      这不是 BUG,而是这段代码就没有考虑这个问题。

  2. 楼主堪称强迫症患者之友 = = :lol:

  3. […] 修改主题中的 function.php,参考小虾的《WordPress 文章 ID 连续之终极方法》 […]

  4. […] 方法一:可在当前主题的 functions.php 中加入以下 PHP 代码,这样如果你只是单纯发文章,不发页面,不添加菜单,不上传媒体的话,基本上此后的文章 ID 是连续的,而且不改变之前已经发布的文章 ID,不影响 SEO(代码参考自:小虾): […]

  5. 能否写个新建文章使用已清空的空余 id 的代码?

  6. […] 只要将上面的代码插入到主题 functions.php 中就可以了,支持 WordPress 3.0~3.6 的任何版本,而且未来升级也不会影响功能,基本算是一劳永逸。以上的代码考虑了使用媒体库和自定义菜单的可能,如果需要文章 ID 完全连续,就不要使用 WordPress 内置的媒体库功能和自定义菜单功能。(小虾版) […]

  7. 呃……看了博主的好几篇博文,发现跟博主纠结的东西都是一样的。
    每次发布文章,都要手动修改数据库的 ID,确保 ID 连续;也不用 WordPress 内置的媒体库功能和自定义菜单功能。