blogスタッフブログ
HOME > スタッフブログ > CMS >PowerCMS Xの全文検索で高度な動的ページネーションを実装する

PowerCMS Xの全文検索で高度な動的ページネーションを実装する

以前、PowerCMS Xで高度な動的ページネーションの実装を紹介しました。そこではオブジェクト一覧を表示するブロックタグの動的ページネーションを例にしていましたが、SearchEstraierプラグインによるサイト内全文検索(サイト内検索)機能のページネーションにも対応させることができます。

高度なページ送りのイメージ: ページ数が多い場合に…とページ数を省略表示している

今回はSearchEstraierプラグインで高度なページネーションの実装例を紹介します。

インクルード・モジュール「ページネーション」を作成

ビューに以下のインクルード・モジュールを作成します。

<mt:Var name="pagination_max_pages" value="3" note="ページネーションに表示する最大ページ数。奇数指定を推奨" />
<mt:Math eq="floor(x / 2)" x="$pagination_max_pages" setvar="pagination_half_number" />
<mt:Math eq="ceil(x / y)" x="$object_count" y="$pagination_limit" setvar="pagination_total_pages"  />
<mt:SetVarBlock name="is_omit"><mt:If name="pagination_total_pages" gt="$pagination_max_pages">1</mt:If></mt:SetVarBlock>

<mt:SetVarTemplate name="create_pager_link" note="ページネーションのリンク生成">
  <mt:Var name="current_archive_url" />?limit=<mt:Var name="pagination_limit" />
  <mt:If name="pager_offset">&offset=<mt:Var name="pager_offset" /></mt:If>
  <mt:If name="estraier_hit"><mt:Var name="search_param_str" replace="'?','&'" /><mt:Else>&_filter=<mt:Var name="pagination_filter_model" /></mt:If>
</mt:SetVarTemplate>
<mt:Var name="regex_pattern" value="/[\r|\n|\t|\s| | ]/g" note="create_pager_linkの不要な改行とスペース置換" />

<mt:If name="is_omit" note="pagination_max_pagesよりページが多ければ省略表示">
  <mt:Var name="current_page" decrement="$pagination_half_number" setvar="pagination_start_page" />
  <mt:Var name="current_page" increment="$pagination_half_number" setvar="pagination_end_page" />
  <mt:If name="pagination_start_page" lt="1">
    <mt:Var name="pagination_start_page" value="1" />
    <mt:Var name="pagination_end_page" value="$pagination_max_pages" />
  <mt:ElseIf name="pagination_end_page" gt="$pagination_total_pages">
    <mt:Math eq="x - (y - 1)" x="$pagination_total_pages" y="$pagination_max_pages" setvar="pagination_start_page" />
    <mt:Var name="pagination_end_page" value="$pagination_total_pages" />
  </mt:If>

<mt:Else note="pagination_max_pagesよりページが少なければ全て表示">
  <mt:Var name="pagination_start_page" value="1" />
  <mt:Var name="pagination_end_page" value="$pagination_max_pages" />
  <mt:If name="pagination_total_pages" lt="$pagination_max_pages">
    <mt:Var name="pagination_end_page" value="$pagination_total_pages" />
  </mt:If>
</mt:If>

