这是一个有趣的项目。我想我可以在一本书中就这一点写一整章(事实上,我实际上是在下面写的)。不管怎样,我胡乱想出了很多方法,下面是我想到的最简单的方法:
function add_glossary_links($content) {
global $wpdb, $wordlist;
if ( !$wordlist && !$wordlist = get_option(\'wordlist\') ) {
mysql_query(\'SET SESSION group_concat_max_len = 100000\');
$wordlist = $wpdb->get_var(\'SELECT GROUP_CONCAT(DISTINCT word SEPARATOR "|") AS `list` FROM \'.$wpdb->prefix.\'glossary\');
add_option(\'wordlist\', $wordlist);
}
$content = preg_replace_callback(
\'/\\b(\'.$wordlist.\')\\b/i\',
create_function(
\'$matches\',
\'return "<a href=\\"/glossary/".strtolower(substr($matches[0],0,1)."/".$matches[0])."/\\">".$matches[0]."</a>";\'
),
$content
);
return preg_replace(\'/(<[^<]+)<a\\s.*?>(.*?)<\\/a>/si\',\'$1$2\', $content);
}
add_filter( \'the_content\', \'add_glossary_links\' );
讨论假设有一个表前缀\\u词汇表,我们将选择一个以管道分隔的所有记录列表。当我们在帖子中搜索单词时,这将成为正则表达式的一部分。在此之前,我们将为group\\u concat\\u max\\u length设置一个会话变量,默认情况下,该变量将截断为1024个字符。100000个字符可以容纳10000个9个字母的单词(准确地说是1个10个字母的单词),所以如果需要更多的单词,您可以将其增加。
在里面preg_replace_callback
, 我们将用锚定标记来替换所有单词实例。根据需要调整HREF。
这可能会导致某些HTML格式错误(例如,在图像alt中用锚定标记包装一个单词),因此下一个preg\\u替换将修复此问题。如果需要,可以执行另一个操作,以确保已包装在锚定标记中的单词不会被包装在另一个锚定标记中。
为了进行性能测试,我构建了一个由1001个5-15个字符长的随机单词组成的词汇表。如果SELECT GROUP_CONCAT...
结果不会以某种方式缓存到整整一秒钟。如您所见,我在这里所做的是将其存储在一个选项中(当然,您希望在更新词汇表时随时更新该选项)。您可以采取任何数量的步骤来提高性能,这只是一个建议。使用apache benchmark进行测试时,我的页面负载平均增加了6.8%(标准差非常大,因此这实际上不是统计上的显著差异,但我离题了),这是一个悬而未决的问题;这是否至关重要完全取决于网站的访问量。尽管如此,如果它获得了大量流量,人们还是希望它能够启用缓存,在这种情况下,差异将完全可以忽略不计。
结论
这是可行的,但如果这6.8%是关键的,你会想重新考虑这个方法。具体来说,您可以考虑使用javascript进行替换。您可以用类似的方式来完成,将单词列表作为JS变量写出来。这样,您的服务器就不必处理搜索处理,您可以让用户的机器完成所有工作。
备选方案
我尝试的另一种方法是在发布或更新帖子时存储索引,这种方法速度明显更快,但需要更多的编码。在这种情况下,我根据帖子中的每个单词搜索字典,并将匹配项存储在索引表中。然后在页面加载时,像上面那样替换帖子中缩短的单词列表,这样我只处理已知匹配的列表,而不是完整的列表(所以,假设5个单词而不是1000个单词)。如果要探索该路线,需要两个表:
CREATE TABLE `wp_glossary` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`word` tinytext,
`definition` text,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1002 DEFAULT CHARSET=latin1;
CREATE TABLE `wp_posts_glossary` (
`post_id` int(11) unsigned NOT NULL,
`glossary_id` int(11) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
您可以在更新后使用以下方法创建索引:
global $wpdb, $post;
$wpdb->query(\'DELETE FROM \'.$wpdb->prefix.\'posts_glossary WHERE post_id=\'.$post->ID);
$sql_regex = rtrim(preg_replace(\'/[\\W\\s]*(\\w+)[\\W\\s]*/\',\'$1|\',$post->post_content),\'|\');
$wpdb->query(\'INSERT INTO \'.$wpdb->prefix.\'posts_glossary (post_id,glossary_id)
SELECT \'.$post->ID.\',ID FROM \'.$wpdb->prefix.\'glossary WHERE word REGEXP("^\'.$sql_regex.\'$")\';
我用我的1001个单词的词汇表和《白鲸》的2215个单词的第一章来测试索引,平均构建时间约为1.5秒。因此,如果您走这条路,您应该考虑利用wp\\u cron,这样您就不必等到点击“更新”或“发布”后再对其进行索引。
有趣的东西。希望这有帮助!
干杯~