解决 WordPress 中的摘要字数问题

WordPress 是一个比较完善的博客系统, 也是我用来淘汰 Emlog 的方案, 但是最近发现有个问题, 即对中文的文字摘要做的不好, 默认是 55 个字符, 但实际上往往会把整片文章进行输出.
通过搜索引擎可以查阅到以下几个解决方案:

从这里面可以了解到, 问题的核心在于 WordPress 的截取算法是默认通过空格进行计算的. 也就是说对于东亚文字而言, 没有空格的长篇大论都是认为是一个字. 所以, 我们需要通过部分的代码修改进行改正.
但是, 考虑到部分文档的历史久远, 以及严谨的态度, 我还是主要从代码出发, 最终定位到代码的位置为 wordpress/wp-includes/formatting.php line:3699 版本号为 5.2.4 也就是目前最新的版本:

function wp_trim_excerpt( $text = '', $post = null ) {
	$raw_excerpt = $text;
	if ( '' == $text ) {
		$post = get_post( $post );
		$text = get_the_content( '', false, $post );
		$text = strip_shortcodes( $text );
		$text = excerpt_remove_blocks( $text );
		$text = apply_filters( 'the_content', $text );
		$text = str_replace( ']]>', ']]>', $text );
		$excerpt_length = apply_filters( 'excerpt_length', 55 );
		$excerpt_more = apply_filters( 'excerpt_more', ' ' . '[…]' );
		$text         = wp_trim_words( $text, $excerpt_length, $excerpt_more );
	}
	return apply_filters( 'wp_trim_excerpt', $text, $raw_excerpt );
}

可以看到, 这段代码的主要用途就是截取摘要, 通常, 很多的教程都是在这里进行替换, 将 wp_trim_words 这句改成 substr 或者截取行数之类的, 但实际上这一步是多余的操作. 我们直接看 wp_trim_words 函数:

function wp_trim_words( $text, $num_words = 55, $more = null ) {
	if ( null === $more ) {
		$more = __( '…' );
	}
	$original_text = $text;
	$text          = wp_strip_all_tags( $text );
	/*
	 * translators: If your word count is based on single characters (e.g. East Asian characters),
	 * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'.
	 * Do not translate into your own language.
	 */
	if ( strpos( _x( 'words', 'Word count type. Do not translate!' ), 'characters' ) === 0
        && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) )
    {
		$text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' );
		preg_match_all( '/./u', $text, $words_array );
		$words_array = array_slice( $words_array[0], 0, $num_words + 1 );
		$sep         = '';
	} else {
		$words_array = preg_split( "/[\n\r\t ]+/", $text, $num_words + 1, PREG_SPLIT_NO_EMPTY );
		$sep         = ' ';
	}
	if ( count( $words_array ) > $num_words ) {
		array_pop( $words_array );
		$text = implode( $sep, $words_array );
		$text = $text . $more;
	} else {
		$text = implode( $sep, $words_array );
	}
	return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
}

注意那段注释, 我们可以看到, 对于不同的语言, 实际上是已经做好了判断, 所以, 最简单的做法就是把网站的文字直接定义为中文. 具体的操作就是在 Settings -> General -> Site Language 中选择’简体中文’. 然后就可以了. 但是如果想在后台使用英文, 但是实际还是使用中文进行博客撰写的人来说, 只需要将那里面的 words 修改成 characters_excluding_spaces 就好.
最后修改完成的结果是:

function wp_trim_words( $text, $num_words = 55, $more = null ) {
	if ( null === $more ) {
		$more = __( '…' );
	}
	$original_text = $text;
	$text          = wp_strip_all_tags( $text );
	/*
	 * translators: If your word count is based on single characters (e.g. East Asian characters),
	 * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'.
	 * Do not translate into your own language.
	 */
    // 主要修改这句
	if ( strpos( _x( 'characters_excluding_spaces', 'Word count type. Do not translate!' ), 'characters' ) === 0
        && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) )
    {
		$text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' );
		preg_match_all( '/./u', $text, $words_array );
		$words_array = array_slice( $words_array[0], 0, $num_words + 1 );
		$sep         = '';
	} else {
		$words_array = preg_split( "/[\n\r\t ]+/", $text, $num_words + 1, PREG_SPLIT_NO_EMPTY );
		$sep         = ' ';
	}
	if ( count( $words_array ) > $num_words ) {
		array_pop( $words_array );
		$text = implode( $sep, $words_array );
		$text = $text . $more;
	} else {
		$text = implode( $sep, $words_array );
	}
	return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
}

就解决了.
PS:
因为升级 5.2.4 不小心把 content 文件删了… 导致现在 15 年以前的博客中的图显示不全…也是挺惨的, 不恢复了, 反正也用不到了.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.