回答:
このソリューションは、CommonおよびLatin Unicodeスクリプトからの文字のみに一致する正規表現を適用することにより、検索文字列をフィルタリングします。
Stack Overflowで気が狂ったばかりです。結局のところ、正規表現には、Unicodeの「スクリプト」全体を指定する値を含むUnicodeカテゴリ全体を照合するメカニズムがあり、それぞれが異なる書記体系で使用される文字のグループに対応しています。
これは\p
、中かっこ内のメタ文字とそれに続くUnicodeカテゴリ識別子を使用して行われます。これにより[\p{Common}\p{Latin}]
、ラテン文字または共通文字のいずれかの単一の文字に一致します。これには、句読点、数字、その他の記号が含まれます。
@Paul「スパローホーク」ビロンが指摘、u
パターン修飾子フラグとして対象文字列を治療するためにPHPのPCRE機能のために、正規表現の末尾に設定されるべきであるUTF-8
Unicodeでエンコード。
まとめると、パターン
/^[\p{Latin}\p{Common}]+$/u
LatinおよびCommon Unicodeスクリプトの1つ以上の文字で構成される文字列全体と一致します。
WordPressがクエリを実行する直前に実行されるアクションは、pre_get_posts
検索文字列をインターセプトするのに適した場所です。でより多くのケア、これも使用して達成することができるフィルタを。request
function wpse261038_validate_search_characters( $query ) {
// Leave admin, non-main query, and non-search queries alone
if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
return;
// Check if the search string contains only Latin/Common Unicode characters
$match_result = preg_match( '/^[\p{Latin}\p{Common}]+$/u', $query->get( 's' ) );
// If the search string only contains Latin/Common characters, let it continue
if( 1 === $match_result )
return;
// If execution reaches this point, the search string contains non-Latin characters
//TODO: Handle non-Latin search strings
//TODO: Set up logic to display error message
}
add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );
検索文字列に非ラテン文字が含まれていることが確認されると、WP_Query::set()
名前付きのクエリ変数を変更してクエリを変更するために使用できます。これにより、SQLクエリに影響を与え、その後WordPressが作成して実行します。
最も関連性の高いクエリ変数は、おそらく次のとおりです。
s
検索文字列に対応するクエリ変数です。それをnull
空の文字列(''
)に設定すると、WordPressはクエリを検索として処理しなくなります-多くの場合、他の値に応じて、すべての投稿またはサイトのフロントページを表示するアーカイブテンプレートが作成されますクエリ変数。' '
ただし、1つのスペース()に設定すると、WordPressが検索として認識し、search.php
テンプレートを表示しようとします。page_id
ユーザーを選択した特定のページに誘導するために使用できます。post__in
クエリを特定の投稿の選択に制限できます。これを不可能な投稿IDの配列に設定することで、クエリがまったく何も返さないことを確認するための手段として機能します。上記を念頭に置いて、不適切な検索に対応するために、search.php
結果のないテンプレートをロードすることにより、次のことを実行できます。
function wpse261038_validate_search_characters( $query ) {
// Leave admin, non-main query, and non-search queries alone
if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
return;
// Check if the search string contains only Latin/Common Unicode characters
$match_result = preg_match( '/^[\p{Latin}\p{Common}]+$/u', $query->get( 's' ) );
// If the search string only contains Latin/Common characters, let it continue
if( 1 === $match_result )
return;
$query->set( 's', ' ' ); // Replace the non-latin search with an empty one
$query->set( 'post__in', array(0) ); // Make sure no post is ever returned
//TODO: Set up logic to display error message
}
add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );
実際にエラーメッセージを表示する方法は、アプリケーションとテーマの機能に大きく依存します。これを行うには多くの方法があります。テーマがget_search_form()
検索テンプレートを呼び出す場合、おそらく最も簡単な解決策は、pre_get_search_form
アクションフックを使用して、検索フォームのすぐ上にエラーを出力することです。
function wpse261038_validate_search_characters( $query ) {
// Leave admin, non-main query, and non-search queries alone
if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
return;
// Check if the search string contains only Latin/Common Unicode characters
$match_result = preg_match( '/^[\p{Latin}\p{Common}]+$/u', $query->get( 's' ) );
// If the search string only contains Latin/Common characters, let it continue
if( 1 === $match_result )
return;
$query->set( 's', ' ' ); // Replace the non-latin search with an empty one
$query->set( 'post__in', array(0) ); // Make sure no post is ever returned
add_action( 'pre_get_search_form', 'wpse261038_display_search_error' );
}
add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );
function wpse261038_display_search_error() {
echo '<div class="notice notice-error"><p>Your search could not be completed as it contains characters from non-Latin alphabets.<p></div>';
}
エラーメッセージを表示するための他のいくつかの可能性は次のとおりです。
wp_enqueue_script
フックを追加します。$priority
そのJavaScriptをエンキューするものよりも大きくwp_localize_script()
、エラーメッセージを含めるようにその変数を設定するために使用します。wp_redirect()
選択したURLにユーザーを送信するために使用します(この方法では、ページをさらに読み込む必要があります)。s
には、クエリ変数を''
代わりに' '
し、使用page_id
の代わりに、post__in
お好みのページを戻すために。loop_start
フックを使用して、WP_Post
エラーを含む偽のオブジェクトをクエリ結果に挿入します。これは間違いなく醜いハックであり、特定のテーマでは正しく見えない可能性がありますが、「結果なし」メッセージを抑制するという潜在的に望ましい副作用があります。template_include
フィルターフックを使用して、エラーを表示するテーマまたはプラグインの検索テンプレートをカスタムテンプレートと入れ替えます。問題のテーマを調べなければ、どのルートを取るべきかを判断するのは困難です。
以下の私の解決策は、文字列を構成するバイトの配置を調べることにより、魔法のようにアルファベットを神聖なものにするために、PHPのmbstring関数を悪用するハックです。これは本当に悪い考えであり、間違いを起こしがちです。
はるかにシンプルで信頼性の高いソリューションについては、他の回答を参照してください。
非ラテン系のアルファベットを使用した検索を防ぐ1つの方法は、PHPのmb_detect_encoding()
関数を使用して、検索文字列が文字エンコーディングのカスタム選択の1つに準拠しているかどうかを確認することです。これを行うのに適した場所はpre_get_posts
actionです。これは、クエリが実行される直前に実行されるためです。
検索が無効なエンコーディングを使用していると判断した後に実際に行うことは、実際にはアプリケーション固有です。ここでは、検索クエリを1つのスペースに設定して、WordPressがクエリを検索として解釈し、search.php
テンプレートを引き続きロードするようにします(検索文字列が空の文字列)。また、絶対に何も返されないことを確認するために、不可能な投稿IDを持つ配列に設定'post__in'
する追加の予防策も講じています。
別の方法として、あなたはに検索文字列を設定することを検討可能性があるnull
と設定page_id
、カスタムエラーメッセージを表示してページにユーザーを導くために。
function wpse261038_validate_search_query_encoding( $query ) {
$valid_encodings = array( 'Windows-1252' );
// Ignore admin, non-main query, and non-search queries
if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
return;
// Retrieve the encoding of the search string (if it's one listed in $valid_encodings)
$search_encoding = mb_detect_encoding( $query->get( 's' ), $valid_encodings, true );
// If the search encoding is one in $valid_encodings, leave the query as-is
if( in_array( $search_encoding, $valid_encodings ) )
return;
// If it wasn't, sabotage the search query
$query->set( 's', ' ' );
$query->set( 'post__in', array(0) );
// Set up your error message logic here somehow, perhaps one of the following:
// - Add a template_include filter to load a custom error template
// - Add a wp_enqueue_scripts hook with a greater priority than your theme/plugin's, and
// use wp_localize_script() in the hook to pass an error message for your JavaScript
// to display
// - Perform a wp_redirect() to send the user to the URL of your choice
// - Set a variable with an error message which your theme or plugin can display
}
add_action( 'pre_get_posts', 'wpse261038_validate_search_query_encoding' );
PHPでサポートされているすべてのデフォルトエンコーディングと異なるアルファベットのダミー文字列を比較するカバレッジテストを作成しました。完全に完璧ではありませんが(ダミー文字列がどれほど現実的であるかわからないため、日本語での検出が困難になるようです)、候補の決定には多少役立ちます。あなたはここでそれを実際に見ることができます。
そのテストによってフラグが付けられた潜在的な文字エンコーディングを調査したところWindows-1252
、ラテンアルファベットと一般的なラテン言語のアクセントをカバーすることは、ニーズに最適な選択のようです。
ISO-8859
文字セットの選択は別の実行可能な選択肢になるはずですが、頭を折り返すことができない理由により、個別のエンコーディングとしてリストされているにもかかわらず、mb_
関数はISO-8859
の異なる文字セットを区別していないようです。
他の一般的な文字を許可するには、を追加することも検討してくださいHTML-ENTITIES
。
ISO-8859
エンコーディングを区別できないようです。
彼は、数日前に同様の質問を投稿する場合、私は文字セット(またはスクリプト)を知って、@MichaelRogersに説明しようとしたとして、文字列で使用されないで検出するのに十分な言語その文字列のを。
したがって、@ boscoで詳述されているメソッドはロシア語などの文字列を削除しますが(以下の2つの修正を含む)、検索を英語に制限しません。
これを確認するには、次のことを試してください。
$strings = array (
'I\'m sorry', // English
'Je suis désolé', // French
'Es tut mir Leid', // German
'Lorem ipsum dolor sit amet', // Lorem ipsum
'أنا سعيد', // Arabic
'я счастлив', // Russian
'我很高兴', // Chinese (Simplified)
'我很高興', // Chinese (Traditional)
) ;
foreach ($strings as $s) {
if (preg_match ('/^[\p{Latin}\p{Common}]+$/u', $s) === 1) {
echo "$s: matches latin+common\n" ;
}
else {
echo "$s: does not match latin+common\n" ;
}
}
[ 注: @boscoが提供したものに対する上記の2つの修正は次のとおりです。
/u
修飾子を追加(パターンと件名をUTF-8エンコードとして扱うために必要。PHP:Regexパターン修飾子を参照)生成されます:
I'm sorry: matches latin+common
Je suis désolé: matches latin+common
Es tut mir Leid: matches latin+common
Lorem ipsum dolor sit amet: matches latin+common
أنا سعيد: does not match latin+common
я счастлив: does not match latin+common
我很高兴: does not match latin+common
我很高興: does not match latin+common
[ 注:私は英語、フランス語、一部のドイツ語(および少しのLorem ipsum :-) を話しますが、アラビア語、ロシア語、中国語はGoogle翻訳に依存しています]
ご覧のように、ラテン文字のチェックに依存しても、英語を持っているとは限りません。
StackOverflowにはいくつかのスレッドがあり(たとえば、PHPの文字列から言語を検出)、主題に関する詳細情報を提供しています。