前台搜尋自訂文章類型(search custom post type),在 wordpress 搜尋的方式我分為兩種,最基礎的就是透過原本架構,透過 search.php 或再載入範本(tamplate)顯示結果,另一種就是透過自訂 API 將結果顯示在想要的頁面或範本,兩者都可以製作自己想要的頁面,頁面範本可以使用兩種方式載入,一種是直接放在布景主題裡,另一種是使用外掛載入。

WordPress 基本搜尋框架 search.php

為了方便說明,創建一個簡單有沒什麼 HTML 的布景主題,佈景主題基本檔案有:index.php、hearder.php、footer.php、functions.php、style.css、search.php,這裡只會在修改的檔案演示,其他檔案內容,到我的 GiteHub 看完整檔案內容,下面是檔案裡面的內容:

<?php get_header();?>
<main class="container">
  <div class="bg-light p-5 rounded">
    <h4>打發時間 搜尋教學範本 dafatime.idv.tw</h4>
    <p class="text-danger">index.php 頁面</p>
    <form class="row g-3" method="GET" action="<?php echo home_url(); ?>">
  <div class="col-auto">
    <label for="search" class="visually-hidden">搜尋</label>
    <input type="search" class="form-control" id="search" placeholder="搜尋" name="s" value="<?php get_search_query(); ?>">
  </div>
   <div class="col-auto">
    <button type="submit" class="btn btn-primary mb-3">搜尋</button>
  </div>
</form>
</div>
</main>
<?php get_footer(); ?>
<?php get_header(); ?>
<main class="container">
  <div class="bg-light p-5 rounded">
  	<h4>打發時間 搜尋教學範本 dafatime.idv.tw</h4>
    <p class="text-danger">search.php 頁面</p>
    <form class="row g-3" method="GET" action="<?php echo home_url(); ?>">
  <div class="col-auto">
    <label for="search" class="visually-hidden">搜尋</label>
    <input type="search" class="form-control" id="search" placeholder="搜尋" name="s" value="<?php echo get_search_query(); ?>">
  </div>
   <div class="col-auto">
    <button type="submit" class="btn btn-primary mb-3">搜尋</button>
  </div>
</form>
</div>
<div class="row">
	<div class="col">
    <ul class="list-group">
      <?php 
      //判斷有沒有搜尋調內容
      if ( have_posts() ) : ?>
        <p class="text-danger">content-search.php 範本</p>
        <?php
        // 搜尋結果迴圈
        while ( have_posts() ) : the_post();
        //這裡會導到 content-search.php 範本檔案
        get_template_part( 'template/content', 'search' );
        endwhile; 
      
    else: ?>
       
       <p class="text-danger">content-none.php 範本</p>
       <?php
        // 沒有找到文章導到 content-none.php 沒找到範本檔案
        get_template_part( 'template/content', 'none' );
      endif; ?>
    </ul>
	</div>
</div>
</main>
<?php get_footer(); ?>

上面的程式碼算是最乾淨的,搜尋結果會顯在 search.php 頁面上,如下圖:

在 search.php 添加搜尋範本

而官方或是大多都會在 search.php 檔案內直接使用 get_template_part() 直接導向搜尋結果的範本檔案,沒有搜尋到文章會導要沒有找到的範本檔案,search.php 程式碼如下:

<?php get_header(); ?>
<main class="container">
  <div class="bg-light p-5 rounded">
  	<h4>打發時間 搜尋教學範本 dafatime.idv.tw</h4>
    <p class="text-danger">Search.php 頁面</p>
    <form class="row g-3" method="GET" action="<?php echo home_url(); ?>">
  <div class="col-auto">
    <label for="search" class="visually-hidden">搜尋</label>
    <input type="search" class="form-control" id="search" placeholder="搜尋" name="s" value="<?php echo get_search_query(); ?>">
  </div>
   <div class="col-auto">
    <button type="submit" class="btn btn-primary mb-3">搜尋</button>
  </div>
</form>
</div>
<div class="row">
	<div class="col">
    <ul class="list-group">
      <?php 
      //判斷有沒有搜尋調內容
      if ( have_posts() ) :
        // 搜尋結果迴圈
	  	while ( have_posts() ) : the_post();
        //這裡會導到 content-search.php 範本檔案
        get_template_part( 'template/content', 'search' );
       	endwhile; 
      
      else:
        // 沒有找到文章導到 content-none.php 沒找到範本檔案
        get_template_part( 'template/content', 'none' );
      endif; ?>
    </ul>
	</div>
</div>
</main>
<?php get_footer(); ?>

這裡使用 have_posts() 還檢查是否有搜尋到文章,搜尋到文章會導到 content-search.php 範本,找不到文章會導到 content-none.php 範本,兩個範本檔案程式碼如下:

<li id="post-<?php the_ID(); ?>" class="list-group-item <?php post_class(); ?>">
    <?php the_title();?>
</li>
<li id="post-<?php the_ID(); ?>" class="list-group-item <?php post_class(); ?>">
    <span class="text-danger">沒有找到任何文章! </span>
