第三节:Vue3 开发WordPress设置选项 - 从筛选功能研究前后台数据交互

本节从WordPress 中拿到用户列表数据,并通过Vue3渲染在页面上,我们还修改了保存选项的接口,以便保存数组类型的数据

承接上文,我们制作了一个简单的,带有两个输入框和一个保存按钮的设置选项,现在,他已经能实现了最基础的填写信息并保存到 WordPress 后台,供PHP调用选项值的功能。

现在,我们更进一步,为其添加人员筛选功能,我们制作一个下列框,从中通过用户名进行选择,并将选择好的用户 ID 通过数组提供给后端使用。大概流程如下

第三节:Vue3 开发WordPress设置选项 - 从筛选功能研究前后台数据交互

最终效果如下

第三节:Vue3 开发WordPress设置选项 - 从筛选功能研究前后台数据交互

准备用户数据

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

第三节:Vue3 开发WordPress设置选项 - 从筛选功能研究前后台数据交互

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.js
console.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() 为以下内容

//保存Option
function 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 - SPA 
Plugin URI: https://www.npc.ink
Description: 将vue构建的页面嵌入WordPress 中并产生交互
Author: Muze
Author URI: https://www.npc.ink
Version: 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_page 
add_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;
}


//保存Option
function 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.js
console.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");
教程

第二节:Vue3 开发WordPress设置选项- 从输入框开始,配置基础设置选项

2023-6-27 22:29:00

教程

第四节:Vue3 开发WordPress设置选项 - 添加图片上传功能

2023-6-28 22:02:00

⚠️
Npcink上的部份代码及教程来源于互联网,仅供网友学习交流,若您喜欢本文可附上原文链接随意转载。
无意侵害您的权益,请发送邮件至 1355471563#qq.com 或点击右侧 私信:Muze 反馈,我们将尽快处理。
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索