我如何为某些帖子创建有效的内容过滤器


How do I go about creating an efficient content filter for certain posts?

我已经将这篇文章标记为WordPress,但我不完全确定它是WordPress特定的,所以我把它发布在StackOverflow而不是WPSE上。该解决方案不必特定于WordPress,只需PHP

场景
我经营着一个养鱼网站,里面有许多热带鱼Species ProfilesGlossary条目。

我们的网站以我们的个人资料为导向。正如您所说的那样,它们是网站的面包和黄油。

我希望实现的是,在每个提到另一个物种或词汇表条目的物种简介中,我可以用链接替换这些词 - 就像你将在这里看到的那样。理想情况下,我也希望这种情况也出现在新闻、文章和博客文章中。

我们有近1400 species profiles1700 glossary entries.我们的物种概况通常很长,最后仅计算我们的物种概况numbered more than 1.7 million words信息。

我目前正在尝试
什么目前,我有一个filter.php,它有一个函数 - 我相信 - 做我需要它做的事情。代码相当长,可以在这里找到完整的代码。

此外,在我的WordPress主题functions.php中,我有以下内容:

# ==============================================================================================
# [Filter]
#
# Every hour, using WP_Cron, `my_updated_posts` is checked. If there are new Post IDs in there,
# it will run a filter on all of the post's content. The filter will search for Glossary terms
# and scientific species names. If found, it will replace those names with links including a 
# pop-up.
    include "filter.php";
# ==============================================================================================
# When saving a post (new or edited), check to make sure it isn't a revision then add its ID
# to `my_updated_posts`.
    add_action( 'save_post', 'my_set_content_filter' );
    function my_set_content_filter( $post_id ) {
        if ( !wp_is_post_revision( $post_id ) ) {
            $post_type = get_post_type( $post_id );
            if ( $post_type == "species" || ( $post_type == "post" && in_category( "articles", $post_id ) ) || ( $post_type == "post" && in_category( "blogs", $post_id ) ) ) {
                //get the previous value
                $ids = get_option( 'my_updated_posts' );
                //add new value if necessary
                if( !in_array( $post_id, $ids ) ) {
                    $ids[] = $post_id;
                    update_option( 'my_updated_posts', $ids );
                }
            }
        }
    }
# ==============================================================================================
# Add the filter to WP_Cron.
    add_action( 'my_filter_posts_content', 'my_filter_content' );
    if( !wp_next_scheduled( 'my_filter_posts_content' ) ) {
        wp_schedule_event( time(), 'hourly', 'my_filter_posts_content' );
    }
# ==============================================================================================
# Run the filter.
    function my_filter_content() {
        //check to see if posts need to be parsed
        if ( !get_option( 'my_updated_posts' ) )
            return false;
        //parse posts
        $ids = get_option( 'my_updated_posts' );
        update_option( 'error_check', $ids );
        foreach( $ids as $v ) {
            if ( get_post_status( $v ) == 'publish' )
                run_filter( $v );
            update_option( 'error_check', "filter has run at least once" );
        }
        //make sure no values have been added while loop was running
        $id_recheck = get_option( 'my_updated_posts' );
        my_close_out_filter( $ids, $id_recheck );
        //once all options, including any added during the running of what could be a long cronjob are done, remove the value and close out
        delete_option( 'my_updated_posts' );
        update_option( 'error_check', 'working m8' );
        return true;
    }
# ==============================================================================================
# A "difference" function to make sure no new posts have been added to `my_updated_posts` whilst
# the potentially time-consuming filter was running.
    function my_close_out_filter( $beginning_array, $end_array ) {
        $diff = array_diff( $beginning_array, $end_array );
        if( !empty ( $diff ) ) {
            foreach( $diff as $v ) {
                run_filter( $v );
            }
        }
        my_close_out_filter( $end_array, get_option( 'my_updated_posts' ) );
    }

正如代码注释(希望)所描述的那样,这种工作方式是WordPress每小时运行一个cron作业(就像一个假cron - 在用户点击时工作,但这并不重要,因为时间并不重要)运行上面找到的过滤器。

每小时运行

一次的理由是,如果我们试图在保存每个帖子时运行它,这将损害作者的利益。一旦我们让客座作者参与进来,这显然不是一种可接受的方式。

问题...
几个月来,我一直在让这个过滤器可靠运行时遇到问题。我不认为问题在于过滤器本身,而在于启用过滤器的功能之一 - 即 cron 作业,或选择过滤哪些帖子的函数,或为过滤器准备单词列表等的函数。

不幸的是,诊断问题非常困难(我可以看到),这要归功于它在后台运行并且仅每小时运行一次。我一直在尝试使用WordPress的update_option函数(基本上写入一个简单的数据库值)进行错误检查,但我没有太多运气 - 老实说,我对问题所在感到非常困惑。

我们最终将网站上线,而此过滤器无法正常工作。有时它似乎有效,有时它没有。因此,我们现在有相当多的物种概况没有被正确过滤。

我想要什么...
我基本上是在寻求有关运行此过滤器的最佳方法的建议。

Cron 工作是答案吗?我可以设置一个每天运行的.php文件,这不是问题。它将如何确定哪些帖子需要过滤?它在运行时会对服务器产生什么影响?

或者,WordPress管理页面是答案吗?如果我知道如何做到这一点,那么类似于页面的内容 - 利用 AJAX - 允许我选择要运行过滤器的帖子将是完美的。有一个名为AJAX Regenerate Thumbnails的插件可以像这样工作,也许这是最有效的?

考虑

  • 受影响的数据库/信息的大小/读取/写入
  • 哪些帖子被过滤
  • 过滤器对服务器的影响;特别是考虑到我似乎无法将WordPress内存限制增加到32Mb以上。
  • 实际过滤器本身是否高效、有效和可靠?

这是一个相当复杂的问题,我不可避免地(因为在这个过程中我被同事分散了大约18次注意力)遗漏了一些细节。请随时向我询问更多信息。

提前感谢,

在创建配置文件时执行此操作。

尝试反转整个过程。与其检查单词的内容,不如检查单词的内容单词。

  1. 在输入单词时中断内容帖子(在空格上)
  2. 消除重复项、数据库中最小大小的单词
  3. 、超过最大大小的重复项以及您保留的"常用单词"列表中的重复项。
  4. 检查每个表,如果你的某些表包含带空格的短语,请执行%text%搜索,否则进行直接匹配(更快),或者如果它真的是一个大问题,甚至构建一个哈希表。(我会将其作为PHP数组并以某种方式缓存结果,重新发明轮子没有意义)
  5. 使用现在明显缩小的列表创建链接。

您应该能够轻松地将其保持在 1 秒以内,即使您正在检查的 100,000 个单词也是如此。我之前已经为贝叶斯过滤器完成了此操作,而无需缓存单词列表。

对于较小的列表,即使它贪婪并收集与"小丑"不匹配的单词也会抓住"小丑泥鳅",由此产生的较小列表应该只有几个到几十个带有链接的单词。这将完全不需要时间来查找和替换一大块文本。

以上并不能真正解决您对旧配置文件的担忧。你没有确切地说有多少,只是说有很多文字,它是在 1400 到 3100(两个项目)放在一起。如果您有信息,您可以根据受欢迎程度来做这些较旧的内容。或输入日期,最新在前。无论如何,最好的方法是编写一个脚本来暂停 PHP 的时间限制,并且只是在所有帖子上批量运行加载/处理/保存。如果每个大约需要 1 秒(可能要少得多,但最坏的情况),那么您正在谈论 3100 秒,这不到一个小时。