前台搜尋自訂文章類型(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 比較不熟的可以研究一下我的作法,上述的方式可以自訂搜尋顯示樣式,也可以自訂搜尋規則,我已經放在 GitHub 上,上面檔案為這篇最後完成的程式碼,中間過程程式碼參閱上面,那就寫到這裡啦~!下篇再見!掰!
留言