写在前面:
最近想给自己的博客实现一个 站内搜索 功能,期望整个过程异步实现。这样用户体验度更好。
遇到问题:
- 如何实现文章的模糊匹配?
- wordpress 如何提供接口?
- 页面如何实现异步请求接口数据,并完成页面的渲染?
问题1 – 模糊搜索:
大胆尝试:
wordpress 原生自带有一个 wp_query 函数,它支持的参数非常完善灵活,实现整个网站与数据库的交互。比如调用最新文章、热门文章、自定义文章类型文章循环输出等。
在官方手册中也有介绍到:wp_query,支持多种 sql 语句的 比较符号:

看!他说可以支持 like 或者 regexp 这种比较符号。
于是我们试一试:
$args = [ 'posts_per_page' => -1, // 每页数量 -1 不限制数量 'ignore_sticky_posts' => 1, // 'post_type' => 'post', // 'post_status' => 'publish', // 已经发布的文章 'meta_query' => [ [ 'key' => 'post_title', 'value' => 'Mac', // 'compare' => 'REGEXP', 'compare' => 'LIKE', ], ], ]; $result = new WP_Query($args);
// 判断查询的结果,检查是否有文章 if ( $result->have_posts() ) : // 通过查询的结果,开始主循环 while ( $result->have_posts() ) : $result->the_post(); //获取到特定的文章 // 要输出的内容,如标题、日期等 endwhile; endif;
但是很遗憾,不知道是我的姿势不对,就是不起作用?? 如果有大佬解决了,望不吝赐教!
转换思路:
其实在数据库使用 like 的查询效率是非常低,所以我们可以把这一部分的逻辑由 php 自己实现。
if ($result->have_posts()) { while ($result->have_posts()) { $result->the_post(); global $post; $post_title = get_the_title(); // mb_stripos 不区分大小 判断字符串中是否存在另一个字符串 if (mb_stripos($post_title, $keyword)) { $articles[] = [ 'id' => get_the_ID(), 'post_name' => $post->post_name, 'post_title' => $post_title, 'post_date' => $post->post_date, ]; } } }
所以,我们可以看到,通过 PHP 的 mb_stripos 可以实现字符串的模糊匹配,这样就可以筛选出我们想要的结果。
问题2 – 接口对接:
上面我们已经实现了文章的模糊匹配,接下来就要提供一个接口,来实现与前端的交互。所以,我们将会用到 wordpress 自带的 admin-ajax.php 文件。
实现原理:
要使用 admin-ajax.php 请求必然首先就是遇到如何使用 wordrpess 的钩子 hook 来做过滤。
//wp_ajax_nopriv_ 效验用户为未登录是启用的方法 add_action( 'wp_ajax_nopriv_search', 'search' ); //wp_ajax_ 效验用户为已登录是启用的方法 add_action( 'wp_ajax_search', 'search' );
具体接口:
我们看到上面 search 这个是我们要定义的搜索函数,逻辑就要用到了刚刚介绍的 模糊匹配 ,
但是其中几点需要注意到的是:
- header(“Content -Type: application/json”); // 指定返回头
- wp_die() //接口响应结束用这个函数结尾,否则会一直走到这个当前页面最下面,多返回一个 0;
- 需要将下面的代码添加到
if
( is_user_logged_in() )
这个代码之前!!!!
/ 文章搜索
function search()
{
$keyword = $_GET['keyword'] ?? $_GET['keyword'];
// 指定返回头
header("Content -Type: application/json");
if (empty($keyword)) {
echo $response = (json_encode([], JSON_UNESCAPED_UNICODE));
wp_die();
}
$args = [
'posts_per_page' => -1,
'ignore_sticky_posts' => 1,
'post_type' => 'post',
'post_status' => 'publish',
];
$result = new WP_Query($args);
$articles = [];
if ($result->have_posts()) {
while ($result->have_posts()) {
$result->the_post();
global $post;
$post_title = get_the_title();
if (mb_stripos($post_title, $keyword) !== false) {
$articles[] = [
'id' => get_the_ID(),
'post_name' => $post->post_name,
'post_title' => $post_title,
'post_date' => $post->post_date,
];
}
}
}
wp_reset_query();
echo $response = (json_encode($articles, JSON_UNESCAPED_UNICODE));
wp_die();
}
add_action( 'wp_ajax_nopriv_search', 'search' );
add_action( 'wp_ajax_search', 'search' );
调用方式:
示例:https://zhaoshuai.me/wp-admin/admin-ajax.php?action=search&keyword=cdn
上面我们用了 wordpress 的钩子函数,所以我们调用的时候用参数 action ,后面拼接相对应的 function
效果展示:

问题3 – 异步渲染
其实很简单,前两部已经完成大部分的工作。我们只需要添加一个监听输入框值变化的事件,使用 JQuery 的 ajax 请求接口就OK了。
$("#input-search").bind("input propertychange", function (event) {
search();
});
// 搜索文章
function search() {
var host = document.location.host;
var protocol = document.location.protocol;
var keyword = $("#input-search").val();
if (keyword.length > 0) {
$.ajax({
type: "GET",
url: protocol + '//' + host + "/wp-admin/admin-ajax.php?action=search&keyword=" + keyword,
data: {},
dataType: "json",
success: function (data) {
addArticle(data);
},
error: function (data) {
console.log(data);
}
});
}
}
上面我们可以看到,这样可以正确拿到接口返回的数据,接下来就是最重要的数据拼装。
由于我们没有框架去做,只能将 Html 标签 与 Js 语法进行拼接。
我们这里是用了 正则表达式 ,写了一个规则,可以通过 键值 格式化我们定义好的字符串,来人上代码!
String.prototype.format = function () {
if (arguments.length === 0) {
return this;
}
var param = arguments[0];
var s = this;
if (typeof (param) == 'object') {
for (var key in param)
s = s.replace(new RegExp("\\{" + key + "\\}", "g"), param[key]);
return s;
} else {
for (var i = 0; i < arguments.length; i++)
s = s.replace(new RegExp("\\{" + i + "\\}", "g"), arguments[i]);
return s;
}
};
// 示例:
var str1 = "hello {0}".format("world"); //log hello world
var str1 = "我叫{0},性别{1}".format("美男子", "男"); //log 我叫美男子,性别男
var user = {name: "美男子",sex: "男",age: 20};
var str2 = "我叫{name},性别{sex},今年{age}岁".format(user); //我叫美男子,性别男,今年20
下面我利用上面的这个 函数,格式化我们要渲染的每个元素。
var item = "<li id='post-{id}'>\n" +
" <time class='mod-archive__time' datetime='{post_date}'> {show_date} </time>\n" +
" <span>—</span>\n" +
" <a href='{post_link}' title='{post_title}'> {post_title} </a>\n" +
" </li>";
var fix = {
'id': article['id'],
'show_date': show_date,
'post_date': article['post_date'],
'post_title': article['post_title'],
'post_link': protocol + '//' + host + '/' + article['post_name']
};
$("#articles").append(item.format(fix));
是不是整个流程就已经很流畅了!!!
效果演示:
http://simple.zhaoshuai.me/search/

评论4