<mt:If name="pagination_total_pages" gt="1" note="2ページ以上あればページネーションを生成">
  <mt:For from="$pagination_start_page" to="$pagination_end_page" step="1">
    <mt:If name="__first__">
      <div class="pagination">
        <mt:SetVarBlock name="has_prev"><mt:If name="current_page" gt="1">1</mt:If></mt:SetVarBlock>
        <mt:If name="has_prev" note="現在のページが2ページ目以降なら前ページへのリンクを生成">
          <div class="pagination__prev">
            <mt:SetVarBlock name="pager_offset"><mt:If name="estraier_prevoffset"><mt:Var name="estraier_prevoffset" /><mt:ElseIf name="prev_offset"><mt:Var name="prev_offset" /></mt:If></mt:SetVarBlock>
            <a href="<mt:Var name="create_pager_link" regex_replace="'$regex_pattern',''" />">前へ</a>
          </div><!-- /.pagination__prev -->
        </mt:If>

        <div class="pagination__page">
          <mt:If name="is_omit" note="省略表示する場合">
            <mt:If name="__value__" ne="1" note="最初のページへのリンクがない場合、リンクを生成">
              <mt:Var name="pager_offset" value="" />
              <a href="<mt:Var name="create_pager_link" regex_replace="'$regex_pattern',''" />"<mt:If name="__value__" eq="$current_page"> class="-is-current"</mt:If>>1</a>

              <mt:If name="__value__" gt="2" note="pagination_start_pageが3以上なら...を挿入">
                <span class="pagination__omission">...</span>
              </mt:If>
            </mt:If>
          </mt:If>
    </mt:If>

    <mt:SetVarBlock name="pager_offset"><mt:Math eq="(x - 1) * y" x="$__value__" y="$pagination_limit" /></mt:SetVarBlock>
    <a href="<mt:Var name="create_pager_link" regex_replace="'$regex_pattern',''" />"<mt:If name="__value__" eq="$current_page"> class="-is-current"</mt:If>><mt:Var name="__value__" /></a>

    <mt:If name="__last__">
          <mt:If name="is_omit" note="省略表示する場合">
            <mt:If name="__value__" ne="$pagination_total_pages" note="最後のページへのリンクがない場合、リンクを生成">
              <mt:SetVarBlock name="end_prev_page"><mt:Var name="pagination_total_pages" decrement="1" /></mt:SetVarBlock>
              <mt:If name="__value__" ne="$end_prev_page" note="pagination_end_pageが最後のページより2以上小さければ...を挿入">
                <span class="pagination__omission">...</span>
              </mt:If>

              <mt:SetVarBlock name="pager_offset"><mt:Math eq="(x - 1) * y" x="$pagination_total_pages" y="$pagination_limit" /></mt:SetVarBlock>
              <a href="<mt:Var name="create_pager_link" regex_replace="'$regex_pattern',''" />"<mt:If name="__value__" eq="$current_page"> class="-is-current"</mt:If>><mt:Var name="pagination_total_pages" /></a>
            </mt:If>
          </mt:If>
        </div><!-- /.pagination__page -->

        <mt:SetVarBlock name="has_next"><mt:If name="current_page" lt="$pagination_total_pages">1</mt:If></mt:SetVarBlock>
        <mt:If name="has_next" note="現在のページが最後のページ以外なら次ページへのリンクを生成">
          <div class="pagination__next">
            <mt:SetVarBlock name="pager_offset"><mt:If name="estraier_nextoffset"><mt:Var name="estraier_nextoffset" /><mt:ElseIf name="next_offset"><mt:Var name="next_offset" /><mt:Else><mt:Var name="pagination_limit" /></mt:If></mt:SetVarBlock>
            <a href="<mt:Var name="create_pager_link" regex_replace="'$regex_pattern',''" />">次へ</a>
          </div><!-- /.pagination__next -->
        </mt:If>
      </div><!-- / .pagination -->
    </mt:If>
  </mt:For>
</mt:If>

PowerCMS Xで高度な動的ページネーションの実装からSearchEstraierプラグインのページネーションに対応させるため3箇所変更しています。なお、以下のコードではブロックタグ <mt:EstraierSearch>prefix="estraier_" と指定してブロックタグ内でセットされるテンプレート変数が estraier_xxxx となる事を想定しています。

// 変更前
<mt:SetVarTemplate name="create_pager_link" note="ページネーションのリンク生成">
  <mt:Var name="current_archive_url" />?limit=<mt:Var name="pagination_limit" />
  <mt:If name="pager_offset">&offset=<mt:Var name="pager_offset" /></mt:If>
  &_filter=<mt:Var name="pagination_filter_model" />
