Skip to content

Instantly share code, notes, and snippets.

@Shelob9
Last active February 4, 2024 20:38
Show Gist options
  • Select an option

  • Save Shelob9/144055408101e2fdfc4bf34adc85dd04 to your computer and use it in GitHub Desktop.

Select an option

Save Shelob9/144055408101e2fdfc4bf34adc85dd04 to your computer and use it in GitHub Desktop.
Example Gutenberg block with server-side rendering. Gutenberg edit() block creates interface. Gutenberg saves settings automatically, the PHP function passed as `render_callback` to `register_block_type` is used to create HTML for front-end rendering of block.
const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const el = wp.element.createElement;
registerBlockType( 'hiRoy/serverSide', {
title: __( 'Server Side Block', 'text-domain' ),
icon: 'networking',
category: 'common',
attributes: {
images : {
default: [],
type: 'array',
}
},
edit({attributes, setAttributes, className, focus, id}) {
//Put a user interface here.
},
save({attributes, className}) {
//gutenberg will save attributes we can use in server-side callback
return null;
},
} );
<?php
register_block_type('hiRoy/serverSide', array(
'render_callback' => 'hi_roy_render_callback',
'attributes' => array(
'images' => array(
'type' => 'array'
)
)
)
);
function hi_roy_render_callback( $attributes ){
$images = $attributes[ 'images' ];
return '<div><!-- put image gallery here--></div>';
}
@andykillen

Copy link
Copy Markdown

great overview but perhaps it should have been hiroy_render_callback()

@emfluenceindia

emfluenceindia commented Feb 4, 2019

Copy link
Copy Markdown

I could not get to work. Here is what I tried.

block.js

//  Import CSS.
import './style.scss';
import './editor.scss';

const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { RichText } = wp.editor;

registerBlockType( 'hall/block-server-side-render', {
	title: __( 'Server Side Rendering' ),
	icon: 'shield',
	category: 'common',
        keywords: [
		__( 'Server Side Rendering' )
	],
    attributes: {
	  innerContent: {
	      type: 'array',
              source: 'children',
              selector: 'p'
      }
    },
   edit: function( props ) {
       function onChangeContent( content ) {
	        props.attributes( { innerContent: content } );
        }

	return (
		<div className={ props.className }>
                   <div class="gray-bg">
                      <RichText tagName="p" role="textbox" aria-multiline="true" value={props.attributes.innerContent} onChange={onChangeContent} />
                   </div>
		</div>
		);
	},
	save: function( props ) {
		return null;
	},
} );

init.php

register_block_type( 'hall/block-server-side-render', array(
	'render_callback' => 'hall_render_inner_content',
	'attributes' => array(
		'innerContent' => array(
			'type' => 'array'
		)
	)
));

function hall_render_inner_content( $attributes ) {
	$innerContent = $attributes['innerContent'];
	return '<div class="inner-content">' . $innerContent . '</div>';
}

When published the content didn't save. The post_content for me is <!-- wp:hall/block-server-side-render /-->.

