本页目录

承接上文,我们制作了一个简单的,带有两个输入框和一个保存按钮的设置选项,现在,他已经能实现了最基础的填写信息并保存到 WordPress 后台,供 PHP 调用选项值的功能。
现在,我们更进一步,为其添加人员筛选功能,我们制作一个下列框,从中通过用户名进行选择,并将选择好的用户 ID 通过数组提供给后端使用。大概流程如下

最终效果如下

准备用户数据
一般的网站用户量较大,大部分都是“订阅者”,为了减少传输数据压力,我们在获取用户数据时将其排除掉 为了将拿到数据方便给 JS 使用,降低 JS 使用数据难度,我们将其整理成如下结构

在 vue-spa.php 文件底部添加以下代码
//整理并提供用户信息function vuespa_get_user_meat(){ //获取所有角色 $editable_roles = wp_roles()->roles; $roles = array_keys($editable_roles); //获取除了'subscriber'(订阅者)角色之外的所有角色的用户数据 $subscriber_key = array_search('subscriber', $roles, true); if (false !== $subscriber_key) { $roles = array_slice($roles, 0, $subscriber_key); }
$users = get_users(array('role__in' => $roles));
//转为关联数组 $user_data = array_map(function ($user) { return [ 'id' => $user->ID, 'name' => $user->display_name, ]; }, $users);
return $user_data;}您可以参考此方法,做出分类筛选、文章筛选、标签筛选等筛选功能,只需按结构提供数据即可。
传递用户数据
我们通过 PHP 将数据传给 JS ,以供使用,我们修改 vue-spa.php 文件中的 vuespa_data() 函数,改为以下内容
function vuespa_data(){ $person = [ "str" => "Hello, world! - Npcink", "num" => 25, "city" => [1, 2, 3, 4, 5], "user" => vuespa_get_user_meat(), ]; return $person;}刷新菜单页面,我们就能看到如上图的效果。
JS 准备页面
JS 中拿到传来的数据,需要将其渲染至页面上,修改 index.js 为以下内容
//vite/dist/index.jsconsole.log(dataLocal.data.user);const App = { setup() {
//存储传来的值 const siteData = dataLocal.data;
//存储选项值 const datas = Vue.reactive({ dataOne: "", dataTwo: "", dataName: [], });
//获取数据 const vuespa_get_option = () => { axios .post(dataLocal.route + "pf/v1/get_option", datas, { headers: { "X-WP-Nonce": dataLocal.nonce, "Content-Type": "application/json", }, }) .then((response) => { const data = response.data; datas.dataOne = data.dataOne; datas.dataTwo = data.dataTwo; datas.dataName = data.dataName; }) .catch((error) => { window.alert("连接服务器失败或后台读取出错!数据读取失败"); console.log(error); }); }; //省略部分代码
return { datas, siteData, vuespa_update_option }; }, template: ` 文本框1:<input type="text" v-model="datas.dataOne"><br/> 文本框2:<input type="text" v-model="datas.dataTwo"><hr/>
用户选择:<select v-model="datas.dataName" multiple> <option v-for="option in siteData.user" :key="option.id" :value="option.id"> {{ option.name }} </option></select><p>你选择了:{{ datas.dataName }}</p><br/>按住command(control)按键即可进行多选<hr/> <button class="button button-primary" @click="vuespa_update_option">保存</button>`,};
Vue.createApp(App).mount("#vuespa");为了方便大家看出不同,我省略了部分未修改的代码,其详细内容,可见上一节。 主要内容如下
-
新建变量 siteData 存储传来的数据
-
新建数组变量 dataName 存储选中数组
-
在获取数据中,通过 datas.dataName = data.dataName;拿到默认值
修改保存接口
原有的保存接口无法识别数组,若您此时修改选中的值并点击保存按钮,刷新页面后会丢失选中的值。
修改 interface.php 文章的保存选项功能函数 update_option_by_RestAPI() 为以下内容
//保存Optionfunction update_option_by_RestAPI($data){ //判断是否是管理员 if (current_user_can('manage_options')) { //转为JSON对象 - 重点,这里没有true,是转为对象 $dataArray = json_decode($data->get_body()); //存储结果 $result = new stdClass();
//循环保存选项 foreach ($dataArray as $option_name => $value) {
//判断,是否为对象 if (is_object($value)) { //是非空数组,循环保存值 foreach ($value as $arr => $data) { //更新值 update_option($arr, $data); } } else { //不是对象,则表示只有一个选项需要保存。 update_option($option_name, $value); } $result->$option_name = $value; }
//返回成功信息 return new WP_REST_Response(array( 'success' => true, 'message' => "已保存!" ), 200); } else { //返回失败信息 return new WP_Error('save_error', '保存失败!', array('status' => 500)); }}此函数的功能可见注释,现在,刷新页面,在下列列表中进行筛选,然后点击保存按钮,刷新页面,可看到值是正常保存的,
使用
此时,您可以使用 get_option 在 PHP 中拿到选项中的值,正如上一节中提到的。
echo get_option('dataName');注意,这会展示数组 ID
总结
这一节我们添加了下拉列表多选功能,并没有解决上一节提到的问题,不要急,我发现目前展示功能类型很方便,我准备在展示完所有常见功能类型后,再去解决上一节提到的问题。
文件代码
vue-spa.php
<?php/*Plugin Name: Vue - SPAPlugin URI: https://www.npc.inkDescription: 将vue构建的页面嵌入WordPress 中并产生交互Author: MuzeAuthor URI: https://www.npc.inkVersion: 1.0.0*/
//接口require_once plugin_dir_path(__FILE__) . 'interface.php';//创建一个菜单function vuespa_create_menu_page(){ add_menu_page( 'VueSpa选项', // 此菜单对应页面上显示的标题 'VueSpa', // 要为此实际菜单项显示的文本 'administrator', // 哪种类型的用户可以看到此菜单 'vuespa_id', // 此菜单项的唯一ID(即段塞) 'vuespa_menu_page_display', // 呈现此页面的菜单时要调用的函数的名称 'dashicons-admin-customizer', //图标 - 默认图标 '500.1', //位置 );} // end vuespa_create_menu_pageadd_action('admin_menu', 'vuespa_create_menu_page');
//菜单回调 - 展示的内容function vuespa_menu_page_display(){?>
<!--在默认WordPress“包装”容器中创建标题--> <div class="wrap"> <!--标题--> <h2><?php echo esc_html(get_admin_page_title()); ?></h2> <!--提供Vue挂载点--> <div id="vuespa">此内容将在挂载Vue后被替换{{data}}</div> </div>
<?php
//展示准备的数据 echo "<pre>"; print_r(vuespa_data()); echo "</pre>";
echo "<h3>调用选项值</h3>"; echo get_option('dataOne'); echo "<br/>"; echo get_option('dataTwo');} // vuespa_menu_page_display
//载入所需 JS 和 CSS 资源 并传递数据function vuespa_load_vues($hook){ //判断当前页面是否是指定页面,是则继续加载 if ('toplevel_page_vuespa_id' != $hook) { return; } //版本号 $ver = '53'; //加载到页面顶部 wp_enqueue_style('vite', plugin_dir_url(__FILE__) . 'vite/dist/index.css', array(), $ver, false); //加载到页面底部 wp_enqueue_script('vue', 'https://unpkg.com/vue@3/dist/vue.global.js', array(), $ver, true); wp_enqueue_script('axios', 'https://unpkg.com/axios/dist/axios.min.js', array(), $ver, true); wp_enqueue_script('vite', plugin_dir_url(__FILE__) . 'vite/dist/index.js', array(), $ver, true);
$pf_api_translation_array = array( 'route' => esc_url_raw(rest_url()), //路由 'nonce' => wp_create_nonce('wp_rest'), //验证标记 'data' => vuespa_data(), //自定义数据 ); wp_localize_script('vite', 'dataLocal', $pf_api_translation_array); //传给vite项目}//样式加载到后台add_action('admin_enqueue_scripts', 'vuespa_load_vues');
//准备待传输的数据function vuespa_data(){ $person = [ "str" => "Hello, world! - Npcink", "num" => 25, "city" => [1, 2, 3, 4, 5], "user" => vuespa_get_user_meat(), ]; return $person;}
//整理并提供用户信息function vuespa_get_user_meat(){ //获取所有角色 $editable_roles = wp_roles()->roles; $roles = array_keys($editable_roles); //获取除了'subscriber'(订阅者)角色之外的所有角色的用户数据 $subscriber_key = array_search('subscriber', $roles, true); if (false !== $subscriber_key) { $roles = array_slice($roles, 0, $subscriber_key); }
$users = get_users(array('role__in' => $roles));
//转为关联数组 $user_data = array_map(function ($user) { return [ 'id' => $user->ID, 'name' => $user->display_name, ]; }, $users);
return $user_data;}interface.php
<?php//interface.php//接口文件function vuespa_create_api(){ register_rest_route('pf/v1', '/get_option/', array( // 完整命名空间为:/wp-json/pf/v1/ 'methods' => 'POST', 'callback' => 'get_option_by_RestAPI', )); register_rest_route('pf/v1', '/update_option/', array( // 完整命名空间为:/wp-json/pf/v1/ 'methods' => 'POST', 'callback' => 'update_option_by_RestAPI', 'permission_callback' => function () { return current_user_can('manage_options'); // 只有管理员才有权限修改 }, ));}add_action('rest_api_init', 'vuespa_create_api');
//读取Option//仅支持一对一的数据请求function get_option_by_RestAPI($data){ //将传递数据转成数组类型 $dataArray = json_decode($data->get_body(), true); //新建数组 $return = array(); //循环获取对应选项ID的值,并将其存储在对应关联数组中,若拿不到值,则为空 foreach ($dataArray as $option_name => $value) { $return[$option_name] = get_option($option_name) ? get_option($option_name) : ""; } return $return;}
//保存Optionfunction update_option_by_RestAPI($data){
//判断是否是管理员 if (current_user_can('manage_options')) { //转为JSON对象 - 重点,这里没有true,是转为对象 $dataArray = json_decode($data->get_body()); //存储结果 $result = new stdClass();
//循环保存选项 foreach ($dataArray as $option_name => $value) {
//判断,是否为对象 if (is_object($value)) { //是非空数组,循环保存值 foreach ($value as $arr => $data) { //更新值 update_option($arr, $data); } } else { //不是对象,则表示只有一个选项需要保存。 update_option($option_name, $value); } $result->$option_name = $value; }
//返回成功信息 return new WP_REST_Response(array( 'success' => true, 'message' => "已保存!" ), 200); } else { //返回失败信息 return new WP_Error('save_error', '保存失败!', array('status' => 500)); }}index.js
//vite/dist/index.jsconsole.log(dataLocal.data.user);const App = { setup() {
//存储传来的值 const siteData = dataLocal.data;
//存储选项值 const datas = Vue.reactive({ dataOne: "", dataTwo: "", dataName: [], });
//获取数据 const vuespa_get_option = () => { axios .post(dataLocal.route + "pf/v1/get_option", datas, { headers: { "X-WP-Nonce": dataLocal.nonce, "Content-Type": "application/json", }, }) .then((response) => { const data = response.data; datas.dataOne = data.dataOne; datas.dataTwo = data.dataTwo; datas.dataName = data.dataName; }) .catch((error) => { window.alert("连接服务器失败或后台读取出错!数据读取失败"); console.log(error); }); };
//保存数据 const vuespa_update_option = () => { axios .post(dataLocal.route + "pf/v1/update_option", datas, { headers: { "X-WP-Nonce": dataLocal.nonce, }, }) .then((response) => { alert("保存成功"); }) .catch((error) => { alert("保存失败"); console.log(error); }); };
//页面初始加载 Vue.onMounted(() => { console.log("简简单单"); vuespa_get_option(); });
return { datas, siteData, vuespa_update_option }; }, template: ` 文本框1:<input type="text" v-model="datas.dataOne"><br/> 文本框2:<input type="text" v-model="datas.dataTwo"><hr/>
用户选择:<select v-model="datas.dataName" multiple> <option v-for="option in siteData.user" :key="option.id" :value="option.id"> {{ option.name }} </option></select><p>你选择了:{{ datas.dataName }}</p><br/>按住command(control)按键即可进行多选<hr/> <button class="button button-primary" @click="vuespa_update_option">保存</button>`,};
Vue.createApp(App).mount("#vuespa");