ラック
Home > CMS > 記事 > 2018年3月 > WordPressのタイトルと本文を置換したい

WordPressのタイトルと本文を置換したい

カテゴリ: WordPress

WordPressの記事のタイトルと本文を「ある特定の文字列があったら、(ユーザの入力、管理画面での編集内容に関わらず)一括で置換したい」という要望があり、これを何とかして実装できないかと考えました。

やりたいこととしては、サイトの閲覧者がページ閲覧のGETリクエストを受け取り、サーバで記事のタイトルと本文が出力、htmlのレスポンスを組み立てる処理を行うタイミングで、アクションフックないしアクションフィルターで処理を挟み込めば行けるだろう、と推測しました。

これに基づき、the_postフィルターで処理すれば良いと思い、以下のようなコードを記述。


if(!is_admin()) {
	function replace_title($post_object) {
        $arr = array("hoge", "piyo"); //検索したい文字列の配列
        $regexp_array = array(); //検索用正規表現の配列(下記ループで生成)
        $replace_array = array(); //置換したい文字列の配列(下記ループで生成)
        //キーから正規表現のセパレータ付きの文字列配列を作る
        foreach($arr as $value) {
            array_push($regexp_array, "/" . $value. "/i");
            array_push($replace_array, "" . $value . $value. ""); //"hoge"を"hogera"クラスを付与したspanタグでくくり、文字列自体も"hogehoge"に変更
        }
        //生成したキーの配列をパターンとして正規表現で検索、置換する
        $post_object -> post_title = preg_replace($regexp_array, $replace_array, $post_object -> post_title);
        $post_object -> post_content = preg_replace($regexp_array, $replace_array, $post_object -> post_content);
    }
    add_action('the_post', 'replace_title');
}

しかし、タイトルは書き変わるのですが、本文が書き変わってくれません。var_dumppreg_replace前後を見ると、きちんと書き変わっているのですが、実際の投稿の内容は書き変わっていないという謎現象。

この現象をTwitterやfacebookで書き込んだところ、WordPressの偉い方のお一人からアドバイスを頂きました。投稿の本文はthe_postフィルター前のcontent_paginationフィルターで処理された$pagesの値が使われるようです(content_paginationフィルターは4.4で追加されたフィルター)。なるほど、処理するタイミングが間違っていたのですね……。

第二引数にWP_Postとあるので投稿のオブジェクトをそのままそっくり持ってこられそうな気がするのですが、functionの引数に第二引数を指定してもnullになってしまったので、諦めて投稿本文だけ処理することにしました。そのため、the_postフィルターでタイトル、content_paginationフィルターで本文、と処理が分かれてしまいましたが、下記のようなコードに。


if(!is_admin()) {
	function replace_title($post_object) {
        $arr = array("hoge", "piyo"); //検索したい文字列の配列
        $regexp_array = array(); //検索用正規表現の配列(下記ループで生成)
        $replace_array = array(); //置換したい文字列の配列(下記ループで生成)
        //キーから正規表現のセパレータ付きの文字列配列を作る
        foreach($arr as $value) {
            array_push($regexp_array, "/" . $value. "/i");
            array_push($replace_array, "" . $value . $value. ""); //"hoge"を"hogera"クラスを付与したspanタグでくくり、文字列自体も"hogehoge"に変更
        }
        //生成したキーの配列をパターンとして正規表現で検索、置換する
        $post_object -> post_title = preg_replace($regexp_array, $replace_array, $post_object -> post_title);
    }
    add_action('the_post', 'replace_title');

    function replace_content($pages) {
        $arr = array("hoge", "piyo"); //検索したい文字列の配列
        $regexp_array = array(); //検索用正規表現の配列(下記ループで生成)
        $replace_array = array(); //置換したい文字列の配列(下記ループで生成)
        //キーから正規表現のセパレータ付きの文字列配列を作る
        foreach($arr as $value) {
            array_push($regexp_array, "/" . $value. "/i");
            array_push($replace_array, "" . $value . $value. ""); //"hoge"を"hogera"クラスを付与したspanタグでくくり、文字列自体も"hogehoge"に変更
        }
        //生成したキーの配列をパターンとして正規表現で検索、置換する
        $pages = preg_replace($regexp_array, $replace_array, $pages);
        return $pages;
    }
    add_action('content_pagination', 'replace_content');
}

これで一括置換できることを確認しました。

追記(3/14)

上記の方法で確かに一括置換はできたのですが……一括置換「し過ぎ」ました。

どういうことかというと、「地の文の文字列は置換するが、htmlタグ内の値は置換したくない」のです。例えば、


<p>aaaaa hoge aaaaaa<p><!-- テキストのhogeは置換する -->
<img src="./images/path/image01.jpg" alt="hoge"> <!-- alt属性の中のhogeは置換したくない -->

こんな感じ。ということで、上記のコードを修正して、以下のようにしました。


if(!is_admin()) {
	function replace_title($post_object) {
        $arr = array("hoge", "piyo"); //検索したい文字列の配列
        $regexp_array = array(); //検索用正規表現の配列(下記ループで生成)
        $replace_array = array(); //置換したい文字列の配列(下記ループで生成)
        //キーから正規表現のセパレータ付きの文字列配列を作る
        foreach($arr as $value) {
            array_push($regexp_array, "/" . $value. "(?![^<]*\"([^'\">]*?)(>|\/>))/i");
            array_push($replace_array, "" . $value . $value. ""); //"hoge"を"hogera"クラスを付与したspanタグでくくり、文字列自体も"hogehoge"に変更
        }
        //生成したキーの配列をパターンとして正規表現で検索、置換する
        $post_object -> post_title = preg_replace($regexp_array, $replace_array, $post_object -> post_title);
    }
    add_action('the_post', 'replace_title');

    function replace_content($pages) {
        $arr = array("hoge", "piyo"); //検索したい文字列の配列
        $regexp_array = array(); //検索用正規表現の配列(下記ループで生成)
        $replace_array = array(); //置換したい文字列の配列(下記ループで生成)
        //キーから正規表現のセパレータ付きの文字列配列を作る
        foreach($arr as $value) {
            array_push($regexp_array, "/" . $value. "(?![^<]*\"([^'\">]*?)(>|\/>))/i");
            array_push($replace_array, "" . $value . $value. ""); //"hoge"を"hogera"クラスを付与したspanタグでくくり、文字列自体も"hogehoge"に変更
        }
        //生成したキーの配列をパターンとして正規表現で検索、置換する
        $pages = preg_replace($regexp_array, $replace_array, $pages);
        return $pages;
    }
    add_action('content_pagination', 'replace_content');
}

検索文字列の後ろに">" />がある場合は処理しない、という感じにするために(?![^<]*\"(.+?)(>|\/>))を追記した形になります。

参考

タグ: プラグイン,カスタマイズ

 



関連する記事一覧