{"id":29150302,"url":"https://github.com/humanmade/block-editor-ssr","last_synced_at":"2026-03-08T04:32:09.942Z","repository":{"id":40394381,"uuid":"427405193","full_name":"humanmade/block-editor-ssr","owner":"humanmade","description":"Server Side render your interactive React Gutenberg blocks","archived":false,"fork":false,"pushed_at":"2022-05-11T07:27:30.000Z","size":44,"stargazers_count":39,"open_issues_count":2,"forks_count":2,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-10-02T10:34:52.810Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/humanmade.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-12T15:20:46.000Z","updated_at":"2024-11-08T12:30:57.000Z","dependencies_parsed_at":"2022-08-09T19:10:39.113Z","dependency_job_id":null,"html_url":"https://github.com/humanmade/block-editor-ssr","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/humanmade/block-editor-ssr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humanmade%2Fblock-editor-ssr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humanmade%2Fblock-editor-ssr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humanmade%2Fblock-editor-ssr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humanmade%2Fblock-editor-ssr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/humanmade","download_url":"https://codeload.github.com/humanmade/block-editor-ssr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humanmade%2Fblock-editor-ssr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30245224,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T00:58:18.660Z","status":"online","status_checked_at":"2026-03-08T02:00:06.215Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-30T23:10:09.898Z","updated_at":"2026-03-08T04:32:09.924Z","avatar_url":"https://github.com/humanmade.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ctable width=\"100%\"\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd align=\"left\" width=\"100%\" colspan=\"2\"\u003e\n\t\t\t\u003cstrong\u003eBlock Editor SSR\u003c/strong\u003e\u003cbr /\u003e\n\t\t\tServer Side render your interactive React Gutenberg blocks.\n\t\t\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e\n\t\t\tA \u003cstrong\u003e\u003ca href=\"https://hmn.md/\"\u003eHuman Made\u003c/a\u003e\u003c/strong\u003e project. Maintained by @joehoyle.\n\t\t\u003c/td\u003e\n\t\t\u003ctd align=\"center\"\u003e\n\t\t\t\u003cimg src=\"https://hmn.md/content/themes/hmnmd/assets/images/hm-logo.svg\" width=\"100\" /\u003e\n\t\t\u003c/td\u003e\n\t\u003c/tr\u003e\n\u003c/table\u003e\n\nBlock Editor SSR adds support for rendering interactive (front-end React powered) Gutenberg blocks server side. If you want to build custom blocks that render in React on the front end, _and_ then have them also render server-side with hydration, this is the library for you.\n\nBlock Editor SSR is experimental, uses the PHP V8JS module and is not production ready. If that doesn't scare you, read on.\n\n---\n\nBuilding blocks that will render as a React-app on the front end has many possible architectures and solutions. Block Editor SSR expects blocks to be built in a _certain_ way (the way that made most sense to me). Before detailing how Block Editor SSR will server-render and hydrate your custom React block, first let's go over how building custom blocks in React (front end) is expected to go.\n\n## Register the block\n\nLike all good things in WordPress, it starts with registering something. In this case, a new custom Gutenbern block. This is done in PHP with `register_block_type()`. For example, say I have a block that is a TV Shows directory or something like that:\n\n```php\nregister_block_type(\n    'joe/tv-shows',\n    [\n        'title' =\u003e 'TV Shows',\n        'category' =\u003e 'embed',\n        'editor_script' =\u003e 'tv-shows-editor',\n        'editor_style' =\u003e 'tv-shows-editor',\n        'script' =\u003e 'tv-shows',\n        'style' =\u003e 'tv-shows',\n    ]\n);\n```\n\nThat makes the block exist, and I've set script / style handles for the editor and the front-end. If you were not familier, WordPress will auto-enqueue my `editor_` scripts in Gutenberg, and will auto-enqueue the `script` / `style` on the front-end whenever the block is rendered on a page.\n\nOf course the scripts / styles also need registering via `wp_register_script` / `wp_enqueue_style`. We'll also assume that the `tv-shows-editor` script has been setup, and registered the block in JavaScrip via `registerBlockType`.\n\nWhen it comes to showing the block on the front-end, we'll make use of the `render_callback` argument for `register_block_type`. The objective is to output a placeholder `\u003cdiv\u003e` that the React component will render to (via `ReactDOM.render`). The most basic version would be something like:\n\n\n```php\nregister_block_type(\n    'joe/tv-shows',\n    [\n        ...,\n        'render_callback' =\u003e function ( array $attributes ) : string {\n            return '\u003cdiv id=\"tv-shows\"\u003e\u003c/div\u003e';\n        },\n    ]\n);\n```\n\nNow when our block is added to a page, we'll have a `\u003cdiv\u003e` to render the React component into.\n\n## Render the React component\n\nBuilding / bundling the React component for the custom block has many options and patterns. I've detailed what I think is the most basic way to get a React build process up and running. This leverages the in-build WordPress scripts for React etc. If you are unfamiliar with `@wordpress/element` and `@wordpress/scripts` it may be a good idea to research those. `@wordpress/scripts` provides a zero-config way to build + bundle JSX / React. Simply create a new `package.json` and add it as a dev dependency. A barebones example to transpile and bundle both the editor script and frontend scripts as seperate bundles:\n\n\n```json\n{\n  \"name\": \"joe/tv-shows\",\n  \"scripts\": {\n    \"build\": \"wp-scripts build ./src/editor.js ./src/frontend.js\",\n    \"start\": \"wp-scripts start ./src/editor.js ./src/frontend.js\"\n  },\n  \"devDependencies\": {\n    \"@wordpress/scripts\": \"^18.0.1\"\n  }\n}\n```\n\nThat's basically it! `npm run start` will auto-rebuild on file changes. No local dev server etc, keep it simple. The above would mean the editor and frontend scripts are `wp_register_script`ed with the `build/editor.js` etc URLs.\n\nSpeaking of which, the `tv-shows` frontend script would then looking like:\n\n\n```jsx\nimport { render } from '@wordpress/element';\n\nrender( \u003ch1\u003eHello World\u003c/h1\u003e, document.getElementById( 'tv-shows' ) ); // Grab the container that was rendered in `render_callback`.\n```\n\nThe above assumed the `@wordpress/element` is added as a dep of the frontend script via `wp_register_script`. `@wordpress/scripts` will automatically \"external\" the WordPress scripts from the bundle. This means there's only ever one copy of React used across many \"React apps\" / blocks.\n\nVoila! That's pretty much, what I think, is the simplest way to get a custom block rendered as a React component on the frontend. It's quite likely you'd make use of `@wordpress/api-fetch` for fetching data from the REST API as part of your React component too.\n\n## Rendering on the server\n\nSo, once we've jumoed through many hoops and technologies to get a frontend JavaScript component, we are at a position of `-1`, as our block requires JavaScript to render (SEO, etc etc). This is where Block Editor SSR comes in. To have a custom block be rendered on the server, you must set the `ssr` flag in `register_block_type`:\n\n```php\nregister_block_type(\n    'joe/tv-shows',\n    [\n        ...,\n        'ssr' =\u003e true,\n    ]\n);\n```\n\nThe library will now know to (basically) override the `render_callback` of the custom block, render the React component via PHP V8JS and put the output directly into the page output. This works by taking the `script` property of the registered block and executing it (with all registered deps). You _can_ also disable \"frontend rendering\" of the block, so the JavaScript is only executed on the server, and not in the browser by setting the `fsr` property in `register_block_type` to `false`. Why would one want to do that? Well, it can be useful for debugging / verifying that SSR is working correctly. It may also be that you want to write your frontend components in React, but not actually execute any JavaScript in the browser.\n\nYou must also adapt your React DOM `render` call to make use of server side rendering too. When any block has the `ssr` flag, the `window.BlockEditorSSR` object will be available. Adapt the render call like so:\n\n```jsx\nimport { render } from '@wordpress/element';\n\nif ( window.BlockEditorSSR ) {\n    window.BlockEditorSSR.render( \u003ch1\u003eHello World\u003c/h1\u003e, document.getElementById( 'tv-shows' ) )\n} else {\n    render( \u003ch1\u003eHello World\u003c/h1\u003e, document.getElementById( 'tv-shows' ) );\n}\n```\n\n`window.BlockEditorSSR.render` will handler the server-side rendering on the server, and when run in the browser, it will automatically hydrate the React app.\n\n## Data Loading Superpowers\n\nWhen you are going to the lengths of creating \"mini React apps\" per component, it's quite possible you'll be doing data-loading as part of the component intialization. In my TV Shows example, I'd load `/wp/v2/shows` from the REST API. WordPress provides the `@wordpress/api-fetch` package for that kind of thing. Block Editor SSR ships with a custom React hook called `useApiFetch` which will provided sychronous data loading when rendered on the server, and use `@wordpress/api-fetch` when loading data in the browser. This means you can write React components that will load data from the REST API and have it auto-load data on the server. What's more, any data loaded via server rendering will automatically be included in the page payload, so the React frontend hydration will have all the data instantly available for the client-side render.\n\n`useApiFetch` is available via the `window.BlockEditorSSR` global. For example, to load all `tv-show` posts:\n\n```jsx\nlet useApiFetch = window.BlockEditorSSR.useApiFetch;\n\nexport default function TvShowsList() {\n    const [ isLoading, tvShows, error ] = useApiFetch( { path: '/wp/v2/tv-shows' } );\n    if ( isLoading ) {\n        return \u003cdiv\u003eLoading...\u003c/div\u003e\n    }\n    if ( error ) {\n        return \u003cdiv\u003e{ error.message }\u003c/div\u003e\n    }\n\n    return \u003cul\u003e\n        { tvShows.map( show ) =\u003e (\n            \u003cli key={ show.id }\u003e{ show.title.rendered }\u003c/li\u003e\n        )}\n    \u003c/ul\u003e\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhumanmade%2Fblock-editor-ssr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhumanmade%2Fblock-editor-ssr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhumanmade%2Fblock-editor-ssr/lists"}