前台搜尋自訂文章類型(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 上,上面檔案為這篇最後完成的程式碼,中間過程程式碼參閱上面,那就寫到這裡啦~!下篇再見!掰!
留言