</mt:SetVarTemplate>

// 変更後
<mt:SetVarTemplate name="create_pager_link" note="ページネーションのリンク生成">
  <mt:Var name="current_archive_url" />?limit=<mt:Var name="pagination_limit" />
  <mt:If name="pager_offset">&offset=<mt:Var name="pager_offset" /></mt:If>
  <mt:If name="estraier_hit"><mt:Var name="search_param_str" replace="'?','&'" /><mt:Else>&_filter=<mt:Var name="pagination_filter_model" /></mt:If>
</mt:SetVarTemplate>
// 変更前
<mt:SetVarBlock name="pager_offset"><mt:If name="prev_offset"><mt:Var name="prev_offset" /></mt:If></mt:SetVarBlock>

// 変更後
<mt:SetVarBlock name="pager_offset"><mt:If name="estraier_prevoffset"><mt:Var name="estraier_prevoffset" /><mt:ElseIf name="prev_offset"><mt:Var name="prev_offset" /></mt:If></mt:SetVarBlock>
// 変更前
<mt:SetVarBlock name="pager_offset"><mt:If name="next_offset"><mt:Var name="next_offset" /><mt:Else><mt:Var name="pagination_limit" /></mt:If></mt:SetVarBlock>

// 変更後
<mt:SetVarBlock name="pager_offset"><mt:If name="estraier_nextoffset"><mt:Var name="estraier_nextoffset" /><mt:ElseIf name="next_offset"><mt:Var name="next_offset" /><mt:Else><mt:Var name="pagination_limit" /></mt:If></mt:SetVarBlock>

検索結果のページネーションの例

ポイントは estraier_hit を変数 object_count にセット、estraier_currentpage を変数 current_page にセットします。そうすることでオブジェクト一覧を表示するブロックタグでセットされるテンプレート変数と互換性を持たせています。

オブジェクト一覧を表示するブロックタグと全文検索のブロックタグで共通のページネーションモジュールが利用可能になります。

実際の実装では検索条件がquery(キーワード)だけではなく複雑になるかと思いますので適宜調整してください。

<mt:Var name="pagination_limit" value="10" note="ページ送り件数" />
<mt:Var name="request.offset" setvar="pagination_offset" />
<mt:Var name="request.query" setvar="query" />
<mt:If name="query">
  <mt:SetVarBlock name="search_param_str" function="push">query=<mt:Var name="query" /></mt:SetVarBlock>
</mt:If>
<mt:SetVarBlock name="search_param_str" note="ページネーションのリンクに検索条件を引き継ぐためにセット"><mt:If name="search_param_str">?<mt:Var name="search_param_str" join="&" /></mt:If></mt:SetVarBlock>
<mt:EstraierSearch phrase="$query" prefix="estraier_" workspace_ids="1" sort_by="@cdate" sort_order="NUMD" limit="$pagination_limit" offset="$pagination_offset">
  <mt:If name="__first__">
    <mt:Var name="object_count" value="$estraier_hit" note="条件に合致するオブジェクトの総数" />
    <mt:Var name="current_page" value="$estraier_currentpage" note="現在のページがページネーションの何ページ目かを示す数字" />
    <ul>
  </mt:If>
  // 中略
  <mt:If name="__last__">
    </ul>
    <mt:Include module="ページネーション" />
  </mt:If>
</mt:EstraierSearch>

さいごに

PowerCMS Xではインクルード・モジュールを工夫することで異なるブロックタグであっても共通モジュールとすることができます。あまり複雑になるとパフォーマンスやメンテナンス性が低下する恐れもありますが、今回のケースでは共通モジュールとすることでデザインや仕様変更に対応しやすくなるメリットがあります。

最近の記事

カテゴリ

アーカイブ

スタッフ別