WordPress ＋ Algoliaで、Algoliaの検索対象から特定の投稿（固定ページ、カスタム投稿タイプ）を除外する

# WordPress の検索機能に Algolia を利用する
具体的な方法は各ドキュメントを参考に。

## Algolia にアカウントを作ってAPIキーを取得する
Algolia

https://www.algolia.com/

## WordPress プラグインをインストールして設定
WP Search with Algolia

https://wordpress.org/plugins/wp-search-with-algolia/

ここまででデフォルトの検索ウィンドウや検索結果が置き換わるが、固定ページに検索結果ページを置いて、検索結果内で表示する投稿の各要素も調整したい場合は次のプラグインを入れてみよう。

Search with Algolia Instantsearch Blocks

https://wordpress.org/plugins/search-with-algolia-instantsearch-blocks/

# Algoliaの検索対象から特定の投稿（固定ページ、カスタム投稿タイプ）を除外したい
本記事の主題。

- サイトトップを固定ページにしてる
- ブログのアーカイブを固定ページに出している

など、**「表示もするし、XMLサイトマップや検索ロボットにインデックスさせたいけど、サイト内検索結果としては出したくない」**ケースを想定しています。

## ドキュメント
WP Search with Algolia プラグインの開発が Algolia からコミュニティ（WebDevStudios）に移管したので、プラグインのドキュメントはこちら。

https://github.com/WebDevStudios/wp-search-with-algolia/wiki/Automated-Sync

WordPress のデータを Algolia に自動同期させるタイミングでフィルターがあるので、条件・処理を加えることで Algolia に同期させない（検索の対象から除外）できる。

## 仕様・設計

- 投稿・固定ページにカスタムフィールドで「Algoliaの検索結果から除外」するフラグを作って保存する
    - メタボックスを作る
    - カスタムフィールドの保存（削除）
- 「Algolia の検索結果から除外」するフラグがある投稿・固定ページは Algolia に自動同期させる時のフィルターで送信させない

## WordPress メタボックスとカスタムフィールドの保存
https://developer.wordpress.org/reference/functions/add_meta_box/

ドキュメント通りに作っておけば良い。概ね下記のような設計になる。

- メタボックスを追加する
    - どの投稿タイプにメタボックスを出すのか？が必要
- メタボックスの中身
    - Nonce フィールド入れておこう。大事。
    - カスタムフィールドの中身があったらメタボックスの要素にちゃんと反映させよう
- カスタムフィールドの保存（削除）
    - Nonce チェック大事。ものすごく大事。大事なことなので2回書きました。
    - 自動保存時は保存しないようにする。
    - 権限チェック大事。
    - 送信された値を確認して、上書きするのか削除するのか

```php
<?php
// Register Meta box
function exclude_algolia_search_meta_boxes() {
	// カスタム投稿タイプを含むpublicな投稿タイプすべてにメタボックスを表示（追加）
	$args = array(
		'public'   => true,
	);
	$my_screens = get_post_types( $args );
	foreach ( $my_screens as $screen ) {
		add_meta_box( 'exclude_algolia_search', 'Exclude Algolia search', 'exclude_algolia_search_cb', $screen, 'side' );
	}

}
add_action( 'add_meta_boxes', 'exclude_algolia_search_meta_boxes', 10, 1 );

// Meta callback function
function exclude_algolia_search_cb( $post ) {
	// Add an nonce field so we can check for it later.
	wp_nonce_field( 'exclude_algolia_search_box', 'exclude_algolia_search_box_nonce' );

	// Use get_post_meta to retrieve an existing value from the database.
	$value = get_post_meta( $post->ID, 'exclude_algolia_search_flag', true );

	// Display the form, using the current value.
	?>
	<p><label><input type="checkbox" name="exclude_algolia_search_flag" value="1" <?php checked( $value, 1 ); ?> >
	Exclude Algolia search</label></p>
	<?php
}

// Save meta value with save post hook
function exclude_algolia_save_post( $post_id ) {
	/*
	 * We need to verify this came from the our screen and with proper authorization,
	 * because save_post can be triggered at other times.
	 */
	// Check if our nonce is set.
	if ( ! isset( $_POST['exclude_algolia_search_box_nonce'] ) ) {
		return $post_id;
	}

	// Verify that the nonce is valid.
	$nonce = $_POST['exclude_algolia_search_box_nonce'];
	if ( ! wp_verify_nonce( $nonce, 'exclude_algolia_search_box' ) ) {
		return $post_id;
	}

	/*
	 * If this is an autosave, our form has not been submitted,
	 * so we don't want to do anything.
	 */
	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
		return $post_id;
	}

	// Check the user's permissions.
	if ( 'page' == $_POST['post_type'] ) {
		if ( ! current_user_can( 'edit_page', $post_id ) ) {
			return $post_id;
		}
	} else {
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return $post_id;
		}
	}

	/* OK, it's safe for us to save the data now. */

	$value = isset($_POST['exclude_algolia_search_flag']) ? $_POST['exclude_algolia_search_flag'] : '';

	if ( ! empty( $value ) ) {
		update_post_meta( $post_id, 'exclude_algolia_search_flag', $value );
	} else {
		delete_post_meta( $post_id, 'exclude_algolia_search_flag' );
	}
}
add_action( 'save_post', 'exclude_algolia_save_post', 10, 1 );
```

## 「Algolia の検索結果から除外」するフラグがある投稿・固定ページは Algolia に自動同期させる時のフィルターで送信させない

ドキュメントにサンプルコードがあるので参考にして、 「Algolia の検索結果から除外」するフラグがあった場合の判定と処理を追加すれば良い。

https://github.com/WebDevStudios/wp-search-with-algolia/wiki/Automated-Sync

```php
// Hook into Algolia to manipulate the post that should be indexed.
function exclude_algolia_filter_post( $should_index, WP_Post $post ) {
	if ( false === $should_index ) {
		return false;
	}

	// カスタムフィールドを取得して除外する投稿の場合は false を返す
	$exclude_algolia_search_flag = get_post_meta( $post->ID, 'exclude_algolia_search_flag', true );
	if ( 1 == $exclude_algolia_search_flag ) {
		return false;
	}

	return $should_index;
}
// Hook into Algolia to manipulate the post that should be indexed.
add_filter( 'algolia_should_index_searchable_post', 'exclude_algolia_filter_post', 10, 2 );
add_filter( 'algolia_should_index_post', 'exclude_algolia_filter_post', 10, 2 );
```

# 完成形
gist にアップしてるのでダウンロード後（必要な場合は加工の上）、プラグインとして追加し有効化すれば使えます。

https://gist.github.com/gatespace/15479631f6b1051c2637d1f6522b3373

＊カスタム投稿タイプで動作しない場合は、すべてのインデックスをやり直して設定を送信すると、次から動きます。

現場からは以上です。