在 WordPress 中使用 REST API

WordPress REST API 为操作 WordPress 网站数据提供统一接口。本课介绍三种内部请求方式,并用 GET 请求获取公开自定义文章类型的数据。

Bookstore 插件

如果完成了“WordPress 插件入门”模块,你已经创建了注册 book 自定义文章类型的插件。跳过该模块时,可从原文的 Bookstore 插件链接下载 GitHub 代码。

安装并启用后,在编辑器中打开主插件文件,可以看到传给 register_post_type 的 show_in_rest:

    $args = array(
        'labels'       => array(
            'name'          => 'Books',
            'singular_name' => 'Book',
            'menu_name'     => 'Books',
            'add_new'       => 'Add New Book',
            'add_new_item'  => 'Add New Book',
            'new_item'      => 'New Book',
            'edit_item'     => 'Edit Book',
            'view_item'     => 'View Book',
            'all_items'     => 'All Books',
        ),
        'public'       => true,
        'has_archive'  => true,
        'show_in_rest' => true,
        'supports'     => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt' ),
    );

它为 true,表示该类型可通过 REST API 访问。打开 wp-json/wp/v2/book,就能看到相应数据。

函数参考还列出其他控制 REST 响应的参数,例如 rest_base 可修改路由。因为请求通常返回多本书,把它改成复数 books 更合适:

        'show_in_rest' => true,
        'rest_base'    => 'books',
        'supports'     => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt' ),

之后就能通过 wp-json/wp/v2/books 访问图书。

发起 REST API 请求

假设希望在后台添加一个页面,获取图书并将标题和永久链接显示为逗号分隔列表。首先通过 admin_menu 钩子与 add_submenu_page,在 Books 菜单下添加子页面:

add_action( 'admin_menu', 'bookstore_add_booklist_submenu', 11 );
function bookstore_add_booklist_submenu() {
    add_submenu_page(
        'edit.php?post_type=book',
        'Book List',
        'Book List',
        'edit_posts',
        'book-list',
        'bookstore_render_booklist'
    );
}

再创建渲染页面 HTML 的回调:

function bookstore_render_booklist() {
    ?>
    <div class="wrap" id="bookstore-booklist-admin">
        <h1>Actions</h1>
        <button id="bookstore-load-books">Load Books</button>
        <h2>Books</h2>
        <textarea id="bookstore-booklist" cols="125" rows="15"></textarea>
    </div>
    <?php
}

后台 Books 菜单现在出现“Book List”,打开可看到“Load Books”按钮与文本框。

可以用 PHP 获取列表,并让按钮触发刷新。但为了更流畅的体验,下面使用 JavaScript 与 REST API 异步获取数据,无需刷新整页。

加载后台 JavaScript

插件入门模块介绍过脚本加载。由于功能位于后台,需要单独调用 wp_enqueue_script,并挂到 admin_enqueue_scripts,确保脚本只在后台加载。

在插件目录创建 admin_bookstore.js,再向主文件添加:

add_action( 'admin_enqueue_scripts', 'bookstore_admin_enqueue_scripts' );
function bookstore_admin_enqueue_scripts() {
    wp_enqueue_script(
        'bookstore-admin',
        plugins_url() . '/bookstore/admin_bookstore.js',
        array(),
        '1.0.0',
        true
    );
}

代码指定了空依赖数组、版本号,并把最后一个参数设为 true,让脚本在页脚加载。参数详情见 wp_enqueue_script 参考。

可暂时添加下面的 alert,刷新后台确认脚本已加载,之后删除这行:

alert( 'Hello from the Book store admin' );

方式一:Backbone.js 客户端

REST API 加入 WordPress 时,就包含了基于 Backbone.js 的 JavaScript 客户端,为所有暴露的端点提供 Model 与 Collection。

要使用它,将 wp-api 加入脚本依赖,即 wp_enqueue_script 的第三个参数:

    wp_enqueue_script(
        'bookstyle-script',
        plugins_url() . '/bookstore/admin_bookstore.js',
        array( 'wp-api' ),
        '1.0.0',
        true
    );

这样插件脚本只会在 REST 客户端加载后运行。

先给按钮注册点击事件:

const loadBooksByRestButton = document.getElementById( 'bookstore-load-books' );
if ( loadBooksByRestButton ) {
    loadBooksByRestButton.addEventListener( 'click', function () {
        //do somthing
    } );
}

在回调中,通过全局 wp 对象创建图书集合:

    const allBooks = new wp.api.collections.Books();

此时集合为空,需要调用 fetch:

   allBooks.fetch();

fetch 返回 Promise,可以链式调用 done 处理响应,并用 books 参数接收结果:

    allBooks.fetch().done(
        function ( books ) {
            // do something with books
        }
    );

然后使用 forEach 遍历每本书:

    allBooks.fetch().done(
        function ( books ) {
            books.forEach( function ( book ) {
              // do something with book
            } );
        }
    );

