概要
WordPressのマルチサイトでは、全ブログを対象とした検索ができない。
そこで全ブログを検索するコードを作成しました。
方針
- switch_to_blog()はペナルティが大きいらしく、サーバに負荷が掛かるようなのでやめる。
- カテゴリー、タグも検索対象とする。Wordpressデフォルトでは、本文、記事タイトルのみが検索対象のため。
作成したコード
wp-content/themes/(テンプレート)/search.php を次のようにしました。
search.php
<?php get_header(); ?>
<!?// ここから書き換え----------------------------------------------- //?>
<?php
global $wpdb;//mysqlのデータベース情報を格納しているグローバル変数$wpdb
$searchfor = get_search_query(); // 検索キーワード取得
?>
<h2>「<?php echo $searchfor; ?>」の検索結果</h2>
<?php
$sql="SHOW TABLES FROM $wpdb->dbname"; //テーブル一覧を取得するSQL文を作成
$res_rows = $wpdb->get_results($sql); //テーブル一覧を$res_rowsに格納
if(!$res_rows){
echo "【データベースエラー】テーブルリストの取得に失敗しました<br />\n";
echo "MySQL Error: ".mysqli_error();
exit;
}
$siteurl_chk_array=array(); //検出される記事のURLを重複を除外するためのチェック用配列(初期化)
foreach($res_rows as $data) { //$data にテーブルを格納するループ
// $objectToArray = (array)$data;
// print_r( array_values($objectToArray)[0] );
// オブジェクトを配列にして値取得
$tablename = array_values( (array)$data )[0]; //テーブル名取得
if( preg_match("/_posts/",$tablename) ) { //postsテーブルループ
if( !preg_match("/v_posts/",$tablename) ) {
# print($tablename);
$siteid="";
if (preg_match('/wp_(\d{1,4})/', $tablename, $tmp_match)){
$siteid = $tmp_match[1]."_";
}
$term_relationships = "wp_".$siteid."term_relationships";
$term_taxonomy = "wp_".$siteid."term_taxonomy";
$terms = "wp_".$siteid."terms";
$options = "wp_".$siteid."options";
// 検索用SQL
// 検索対象: 公開された記事で、記事本文(post_content), 記事タイトル(post_title),
// 記事カテゴリ/タグ名(wp_x_term.terms ), 抜粋(wp_x_term_taxonomy.description)
// → → 記事本文(post_content), 記事タイトル(post_title)で検索して見つかる記事
// または、記事カテゴリ/タグ名を検索し該当の term_id を使用する記事
$searchquery_posts =
"SELECT * FROM " .$tablename. "
WHERE post_status = 'publish' AND
(post_type = 'post' OR post_type = 'page') AND
(post_content LIKE '%" .$searchfor. "%' OR post_title LIKE '%" .$searchfor. "%'
OR ID IN (
SELECT distinct r.object_id
FROM ".$term_relationships." AS r
INNER JOIN ".$term_taxonomy." AS tt ON r.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN ".$terms." AS t ON tt.term_id = t.term_id
WHERE t.name LIKE '" .$searchfor. "'
OR t.slug LIKE '" .$searchfor. "'
OR tt.description LIKE '" .$searchfor. "'
)
)";
// 検索SQLを実行
$result_posts = $wpdb->get_results($searchquery_posts, ARRAY_A);
$siteurl=""; //各ブログのURL
if($result_posts===null){
continue;
}elseif ($result_posts) {
// 各ブログのURLを見つけるSQL
$searchquery_siteurl = "SELECT option_value FROM " .$options. " WHERE option_name = 'siteurl' ";
$siteurl = $wpdb->get_var($searchquery_siteurl);
if($siteurl===null){
continue;
}
}
}
}
// print_r($result_posts);
foreach($result_posts as $row) {//検索結果を表示するHTMLを出力
$tmpurl = $siteurl. "?page_id=" .$row['ID'];
if (!in_array($tmpurl, $siteurl_chk_array)){
echo "<div class='searchlink'><a href='";
print($tmpurl);
echo "'>「";
print($row['post_title']);
echo "」</a></div>";
print(mb_substr(strip_tags($row['post_content']),0,200));//contentからHTMLタグを取り除き200文字のみ表示
echo "<br />\n";
// 記事のURLを重複を除外するためのチェック用配列に追加
$siteurl_chk_array[] = $tmpurl;
}
}
}
// print_r($siteurl_chk_array);
?>
<!?// ここまで書き換え----------------------------------------------- //?>
<?php get_footer();
参考にしたサイト
-
流れはこの↓サイトのコードを参照にました(mysql_connect()などが、php5用だったため、php7で対応できるようにしました)。
https://d7r.com/2197
課題
- 検索結果が、一覧ですべて表示されます。ページネイション機能を入れて、ページ送りが必要です。
- → これは必須の機能ですね。。。
- 自作のHTMLのためWordpressデフォルトの検索結果ページデザインと異なってしまいます。検索結果ページをブログのデザインに合わせる必要があります。
- 複数語の検索には未対応です。検索文字が「AAA, BBB, CCC」とあったら、「AAA」, 「BBB」, 「CCC」の全部の単語が見つかるように検索ではなく、「AAA, BBB, CCC」という文字列で検索します。
- 検索結果は、見つかった順です。検出件数の多い順などでは、ありません。