検索結果に投稿内のhtml属性値を検索対象から除く

WordPressの検索では、検索結果にhtmlの属性値等でも、キーワードに含まれると検索結果に表示されます。

デフォルトの状態であれば、特に大きな不具合にはなりませんが 

最悪、例えば 投稿本文内でPHPが記述できるようなプラグインを使用したりしていれば、

$_GET 等をキーワードにすると、そこにPHPスクリプトが含まれている投稿であるという事が簡単に推測できてしまいます。
Insert PHP — WordPress Plugins を使って投稿本文にPHPを書いてみましょう
<?php echo $_GET; ?>

[insert_php]
echo 'hello world';
[/insert_php]

表示は以下のようになります。

htmlソースは、以下のようになります。

<div class="entry-content clearfix">
	<span id="read"></span><p><!--?php echo $_GET; ?--></p>
<p>hello world</p>
	<br class="clear">
</div>

PHPコードを直書きした部分は、WordPressがhtmlコメントを追加して、表示しないようになり、PHPの実行結果のhello wordが表示されます。

しかし、検索する場合はこれとは全く異なります。

検索すれば、insert_phpでも echo でも検索結果のページにこの投稿は、表示されます。

検索の場合は、実際に本文に記述された文字列を調べるので、検索にヒットするのです。

このページのコードは、このようなショートコードを検索でヒットさせないといったコードを目指しているわけではありませんが、検索機能が何を行っているかを解かりやすくするために、このような実験をしています。

WordPressの検索機能がそのようなものだと知っている人は、プラグインの使用を思いとどまる事もできるわけですが、そのような事に気づかないままに利用している人も少なくないだろうと思います。

Raindropsテーマでも、これまで検索フォームではhtmlタグを使えないといった処理を行ってきたわけですが、直接 urlに検索キーワードを打ち込むと検索できる状況にあり

いつかは取り組んでおくべきだろうと考えていました。

以前にも、検索結果を表示する仕組み – WordPress Snippetという記事の中で触れていましたが

日本語フォーラムでも トピック: ウィジェットの検索で画像ファイル名を対象外にしたい « サポートフォーラム — WordPress 等 似通った質問が時々見られます。

改めて、方法を模索してみようと思いました。

functions.php

add_filter('posts_where', 'raindrops_exclude_html_search' );

function raindrops_exclude_html_search($where) {
 if( is_search() ) {
 global $wpdb;
 $query= get_search_query();
 $query= $wpdb->esc_like( $query );

 $where .=" AND {$wpdb->posts}.post_content NOT REGEXP '\<{1}[^\>]*$query*[^\>]*\>{1}' ";
 }
 return $where;
}

searchform.php

 <form method="get" name="searchform" id="searchform" action="<?php echo esc_url( home_url( '/' ) ); ?>">
 <div class="searchform">
<label class="screen-reader-text" for="s"><?php esc_attr_e('Search for:', 'raindrops');?></label>
<input type="text" value="<?php the_search_query(); ?>" pattern="^[^(< |>)]+$" title="<?php esc_attr_e( 'must not contain html tags', 'raindrops' ); ?>" placeholder="<?php esc_attr_e( 'Search', 'raindrops' ); ?>" name="s" id="s" />
<input type="submit" id="searchsubmit" value="<?php esc_attr_e( 'Search', 'raindrops' ); ?>" />
 </div>
 </form>

Memo

wp-includes/class-wp-query.php

		/**
		 * Filters the prefix that indicates that a search term should be excluded from results.
		 *
		 * @since 4.7.0
		 *
		 * @param string $exclusion_prefix The prefix. Default '-'. Returning
		 *an empty value disables exclusions.
		 */
		$exclusion_prefix= apply_filters( 'wp_query_search_exclusion_prefix', '-' );

AMPプラグイン関連

AMPプラグインでは、PHPコード部分は、以下のように変換されていました。
致命的エラーが発生していました。

<i nsert_php="" echo="" world="">
[emulsion_relate_posts]