最后把标题和永久链接加入文本框。先在循环外取得文本框,再在循环内追加到 value:

        allBooks.fetch().done(
            function ( books ) {
                const textarea = document.getElementById( 'bookstore-booklist' );
                books.forEach( function ( book ) {
                    textarea.value += book.title.rendered + ',' + book.link + ',\n'
                });
            }
        );

完整代码如下:

const loadBooksByRestButton = document.getElementById( 'bookstore-load-books' );
if ( loadBooksByRestButton ) {
    loadBooksByRestButton.addEventListener( 'click', function () {
        const allBooks = new wp.api.collections.Books();
        allBooks.fetch().done(
            function ( books ) {
                const textarea = document.getElementById( 'bookstore-booklist' );
                books.forEach( function ( book ) {
                    textarea.value += book.title.rendered + ',' + book.link + ',\n'
                });
            }
        );
    });
}

回到 Book List,点击“Load Books”,文本框会显示图书列表。

方式二:apiFetch

WordPress 5.0 引入区块编辑器后,也提供了 API Fetch 包,封装浏览器 fetch API,以更现代、灵活的方式请求 REST API。原文小节称其为 @wordpress/fetch-api,后面的参考链接为 api-fetch 包。

将 wp-api-fetch 加入插件脚本依赖:

    wp_enqueue_script(
        'bookstyle-script',
        plugins_url() . '/bookstore/admin_bookstore.js',
        array( 'wp-api', 'wp-api-fetch' ),
        '1.0.0',
        true
    );

可以移除原来的 wp-api,也可以同时保留。

在 Actions 区域添加按钮:

<button id="bookstore-fetch-books">Fetch Books</button>

与前面一样,为新按钮添加 click 监听器,这次使用 apiFetch:

const fetchBooksByRestButton = document.getElementById( 'bookstore-fetch-books' );
if ( fetchBooksByRestButton ) {
    fetchBooksByRestButton.addEventListener( 'click', function () {
        wp.apiFetch( { path: '/wp/v2/books' } ).then( ( books ) => {
            const textarea = document.getElementById( 'bookstore-booklist' );
            books.map( ( book ) => {
                textarea.value += book.title.rendered + ',' + book.link + ',\n'
            });
        } );
    });
}

端点路径通过对象传给 wp.apiFetch,比必须使用特定 Collection 的 Backbone 客户端更灵活。

then 与前面的 done 类似,等待请求完成,再将结果传给回调。回调中用 map 遍历 books,将标题与链接追加到文本框。这段代码采用更现代的箭头函数语法。

刷新后台,点击“Fetch Books”,即可看到列表。

方式三:@wordpress/core-data

开发区块时,也可以使用 core-data 访问 REST 数据。它简化 WordPress 核心实体的读取和修改,注册自己的 store,提供自动解析 REST 数据的 selector,以及用于修改数据的 action creator。

core-data 使用 React 功能,因此最适合区块环境。

先使用区块开发入门中介绍的 create-block,创建 bookstore-block:

cd path/to/local/site/wp-content/plugins
npx @wordpress/create-block bookstore-block

脚手架会生成可编辑代码。在 edit.js 中导入 useSelect 和 core-data store:

import { useSelect } from '@wordpress/data';
import { store as bookStore } from '@wordpress/core-data';

然后读取图书:

    const books = useSelect(
        select =>
            select( bookStore ).getEntityRecords( 'postType', 'book' ),
        []
    );

useSelect 从已注册 selector 中取数据。第一个参数是回调,在其中调用 bookStore 的 getEntityRecords,结果保存到 books。

没有数据时返回空组件,否则遍历图书并输出标题、链接:

    if ( ! books ) {
        return (
            <div { ...useBlockProps() }></div>
        )
    }

    return (
        <div { ...useBlockProps() }>
            { books.map( ( book ) => (
                <p>
                    <a href={ book.link }>{book.title.rendered}</a>
                </p>
            ) ) }
        </div>
    );

运行区块构建,启用插件,并把 bookstore 区块加入文章或页面,就能看到从 REST API 获取的标题和链接。

三种方式的区别

Backbone 客户端最早出现,与 REST API 集成紧密。需要用 REST API 构建后台页面时,是不错的选择,也比旧 admin-ajax.php 端点更合适。

apiFetch 是通用方案,既适用于后台页面,也适用于编辑器区块;更现代,也比 Backbone 更灵活。

core-data 最适合区块,因为它依赖区块编辑器环境中的 React 功能。

进一步阅读

更多信息见 REST API 手册的 Backbone JavaScript 客户端部分,以及区块编辑器手册的 api-fetch 和 core-data 包。


原文:Using the WordPress REST API。作者/维护者:WordPress Learn 教学团队。本文为原文的中文译文;代码保留原文内容。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容