</li>

可能會覺得範本的內容很少,我並沒做什麼樣式,所以範本樣式要做得如何就看需求,上面的基本搜尋都只會搜尋文章類型為 post,在之前幾篇教學有自訂文章類型為 books 是不會搜到的,接下來為了不干擾原本的文章搜尋,我會開一個新的頁面範本,來作為 books 的搜尋頁面與定義新的 API 來做搜尋詞的傳遞。

WordPress 搜尋自訂文章類型

我建立一個 books-search.php 範本,範本名稱為 “books 搜尋頁面”,再建立一個 Books Search 頁面,頁面選擇 “books 搜尋頁面”範本,範本內程式碼入下:

<?php
/**
 * Template Name: Books 搜尋頁面
 */
get_header();
?>
<main class="container">
  <div class="bg-light p-5 rounded">
  	<h4>打發時間 搜尋 books 文章類型 dafatime.idv.tw</h4>
    <p class="text-danger">books-search.php 頁面</p>
    <form class="row g-3" method="GET" action="<?php echo home_url('/books-search/'); ?>">
  <div class="col-auto">
    <label for="search" class="visually-hidden">搜尋</label>
    <input type="search" class="form-control" id="search" placeholder="搜尋" name="b" value="<?php echo $_GET['b'] ?? ''; ?>">
  </div>
   <div class="col-auto">
    <button type="submit" class="btn btn-primary mb-3">搜尋</button>
  </div>
</form>
</div>
<div class="row">
	<div class="col">
    <ul class="list-group">
      <?php 
      //得到搜尋詞,沒有搜尋詞為空值
      $books_word = $_GET['b'] ?? '';
	  //只搜尋 books 文章類型
      $args = array(
        'post_type' => 'books',
        's' => $books_word,
      );
      $books_query = new WP_Query( $args );
      //判斷有沒有搜尋調內容
      if ( $books_query->have_posts() ) : ?>
        
        <?php
        //這個判斷可以在無值時不會顯示出所有文章
        if ( empty($books_word) ){
            return;
        }
        // 搜尋結果迴圈
        while ( $books_query->have_posts() ) : $books_query->the_post();?>
        <li id="post-<?php the_ID(); ?>" class="list-group-item <?php post_class(); ?>">
        <?php the_title();?>
        </li>
        <?php endwhile; 
      
        else: ?>
        <li  class="list-group-item">
        <span class="text-danger">沒有找到任何文章! </span>
        </li>
      <?php endif; ?>
    </ul>
	</div>
</div>
</main>
<?php get_footer();

上面程式碼只會搜尋自訂文章類型,在第29行定義搜尋 books 文章類型與搜尋詞,使用 WP_Query() 回圈搜尋到的文章列表出來。

搜尋表單 FORM

第12行 form 使用 GET 的動作 action 傳送回 Books Search 頁面(這裡我就沒有產生一個列表頁面,而是在同一頁顯示搜尋結果),第15行為搜尋框 name 改為 “b”,這個就自訂搜尋 API 參數,原本 WP 搜尋 API 為 “s”,傳送搜尋詞的網址後面為 ?s=搜尋詞,這裡定義 “b” 傳送搜尋詞的網址後面會變成 ?b=搜尋詞,這種方式就可以自己定義搜尋參數,如下圖。

如何搜尋自訂欄位的內容

上面的的搜尋都不會搜尋自訂欄位的內容,因為自訂欄位內容是存在另一張資料表,上面程式碼添加’meta_query’,就可以搜尋自訂文章類型與自訂定欄位裡面的內容,下面就是修改的程式碼:

<?php
/**
 * Template Name: Books 搜尋頁面
 */
get_header();
?>
<main class="container">
  <div class="bg-light p-5 rounded">
  	<h4>打發時間 搜尋 books 文章類型 dafatime.idv.tw</h4>
    <p class="text-danger">books-search.php 頁面</p>
    <form class="row g-3" method="GET" action="<?php echo home_url('/books-search/'); ?>">
  <div class="col-auto">
    <label for="search" class="visually-hidden">搜尋</label>
    <input type="search" class="form-control" id="search" placeholder="搜尋" name="b" value="<?php echo $_GET['b'] ?? ''; ?>">
  </div>
   <div class="col-auto">
    <button type="submit" class="btn btn-primary mb-3">搜尋</button>
  </div>