I am new to Gutenberg development. Please let me know what went wrong! :(

@sagarseth9

Copy link
Copy Markdown

How do we call the render_callback inside a php class? It doesn't work the usual way.

@rajo-vilo

Copy link
Copy Markdown

Hello,

I have the same issues on the gutenberg block. Nothing show on frontend! just
Is there no function we need to call on save() function JS to say wp that show content in render php function ?

WP: 5.1.1

@andrewlimaza

Copy link
Copy Markdown

Your render_callback method will be output on the save() function so you don't need to call to render the PHP side of things @rajogit

@andrewlimaza

Copy link
Copy Markdown

So the save method can just return null.

@sanzeeb3

sanzeeb3 commented May 6, 2019

Copy link
Copy Markdown

Is there anyway to render the content for edit() method from the server side? Just like return null and render_callback similar to save()?

@JuanVqz

JuanVqz commented Dec 4, 2019

Copy link
Copy Markdown

You need to register a method render_my_php_block in a public wordpress hook like:
add_action( 'wp_enqueue_scripts', 'render_my_php_block');
put register_block_type.... inside render_my_php_block

register_block_type( 'hall/block-server-side-render', array(
	'render_callback' => 'hall_render_inner_content',
	'attributes' => array(
		'innerContent' => array(
			'type' => 'array'
		)
	)
));

@latiosthinh

latiosthinh commented Feb 11, 2020

Copy link
Copy Markdown

Can you show me how to use the example attribute on the serverside?

 register_block_type('hiRoy/serverSide', array(
        'render_callback' => 'hi_roy_render_callback',
        'attributes' => [
            'name' => [
                'type' => 'string'
            ]
        ],
        'example' => [ // <== THIS ONE
           'attributes' => [
               'name' => 'Thomas'
            ]
        ]
    )
);

@timotheemoulin

Copy link
Copy Markdown

How do we call the render_callback inside a php class? It doesn't work the usual way.

You have to specify the class that is responsible for the render

'render_callback' =>[$this, 'render_function']

@mtoensing

Copy link
Copy Markdown

Hi! This seems to be the exact same question and maybe answer to my question here: "How to use output of php render_callback function in the block editors backend?" https://wordpress.stackexchange.com/questions/363703/gutenberg-how-to-use-output-of-php-render-callback-function-in-the-block-editor Maybe someone can help?

@cre-mer

cre-mer commented Aug 4, 2020

Copy link
Copy Markdown

How do we call the render_callback inside a php class? It doesn't work the usual way.

As @timotheemoulin already said, or

'render_callback' => function($atts) {
    return $this->render_function($atts);
}

@sharif1752

sharif1752 commented Sep 23, 2020

Copy link
Copy Markdown

`// const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { TextControl }= wp.components;

registerBlockType( 'mygutenberg-block/slide-title', {
title: __( 'Server Side Rendering' ),
icon: 'shield',
category: 'common',
keywords: [
__( 'Server Side Rendering' )
],
attributes: {
innerContent: {
type: 'string',
source: 'text',
}
},
edit( {attributes, setAttributes, className, focus, id} ) {
console.log(attributes);

return (
    <div className={ className }>
               <TextControl 
                    label={ __( 'innerContent', 'recipe' ) } 
                    value={ attributes.innerContent }
                    onChange={ ( new_val ) => {
                        setAttributes({ innerContent: new_val })
                    }} />
    </div>
    );
},
save( {attributes, className} ) {
    return null;
},

} );`

`// function hall_render_inner_content($attributes){

return print_r($attributes);

}

function my_custom_block_register_block(){
register_block_type(
'mygutenberg-block/slide-title',
array(
'render_callback' => 'hall_render_inner_content',
'attributes' => array(
'innerContent' => array(
'type' => 'string',
'default' => 'test',
)
)
)
);
}

add_action( 'init', 'my_custom_block_register_block' );`

but when i update or save the post give this error "Updating failed. The response is not a valid JSON response."
screenshot given bellow

https://prnt.sc/umgmzt

@wpexplorer

Copy link
Copy Markdown

Is there any conditional check we can use to check if we are rendering the element in the Gutenberg editor as opposed to the live site? For example I'm showing a form but I want the button disabled when viewing in Gutenberg, thanks!

@eliot-akira

Copy link
Copy Markdown

@wpexplorer Here's a way to check if a block is being rendered inside the Gutenberg editor.

$in_gutenberg_editor = defined('REST_REQUEST') && REST_REQUEST && !empty($_REQUEST['context']) && $_REQUEST['context']==='edit';

Reference:

@wpexplorer

Copy link
Copy Markdown

@eliot-akira - thanks!

@bizm

bizm commented Feb 15, 2022

Copy link
Copy Markdown

How is it supposed to work without calling wp_enqueue_script? Below is the example how i do it in my custom wordpress theme:

<?php
  // this is probably your functions.php file

  function register_hiroy_serverside_block() {
    $script_path = get_template_directory_uri() . '/path/to/your/block/index.js';
    $asset_file = include( '/path/to/your/block/index.asset.php' );

    wp_enqueue_script(
      'hiroy-server-side',
      $script_path,
      $asset_file['dependencies'],
      $asset_file['version']
    );

    register_block_type('hiRoy/serverSide', array(
            'render_callback' => 'hi_roy_render_callback',
            'attributes' => array(
                'images' => array(
                    'type' => 'array'
                )
            )
        )
    );
  }

  function hiroy_render_callback( $attributes ){
    $images = $attributes[ 'images' ];
    return '<div><!-- put image gallery here--></div>';
  }

  add_action( 'init', 'register_hiroy_serverside_block' );
?>

That is the only way i could've got it working. All the tutorials and articles i found did not help me. I still don't understand how your example above can work at all. I mean it is in fact not registering anything, thus no blocks should appear in UI. Please anyone explain me what is it that i'm missing here. The whole wordpress architecture is driving me mad!

@wpexplorer

Copy link
Copy Markdown

@bizm - This gist isn't intended to explain how to register blocks it's just an example showing how to use the render_callback argument. Now, you don't actually have to use wp_enqueue_script to load your block JS file - you can and probably should be loading the file via your block.json file, see here: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/ and scroll down to "Editor Script".

@Shelob9

Shelob9 commented Feb 16, 2022

Copy link
Copy Markdown
Author

@bizm Here is a more up to date example of how to set up a server-side rendered block: https://github.com/imaginarymachines/everything-all-of-the-time/blob/main/blocks/php-block/init.php

Two issues with your snippet that need corrected:

@ducktype

ducktype commented Nov 21, 2023

Copy link
Copy Markdown
add_action('init',function(){
  $block_meta = [
    'name' => 'test/test',
    'title' => 'Test',
    'render_callback' => function($attrs,$content,$block){
      return "TEST";
    }
  ];
  register_block_type($block_meta['name'],$block_meta);
  add_action('enqueue_block_editor_assets',function()use($block_meta){
    $screen = get_current_screen();
    if(!$screen->is_block_editor()) return;
    add_action('admin_print_footer_scripts',function()use($block_meta){
      echo "
       <script>
        var block = {
          edit: function({attributes, setAttributes, className, focus, id}) {
            return "HELLO"
          },
          save: function({attributes, className}) {
            return
          }
        }
        wp.blocks.registerBlockType('{$block_meta['name']}',block)
      </script>
      ";
    });
  });
});

@1ucay

1ucay commented Dec 3, 2023

Copy link
Copy Markdown
$block_metas = array(
    array(
        'name'  => 'domain/faq',
        'title' => __( 'FAQ', 'domain' ),
        'description' => '',
        'category' => 'text',
        'icon'  => 'star-filled',
        'api_version' => 2
    ),
    array(
        'name'  => 'domain/accordion',
        'title' => __( 'Accordion', 'domain' ),
        'description' => '',
        'category' => 'text',
        'icon'  => 'star-filled',
        'api_version' => 2
    )
);
foreach( $block_metas as $block_meta ) {

    $block_meta['render_callback'] = function ( $block_attributes, $content ) use ( $block_meta ) {
        ob_start();

        $file = ( str_contains( $block_meta['name'], '/' ) ) ? explode( '/', $block_meta['name'] )[1] : $block_meta['name'];

        if ( ob_get_level() ) {
            // https://wordpress.stackexchange.com/questions/4462/passing-variables-through-locate-template
            if ( $filepath = locate_template( "blocks/{$file}/{$file}.php", true, true, array_merge( $_REQUEST, $block_meta, $block_attributes ) ) )
                include_once( $filepath );

            $output = ob_get_contents();
            ob_end_clean();
        }

        return $output;
    };
    register_block_type( $block_meta['name'], $block_meta );

    add_action( 'enqueue_block_editor_assets', function() use ( $block_meta ) {
        add_action( 'admin_print_footer_scripts', function() use ( $block_meta ) {
            echo "
            <script>
                wp.blocks.registerBlockType('{$block_meta['name']}', {
                    edit: function( props ) {
                        return wp.element.createElement(
                            wp.serverSideRender, {
                                block: props.name
                            }
                        );
                    },
                    save: function({attributes, className}) {
                        return null;
                    }
                })
            </script>
            ";
        });
    });
}

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