Algolia の InstantSearch.js を使って、WordPress の固定ページ (テンプレート) で、投稿の検索ページを作成する。

# ０．はじめに

[CloudFront 適用済みの WordPress サイトを、Shifter へ移行する。 \- Qiita](https://qiita.com/kusokamayarou/items/bb2ddce5f917935cfecc)

という記事に書いたんですが、

先日、[WordPress](https://wordpress.com) を [Shifter](https://go.getshifter.io) に移行しました。

問い合わせフォームやら、予約フォームやらについては、サードパーティのサービスを使ってうまいこと静的化できたんですが…、

検索ページについては、あまり利用されていないこともあって、ちょっと保留にしていて…

ただ、そろそろちゃんとしないとなぁ…、というところで、

[Algolia](https://www.algolia.com/) を利用して頑張って作ってみました。

動き的には、こんな感じです。

* [お役立ち \- 1分でステップアップできる現場お役立ちブログ \- \| 現場クラウド Conne （コンネ）](https://conne.genbasupport.com/tips/)

---

こちらの [@t2hnd](https://qiita.com/t2hnd) さんの記事が非常に参考になりました。

というか、まんま利用させて頂いたといった方が正しいかも…。

* [Kindle Library の蔵書をAlgoliaで検索する \- Qiita](https://qiita.com/t2hnd/items/88ceb9e2177197286432)

[@t2hnd](https://qiita.com/t2hnd) さん、本当にありがとうございました !!!

感謝 ♪♪♪

😘😘😘

# １． [Algolia](https://www.algolia.com/) に [WordPress](https://wordpress.com) の投稿データをインポートする。

1. [Shifter](https://go.getshifter.io) のサポートドキュメントに掲載されている、こちらの記事の手順に従って、[WP Search with Algolia](https://wordpress.org/plugins/wp-search-with-algolia/) プラグインをインストールして、[Algolia](https://www.algolia.com/) に [WordPress](https://wordpress.com) の投稿データをインポートします。
    * [Integrating Algolia Search with WordPress \| Shifter Documentation](https://support.getshifter.io/en/articles/762156-integrating-algolia-search-with-wordpress)
    * 手順と異なる点としては、以下。
        * <b><font color="red">[Algolia Search] -> [Autocomplete] で、[Enable autocomplete] にチェックしない。</font></b>
            * ※ Autocomplete 機能を利用しない為、また、この機能を有効にすると IE11 で正常に動作しない為。
        * <b><font color="red">[Algolia Search] -> [Search Page] で、[Do not use Algolia] にチェック。</font></b>
            * ※ サイト内で [WordPress](https://wordpress.com) のデフォルトの検索ボックスを利用しない為。
1. 検索一覧で表示する際の投稿内容のスニペットの値を設定します。[Algolia](https://www.algolia.com/) のダッシュボードから所定の Indices (wp_posts_post) を選択し、以下の設定を変更します。
    * Configuration
        * PAGINATION AND DISPLAY
            * Snippeting
                * ※ それぞれのデザインレイアウトに合わせて、各値を変更して下さい。
                * ※ 今回は、content をデフォルトの 30 から 99 に変更。
<br><br>
    * ![FireShot Capture 464 - Indices - Algolia - www.algolia.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161939/d55f733a-1a9b-505c-1474-1612240d60d6.png)

# ２． [WordPress](https://wordpress.com) テーマに、固定ページのテンプレートを追加し、固定ページを新たに作成する。

1. 以下の３つのファイルを[WordPress](https://wordpress.com) テーマに追加します。
    * ./page-algolia.php

    ```php:page-algolia.php
        <?php
        /*
        Template Name: algolia 検索用ページのテンプレート
        */
        
        // 特定のテンプレートのみにCSSを追加する | WordPressカスタマイズ事典
        // http://wpcj.net/1587
        function add_files() {
            wp_enqueue_style( 'style-page-algolia', get_template_directory_uri() . '/page-algolia.css' );
            //[Javascript] Moment.jsを使って日付を扱おう - YoheiM .NET https://www.yoheim.net/blog.php?q=20180201
            wp_enqueue_script( 'script-ajax-moment', 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js' );
            // Polyfill.io https://polyfill.io/v3/url-builder/
            wp_enqueue_script( 'script-polyfill-features', 'https://polyfill.io/v3/polyfill.min.js?features=Object.assign%2CObject.entries' );
            // webpackでPromiseを使用する(IE対策) - Qiita https://qiita.com/gdtypk/items/1ec4c8e895b0a9a5c0c2
            wp_enqueue_script( 'script-polyfills-promise', 'https://www.promisejs.org/polyfills/promise-7.0.4.min.js' );
        }
        add_action( 'wp_enqueue_scripts', 'add_files');
        
        get_header(); ?>
        
            <div id="primary" class="content-area">
                <main id="main" class="site-main" role="main">
                    <?php
                    while ( have_posts() ) : the_post();
        
                        get_template_part( 'template-parts/content', 'algolia' );
        
                    endwhile; // End of the loop.
                    ?>
        
                </main><!-- #main -->
            </div><!-- #primary -->
        
        <?php
        get_footer();
```
    * ./page-algolia.css
        * <b><font color="red">※ ファイルの内容については、テーマのデザインレイアウトによって変更する必要があります。</font></b>
        * <b><font color="red">※ 詳細については、以降に記載。</font></b>

    ```php:page-algolia.css
        .tips-content {
            width: 1500px;
        }
        @media only screen and (min-width: 900px) {
            .tips-content {
                display: -webkit-box;
                display: -ms-flexbox;
                display: flex;
                justify-content: space-between;
                align-items: flex-start;
            }
            .tips-content .tips-main-content {
                width: 76%;
            }
            .tips-content .tips-sub-content {
                width: 20%;
            }
            .search-panel {
                display: -webkit-box;
                display: -ms-flexbox;
                display: flex;
                justify-content: space-between;
                align-items: flex-start;
                margin: 0;
            }
            .search-panel .left-panel {
                width: 25%;
            }
            .search-panel .news-content {
                width: 73%;
            }
        }
        .left-panel h2 {
            margin: 0;
        }
        .tips-content .post-content {
            display: inline-block;
            word-break: break-all;
        }
        .tips-content .post-content .post-img {
            width: 180px;
            display: inline-block;
            vertical-align: top;
        }
        .tips-content .post-content .post-txt {
            width: calc(100% - 204px);
            display: inline-block;
            vertical-align: top;
        }
        
        /* RefinementList-list */
        .ais-RefinementList-list {
            margin: 0;
            padding: 0;
            list-style: none;
            font-weight: normal;
            line-height: 1.5;
        }
        .ais-RefinementList-item {
            margin: 1rem 0 1rem 0;
            padding: 0;
        }
        .ais-RefinementList-count {
            padding: 0.1rem 0.4rem;
            font-size: 0.8rem;
            color: #3a4570;
            background-color: #dfe2ee;
            border-radius: 8px;
        }
        
        /* Stats */
        .ais-Stats {
            margin: 0 0 1rem 0;
        }
        .ais-Stats-text {
            font-size: small;
        }
        
        /* SearchBox */
        .ais-SearchBox {
            color: #3a4570;
            margin: 0 0 0 0;
        }
        .ais-SearchBox-form {
            display: block;
            position: relative;
        }
        .ais-SearchBox-submit,
        .ais-SearchBox-reset {
            padding: 0;
            overflow: visible;
            font: inherit;
            line-height: normal;
            color: inherit;
            background: none;
            border: 0;
            cursor: pointer;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
        }
        .ais-SearchBox-submit,
        .ais-SearchBox-reset,
        .ais-SearchBox-loadingIndicator {
            -webkit-appearance: none;
            -moz-appearance: none;
            appearance: none;
            position: absolute;
            z-index: 1;
            width: 20px;
            height: 20px;
            top: 50%;
            right: 0.3rem;
            -webkit-transform: translateY(-50%);
            transform: translateY(-50%);
        }
        .ais-SearchBox-submit {
            left: 0.3rem;
        }
        .ais-SearchBox-reset {
            right: 0.3rem;
        }
        .ais-SearchBox-submit::-moz-focus-inner,
        .ais-SearchBox-reset::-moz-focus-inner {
            padding: 0;
            border: 0;
        }
        .ais-SearchBox-submit[disabled],
        .ais-SearchBox-reset[disabled] {
            cursor: default;
        }
        .ais-SearchBox-input::-ms-clear, .ais-SearchBox-input::-ms-reveal {
            display: none;
            width: 0;
            height: 0;
        }
        .ais-SearchBox-input::-webkit-search-decoration, .ais-SearchBox-input::-webkit-search-cancel-button, .ais-SearchBox-input::-webkit-search-results-button, .ais-SearchBox-input::-webkit-search-results-decoration {
            display: none;
        }
        .ais-SearchBox-input {
            -webkit-appearance: none;
            -moz-appearance: none;
            appearance: none;
            padding: 0.3rem 1.7rem;
            width: 100%;
            position: relative;
            background-color: #fff;
            border: 1px solid #c4c8d8;
            border-radius: 5px;
        }
        .ais-SearchBox-input::-webkit-input-placeholder {
            color: #a5aed1;
        }
        .ais-SearchBox-input::-moz-placeholder {
            color: #a5aed1;
        }
        .ais-SearchBox-input:-ms-input-placeholder {
            color: #a5aed1;
        }
        .ais-SearchBox-input:-moz-placeholder {
            color: #a5aed1;
        }
        .ais-SearchBox-submitIcon,
        .ais-SearchBox-resetIcon,
        .ais-SearchBox-loadingIcon {
            position: absolute;
            top: 50%;
            left: 50%;
            -webkit-transform: translateX(-50%) translateY(-50%);
            transform: translateX(-50%) translateY(-50%);
        }
        .ais-SearchBox-submitIcon path,
        .ais-SearchBox-resetIcon path {
            fill: #495588;
        }
        .ais-SearchBox-submitIcon {
            width: 14px;
            height: 14px;
        }
        .ais-SearchBox-resetIcon {
            width: 12px;
            height: 12px;
        }
        .ais-SearchBox-loadingIcon {
            width: 16px;
            height: 16px;
        }
        #searchbox .ais-SearchBox .ais-SearchBox-form input {
            font-size: 1rem;
            padding-left: 2rem;
        }
        
        /* Hits-list */
        .ais-Hits-list {
            margin: 0;
            padding: 0;
        }
        
        /* Highlight */
        .ais-Highlight-highlighted,
        .ais-Snippet-highlighted {
            background-color: #ffc168;
        }
        
        /* Pagination */
        .ais-Pagination {
            color: #3a4570;
            list-style: none;
        }
        .ais-Pagination-list {
            display: flex;
            display: -webkit-box;
            display: -ms-flexbox;
            margin: 0;
            padding: 0;
            list-style: none;
            align-items: center;
            justify-content: center;
            -webkit-box-align: center;
            -webkit-box-pack: center;
            -ms-flex-align: center;
            -ms-flex-pack: center;
        }
        .ais-Pagination-link {
            display: block;
            color: #0096db;
            padding: 0.3rem 0.6rem;
            border: 1px solid #c4c8d8;
            border-radius: 5px;
            transition: color 0.2s ease-out;
            transition: background-color 0.2s ease-out;
            -webkit-transition: color 0.2s ease-out;
            -webkit-transition: background-color 0.2s ease-out;
        }
        .ais-Pagination-link:hover,
        .ais-Pagination-link:focus {
            color: #0073a8;
        }
        .ais-Pagination-item + .ais-Pagination-item {
            margin-left: 0.3rem;
            list-style: none;
        }
        .ais-Pagination-link:hover, .ais-Pagination-link:focus {
            background-color: #e3e5ec;
        }
        .ais-Pagination-item--disabled .ais-Pagination-link {
            opacity: 0.6;
            cursor: not-allowed;
            color: #a5abc4;
        }
        .ais-Pagination-item--disabled .ais-Pagination-link:hover, .ais-Pagination-item--disabled .ais-Pagination-link:focus {
            color: #a5abc4;
            background-color: #fff;
        }
        .ais-Pagination-item--selected .ais-Pagination-link {
            color: #fff;
            background-color: #0096db;
            border-color: #0096db;
        }
        .ais-Pagination-item--selected .ais-Pagination-link:hover, .ais-Pagination-item--selected .ais-Pagination-link:focus {
            color: #fff;
        }
        #pagination {
            margin: 2rem auto;
            text-align: center;
        }
```
    * ./template-parts/content-algolia.php
<br><br>
        * Index Name : 'wp_posts_post' ※ [Algolia](https://www.algolia.com/) の所定のインデックス名
        * Application ID : ※ [Algolia](https://www.algolia.com/) の所定の Application の ID
        * Search-Only API Key : ※ [Algolia](https://www.algolia.com/) の所定の Application の Search-Only API Key
<br><br>
        * ![FireShot Capture 467 - API Keys - Algolia - www.algolia.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161939/f62ccece-2088-c12d-d28c-6e2953e87e8f.png)
<br><br>
        * <b><font color="red">※ ファイルの内容については、テーマのデザインレイアウトによって変更する必要があります。</font></b>
        * <b><font color="red">※ 詳細については、以降に記載。</font></b>

    ```php:content-algolia.php
        <?php
        /**
         * Template part for displaying posts
         *
         * @link https://codex.wordpress.org/Template_Hierarchy
         *
         * @package genba-conne
         */
        
        // Kindle Library の蔵書をAlgoliaで検索する - Qiita https://qiita.com/t2hnd/items/88ceb9e2177197286432
        
        ?>
        
        <article>
            <header class="entry-header">
                <div class="entry-header-img"></div>
                <h1 class="entry-title">カイゼン</h1>
            </header><!-- .entry-header -->
            <?php get_template_part( 'inc/breadcrumb'); ?>
            <div class="tips-content">
                <div class="tips-main-content">
                    <div class="search-panel">
                        <div class="left-panel">
                            <h2>CATEGORY</h2>
                            <div id="refinementList"></div>
                        </div><!-- left-panel -->
                        <div class="news-content news-info">
                            <div id="searchbox"></div>
                            <div id="stats"></div>
                            <ul>
                                <div id="hits"></div>
                            </ul>
                            <div id="pagination" class="text-center"></div>
                        </div><!-- news-content news-info -->
                    </div><!-- search-panel -->
                </div><!-- tips-main-content -->
                <div class="tips-sub-content">
                    <div class="side-widget-area" role="complementary">
                        <?php dynamic_sidebar( 'sidebar-2' ); ?>
                    </div><!-- side-widget-area -->
                </div><!-- tips-sub-content -->
            </div>
        </article>
        
        <script src="https://cdn.jsdelivr.net/npm/algoliasearch@4.0.0/dist/algoliasearch-lite.umd.js" integrity="sha256-MfeKq2Aw9VAkaE9Caes2NOxQf6vUa8Av0JqcUXUGkd0=" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4.0.0/dist/instantsearch.production.min.js" integrity="sha256-6S7q0JJs/Kx4kb/fv0oMjS855QTz5Rc2hh9AkIUjUsk=" crossorigin="anonymous"></script>
        
        <script>
            var search = instantsearch({
                indexName: '[Index Name]',
                searchClient: algoliasearch('[Application ID]', '[Search-Only API Key]'),
                routing: true,
            });
            search.addWidgets([
                // facetingAfterDistinct is not showing the correct values - Open Q&A - Algolia Community 
                // https://discourse.algolia.com/t/facetingafterdistinct-is-not-showing-the-correct-values/9712
                instantsearch.widgets.configure({
                    facetingAfterDistinct: true,
                    hitsPerPage: 5,
                }),
                instantsearch.widgets.searchBox({
                    container: '#searchbox',
                }),
                instantsearch.widgets.stats({
                    container: '#stats',
                }),
                instantsearch.widgets.hits({
                    container: '#hits',
                    templates: {
                        // mustache記法について簡単にまとめてみた - Qiita https://qiita.com/sengok/items/1d958348215647a5eaf0
                        empty: '<div class="text-center">No results found matching <strong>{{query}}</strong>.</div>',
                        item: '\
                            <div class="post-info">\
                            <span class="post-date">{{post_date_formatted}}</span>\
                            {{#taxonomies.category}}<span class="post-cat cat-column">{{.}}</span>{{/taxonomies.category}}\
                            </div>\
                            <div class="post-content">\
                            <div class="post-img"><a href="{{permalink}}">\
                            {{#images.thumbnail}}<img src="{{images.thumbnail.url}}" alt="{{post_title}}" title="{{post_title}}" itemprop="image" />{{/images.thumbnail}}\
                            {{^images.thumbnail}}<img src="/wp-content/themes/genba-conne-theme/images/logo.png" alt="{{post_title}}" title="{{post_title}}" itemprop="image" />{{/images.thumbnail}}\
                            </a></div>\
                            <div class="post-txt">\
                            <h3 class="post-title">\
                            <a href="{{permalink}}" title="{{post_title}}" itemprop="url">\
                            {{#helpers.highlight}}{ "attribute": "post_title" }{{/helpers.highlight}}\
                            </a>\
                            </h3>\
                            <div class="post-excerpt">\
                            <a href="{{permalink}}" title="{{content}}" itemprop="url">\
                            <p>{{#helpers.snippet}}{ "attribute": "content" }{{/helpers.snippet}}</p>\
                            </a>\
                            </div>\
                            <div class="post-btn">\
                            <a href="{{permalink}}"><i class="fa fa-arrow-circle-right"> 続きを読む</i></a>\
                            </div>\
                            </div>\
                            </div>',
                    },
                    // hits | InstantSearch.js | API parameters | API Reference | Algolia Documentation https://www.algolia.com/doc/api-reference/widgets/hits/js/
                    // customized hit widget new transformItems not highlighting · Issue #3544 · algolia/instantsearch.js https://github.com/algolia/instantsearch.js/issues/3544
                    // Build a Production grade Search experience using Algolia & MongoDB. (No Webserver Required ) | by Arneesh Aima | Data Driven Investor | Medium
                    // https://medium.com/datadriveninvestor/build-a-production-grade-search-experience-using-algolia-mongodb-no-webserver-required-6ff0661bf228
                    // Edit result templates widgets.hits - Show & Tell - Algolia Community https://discourse.algolia.com/t/edit-result-templates-widgets-hits/8538
                    /*transformItems: items => items.map(function(item) {
                        console.log(item)
                        console.log(moment.unix(item.post_date).format("YYYY年MM月DD日"))
                        return {
                            ...item
                        }
                    }),*/
                }),
                instantsearch.widgets.pagination({
                    container: '#pagination',
                }),
                instantsearch.widgets.refinementList({
                    container: "#refinementList",
                    attribute: "taxonomies.category",
                    searchable: false,
                    showMore: false,
                    sortBy: ['name:asc'],
                }),
            ]);
            search.start();
        </script>
```
<br>
1. [WordPress](https://wordpress.com) で固定ページを作成し、追加したテンプレートを選択します。
    * <img width="840" alt="スクリーンショット 2020-08-12 10.05.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161939/5b529166-0d32-7464-0b7a-3cbccc2e6640.png">

## ※ 各種ファイルの簡単な説明

### ※ ./page-algolia.css

* テーマのデザインレイアウトに合わせたページのスタイルの設定

```php
.tips-content {
    width: 1500px;
}
@media only screen and (min-width: 900px) {
    .tips-content {
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        justify-content: space-between;
        align-items: flex-start;
    }
    .tips-content .tips-main-content {
        width: 76%;
    }
    .tips-content .tips-sub-content {
        width: 20%;
    }
    .search-panel {
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        justify-content: space-between;
        align-items: flex-start;
        margin: 0;
    }
    .search-panel .left-panel {
        width: 25%;
    }
    .search-panel .news-content {
        width: 73%;
    }
}
.left-panel h2 {
    margin: 0;
}
.tips-content .post-content {
    display: inline-block;
    word-break: break-all;
}
.tips-content .post-content .post-img {
    width: 180px;
    display: inline-block;
    vertical-align: top;
}
.tips-content .post-content .post-txt {
    width: calc(100% - 204px);
    display: inline-block;
    vertical-align: top;
}
```

* 検索結果一覧の左側に表示されるカテゴリのフィルタのスタイルの設定
    * ※ 参考 : https://cdn.jsdelivr.net/npm/instantsearch.css@7.3.1/themes/algolia.css

```php
/* RefinementList-list */
.ais-RefinementList-list {
    margin: 0;
    padding: 0;
    list-style: none;
    font-weight: normal;
    line-height: 1.5;
}
.ais-RefinementList-item {
    margin: 1rem 0 1rem 0;
    padding: 0;
}
.ais-RefinementList-count {
    padding: 0.1rem 0.4rem;
    font-size: 0.8rem;
    color: #3a4570;
    background-color: #dfe2ee;
    border-radius: 8px;
}
```

* 検索結果一覧の上部に表示される検索ボックスのスタイルの設定
    * ※ 参考 : https://cdn.jsdelivr.net/npm/instantsearch.css@7.3.1/themes/algolia.css

```php
/* SearchBox */
.ais-SearchBox {
    color: #3a4570;
    margin: 0 0 0 0;
}
.ais-SearchBox-form {
    display: block;
    position: relative;
}
.ais-SearchBox-submit,
.ais-SearchBox-reset {
    padding: 0;
    overflow: visible;
    font: inherit;
    line-height: normal;
    color: inherit;
    background: none;
    border: 0;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.ais-SearchBox-submit,
.ais-SearchBox-reset,
.ais-SearchBox-loadingIndicator {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    position: absolute;
    z-index: 1;
    width: 20px;
    height: 20px;
    top: 50%;
    right: 0.3rem;
    -webkit-transform: translateY(-50%);
    transform: translateY(-50%);
}
.ais-SearchBox-submit {
    left: 0.3rem;
}
.ais-SearchBox-reset {
    right: 0.3rem;
}
.ais-SearchBox-submit::-moz-focus-inner,
.ais-SearchBox-reset::-moz-focus-inner {
    padding: 0;
    border: 0;
}
.ais-SearchBox-submit[disabled],
.ais-SearchBox-reset[disabled] {
    cursor: default;
}
.ais-SearchBox-input::-ms-clear, .ais-SearchBox-input::-ms-reveal {
    display: none;
    width: 0;
    height: 0;
}
.ais-SearchBox-input::-webkit-search-decoration, .ais-SearchBox-input::-webkit-search-cancel-button, .ais-SearchBox-input::-webkit-search-results-button, .ais-SearchBox-input::-webkit-search-results-decoration {
    display: none;
}
.ais-SearchBox-input {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    padding: 0.3rem 1.7rem;
    width: 100%;
    position: relative;
    background-color: #fff;
    border: 1px solid #c4c8d8;
    border-radius: 5px;
}
.ais-SearchBox-input::-webkit-input-placeholder {
    color: #a5aed1;
}
.ais-SearchBox-input::-moz-placeholder {
    color: #a5aed1;
}
.ais-SearchBox-input:-ms-input-placeholder {
    color: #a5aed1;
}
.ais-SearchBox-input:-moz-placeholder {
    color: #a5aed1;
}
.ais-SearchBox-submitIcon,
.ais-SearchBox-resetIcon,
.ais-SearchBox-loadingIcon {
    position: absolute;
    top: 50%;
    left: 50%;
    -webkit-transform: translateX(-50%) translateY(-50%);
    transform: translateX(-50%) translateY(-50%);
}
.ais-SearchBox-submitIcon path,
.ais-SearchBox-resetIcon path {
    fill: #495588;
}
.ais-SearchBox-submitIcon {
    width: 14px;
    height: 14px;
}
.ais-SearchBox-resetIcon {
    width: 12px;
    height: 12px;
}
.ais-SearchBox-loadingIcon {
    width: 16px;
    height: 16px;
}
#searchbox .ais-SearchBox .ais-SearchBox-form input {
    font-size: 1rem;
    padding-left: 2rem;
}
```

* 検索ボックスの下に表示される検索結果のステータスのスタイルの設定
    * ※ 参考 : https://cdn.jsdelivr.net/npm/instantsearch.css@7.3.1/themes/algolia.css

```php
/* Stats */
.ais-Stats {
    margin: 0 0 1rem 0;
}
.ais-Stats-text {
    font-size: small;
}
```

* 検索結果一覧の枠のスタイルの設定
    * ※ 参考 : https://cdn.jsdelivr.net/npm/instantsearch.css@7.3.1/themes/algolia.css

```php
/* Hits-list */
.ais-Hits-list {
    margin: 0;
    padding: 0;
}
```

* 検索文字列のハイライトのスタイルの設定
    * ※ 参考 : https://cdn.jsdelivr.net/npm/instantsearch.css@7.3.1/themes/algolia.css

```php
/* Highlight */
.ais-Highlight-highlighted,
.ais-Snippet-highlighted {
    background-color: #ffc168;
}
```

* 検索結果一覧のページネーションのスタイルの設定
    * ※ 参考 : https://cdn.jsdelivr.net/npm/instantsearch.css@7.3.1/themes/algolia.css

```php
/* Pagination */
.ais-Pagination {
    color: #3a4570;
    list-style: none;
}
.ais-Pagination-list {
    display: flex;
    display: -webkit-box;
    display: -ms-flexbox;
    margin: 0;
    padding: 0;
    list-style: none;
    align-items: center;
    justify-content: center;
    -webkit-box-align: center;
    -webkit-box-pack: center;
    -ms-flex-align: center;
    -ms-flex-pack: center;
}
.ais-Pagination-link {
    display: block;
    color: #0096db;
    padding: 0.3rem 0.6rem;
    border: 1px solid #c4c8d8;
    border-radius: 5px;
    transition: color 0.2s ease-out;
    transition: background-color 0.2s ease-out;
    -webkit-transition: color 0.2s ease-out;
    -webkit-transition: background-color 0.2s ease-out;
}
.ais-Pagination-link:hover,
.ais-Pagination-link:focus {
    color: #0073a8;
}
.ais-Pagination-item + .ais-Pagination-item {
    margin-left: 0.3rem;
    list-style: none;
}
.ais-Pagination-link:hover, .ais-Pagination-link:focus {
    background-color: #e3e5ec;
}
.ais-Pagination-item--disabled .ais-Pagination-link {
    opacity: 0.6;
    cursor: not-allowed;
    color: #a5abc4;
}
.ais-Pagination-item--disabled .ais-Pagination-link:hover, .ais-Pagination-item--disabled .ais-Pagination-link:focus {
    color: #a5abc4;
    background-color: #fff;
}
.ais-Pagination-item--selected .ais-Pagination-link {
    color: #fff;
    background-color: #0096db;
    border-color: #0096db;
}
.ais-Pagination-item--selected .ais-Pagination-link:hover, .ais-Pagination-item--selected .ais-Pagination-link:focus {
    color: #fff;
}
#pagination {
    margin: 2rem auto;
    text-align: center;
}
```

### ※ ./template-parts/content-algolia.php

* テーマのデザインレイアウトに合わせたページのコンテンツの設定
    * `<div id="refinementList"></div>` : カテゴリのフィルタ
    * `<div id="searchbox"></div>` : 検索ボックス
    * `<div id="stats"></div>` : 検索結果ステータス
    * `<div id="hits"></div>` : 検索結果一覧
    * `<div id="pagination" class="text-center"></div>` : 検索結果のページネーション

```html
<article>
    <header class="entry-header">
        <div class="entry-header-img"></div>
        <h1 class="entry-title">カイゼン</h1>
    </header><!-- .entry-header -->
    <?php get_template_part( 'inc/breadcrumb'); ?>
    <div class="tips-content">
        <div class="tips-main-content">
            <div class="search-panel">
                <div class="left-panel">
                    <h2>CATEGORY</h2>
                    <div id="refinementList"></div>
                </div><!-- left-panel -->
                <div class="news-content news-info">
                    <div id="searchbox"></div>
                    <div id="stats"></div>
                    <ul>
                        <div id="hits"></div>
                    </ul>
                    <div id="pagination" class="text-center"></div>
                </div><!-- news-content news-info -->
            </div><!-- search-panel -->
        </div><!-- tips-main-content -->
        <div class="tips-sub-content">
            <div class="side-widget-area" role="complementary">
                <?php dynamic_sidebar( 'sidebar-2' ); ?>
            </div><!-- side-widget-area -->
        </div><!-- tips-sub-content -->
    </div>
</article>
```

* 外部スクリプトの読み込み
    * `https://〜/algoliasearch-lite.umd.js` :
        * [Quick Start with the JavaScript API Client \| JavaScript \| Tutorials \| Algolia Documentation](https://www.algolia.com/doc/guides/getting-started/quick-start/tutorials/quick-start-with-the-api-client/javascript/?language=javascript)
    * `https://〜/instantsearch.production.min.js` :
        * [Algolia](https://www.algolia.com/) の [InstantSearch\.js](https://www.algolia.com/doc/api-reference/widgets/js/) ライブラリ

```html
<script src="https://cdn.jsdelivr.net/npm/algoliasearch@4.0.0/dist/algoliasearch-lite.umd.js" integrity="sha256-MfeKq2Aw9VAkaE9Caes2NOxQf6vUa8Av0JqcUXUGkd0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4.0.0/dist/instantsearch.production.min.js" integrity="sha256-6S7q0JJs/Kx4kb/fv0oMjS855QTz5Rc2hh9AkIUjUsk=" crossorigin="anonymous"></script>
```

* 検索時に実行されるスクリプト
    * `instantsearch.widgets.configure` :
        * [configure \| InstantSearch\.js \| API parameters \| API Reference \| Algolia Documentation](https://www.algolia.com/doc/api-reference/widgets/configure/js/)
    * `instantsearch.widgets.searchBox` :
        * [searchBox \| InstantSearch\.js \| API parameters \| API Reference \| Algolia Documentation](https://www.algolia.com/doc/api-reference/widgets/search-box/js/)
    * `instantsearch.widgets.stats` :
        * [stats \| InstantSearch\.js \| API parameters \| API Reference \| Algolia Documentation](https://www.algolia.com/doc/api-reference/widgets/stats/js/)
    * `instantsearch.widgets.hits` :
        * [hits \| InstantSearch\.js \| API parameters \| API Reference \| Algolia Documentation](https://www.algolia.com/doc/api-reference/widgets/hits/js/)
    * `instantsearch.widgets.pagination` :
        * [pagination \| InstantSearch\.js \| API parameters \| API Reference \| Algolia Documentation](https://www.algolia.com/doc/api-reference/widgets/pagination/js/)
    * `instantsearch.widgets.refinementList` :
        * [refinementList \| InstantSearch\.js \| API parameters \| API Reference \| Algolia Documentation](https://www.algolia.com/doc/api-reference/widgets/refinement-list/js/)

```javascript
<script>
    var search = instantsearch({
        indexName: '[Index Name]',
        searchClient: algoliasearch('[Application ID]', '[Search-Only API Key]'),
        routing: true,
    });
    search.addWidgets([
        // facetingAfterDistinct is not showing the correct values - Open Q&A - Algolia Community 
        // https://discourse.algolia.com/t/facetingafterdistinct-is-not-showing-the-correct-values/9712
        instantsearch.widgets.configure({
            facetingAfterDistinct: true,
            hitsPerPage: 5,
        }),
        instantsearch.widgets.searchBox({
            container: '#searchbox',
        }),
        instantsearch.widgets.stats({
            container: '#stats',
        }),
        instantsearch.widgets.hits({
            container: '#hits',
            templates: {
                〜〜〜
            },
            // hits | InstantSearch.js | API parameters | API Reference | Algolia Documentation https://www.algolia.com/doc/api-reference/widgets/hits/js/
            // customized hit widget new transformItems not highlighting · Issue #3544 · algolia/instantsearch.js https://github.com/algolia/instantsearch.js/issues/3544
            // Build a Production grade Search experience using Algolia & MongoDB. (No Webserver Required ) | by Arneesh Aima | Data Driven Investor | Medium
            // https://medium.com/datadriveninvestor/build-a-production-grade-search-experience-using-algolia-mongodb-no-webserver-required-6ff0661bf228
            // Edit result templates widgets.hits - Show & Tell - Algolia Community https://discourse.algolia.com/t/edit-result-templates-widgets-hits/8538
            /*transformItems: items => items.map(function(item) {
                console.log(item)
                console.log(moment.unix(item.post_date).format("YYYY年MM月DD日"))
                return {
                    ...item
                }
            }),*/
        }),
        instantsearch.widgets.pagination({
            container: '#pagination',
        }),
        instantsearch.widgets.refinementList({
            container: "#refinementList",
            attribute: "taxonomies.category",
            searchable: false,
            showMore: false,
            sortBy: ['name:asc'],
        }),
    ]);
    search.start();
</script>
```

* 検索結果の一投稿毎のコンテンツの設定
    * [\{\{ mustache \}\}](https://mustache.github.io/) 記法に倣っているみたい？？？
        *  [mustache記法について簡単にまとめてみた \- Qiita](https://qiita.com/sengok/items/1d958348215647a5eaf0)
    * `{{#helpers.highlight}}{ "attribute": "xxxx" }{{/helpers.highlight}}` : [highlight \| InstantSearch\.js \| API parameters \| API Reference \| Algolia Documentation](https://www.algolia.com/doc/api-reference/widgets/highlight/js/)
    * `{{#helpers.snippet}}{ "attribute": "xxxx" }{{/helpers.snippet}}` : [snippet \| InstantSearch\.js \| API parameters \| API Reference \| Algolia Documentation](https://www.algolia.com/doc/api-reference/widgets/snippet/js/)
    * [Algolia](https://www.algolia.com/)からのレスポンス項目例
        * `__position: 1`
        * `_highlightResult: {post_title: {value: "タイトル", matchLevel: "none", matchedWords: []}, taxonomies: Object, content: Object}`
        * `_snippetResult: {post_title: {value: "タイトル", matchLevel: "none"}, content: {matchLevel: "full", value: "〜〜〜"}}`
        * `comment_count: 0`
        * `content: "〜〜〜…"`
        * `images: {thumbnail: {url: "http://example.com/wp-content/uploads/YYYY/MM/DD00_000-150x150.png", width: 150, height: 150}}`
        * `is_sticky: 0`
        * `menu_order: 0`
        * `objectID: "0000-0"`
        * `permalink: "http://example.com/0000/"`
        * `post_author: {user_i * d: 0, display_name: "xxxx", user_url: "", user_login: "xxxx"}`
        * `post_date: 0000000000`
        * `post_date_formatted: "YYYY年M月D日"`
        * `post_excerpt: ""`
        * `post_id: 0000`
        * `post_mime_type: ""`
        * `post_modified: 0000000000`
        * `post_title: "タイトル"`
        * `post_type: "post"`
        * `post_type_label: "投稿"`
        * `record_index: 0`
        * `taxonomies: {category: ["カテゴリ"]}`
        * `taxonomies_hierarchical: {category: {lvl0: ["カテゴリ"]}}`

```javascript
templates: {
    // mustache記法について簡単にまとめてみた - Qiita https://qiita.com/sengok/items/1d958348215647a5eaf0
    empty: '<div class="text-center">No results found matching <strong>{{query}}</strong>.</div>',
    item: '\
        <div class="post-info">\
        <span class="post-date">{{post_date_formatted}}</span>\
        {{#taxonomies.category}}<span class="post-cat cat-column">{{.}}</span>{{/taxonomies.category}}\
        </div>\
        <div class="post-content">\
        <div class="post-img"><a href="{{permalink}}">\
        {{#images.thumbnail}}<img src="{{images.thumbnail.url}}" alt="{{post_title}}" title="{{post_title}}" itemprop="image" />{{/images.thumbnail}}\
        {{^images.thumbnail}}<img src="/wp-content/themes/genba-conne-theme/images/logo.png" alt="{{post_title}}" title="{{post_title}}" itemprop="image" />{{/images.thumbnail}}\
        </a></div>\
        <div class="post-txt">\
        <h3 class="post-title">\
        <a href="{{permalink}}" title="{{post_title}}" itemprop="url">\
        {{#helpers.highlight}}{ "attribute": "post_title" }{{/helpers.highlight}}\
        </a>\
        </h3>\
        <div class="post-excerpt">\
        <a href="{{permalink}}" title="{{content}}" itemprop="url">\
        <p>{{#helpers.snippet}}{ "attribute": "content" }{{/helpers.snippet}}</p>\
        </a>\
        </div>\
        <div class="post-btn">\
        <a href="{{permalink}}"><i class="fa fa-arrow-circle-right"> 続きを読む</i></a>\
        </div>\
        </div>\
        </div>',
},
```

# ９９．ハマりポイント

* 今回は、とにかくめちゃくちゃハマってました…。
* 結果を見れば、何だ、って感じなんですが、随分遠回りをしてエラい時間が掛かっちゃいました…。
<br><br>
* まず最初に、[WP Search with Algolia](https://wordpress.org/plugins/wp-search-with-algolia/) プラグインを改造したら、出来るんじゃないか？と思い、`wp-search-with-algolia-conne/templates/instantsearch.php` を色々いじって試したんですが、いざ [Shifter](https://go.getshifter.io) に移行したところ、全然ダメで…。
<br><br>
* その後、固定ページのテンプレートでやってみたところ、\{\{ mustache \}\}](https://mustache.github.io/) 記法に倣っていることに気付くのにも、エラい時間が掛かっちゃって…。
<br><br>
* それで、ようやく出来たと思ったら、IE11 だと正常に動かないことがわかって…。
<br><br>
* 他にも、[Algolia](https://www.algolia.com/)からのレスポンス項目にフォーマット化された作成日があることにも気付かなくて…。
<br><br>
* 正直、もう ウェブ も、[WordPress](https://wordpress.com) も、[Shifter](https://go.getshifter.io) も、[Algolia](https://www.algolia.com/) も、当分見たくない…

😫😫😫

# ＸＸ．まとめ

今回は、検索ページにサイドバーを表示する必要があったので、固定ページのレイアウトを作成しましたが、特にその必要が無ければ、固定ページの設定だけでも、作成することも出来ると思います。

私は、色々と遠回りして時間食っちゃいましたが、同じ様に、[Shifter](https://go.getshifter.io) に移行したり、検索ページの静的化をする時に、当記事がお役に立つと非常に嬉しいです。

参考になれば♪

👋👋👋