</form>
</div>
<div class="row">
	<div class="col">
    <ul class="list-group">
      <?php 
      $books_word = $_GET['b'] ?? '';
      //只搜尋 books 文章類型
      $args = array(
        'post_type' => 'books',
        // 's' => $books_word,
        'meta_query' => array(
          'relation' => 'OR',
          array(
            'meta_key' => 'isbn', // 欄位名稱
            'value' => $books_word, // 搜尋字串
            'compare' => 'LIKE' // 使用 LIKE 比較
            ),
          array(
            'meta_key' => 'publish_date', // 欄位名稱
            'value' => $books_word, // 搜尋字串
            'compare' => 'LIKE' // 使用 LIKE 比較
            )
          )
      );
      $books_query = new WP_Query( $args );
      //判斷有沒有搜尋調內容
      if ( $books_query->have_posts() ) : ?>
        
        <?php
        //這個判斷可以在無值時不會顯示出所有文章
        if ( empty($books_word) ){
            return;
        }
        // 搜尋結果迴圈
        while ( $books_query->have_posts() ) : $books_query->the_post();?>
        <li id="post-<?php the_ID(); ?>" class="list-group-item <?php post_class(); ?>">
        <?php the_title();?>
        </li>
        <?php endwhile; 
      
        else: ?>
        <li  class="list-group-item">
        <span class="text-danger">沒有找到任何文章! </span>
        </li>
      <?php endif; 
      wp_reset_postdata(); // 重設 WP_Query 的設定?>
    </ul>
	</div>
</div>
</main>
<?php get_footer();

在上述程式碼中,$args 參數用於搜尋自訂欄位。我已經設定了搜尋 isbn 和出版日期兩個自訂欄位,但是你們可能已經注意到了,在第30行我加上了註解!經過多次測試後,我發現如果我想要搜尋文章標題、內容以及自訂欄位,卻得不到任何搜尋結果😏讓我糾結了好幾天(原本這篇文章兩週前就該發布),只好放大絕了~!直接使用SQL指令來實現對文章標題、內容以及自訂欄位的搜尋。

使用SQL指令進行搜尋

<?php
/**
 * Template Name: Books 搜尋頁面
 */
get_header();
?>
<main class="container">
  <div class="bg-light p-5 rounded">
  	<h4>打發時間 搜尋 books 文章類型 dafatime.idv.tw</h4>
    <p class="text-danger">books-search.php 頁面</p>
    <form class="row g-3" method="GET" action="<?php echo home_url('/books-search/'); ?>">
  <div class="col-auto">
    <label for="search" class="visually-hidden">搜尋</label>
    <input type="search" class="form-control" id="search" placeholder="搜尋" name="b" value="<?php echo $_GET['b'] ?? ''; ?>">
  </div>
   <div class="col-auto">
    <button type="submit" class="btn btn-primary mb-3">搜尋</button>
  </div>
</form>
</div>
<div class="row">
	<div class="col">
    <ul class="list-group">
      <?php 
      global $wpdb;
      $wp_posts = $wpdb->prefix . 'posts';
      $wp_postmeta = $wpdb->prefix . 'postmeta';
      $books_word = $_GET['b'] ?? '';
	  //SQL 指令 以點長,我調整了一下postmeta資料表結構,在 JOIN
      $join_sql = $wpdb->prepare("SELECT  p.ID,   
                                          p.post_title, 
                                          p.post_content,
                                          pm.isbn,
                                          pm.publish_date
                                          FROM (SELECT
                                            post_id,
                                            MAX(CASE WHEN meta_key = 'isbn' THEN meta_value END) AS isbn,
                                            MAX(CASE WHEN meta_key = 'publish_date' THEN meta_value END) AS publish_date
                                          FROM {$wp_postmeta}
                                          GROUP BY post_id) AS pm
                                          JOIN {$wp_posts} AS p
                                          ON p.ID = pm.post_id 
                                          WHERE post_type = 'books' AND
                                                post_status = 'publish'
                                                AND p.post_title LIKE '%".$books_word."%'
                                                OR p.post_content LIKE '%".$books_word."%'
                                                OR pm.isbn LIKE '%".$books_word."%'
                                                OR pm.publish_date LIKE '%".$books_word."%'");
  
      // 執行查詢
    $results = $wpdb->get_results($join_sql);
      // var_dump($books_query->request);
      //判斷有沒有搜尋調內容
      if ($results) {
        //這個判斷可以在無值時不會顯示出所有文章
        if ( empty($books_word) ){
            return;
        }
        // 搜尋結果迴圈
       foreach ($results as $result) {?>
        <li id="post-<?php echo $result->ID; ?>" class="list-group-item">
        <?php echo $result->post_title;?>
        </li>
       
       <?php }}else{ ?>
        <li  class="list-group-item">
        <span class="text-danger">沒有找到任何文章! </span>
        </li>
      <?php }; ?>
    </ul>
	</div>
</div>
</main>
<?php get_footer();

上面就是使用 SQL 指令方式來搜尋 posts 資料表與 postmeta 資料表,這樣就可以達到,對文章標題、內容以及自訂欄位進行搜尋,在第 44 行我只對 books 自訂文章類型來搜尋,對於 SQL 比較不熟的可以研究一下我的作法,上述的方式可以自訂搜尋顯示樣式,也可以自訂搜尋規則,注意一下!上面列出搜尋結果不是使用 WP_Query,我已經放在 GitHub 上,上面檔案為這篇最後完成的程式碼,中間過程程式碼參閱上面,那就寫到這裡啦~!下篇再見!掰!

最後修改日期: 2023 年 10 月 4 日

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。