简体   繁体   English

准备WordPress后期修订以在WP REST API中输出

[英]Prepare Wordpress Post Revision for Output in WP REST API

I built a custom endpoint for the WordPress REST API to get a post revision. 我为WordPress REST API构建了自定义终结点,以获取后期修订。 The result is in the Wordpress Post syntax: 结果使用Wordpress Post语法:

[ID] => 478
[post_author] => 1
[post_date] => 2017-11-20 17:22:11
[post_date_gmt] => 2017-11-20 16:22:11
[post_content] => My Post content

Whereas the Wordpress REST API would provide me something like this: 而Wordpress REST API将为我提供以下信息:

"author": 1,
"title": {
    "rendered": "My title"
},
"content": {
    "rendered": "",
    "protected": false
},

(one is printed via php the other is in a JSON format, but what is important is that in the first example it says: post_content and in the second it's content which is then separated in rendered and protected for example. (一个是通过php打印的,另一个是JSON格式的,但是重要的是在第一个示例中它说: post_content ,在第二个示例中它是content ,然后将其分离为例如renderedprotected

I am pretty sure that it's almost the same thing as described here: https://wordpress.stackexchange.com/questions/236249/wp-api-v2-custom-endpoint-response-formatting?newreg=7edb54e1ae494e528e5e146982469664 我非常确定这几乎与此处所述相同: https : //wordpress.stackexchange.com/questions/236249/wp-api-v2-custom-endpoint-response-formatting?newreg=7edb54e1ae494e528e5e146982469664

But in my case I have revisions. 但就我而言,我有修改。

I tried to prepare the Post Object for the REST API. 我试图为REST API准备发布对象。 I created a new instance of the WP_REST_Revisions_Controller and tried to use its method prepare_item_for_response . 我创建了WP_REST_Revisions_Controller的新实例,并尝试使用其方法prepare_item_for_response $request ist a WP_Rest_Request. $ request和WP_Rest_Request。 (btw: why do I have to write new \\WP_REST_Revisions_Controller with a backslash \\ before). (顺便说一句:为什么我必须new \\WP_REST_Revisions_Controller用反斜杠\\编写new \\WP_REST_Revisions_Controller )。

$latest_revision = wp_get_post_revisions( $id, $args ); //WP Post Object

$postController = new \WP_REST_Revisions_Controller('revision');
$response = $postController->prepare_item_for_response( $latest_revision, $request );
print_r($response);

The problem is that I get Notices: 问题是我收到通知:

<b>Notice</b>:  Trying to get property of non-object in <b>/Users/USER/Documents/my-api/wp/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php</b> on line <b>350</b>

<b>Notice</b>:  Trying to get property of non-object in <b>/Users/USER/Documents/my-api/wp/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php</b> on line <b>354</b>

<b>Notice</b>:  Trying to get property of non-object in <b>/Users/USER/Documents/my-api/wp/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php</b> on line <b>354</b>
....    

Which must refer to these lines: https://developer.wordpress.org/reference/classes/wp_rest_revisions_controller/ (line 350 and following). 必须参考以下行: https : //developer.wordpress.org/reference/classes/wp_rest_revisions_controller/ (第350行及以下)。

After the notices I print the $response and I get this: 发出通知后,我将打印$response并得到以下信息:

WP_REST_Response Object
(
    [links:protected] => Array
        (
        )

    [matched_route:protected] => 
    [matched_handler:protected] => 
    [data] => Array
        (
            [author] => 0
            [date] => 
            [date_gmt] => 
            [id] => 
            [modified] => 
            [modified_gmt] => 
            [parent] => 0
            [slug] => 
            [guid] => Array
                (
                    [rendered] => 
                    [raw] => 
                )

        )

    [headers] => Array
        (
        )

    [status] => 200
)

.. somehow the data is missing or something else went wrong. ..不知何故,数据丢失或其他原因出了问题。

And here is the whole php script to see what I am doing: 这是整个php脚本,以查看我在做什么:

<?php

/**
 * Add a new API route for a post or pages preview
 */

class Preview_To_REST_API_Controller extends WP_REST_Controller {

    //The namespace and version for the REST SERVER
    var $namespace = 'previews/v';
    var $version   = '1';

    public function register_routes() {
        $namespace = $this->namespace . $this->version;
        $base      = 'preview';
        register_rest_route( $namespace, '/' . $base, array(
            array(
                    'methods'         => WP_REST_Server::READABLE,
                    'callback'        => array( $this, 'get_preview' ),
                    'permission_callback'   => array( $this, 'get_permission' )
                )
        )  );
    }

    // Register our REST Server
    public function hook_rest_server(){
        add_action( 'rest_api_init', array( $this, 'register_routes' ) );
    }

    public function get_permission(){
        if ( ! current_user_can( 'edit_posts' ) ) {
            return new WP_Error( 'rest_forbidden', esc_html__( 'You do not have permissions to view this data.', 'my-text-domain' ), array( 'status' => 401 ) );
        }

        // This approach blocks the endpoint operation. You could alternatively do this by an un-blocking approach, by returning false here and changing the permissions check.
        return true;
    }

    public function get_preview( WP_REST_Request $request ){
        // use the helper methods to get the parameters
        $id = $request->get_param( 'id' );

        // Only return the newest
        $args = array (
            'order' => 'DESC',
            'orderby' => 'date',
            'posts_per_page' => '1'
        );

        // Preview version is saved in the latest revision of the page/post
        $latest_revision = wp_get_post_revisions( $id, $args );

        print_r($latest_revision);

        $postController = new \WP_REST_Revisions_Controller('revision');
        $response = $postController->prepare_item_for_response( $latest_revision, $request );
        print_r($response);

        if ($latest_revision) {
            // Use the current method to get the only element in the revisions array
            // [0] does not return anything, because the Array's value is saved
            // as the ID key: Array[$id], but this ID we need to find out first
            $revision_id = current($latest_revision) -> ID;
            $acf_fields = get_fields($revision_id);

            if ( empty($latest_revision) ) {
                return null;
            }

            // Add acf fields to latest revision
            $latest_revision[$revision_id] -> acf = $acf_fields;

            return $latest_revision;

        } else {
            return null;
        }
    }
}

$preview_controller = new Preview_To_REST_API_Controller();
$preview_controller->hook_rest_server();

I would be really glad to receive any hints for solving this problem. 收到解决该问题的任何提示,我将非常高兴。 Cheers 干杯

I haven't seen the result of your print_r but I'm going to guess that it's an array of WP_Post objects. 我还没有看到您的print_r的结果,但是我猜想它是WP_Post对象的数组。 prepare_item_for_response requires a single WP_Post as the first argument and you're passing it an array. prepare_item_for_response需要一个WP_Post作为第一个参数,并且您要向其传递一个数组。

Try this, after you set $latest_revision : 设置$latest_revision后,尝试以下$latest_revision

if (!is_array($latest_revision) || !count($latest_revision))
    return null;
$latest_revision = array_values($latest_revision)[0];

The array_values call is a quick and easy way to re-index your array. array_values调用是重新索引数组的快速简便的方法。

This should give you a single post and not an array. 这应该给您一个帖子而不是一个数组。

Update: per your own answer to your question and the questions you asked. 更新:根据您自己对问题和所提问题的回答。

prepare_item_for_response rewrites a WP_Post object as something that can be serialized uniformly by the REST controller to output. prepare_item_for_responseWP_Post对象重写为WP_Post REST控制器统一序列化以输出的对象。 For instance, it handles attachments rather than simply ignoring them. 例如,它处理附件而不是简单地忽略它们。 If you simply returned a WP_Post object over, say, JSON, you'd miss out on a lot of the post content. 如果仅通过JSON返回WP_Post对象,那么您将错过很多帖子内容。 You can think of prepare_response_for_collection as the array version of the same thing. 您可以将prepare_response_for_collection视为同一事物的数组版本。 Really, it's more like the WP_Query version of the same thing so the WP rest controller can act as one-stop shopping to return lists of WP_Post objects to a REST consumer. 实际上,它更像是同一事物的WP_Query版本,因此WP rest控制器可以充当一站式购物,将WP_Post对象的列表返回给REST使用者。

rest_ensure_response does something similar for any REST response. rest_ensure_response任何 REST响应rest_ensure_response执行类似的操作。 It hides the loose typing of PHP (and WP), where actions like function calls can return nothing or indeterminate things, from REST, where every request must have an appropriate response. 它隐藏了PHP(和WP)的松散类型,在这种类型中,函数调用之类的操作无法从REST返回任何内容或不确定的事情,而REST中的每个请求都必须具有适当的响应。 It's not much more than a wrapper that is aware of WP_Error . 它只不过是知道WP_Error的包装器WP_Error

I think I found a solution: Using $postController = new \\WP_REST_Revisions_Controller('revision'); 我想我找到了一个解决方案:使用$postController = new \\WP_REST_Revisions_Controller('revision'); would not return a content field, so I had to use $postController = new \\WP_REST_Posts_Controller('post'); 不会返回内容字段,所以我不得不使用$postController = new \\WP_REST_Posts_Controller('post'); although my result would actually be a 'revision'. 尽管我的结果实际上是“修订”。

Furthermore I used prepare_item_for_response , prepare_response_for_collection and rest_ensure_response . 此外,我使用了prepare_item_for_responseprepare_response_for_collectionrest_ensure_response Unfortunately I don't really know what these methods are actually doing...? 不幸的是,我真的不知道这些方法实际上在做什么……?

My new code: 我的新代码:

/**
 * Add a new API route for a post or pages preview
 */

class Preview_To_REST_API_Controller extends WP_REST_Controller {

    //The namespace and version for the REST SERVER
    var $namespace = 'previews/v';
    var $version   = '1';

    public function register_routes() {
        $namespace = $this->namespace . $this->version;
        $base      = 'preview';
        register_rest_route( $namespace, '/' . $base, array(
            array(
                    'methods'         => WP_REST_Server::READABLE,
                    'callback'        => array( $this, 'get_preview' ),
                    'permission_callback'   => array( $this, 'get_permission' )
                )
        )  );
    }

    // Register our REST Server
    public function hook_rest_server(){
        add_action( 'rest_api_init', array( $this, 'register_routes' ) );
    }

    public function get_permission(){
        if ( ! current_user_can( 'edit_posts' ) ) {
            return new WP_Error( 'rest_forbidden', esc_html__( 'You do not have permissions to view this data.', 'my-text-domain' ), array( 'status' => 401 ) );
        }

        // This approach blocks the endpoint operation. You could alternatively do this by an un-blocking approach, by returning false here and changing the permissions check.
        return true;
    }

    public function get_preview( WP_REST_Request $request ){
        // use the helper methods to get the parameters
        $id = $request->get_param( 'id' );

        // Only return the newest
        $args = array (
            'order' => 'DESC',
            'orderby' => 'date',
            'posts_per_page' => '1'
        );

        // Preview version is saved in the latest revision of the page/post
        $latest_revision = wp_get_post_revisions( $id, $args );

        if (!is_array($latest_revision) || !count($latest_revision)){
            return null;
        }
        $latest_revision = array_values($latest_revision)[0];

        $postController = new \WP_REST_Posts_Controller('post');
        $response = $postController->prepare_item_for_response( $latest_revision, $request );
        $data = $postController->prepare_response_for_collection( $response );


        if ($latest_revision) {
            // Use the current method to get the only element in the revisions array
            // [0] does not return anything, because the Array's value is saved
            // as the ID key: Array[$id], but this ID we need to find out first
            $revision_id = $latest_revision -> ID;
            $acf_fields = get_fields($revision_id);

            if ( empty($latest_revision) ) {
                return null;
            }

            // Add acf fields to latest revision
            $data['acf'] = $acf_fields;

            return rest_ensure_response($data);

        } else {
            return null;
        }
    }
}

$preview_controller = new Preview_To_REST_API_Controller();
$preview_controller->hook_rest_server();

This gives me neat results like: 这给了我整洁的结果,例如:

{
    "id": 478,
    "date": "2017-11-20T23:51:10",
    "date_gmt": "2017-11-20T22:51:10",
    "guid": {
        "rendered": "http://localhost:3000/51-autosave-v1/"
    },
    "modified": "2017-11-20T23:51:10",
    "modified_gmt": "2017-11-20T22:51:10",
    "slug": "51-autosave-v1",
    "status": "inherit",
    "type": "revision",
    "link": "http://localhost:3000/51-autosave-v1/",
    "title": {
        "rendered": "my title"
    },
        "content": {
        "rendered": "",
        "protected": false
    },
    "excerpt": {
        "rendered": "",
        "protected": false
    },
    "author": 1,
    "featured_media": 0,
    "comment_status": "closed",
    "ping_status": "closed",
    "sticky": false,
    "template": "", ... etc.

If some feels like explaining what I did, I would be glad to read about it. 如果有些人想解释我的所作所为,那么我将很高兴读到它。 🤙🏼 🤙🏼

Cheers 干杯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM