New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add block data to REST API #2649

Open
wants to merge 54 commits into
base: master
from

Conversation

Projects
None yet
9 participants
@adamsilverstein
Contributor

adamsilverstein commented Sep 2, 2017

This pull request adds Gutenberg block data to the post endpoints

This provides a way to get the data and content of each block of a Gutenberg-built page from the front end. This would be very useful for building component based front ends, because the components could map one-to-one with gutenberg blocks. With these endpoints, an App could easily get the data it needs to render each component. This might also provide a patch for a standard component library matching Gutenberg blocks.

@adamsilverstein adamsilverstein requested a review from rmccue Sep 2, 2017

@BE-Webdesign

This comment has been minimized.

Show comment
Hide comment
@BE-Webdesign

BE-Webdesign Sep 2, 2017

Contributor

#2503 is similar. They are addressing two different problems but, it would be good to have coordination between this and #2503 .

Contributor

BE-Webdesign commented Sep 2, 2017

#2503 is similar. They are addressing two different problems but, it would be good to have coordination between this and #2503 .

@adamsilverstein

This comment has been minimized.

Show comment
Hide comment
@adamsilverstein

adamsilverstein Sep 2, 2017

Contributor

@BE-Webdesign thanks for pointing out #2503 - I searched for a similar PR and couldn't find one.

As you pointed out, these PRs are pretty different; from a brief view it looks like #2503 is an API for (reusable) block objects themselves, while this PR is focused on exposing a (gutenberg built) post's blocks (and their data)

Contributor

adamsilverstein commented Sep 2, 2017

@BE-Webdesign thanks for pointing out #2503 - I searched for a similar PR and couldn't find one.

As you pointed out, these PRs are pretty different; from a brief view it looks like #2503 is an API for (reusable) block objects themselves, while this PR is focused on exposing a (gutenberg built) post's blocks (and their data)

@rmccue

I think rather than creating separate endpoints, we should build this into the existing endpoints instead. In particular .content on the post type is intentionally an object to allow adding extra properties.

(I'll follow this up in a minute; GH's review comment UI isn't great for leaving long comments.)

Show outdated Hide outdated lib/class-wp-rest-gutenberg-blocks.php
Show outdated Hide outdated lib/class-wp-rest-gutenberg-blocks.php
Show outdated Hide outdated lib/class-wp-rest-gutenberg-blocks.php
Show outdated Hide outdated lib/class-wp-rest-gutenberg-blocks.php
@rmccue

This comment has been minimized.

Show comment
Hide comment
@rmccue

rmccue Sep 4, 2017

Contributor

In the post object, content contains the various representations of the same piece of data: the post content. As I understand it, with Gutenberg, the blocks are simply another representation of that same piece of data. (We also intentionally designed content for this purpose; although Gutenberg wasn't in sight at the time, other page builders were, and making content an object gave us more extensibility there.)

It also seems like (maybe) Gutenberg distinguishes between rendered and raw block content, based on this PR. (I could be wrong there.) Given that, I'd probably add a new sub-field under content called blocks, which could also contain its own raw and rendered fields (based on the provided context).

Something like this:

{
    "content": {
        "raw": "<!-- gutenberg comments --> interspersed with HTML",
        "rendered": "<div class='block-foo'><p>bar</p></div><p>interspersed with HTML</p>",
        "blocks": [
            {
                "type": "foo",
                "attributes": {
                    "value": "bar"
                },
                "rendered": "<p>bar</p>"
            },
            {
                "type": "html",
                "attributes": {
                    "content": "interspersed with HTML"
                },
                "rendered": "<p>interspersed with HTML</p>"
            }
        ]
    }
}

(Disclaimer: I only know the data model in very broad strokes here.)

Contributor

rmccue commented Sep 4, 2017

In the post object, content contains the various representations of the same piece of data: the post content. As I understand it, with Gutenberg, the blocks are simply another representation of that same piece of data. (We also intentionally designed content for this purpose; although Gutenberg wasn't in sight at the time, other page builders were, and making content an object gave us more extensibility there.)

It also seems like (maybe) Gutenberg distinguishes between rendered and raw block content, based on this PR. (I could be wrong there.) Given that, I'd probably add a new sub-field under content called blocks, which could also contain its own raw and rendered fields (based on the provided context).

Something like this:

{
    "content": {
        "raw": "<!-- gutenberg comments --> interspersed with HTML",
        "rendered": "<div class='block-foo'><p>bar</p></div><p>interspersed with HTML</p>",
        "blocks": [
            {
                "type": "foo",
                "attributes": {
                    "value": "bar"
                },
                "rendered": "<p>bar</p>"
            },
            {
                "type": "html",
                "attributes": {
                    "content": "interspersed with HTML"
                },
                "rendered": "<p>interspersed with HTML</p>"
            }
        ]
    }
}

(Disclaimer: I only know the data model in very broad strokes here.)

@noisysocks

This comment has been minimized.

Show comment
Hide comment
@noisysocks

noisysocks Sep 4, 2017

Member

As you pointed out, these PRs are pretty different; from a brief view it looks like #2503 is an API for (reusable) block objects themselves, while this PR is focused on exposing a (gutenberg built) post's blocks (and their data)

While the two endpoints address different use cases, it'd be highly useful to have both endpoints represent a block in a consistent way, e.g.

{
    "type": "core/paragraph",
    "attributes": {
        "content": "How are you?",
        "dropCap": true
    },
    "content": "<!-- wp:core/paragraph {\"dropCap\":true} -->\n<p class=\"has-drop-cap\">How are you?</p>\n<!-- /wp:core/paragraph -->",
    "rendered": "<p class=\"has-drop-cap\">How are you?</p>"
}

In the post object, content contains the various representations of the same piece of data: the post content. As I understand it, with Gutenberg, the blocks are simply another representation of that same piece of data.

+1

Member

noisysocks commented Sep 4, 2017

As you pointed out, these PRs are pretty different; from a brief view it looks like #2503 is an API for (reusable) block objects themselves, while this PR is focused on exposing a (gutenberg built) post's blocks (and their data)

While the two endpoints address different use cases, it'd be highly useful to have both endpoints represent a block in a consistent way, e.g.

{
    "type": "core/paragraph",
    "attributes": {
        "content": "How are you?",
        "dropCap": true
    },
    "content": "<!-- wp:core/paragraph {\"dropCap\":true} -->\n<p class=\"has-drop-cap\">How are you?</p>\n<!-- /wp:core/paragraph -->",
    "rendered": "<p class=\"has-drop-cap\">How are you?</p>"
}

In the post object, content contains the various representations of the same piece of data: the post content. As I understand it, with Gutenberg, the blocks are simply another representation of that same piece of data.

+1

@adamsilverstein

This comment has been minimized.

Show comment
Hide comment
@adamsilverstein

adamsilverstein Sep 4, 2017

Contributor

While the two endpoints address different use cases, it'd be highly useful to have both endpoints represent a block in a consistent way.

Good point @noisysocks, I was simply passing the data back as provided by gutenberg_parse_blocks(). looks like I need to transform the naming anyway so I'll try to match the block object format from #2503.

Thanks for the feedback @rmccue - I like your suggestion of adding this data onto the regular post endpoint content object - my only concern would be the overhead introduced in block parsing the post content, even if it hasn't been edited in gutenberg, seems like we need a performat has_been_edited_in_gutenberg() helper, if there is one I couldn't find it.

Contributor

adamsilverstein commented Sep 4, 2017

While the two endpoints address different use cases, it'd be highly useful to have both endpoints represent a block in a consistent way.

Good point @noisysocks, I was simply passing the data back as provided by gutenberg_parse_blocks(). looks like I need to transform the naming anyway so I'll try to match the block object format from #2503.

Thanks for the feedback @rmccue - I like your suggestion of adding this data onto the regular post endpoint content object - my only concern would be the overhead introduced in block parsing the post content, even if it hasn't been edited in gutenberg, seems like we need a performat has_been_edited_in_gutenberg() helper, if there is one I couldn't find it.

@adamsilverstein

This comment has been minimized.

Show comment
Hide comment
@adamsilverstein

adamsilverstein Sep 4, 2017

Contributor

I remapped the response fields to match #2503 and also moved the data to the post object response as content->blocks.

Here is what the response from the demo page provided by my install of gutenberg looks like:

https://gist.github.com/adamsilverstein/5369160faca6097c5e22e0256e380962

Contributor

adamsilverstein commented Sep 4, 2017

I remapped the response fields to match #2503 and also moved the data to the post object response as content->blocks.

Here is what the response from the demo page provided by my install of gutenberg looks like:

https://gist.github.com/adamsilverstein/5369160faca6097c5e22e0256e380962

@adamsilverstein

This comment has been minimized.

Show comment
Hide comment
@adamsilverstein

adamsilverstein Sep 4, 2017

Contributor

@noisysocks & @rmccue can you please take another look after my recent changes where I have addressed your suggestions.

Contributor

adamsilverstein commented Sep 4, 2017

@noisysocks & @rmccue can you please take another look after my recent changes where I have addressed your suggestions.

@rmccue

This comment has been minimized.

Show comment
Hide comment
@rmccue

rmccue Sep 5, 2017

Contributor

my only concern would be the overhead introduced in block parsing the post content, even if it hasn't been edited in gutenberg

Won't this point become moot at the point where Gutenberg is the default editor anyway? Also, we could choose to only expose all the block pieces for context=edit if it's a frontend concern.

Contributor

rmccue commented Sep 5, 2017

my only concern would be the overhead introduced in block parsing the post content, even if it hasn't been edited in gutenberg

Won't this point become moot at the point where Gutenberg is the default editor anyway? Also, we could choose to only expose all the block pieces for context=edit if it's a frontend concern.

Show outdated Hide outdated lib/blocks.php
Show outdated Hide outdated lib/blocks.php
Show outdated Hide outdated lib/blocks.php
Show outdated Hide outdated lib/blocks.php
Show outdated Hide outdated lib/blocks.php
Show outdated Hide outdated lib/blocks.php
Show outdated Hide outdated lib/blocks.php
@joemcgill

This comment has been minimized.

Show comment
Hide comment
@joemcgill

joemcgill Sep 6, 2017

Contributor

+1 for this being a part of the regular content endpoint(s) and glad to see that #1516 was mentioned.

Architecturally, we should be thinking about more than just default post content here too since the blocks concept will likely be used in other scenarios (i.e. widgets and menus) in the future.

Contributor

joemcgill commented Sep 6, 2017

+1 for this being a part of the regular content endpoint(s) and glad to see that #1516 was mentioned.

Architecturally, we should be thinking about more than just default post content here too since the blocks concept will likely be used in other scenarios (i.e. widgets and menus) in the future.

@adamsilverstein

This comment has been minimized.

Show comment
Hide comment
@adamsilverstein

adamsilverstein Jan 2, 2018

Contributor

@aduth & @youknowriad
appreciate any further feedback here on the idea of exposing a post's (raw) block data as part of the REST API response for posts? This seems incredibly useful to me - I want to build a React front end with a 1-1 component to Gutenberg block mapping and this makes that possible.

Contributor

adamsilverstein commented Jan 2, 2018

@aduth & @youknowriad
appreciate any further feedback here on the idea of exposing a post's (raw) block data as part of the REST API response for posts? This seems incredibly useful to me - I want to build a React front end with a 1-1 component to Gutenberg block mapping and this makes that possible.

@adamsilverstein

This comment has been minimized.

Show comment
Hide comment
@adamsilverstein

adamsilverstein Jan 2, 2018

Contributor

Here is what the sample post returns, note the block data served under content:

https://gist.github.com/adamsilverstein/a1b309576ed29fe07ec79d1d8434ba05

Contributor

adamsilverstein commented Jan 2, 2018

Here is what the sample post returns, note the block data served under content:

https://gist.github.com/adamsilverstein/a1b309576ed29fe07ec79d1d8434ba05

@loremipson

This comment has been minimized.

Show comment
Hide comment
@loremipson

loremipson Jan 16, 2018

This is great @adamsilverstein!

I've barely cloned down gutenberg, so I'm unfamiliar with the project and any limitations it may have. In your returned json sample, each blocks content value looks to be what should be set as the rendered value.

Is it intended to break this down further, or does gutenberg limit this currently? Something like this would be more beneficial, imo:

"blocks": [
    {
        "type": "core/cover-image",
        "attributes": {
          "url": "https://cldup.com/Fz-ASbo2s3.jpg",
          "align": "wide"
        },
        "content": {
            "title": "Of Mountains &amp; Printing Presses"
        },
        "rendered": "\n<section class=\"wp-block-cover-image has-background-dim\" style=\"background-image:url(https://cldup.com/Fz-ASbo2s3.jpg)\">\n    <h2>Of Mountains &amp; Printing Presses</h2>\n</section>\n",
      },
]

loremipson commented Jan 16, 2018

This is great @adamsilverstein!

I've barely cloned down gutenberg, so I'm unfamiliar with the project and any limitations it may have. In your returned json sample, each blocks content value looks to be what should be set as the rendered value.

Is it intended to break this down further, or does gutenberg limit this currently? Something like this would be more beneficial, imo:

"blocks": [
    {
        "type": "core/cover-image",
        "attributes": {
          "url": "https://cldup.com/Fz-ASbo2s3.jpg",
          "align": "wide"
        },
        "content": {
            "title": "Of Mountains &amp; Printing Presses"
        },
        "rendered": "\n<section class=\"wp-block-cover-image has-background-dim\" style=\"background-image:url(https://cldup.com/Fz-ASbo2s3.jpg)\">\n    <h2>Of Mountains &amp; Printing Presses</h2>\n</section>\n",
      },
]
@adamsilverstein

This comment has been minimized.

Show comment
Hide comment
@adamsilverstein

adamsilverstein Jan 16, 2018

Contributor

@loremipson this is essentially the data as returned by gutenberg_parse_blocks - I don't fully understand how the data is set or structureds. You will see some blocks have more of the attributes you are looking for - it depends on the block.

For example in the sample page there is a video embed:

{
        "type": "core/embed",
        "attributes": {
          "url": "https://vimeo.com/22439234",
          "align": "wide"
        },
        "content": "\n<figure class=\"wp-block-embed alignwide\">\n    https://vimeo.com/22439234\n</figure>\n",
        "rendered": null
      }
Contributor

adamsilverstein commented Jan 16, 2018

@loremipson this is essentially the data as returned by gutenberg_parse_blocks - I don't fully understand how the data is set or structureds. You will see some blocks have more of the attributes you are looking for - it depends on the block.

For example in the sample page there is a video embed:

{
        "type": "core/embed",
        "attributes": {
          "url": "https://vimeo.com/22439234",
          "align": "wide"
        },
        "content": "\n<figure class=\"wp-block-embed alignwide\">\n    https://vimeo.com/22439234\n</figure>\n",
        "rendered": null
      }

@adamsilverstein adamsilverstein changed the title from Add block rest api endpoints to Add block data to REST API Jan 25, 2018

@youknowriad

This comment has been minimized.

Show comment
Hide comment
@youknowriad

youknowriad Jan 30, 2018

Contributor

Thanks for your work on this PR @adamsilverstein I'm leaning towards closing this PR for now as we don't have full parsing server-side and half-parsed blocks is not idea for an API returned value.

There are plans to move blocks registration server-side which will get us closer to server-side parsing. We can still revisit once we add those.

Contributor

youknowriad commented Jan 30, 2018

Thanks for your work on this PR @adamsilverstein I'm leaning towards closing this PR for now as we don't have full parsing server-side and half-parsed blocks is not idea for an API returned value.

There are plans to move blocks registration server-side which will get us closer to server-side parsing. We can still revisit once we add those.

@adamsilverstein

This comment has been minimized.

Show comment
Hide comment
@adamsilverstein

adamsilverstein Jan 30, 2018

Contributor

half-parsed blocks is not idea for an API returned value

I still don't understand why the additional parsing can't be [completed in JavaScript ](#2649 (comment), maybe I may be missing something.

Go ahead and close the PR if you feel this is the wrong approach, I can open a matching Issue as I still want to be able to retrieve block data via the REST API.

Contributor

adamsilverstein commented Jan 30, 2018

half-parsed blocks is not idea for an API returned value

I still don't understand why the additional parsing can't be [completed in JavaScript ](#2649 (comment), maybe I may be missing something.

Go ahead and close the PR if you feel this is the wrong approach, I can open a matching Issue as I still want to be able to retrieve block data via the REST API.

@khromov

This comment has been minimized.

Show comment
Hide comment
@khromov

khromov Mar 19, 2018

@youknowriad Being able to fetch structured block data from the REST API is an absolute necessity. I'm just starting a project that will use Gutenberg and output content through the REST API to a separate frontend and native apps. Surely that has to be in scope for Gutenberg as it currently exists?

khromov commented Mar 19, 2018

@youknowriad Being able to fetch structured block data from the REST API is an absolute necessity. I'm just starting a project that will use Gutenberg and output content through the REST API to a separate frontend and native apps. Surely that has to be in scope for Gutenberg as it currently exists?

@aduth

This comment has been minimized.

Show comment
Hide comment
@aduth

aduth Sep 13, 2018

Member

Is it likely this will be resumed, or can it be closed?

Member

aduth commented Sep 13, 2018

Is it likely this will be resumed, or can it be closed?

@adamsilverstein

This comment has been minimized.

Show comment
Hide comment
@adamsilverstein

adamsilverstein Sep 22, 2018

Contributor

Is it likely this will be resumed, or can it be closed?

@aduth -

I will resume work on this, I would like to consider how block level information can be exposed in the REST API. If you prefer, I can open an issue for now, then open a new PR?

Contributor

adamsilverstein commented Sep 22, 2018

Is it likely this will be resumed, or can it be closed?

@aduth -

I will resume work on this, I would like to consider how block level information can be exposed in the REST API. If you prefer, I can open an issue for now, then open a new PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment