为WP REST API中的输出准备Wordpress Post修订版

时间:2017-11-20 17:37:09

标签: php wordpress wordpress-rest-api revisions

我为WordPress REST API构建了一个自定义端点,以获得后期修订。结果是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

而Wordpress REST API将为我提供如下内容:

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

(一个是通过php打印的,另一个是JSON格式,但重要的是,在第一个例子中它表示:post_content而在第二个例子中它是content然后在例如renderedprotected

我很确定这与此处描述的几乎相同: https://wordpress.stackexchange.com/questions/236249/wp-api-v2-custom-endpoint-response-formatting?newreg=7edb54e1ae494e528e5e146982469664

但在我的情况下,我有修改。

我尝试为REST API准备Post对象。 我创建了WP_REST_Revisions_Controller的新实例,并尝试使用其方法prepare_item_for_response。 $ request是一个WP_Rest_Request。 (顺便说一句:为什么我必须先用反斜杠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);

问题在于我收到通知:

<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>
....    

必须参考以下几行: https://developer.wordpress.org/reference/classes/wp_rest_revisions_controller/(第350行及以下)。

发出通知后,我打印$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
)

..某种程度上数据丢失或出现其他问题。

这是整个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();

我很高兴收到解决这个问题的任何提示。 干杯

2 个答案:

答案 0 :(得分:1)

我没有看到你print_r的结果,但我猜它是一组WP_Post个对象。 prepare_item_for_response需要一个WP_Post作为第一个参数,并且您将它传递给数组。

设置$latest_revision

后尝试此操作
if (!is_array($latest_revision) || !count($latest_revision))
    return null;
$latest_revision = array_values($latest_revision)[0];

array_values调用是一种快速简便的重新索引数组的方法。

这应该会给你一个帖子,而不是一个数组。

更新:根据您自己对问题的回答和您提出的问题。

prepare_item_for_responseWP_Post对象重写为REST控制器可以统一序列化输出的内容。例如,它处理附件而不是简单地忽略它们。如果您只是简单地返回一个WP_Post对象,比如JSON,那么您将错过很多帖子内容。您可以将prepare_response_for_collection视为同一事物的数组版本。实际上,它更像是同一事物的WP_Query版本,因此WP休息控制器可以作为一站式购物,将WP_Post对象列表返回给REST消费者。

rest_ensure_response任何 REST响应做了类似的事情。它隐藏了PHP(和WP)的松散类型,其中函数调用之类的操作可以从REST返回任何内容或不确定内容,其中每个请求必须具有适当的响应。它只不过是一个知道WP_Error的包装器。

答案 1 :(得分:0)

我想我找到了一个解决方案: 使用$postController = new \WP_REST_Revisions_Controller('revision');不会返回内容字段,因此我必须使用$postController = new \WP_REST_Posts_Controller('post');,但我的结果实际上是“修订版”。

此外,我使用了prepare_item_for_responseprepare_response_for_collectionrest_ensure_response。不幸的是,我真的不知道这些方法实际上在做什么......?

我的新代码:

/**
 * 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();

这给了我很好的结果,如:

{
    "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.

如果有人想解释我做了什么,我会很高兴看到它。

干杯