12

この投稿に WordPress のタグを付けましたが、WordPress 固有のものかどうか完全にはわからないため、WPSE ではなく StackOverflow に投稿しています。ソリューションは WordPress 固有である必要はなく、単純に PHPです。

シナリオ
私は、多数の熱帯魚とエントリを含む魚飼育 Web サイトを運営しています。Species ProfilesGlossary

私たちのウェブサイトは、私たちのプロフィールを中心にしています。それらは、あなたがそれを呼ぶかもしれないように、ウェブサイトのパンとバターです.

私が達成したいと思っていることは、別の種または用語集のエントリに言及しているすべての種のプロファイルで、それらの単語をリンクに置き換えることができるということです。理想的には、これがニュース、記事、ブログ投稿でも発生することを望みます.

ほとんど1400 species profilesとがあり1700 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 が 1 時間ごとに cron ジョブを実行することです (これは偽の cron のようなものです - ユーザーのヒット時に機能しますが、タイミングがそうではないため、それは実際には問題ではありません)。重要) 上記のフィルターを実行します。

1 時間ごとに実行する理由は、投稿が保存されるたびに実行しようとすると、作成者に不利益をもたらすからです。ゲストの著者を巻き込むと、それは明らかに容認できる方法ではありません。

問題...
何ヶ月もの間、私はこのフィルターを確実に動作させるのに問題を抱えていました。問題はフィルター自体にあるとは思いませんが、フィルターを有効にする機能の1つ-つまり、cronジョブ、またはフィルターされる投稿を選択する機能、または単語リストなどを準備する機能にあると思います.フィルター。

残念ながら、バックグラウンドで 1 時間ごとにしか実行されないため、この問題を診断するのは非常に困難です (私には分かります)。WordPress の関数 (基本的に単純なデータベース値を書き込む) を使用してエラーをチェックしようとしてきましたがupdate_option、うまくいきませんでした。正直なところ、問題がどこにあるのかについてかなり混乱しています。

このフィルターが正しく機能せずに、ウェブサイトを公開することになりました。うまくいくように見えることもあれば、うまくいかないこともあります。その結果、正しくフィルタリングされていない種のプロファイルがかなり多くなりました。

私が望むこと...
基本的に、このフィルターを実行するための最良の方法についてアドバイスを求めています。

Cronジョブが答えですか? .php毎日実行されるファイルを設定できますが、それは問題になりません。どの投稿をフィルタリングする必要があるかをどのように判断しますか? 実行時にサーバーにどのような影響がありますか?

あるいは、WordPress の管理ページが答えですか? その方法を知っていれば、フィルターを実行する投稿を選択できる、AJAX を利用したページの行に沿った何かが完璧でしょう。このように機能するというプラグインがありますがAJAX Regenerate Thumbnails、おそらくそれが最も効果的でしょうか?

考慮事項

  • データベースのサイズ/影響を受ける情​​報/読み取り/書き込み
  • フィルタリングされる投稿
  • フィルターがサーバーに与える影響。特に、WordPress のメモリ制限を 32Mb を超えて増やすことはできないようです。
  • 実際のフィルター自体は効率的で効果的で信頼性がありますか?

これは非常に複雑な質問であり、必然的に (その過程で同僚に約 18 回注意を​​そらされたため) いくつかの詳細を省略しました。詳細については、お気軽にお問い合わせください。

前もって感謝します、

4

1 に答える 1

5

プロファイル作成時に行います。

プロセス全体を逆にしてみてください。内容を言葉でチェックするのではなく、言葉で内容の言葉をチェックする。

  1. エントリのコンテンツ投稿を単語に分割します (スペース上)
  2. 重複、データベース内の単語の最小サイズ未満のもの、最大サイズを超えるもの、および保持している「一般的な単語」リスト内のものを排除します。
  3. 各テーブルをチェックし、テーブルの一部にスペースを含むフレーズが含まれている場合は、%text% 検索を実行します。それ以外の場合は、直接一致 (はるかに高速) を実行するか、それが本当に大きな問題である場合はハッシュ テーブルを作成します。(私はこれを PHP 配列として実行し、何らかの方法で結果をキャッシュします。車輪を再発明する意味はありません)
  4. 大幅に縮小されたリストでリンクを作成します。

チェックしている単語数が 100,000 語に達したとしても、これを 1 秒未満に簡単に抑えることができるはずです。以前に、ベイジアン フィルターの単語リストをキャッシュせずに、これを正確に実行しました。

より小さなリストでは、貪欲に "ピエロ" に一致しない単語を集めて "ピエロ ドジョウ" を捕まえたとしても、結果として得られる小さなリストはリンク付きの数単語から数十単語に過ぎないはずです。これは、テキストのチャンクを検索して置換するのにまったく時間がかかりません。

上記は、古いプロファイルに対するあなたの懸念に実際には対処していません。正確な数はわかりませんが、テキストが多く、1400 から 3100 (両方の項目) にあるというだけです。この古いコンテンツは、情報があれば人気に基づいて実行できます。または、入力された日付の新しい順。とにかく、これを行う最善の方法は、PHP の時間制限を一時停止し、すべての投稿で読み込み/処理/保存をバッチ実行するスクリプトを作成することです。それぞれが約1秒かかる場合(おそらくはるかに短いですが、最悪の場合)、1時間弱の3100秒を話していることになります。

于 2012-06-15T15:33:56.673 に答える