最近想给自己的博客实现一个 站内搜索 功能,期望整个过程异步实现。这样用户体验度更好。
wordpress 原生自带有一个 wp_query 函数,它支持的参数非常完善灵活,实现整个网站与数据库的交互。比如调用最新文章、热门文章、自定义文章类型文章循环输出等。
在官方手册中也有介绍到:wp_query,支持多种 sql 语句的 比较符号:
看!他说可以支持 like 或者 regexp 这种比较符号。
于是我们试一试:
Shell
$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);
123456789101112131415 | $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); |
---|
Shell
// 判断查询的结果,检查是否有文章 if ( $result->have_posts() ) : // 通过查询的结果,开始主循环 while ( $result->have_posts() ) : $result->the_post(); //获取到特定的文章 // 要输出的内容,如标题、日期等 endwhile; endif;
1234567891011 | // 判断查询的结果,检查是否有文章if ( $result->have_posts() ) : // 通过查询的结果,开始主循环 while ( $result->have_posts() ) : $result->the_post(); //获取到特定的文章 // 要输出的内容,如标题、日期等 endwhile;endif; |
---|
但是很遗憾,不知道是我的姿势不对,就是不起作用?? 如果有大佬解决了,望不吝赐教!
其实在数据库使用 like 的查询效率是非常低,所以我们可以把这一部分的逻辑由 php 自己实现。
Shell
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, ]; } } }
1234567891011121314151617 | 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 可以实现字符串的模糊匹配,这样就可以筛选出我们想要的结果。
上面我们已经实现了文章的模糊匹配,接下来就要提供一个接口,来实现与前端的交互。所以,我们将会用到 wordpress 自带的 admin-ajax.php 文件。
要使用 admin-ajax.php 请求必然首先就是遇到如何使用 wordrpess 的钩子 hook 来做过滤。
Shell
//wp_ajax_nopriv_ 效验用户为未登录是启用的方法 add_action( 'wp_ajax_nopriv_search', 'search' ); //wp_ajax_ 效验用户为已登录是启用的方法 add_action( 'wp_ajax_search', 'search' );
1234 | //wp_ajax_nopriv_ 效验用户为未登录是启用的方法add_action( 'wp_ajax_nopriv_search', 'search' );//wp_ajax_ 效验用户为已登录是启用的方法add_action( 'wp_ajax_search', 'search' ); |
---|
我们看到上面 search 这个是我们要定义的搜索函数,逻辑就要用到了刚刚介绍的 模糊匹配 ,
但是其中几点需要注意到的是:
if
( is_user_logged_in() )
这个代码之前!!!!Shell
/ 文章搜索 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' );
123456789101112131415161718192021222324252627282930313233343536373839404142 | / 文章搜索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
其实很简单,前两部已经完成大部分的工作。我们只需要添加一个监听输入框值变化的事件,使用 JQuery 的 ajax 请求接口就OK了。
Shell
$("#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); } }); } }
12345678910111213141516171819202122232425 | $("#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 语法进行拼接。
我们这里是用了 正则表达式 ,写了一个规则,可以通过 键值 格式化我们定义好的字符串,来人上代码!
Shell
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
1234567891011121314151617181920212223 | 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 worldvar str1 = "我叫{0},性别{1}".format("美男子", "男"); //log 我叫美男子,性别男var user = {name: "美男子",sex: "男",age: 20};var str2 = "我叫{name},性别{sex},今年{age}岁".format(user); //我叫美男子,性别男,今年20 |
---|
下面我利用上面的这个 函数,格式化我们要渲染的每个元素。
Shell
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));
123456789101112131415 | 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)); |
---|
是不是整个流程就已经很流畅了!!!