Gutenberg: How to server render block with nested blocks?

Created on 15 May 2018  路  13Comments  路  Source: WordPress/gutenberg

Hi,

I have a block that uses InnerBlocks that I want to have server-rendered:

const { __ } = wp.i18n;
const { Button } = wp.components;
const { MediaUpload, InnerBlocks } = wp.blocks;

export const attributes = {
  background: {
    type: 'string',
  },
  backgroundUrl: {
    type: 'string',
  },
};

export const edit = ({ attributes, setAttributes }) => (
  <section
    className="partners-main"
    style={{ background: `center / cover no-repeat url(${attributes.backgroundUrl})` }}
  >
    <MediaUpload
      onSelect={image => setAttributes({
        background: image.id,
        backgroundUrl: image.sizes['full'],
      })}
      type="image"
      value={attributes.backgroundId}
      render={({ open }) => (
        <Button className={'button button-large'} onClick={open}>
          { __( 'Upload the background' ) }
        </Button>
      )}
    />
    <InnerBlocks />
  </section>
);

export const save = () => null;

I'm trying to do a server-rendering:

<?php
namespace App;

$theme = explode('/', get_stylesheet(), 2)[0];

function render_block_partners_main($attributes, $content = null) {
    var_dump($attributes, $content); // returns array(1) { ["backgroundUrl"]=> string(73) "https://localhost:3000/wp-content/uploads/sites/2/2018/02/sp-partneri.png" } NULL
    return sage('blade')->render('blocks.partners-main', $attributes);
}

register_block_type($theme . '/partners-main', [
    'render_callback' => __NAMESPACE__ . '\\render_block_partners_main',
]);

I would imagine similar behaviour like with shortcodes where I get nested blocks in $content attribute. Is it something that is in the roadmap or something I can achieve now but don't know how?

Thank you.
Dan

Needs Technical Feedback [Feature] Block API [Feature] Extensibility [Type] Help Request

Most helpful comment

Now it looks it works. Here are my examples:

Here is how my JS save function of the block looks like. Whatever you return in save function is in $content variable of PHP render function.

function save() {
  return <InnerBlocks.Content />;
}

and here is my render PHP function:

function render($attributes, $content) {
  return '<div>doing some server magic :) ' . uniqid() . '<br />' . $content . '</div>';
}

So I would consider it as solved!

All 13 comments

Is there a possibility of introducing multiple InnerBlocks per block? Like this:

el( wp.editor.InnerBlocks, {
    value: someAttribute,
    onChange: function( content ) {
        props.setAttributes({ someAttribute: content });
    }
} ),

el( wp.editor.InnerBlocks, {
    value: someAttribute2,
    onChange: function( content ) {
        props.setAttributes({ someAttribute2: content });
    }
} ),

This would be more useful.

Currently it's only possible to achieve this using a workaround of creating a second block. This is almost acceptable.

If I could save InnerBlocks in an array (as I can with RichText) then it would be also an advantage.

@chrisvanpatten and @jorgefilipecosta #7247 #11271 #10745 #7785

Is there a Timetable for this? We currently have a custom block with core/freeform and Timber rendering and right now this breaks our custom block.

I鈥檓 going to dig into this today. As it turns out I need this for a client project myself, so I鈥檒l report back what I find.

I gave up on this and just accept that Innerblocks containers have to be rendered in JS, which is less than ideal, to say the least.

For my purposes, if the server-side render of an Innerblocks container was handed an array like:

[
    'my_container_title' => 'blah',
    'my_inspector_field' => 'bleh',
    'innerblocks' => [
        [
            'namespace' => 'core',
            'name' => 'paragraph',
            'attributes' => [ ... ],
            'render_callback' => null,
            'rendered' => '<p>...</p>'
        ],
        [
            'namespace' => 'superduper',
            'name' => 'amazingblock',
            'attributes' => [ ... ],
            'render_callback' => 'superduper_function' // callable of any sort
            'rendered' => '<div>...</div>'
        ],
        ...
    ]
]

That's "all" that's needed. (Edited to add that knowing if there is a server-side render function registered would allow me to call that instead of relying on the pre-rendered content; in that way, if I have multiple custom blocks which do server-side renders I could provide them with context information in PHP, since that's nearly impossible to achieve in JS, apparently.)

Hey sorry all for the delay but it is possible to have an InnerBlocks and render your block on the server. I have a sample plugin but have been offline today. I鈥檒l push it up as soon as I can.

@chrisvanpatten Hi! Got any update on this?

Now it looks it works. Here are my examples:

Here is how my JS save function of the block looks like. Whatever you return in save function is in $content variable of PHP render function.

function save() {
  return <InnerBlocks.Content />;
}

and here is my render PHP function:

function render($attributes, $content) {
  return '<div>doing some server magic :) ' . uniqid() . '<br />' . $content . '</div>';
}

So I would consider it as solved!

It doesn't work if the innerblocks is a dynamic block as well... But if it's not dynamic it works... That definitely sounds like a bug

It doesn't work if the innerblocks is a dynamic block as well... But if it's not dynamic it works... That definitely sounds like a bug

Hi. This appears to be unrelated to the current issue.

Feel free to open a new one, and if so please provide some context, such as intended use cases. Thanks.

It doesn't work if the innerblocks is a dynamic block as well... But if it's not dynamic it works... That definitely sounds like a bug

Did you find a solution for this?

stil today I need a solution for the same problem

Yes the issue was within my hooks, I really don't remember what was my issue and how I solved it but there is no issue there with gutenberg, I think maybe I just forgot to return the result in the dynamic block or I had a bad condition returning nothing

Was this page helpful?
0 / 5 - 0 ratings