@wordpress/server-side-render 6.24.0 → 6.24.2-next.v.202606191442.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -1
- package/README.md +4 -17
- package/build/hook.cjs +8 -5
- package/build/hook.cjs.map +3 -3
- package/build/index.cjs +2 -1
- package/build/index.cjs.map +3 -3
- package/build/server-side-render.cjs +18 -7
- package/build/server-side-render.cjs.map +3 -3
- package/build/types.cjs +19 -0
- package/build/types.cjs.map +7 -0
- package/build-module/hook.mjs +7 -5
- package/build-module/hook.mjs.map +3 -3
- package/build-module/index.mjs +1 -1
- package/build-module/index.mjs.map +3 -3
- package/build-module/server-side-render.mjs +19 -9
- package/build-module/server-side-render.mjs.map +3 -3
- package/build-module/types.mjs +1 -0
- package/build-module/types.mjs.map +7 -0
- package/build-types/hook.d.ts +68 -0
- package/build-types/hook.d.ts.map +1 -0
- package/build-types/index.d.ts +23 -0
- package/build-types/index.d.ts.map +1 -0
- package/build-types/server-side-render.d.ts +32 -0
- package/build-types/server-side-render.d.ts.map +1 -0
- package/build-types/types.d.ts +34 -0
- package/build-types/types.d.ts.map +1 -0
- package/package.json +19 -12
- package/src/{hook.js → hook.ts} +57 -22
- package/src/{index.js → index.ts} +6 -1
- package/src/{server-side-render.js → server-side-render.tsx} +31 -22
- package/src/types.ts +40 -0
- /package/src/test/{index.js → index.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
-
## 6.24.
|
|
5
|
+
## 6.24.1 (2026-06-16)
|
|
6
|
+
|
|
7
|
+
## 6.24.0 (2026-06-10)
|
|
8
|
+
|
|
9
|
+
### Code Quality
|
|
10
|
+
|
|
11
|
+
- Add missing `@types/react` dependency. [#78882](https://github.com/WordPress/gutenberg/pull/78882).
|
|
6
12
|
|
|
7
13
|
## 6.23.0 (2026-05-27)
|
|
8
14
|
|
package/README.md
CHANGED
|
@@ -63,20 +63,12 @@ function Example() {
|
|
|
63
63
|
|
|
64
64
|
_Parameters_
|
|
65
65
|
|
|
66
|
-
- _props_ `
|
|
67
|
-
- _props.
|
|
68
|
-
- _props.attributes_ `Object`: The block attributes to be sent to the server for rendering.
|
|
69
|
-
- _props.className_ `[string]`: Additional classes to apply to the wrapper element.
|
|
70
|
-
- _props.httpMethod_ `[string]`: The HTTP method to use ('GET' or 'POST'). Default is 'GET'
|
|
71
|
-
- _props.urlQueryArgs_ `[Object]`: Additional query arguments to append to the request URL.
|
|
72
|
-
- _props.skipBlockSupportAttributes_ `[boolean]`: Whether to remove block support attributes before sending.
|
|
73
|
-
- _props.EmptyResponsePlaceholder_ `[Function]`: Component rendered when the API response is empty.
|
|
74
|
-
- _props.ErrorResponsePlaceholder_ `[Function]`: Component rendered when the API response is an error.
|
|
75
|
-
- _props.LoadingResponsePlaceholder_ `[Function]`: Component rendered while the API request is loading.
|
|
66
|
+
- _props_ `ServerSideRenderWithPostIdProps`: Component props.
|
|
67
|
+
- _props.urlQueryArgs_ `ServerSideRenderWithPostIdProps[ 'urlQueryArgs' ]`: Additional query arguments to append to the request URL.
|
|
76
68
|
|
|
77
69
|
_Returns_
|
|
78
70
|
|
|
79
|
-
-
|
|
71
|
+
- The rendered server-side content.
|
|
80
72
|
|
|
81
73
|
### useServerSideRender
|
|
82
74
|
|
|
@@ -112,12 +104,7 @@ function MyServerSideRender( { attributes, block } ) {
|
|
|
112
104
|
|
|
113
105
|
_Parameters_
|
|
114
106
|
|
|
115
|
-
- _args_ `
|
|
116
|
-
- _args.attributes_ `Object`: The block attributes to be sent to the server for rendering.
|
|
117
|
-
- _args.block_ `string`: The identifier of the block to be serverside rendered. Example: 'core/archives'.
|
|
118
|
-
- _args.skipBlockSupportAttributes_ `[boolean]`: Whether to remove block support attributes before sending.
|
|
119
|
-
- _args.httpMethod_ `[string]`: The HTTP method to use ('GET' or 'POST'). Default is 'GET'.
|
|
120
|
-
- _args.urlQueryArgs_ `[Object]`: Additional query arguments to append to the request URL.
|
|
107
|
+
- _args_ `UseServerSideRenderArgs`: The hook configuration object.
|
|
121
108
|
|
|
122
109
|
_Returns_
|
|
123
110
|
|
package/build/hook.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -26,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
27
|
));
|
|
27
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
29
|
|
|
29
|
-
// packages/server-side-render/src/hook.
|
|
30
|
+
// packages/server-side-render/src/hook.ts
|
|
30
31
|
var hook_exports = {};
|
|
31
32
|
__export(hook_exports, {
|
|
32
33
|
removeBlockSupportAttributes: () => removeBlockSupportAttributes,
|
|
@@ -72,7 +73,9 @@ function removeBlockSupportAttributes(attributes) {
|
|
|
72
73
|
};
|
|
73
74
|
}
|
|
74
75
|
function useServerSideRender(args) {
|
|
75
|
-
const [response, setResponse] = (0, import_element.useState)({
|
|
76
|
+
const [response, setResponse] = (0, import_element.useState)({
|
|
77
|
+
status: "idle"
|
|
78
|
+
});
|
|
76
79
|
const shouldDebounceRef = (0, import_element.useRef)(false);
|
|
77
80
|
const {
|
|
78
81
|
attributes,
|
|
@@ -82,7 +85,7 @@ function useServerSideRender(args) {
|
|
|
82
85
|
urlQueryArgs
|
|
83
86
|
} = args;
|
|
84
87
|
let sanitizedAttributes = attributes && (0, import_blocks.__experimentalSanitizeBlockAttributes)(block, attributes);
|
|
85
|
-
if (skipBlockSupportAttributes) {
|
|
88
|
+
if (skipBlockSupportAttributes && sanitizedAttributes) {
|
|
86
89
|
sanitizedAttributes = removeBlockSupportAttributes(sanitizedAttributes);
|
|
87
90
|
}
|
|
88
91
|
const isPostRequest = "POST" === httpMethod;
|
|
@@ -109,12 +112,12 @@ function useServerSideRender(args) {
|
|
|
109
112
|
content: res ? res.rendered : ""
|
|
110
113
|
});
|
|
111
114
|
}).catch((error) => {
|
|
112
|
-
if (error.name === "AbortError") {
|
|
115
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
113
116
|
return;
|
|
114
117
|
}
|
|
115
118
|
setResponse({
|
|
116
119
|
status: "error",
|
|
117
|
-
error: error.message
|
|
120
|
+
error: error instanceof Error ? error.message : String(error)
|
|
118
121
|
});
|
|
119
122
|
}).finally(() => {
|
|
120
123
|
shouldDebounceRef.current = true;
|
package/build/hook.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/hook.
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { debounce } from '@wordpress/compose';\nimport { useEffect, useState, useRef } from '@wordpress/element';\nimport apiFetch from '@wordpress/api-fetch';\nimport { addQueryArgs } from '@wordpress/url';\nimport { __experimentalSanitizeBlockAttributes } from '@wordpress/blocks';\n\nexport function rendererPath(
|
|
5
|
-
"mappings": "
|
|
3
|
+
"sources": ["../src/hook.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { debounce } from '@wordpress/compose';\nimport { useEffect, useState, useRef } from '@wordpress/element';\nimport apiFetch from '@wordpress/api-fetch';\nimport { addQueryArgs } from '@wordpress/url';\n\nimport { __experimentalSanitizeBlockAttributes } from '@wordpress/blocks';\n\nexport function rendererPath(\n\tblock: string,\n\tattributes: Record< string, unknown > | null = null,\n\turlQueryArgs: Record< string, unknown > = {}\n): string {\n\treturn addQueryArgs( `/wp/v2/block-renderer/${ block }`, {\n\t\tcontext: 'edit',\n\t\t...( null !== attributes ? { attributes } : {} ),\n\t\t...urlQueryArgs,\n\t} );\n}\n\nexport function removeBlockSupportAttributes(\n\tattributes: Record< string, unknown > & {\n\t\tstyle?: Record< string, unknown >;\n\t}\n): Record< string, unknown > {\n\tconst {\n\t\tbackgroundColor,\n\t\tborderColor,\n\t\tfontFamily,\n\t\tfontSize,\n\t\tgradient,\n\t\ttextColor,\n\t\tclassName,\n\t\t...restAttributes\n\t} = attributes;\n\n\tconst {\n\t\tborder,\n\t\tcolor,\n\t\telements,\n\t\tshadow,\n\t\tspacing,\n\t\ttypography,\n\t\t...restStyles\n\t} = attributes?.style || {};\n\n\treturn {\n\t\t...restAttributes,\n\t\tstyle: restStyles,\n\t};\n}\n\n/**\n * Server-side render response object.\n */\nexport interface ServerSideRenderResponse {\n\t/** The current request status: 'idle', 'loading', 'success', or 'error'. */\n\tstatus: 'idle' | 'loading' | 'success' | 'error';\n\t/** The rendered block content (available when status is 'success'). */\n\tcontent?: string;\n\t/** The error message (available when status is 'error'). */\n\terror?: string;\n}\n\n/**\n * Configuration object for the useServerSideRender hook.\n */\nexport interface UseServerSideRenderArgs {\n\t/** The block attributes to be sent to the server for rendering. */\n\tattributes: Record< string, unknown >;\n\t/** The identifier of the block to be serverside rendered. Example: 'core/archives'. */\n\tblock: string;\n\t/** Whether to remove block support attributes before sending. */\n\tskipBlockSupportAttributes?: boolean;\n\t/** The HTTP method to use ('GET' or 'POST'). Default is 'GET'. */\n\thttpMethod?: 'GET' | 'POST';\n\t/** Additional query arguments to append to the request URL. */\n\turlQueryArgs?: Record< string, unknown >;\n}\n\n/**\n * A hook for server-side rendering a preview of dynamic blocks to display in the editor.\n *\n * Handles fetching server-rendered previews for blocks, managing loading states,\n * and automatically debouncing requests to prevent excessive API calls. It supports both\n * GET and POST requests, with POST requests used for larger attribute payloads.\n *\n * @example\n * Basic usage:\n *\n * ```jsx\n * import { RawHTML } from '@wordpress/element';\n * import { useServerSideRender } from '@wordpress/server-side-render';\n *\n * function MyServerSideRender( { attributes, block } ) {\n * const { content, status, error } = useServerSideRender( {\n * attributes,\n * block,\n * } );\n *\n * if ( status === 'loading' ) {\n * return <div>Loading...</div>;\n * }\n *\n * if ( status === 'error' ) {\n * return <div>Error: { error }</div>;\n * }\n *\n * return <RawHTML>{ content }</RawHTML>;\n * }\n * ```\n *\n * @param args The hook configuration object.\n *\n * @return The server-side render response object.\n */\nexport function useServerSideRender(\n\targs: UseServerSideRenderArgs\n): ServerSideRenderResponse {\n\tconst [ response, setResponse ] = useState< ServerSideRenderResponse >( {\n\t\tstatus: 'idle',\n\t} );\n\tconst shouldDebounceRef = useRef< boolean >( false );\n\n\tconst {\n\t\tattributes,\n\t\tblock,\n\t\tskipBlockSupportAttributes = false,\n\t\thttpMethod = 'GET',\n\t\turlQueryArgs,\n\t} = args;\n\n\tlet sanitizedAttributes: Record< string, unknown > | null =\n\t\tattributes &&\n\t\t__experimentalSanitizeBlockAttributes( block, attributes );\n\n\tif ( skipBlockSupportAttributes && sanitizedAttributes ) {\n\t\tsanitizedAttributes =\n\t\t\tremoveBlockSupportAttributes( sanitizedAttributes );\n\t}\n\n\t// If httpMethod is 'POST', send the attributes in the request body instead of the URL.\n\t// This allows sending a larger attributes object than in a GET request, where the attributes are in the URL.\n\tconst isPostRequest = 'POST' === httpMethod;\n\tconst urlAttributes = isPostRequest ? null : sanitizedAttributes;\n\tconst path = rendererPath( block, urlAttributes, urlQueryArgs );\n\tconst body = isPostRequest\n\t\t? JSON.stringify( { attributes: sanitizedAttributes ?? null } )\n\t\t: undefined;\n\n\tuseEffect( () => {\n\t\tconst controller = new AbortController();\n\t\tconst debouncedFetch = debounce(\n\t\t\tfunction () {\n\t\t\t\t{\n\t\t\t\t\tsetResponse( { status: 'loading' } );\n\n\t\t\t\t\tapiFetch< { rendered: string } >( {\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tmethod: isPostRequest ? 'POST' : 'GET',\n\t\t\t\t\t\tbody,\n\t\t\t\t\t\theaders: isPostRequest\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t: {},\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t} )\n\t\t\t\t\t\t.then( ( res ) => {\n\t\t\t\t\t\t\tsetResponse( {\n\t\t\t\t\t\t\t\tstatus: 'success',\n\t\t\t\t\t\t\t\tcontent: res ? res.rendered : '',\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.catch( ( error: unknown ) => {\n\t\t\t\t\t\t\t// The request was aborted, do not update the response.\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\t\t\terror.name === 'AbortError'\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsetResponse( {\n\t\t\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\t\t\terror:\n\t\t\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t\t\t: String( error ),\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.finally( () => {\n\t\t\t\t\t\t\t// Debounce requests after first fetch.\n\t\t\t\t\t\t\tshouldDebounceRef.current = true;\n\t\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t},\n\t\t\tshouldDebounceRef.current ? 500 : 0\n\t\t);\n\n\t\tdebouncedFetch();\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t\tdebouncedFetch.cancel();\n\t\t};\n\t}, [ path, isPostRequest, body ] );\n\n\treturn response;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAAyB;AACzB,qBAA4C;AAC5C,uBAAqB;AACrB,iBAA6B;AAE7B,oBAAsD;AAE/C,SAAS,aACf,OACA,aAA+C,MAC/C,eAA0C,CAAC,GAClC;AACT,aAAO,yBAAc,yBAA0B,KAAM,IAAI;AAAA,IACxD,SAAS;AAAA,IACT,GAAK,SAAS,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IAC7C,GAAG;AAAA,EACJ,CAAE;AACH;AAEO,SAAS,6BACf,YAG4B;AAC5B,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACJ,IAAI;AAEJ,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACJ,IAAI,YAAY,SAAS,CAAC;AAE1B,SAAO;AAAA,IACN,GAAG;AAAA,IACH,OAAO;AAAA,EACR;AACD;AAkEO,SAAS,oBACf,MAC2B;AAC3B,QAAM,CAAE,UAAU,WAAY,QAAI,yBAAsC;AAAA,IACvE,QAAQ;AAAA,EACT,CAAE;AACF,QAAM,wBAAoB,uBAAmB,KAAM;AAEnD,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA,6BAA6B;AAAA,IAC7B,aAAa;AAAA,IACb;AAAA,EACD,IAAI;AAEJ,MAAI,sBACH,kBACA,qDAAuC,OAAO,UAAW;AAE1D,MAAK,8BAA8B,qBAAsB;AACxD,0BACC,6BAA8B,mBAAoB;AAAA,EACpD;AAIA,QAAM,gBAAgB,WAAW;AACjC,QAAM,gBAAgB,gBAAgB,OAAO;AAC7C,QAAM,OAAO,aAAc,OAAO,eAAe,YAAa;AAC9D,QAAM,OAAO,gBACV,KAAK,UAAW,EAAE,YAAY,uBAAuB,KAAK,CAAE,IAC5D;AAEH,gCAAW,MAAM;AAChB,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,qBAAiB;AAAA,MACtB,WAAY;AACX;AACC,sBAAa,EAAE,QAAQ,UAAU,CAAE;AAEnC,+BAAAA,SAAkC;AAAA,YACjC;AAAA,YACA,QAAQ,gBAAgB,SAAS;AAAA,YACjC;AAAA,YACA,SAAS,gBACN;AAAA,cACA,gBAAgB;AAAA,YAChB,IACA,CAAC;AAAA,YACJ,QAAQ,WAAW;AAAA,UACpB,CAAE,EACA,KAAM,CAAE,QAAS;AACjB,wBAAa;AAAA,cACZ,QAAQ;AAAA,cACR,SAAS,MAAM,IAAI,WAAW;AAAA,YAC/B,CAAE;AAAA,UACH,CAAE,EACD,MAAO,CAAE,UAAoB;AAE7B,gBACC,iBAAiB,SACjB,MAAM,SAAS,cACd;AACD;AAAA,YACD;AAEA,wBAAa;AAAA,cACZ,QAAQ;AAAA,cACR,OACC,iBAAiB,QACd,MAAM,UACN,OAAQ,KAAM;AAAA,YACnB,CAAE;AAAA,UACH,CAAE,EACD,QAAS,MAAM;AAEf,8BAAkB,UAAU;AAAA,UAC7B,CAAE;AAAA,QACJ;AAAA,MACD;AAAA,MACA,kBAAkB,UAAU,MAAM;AAAA,IACnC;AAEA,mBAAe;AAEf,WAAO,MAAM;AACZ,iBAAW,MAAM;AACjB,qBAAe,OAAO;AAAA,IACvB;AAAA,EACD,GAAG,CAAE,MAAM,eAAe,IAAK,CAAE;AAEjC,SAAO;AACR;",
|
|
6
6
|
"names": ["apiFetch"]
|
|
7
7
|
}
|
package/build/index.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -16,7 +17,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
17
|
};
|
|
17
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
19
|
|
|
19
|
-
// packages/server-side-render/src/index.
|
|
20
|
+
// packages/server-side-render/src/index.ts
|
|
20
21
|
var index_exports = {};
|
|
21
22
|
__export(index_exports, {
|
|
22
23
|
ServerSideRender: () => import_server_side_render.ServerSideRenderWithPostId,
|
package/build/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.
|
|
4
|
-
"sourcesContent": ["/**\n * Internal dependencies\n */\nimport { ServerSideRenderWithPostId } from './server-side-render';\nimport { useServerSideRender } from './hook';\n\n/**\n * A compatibility layer for the `ServerSideRender` component when used with `wp` global namespace.\n *\n * @deprecated Use `ServerSideRender` non-default export instead.\n *\n * @example\n * ```js\n * import ServerSideRender from '@wordpress/server-side-render';\n * ```\n */\nconst ServerSideRenderCompat
|
|
5
|
-
"mappings": "
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Internal dependencies\n */\nimport { ServerSideRenderWithPostId } from './server-side-render';\nimport { useServerSideRender } from './hook';\n\n/**\n * A compatibility layer for the `ServerSideRender` component when used with `wp` global namespace.\n *\n * @deprecated Use `ServerSideRender` non-default export instead.\n *\n * @example\n * ```js\n * import ServerSideRender from '@wordpress/server-side-render';\n * ```\n */\nconst ServerSideRenderCompat =\n\tServerSideRenderWithPostId as typeof ServerSideRenderWithPostId & {\n\t\tServerSideRender: typeof ServerSideRenderWithPostId;\n\t\tuseServerSideRender: typeof useServerSideRender;\n\t};\n\nServerSideRenderCompat.ServerSideRender = ServerSideRenderWithPostId;\nServerSideRenderCompat.useServerSideRender = useServerSideRender;\n\nexport { ServerSideRenderWithPostId as ServerSideRender };\nexport { useServerSideRender };\nexport default ServerSideRenderCompat;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,gCAA2C;AAC3C,kBAAoC;AAYpC,IAAM,yBACL;AAKD,uBAAuB,mBAAmB;AAC1C,uBAAuB,sBAAsB;AAI7C,IAAO,gBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -16,7 +17,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
17
|
};
|
|
17
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
19
|
|
|
19
|
-
// packages/server-side-render/src/server-side-render.
|
|
20
|
+
// packages/server-side-render/src/server-side-render.tsx
|
|
20
21
|
var server_side_render_exports = {};
|
|
21
22
|
__export(server_side_render_exports, {
|
|
22
23
|
ServerSideRender: () => ServerSideRender,
|
|
@@ -33,15 +34,20 @@ var EMPTY_OBJECT = {};
|
|
|
33
34
|
function DefaultEmptyResponsePlaceholder({ className }) {
|
|
34
35
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Placeholder, { className, children: (0, import_i18n.__)("Block rendered as empty.") });
|
|
35
36
|
}
|
|
36
|
-
function DefaultErrorResponsePlaceholder({
|
|
37
|
+
function DefaultErrorResponsePlaceholder({
|
|
38
|
+
message,
|
|
39
|
+
className
|
|
40
|
+
}) {
|
|
37
41
|
const errorMessage = (0, import_i18n.sprintf)(
|
|
38
42
|
// translators: %s: error message describing the problem
|
|
39
43
|
(0, import_i18n.__)("Error loading block: %s"),
|
|
40
|
-
message
|
|
44
|
+
message || (0, import_i18n.__)("Unknown error")
|
|
41
45
|
);
|
|
42
46
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Placeholder, { className, children: errorMessage });
|
|
43
47
|
}
|
|
44
|
-
function DefaultLoadingResponsePlaceholder({
|
|
48
|
+
function DefaultLoadingResponsePlaceholder({
|
|
49
|
+
children
|
|
50
|
+
}) {
|
|
45
51
|
const [showLoader, setShowLoader] = (0, import_element.useState)(false);
|
|
46
52
|
(0, import_element.useEffect)(() => {
|
|
47
53
|
const timeout = setTimeout(() => {
|
|
@@ -82,7 +88,11 @@ function ServerSideRender(props) {
|
|
|
82
88
|
}
|
|
83
89
|
}, [content]);
|
|
84
90
|
if (status === "loading") {
|
|
85
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingResponsePlaceholder, { ...props, children: !!prevContentRef.current && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_element.RawHTML, {
|
|
91
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingResponsePlaceholder, { ...props, children: !!prevContentRef.current && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_element.RawHTML, {
|
|
92
|
+
className,
|
|
93
|
+
// eslint-disable-next-line react-hooks/refs
|
|
94
|
+
children: prevContentRef.current
|
|
95
|
+
}) });
|
|
86
96
|
}
|
|
87
97
|
if (status === "success" && !content) {
|
|
88
98
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptyResponsePlaceholder, { ...props });
|
|
@@ -90,14 +100,15 @@ function ServerSideRender(props) {
|
|
|
90
100
|
if (status === "error") {
|
|
91
101
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorResponsePlaceholder, { message: error, ...props });
|
|
92
102
|
}
|
|
93
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_element.RawHTML, { className, children: content });
|
|
103
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_element.RawHTML, { className, children: content || "" });
|
|
94
104
|
}
|
|
95
105
|
function ServerSideRenderWithPostId({
|
|
96
106
|
urlQueryArgs = EMPTY_OBJECT,
|
|
97
107
|
...props
|
|
98
108
|
}) {
|
|
99
109
|
const currentPostId = (0, import_data.useSelect)((select) => {
|
|
100
|
-
const
|
|
110
|
+
const editorStore = select("core/editor");
|
|
111
|
+
const postId = editorStore?.getCurrentPostId?.();
|
|
101
112
|
return postId && typeof postId === "number" ? postId : null;
|
|
102
113
|
}, []);
|
|
103
114
|
const newUrlQueryArgs = (0, import_element.useMemo)(() => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/server-side-render.
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tRawHTML,\n\tuseEffect,\n\tuseState,\n\
|
|
5
|
-
"mappings": "
|
|
3
|
+
"sources": ["../src/server-side-render.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tRawHTML,\n\tuseEffect,\n\tuseState,\n\tuseMemo,\n\tuseRef,\n} from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { Placeholder, Spinner } from '@wordpress/components';\nimport { useSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport { useServerSideRender } from './hook';\nimport type {\n\tPlaceholderProps,\n\tErrorPlaceholderProps,\n\tLoadingPlaceholderProps,\n\tServerSideRenderProps,\n\tServerSideRenderWithPostIdProps,\n} from './types';\n\nconst EMPTY_OBJECT = {};\n\nfunction DefaultEmptyResponsePlaceholder( { className }: PlaceholderProps ) {\n\treturn (\n\t\t<Placeholder className={ className }>\n\t\t\t{ __( 'Block rendered as empty.' ) }\n\t\t</Placeholder>\n\t);\n}\n\nfunction DefaultErrorResponsePlaceholder( {\n\tmessage,\n\tclassName,\n}: ErrorPlaceholderProps ) {\n\tconst errorMessage = sprintf(\n\t\t// translators: %s: error message describing the problem\n\t\t__( 'Error loading block: %s' ),\n\t\tmessage || __( 'Unknown error' )\n\t);\n\treturn <Placeholder className={ className }>{ errorMessage }</Placeholder>;\n}\n\nfunction DefaultLoadingResponsePlaceholder( {\n\tchildren,\n}: LoadingPlaceholderProps ) {\n\tconst [ showLoader, setShowLoader ] = useState( false );\n\n\tuseEffect( () => {\n\t\t// Schedule showing the Spinner after 1 second.\n\t\tconst timeout = setTimeout( () => {\n\t\t\tsetShowLoader( true );\n\t\t}, 1000 );\n\t\treturn () => clearTimeout( timeout );\n\t}, [] );\n\n\treturn (\n\t\t<div style={ { position: 'relative' } }>\n\t\t\t{ showLoader && (\n\t\t\t\t<div\n\t\t\t\t\tstyle={ {\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: '50%',\n\t\t\t\t\t\tleft: '50%',\n\t\t\t\t\t\tmarginTop: '-9px',\n\t\t\t\t\t\tmarginLeft: '-9px',\n\t\t\t\t\t} }\n\t\t\t\t>\n\t\t\t\t\t<Spinner />\n\t\t\t\t</div>\n\t\t\t) }\n\t\t\t<div style={ { opacity: showLoader ? '0.3' : 1 } }>\n\t\t\t\t{ children }\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function ServerSideRender( props: ServerSideRenderProps ) {\n\tconst prevContentRef = useRef( '' );\n\tconst {\n\t\tclassName,\n\t\tEmptyResponsePlaceholder = DefaultEmptyResponsePlaceholder,\n\t\tErrorResponsePlaceholder = DefaultErrorResponsePlaceholder,\n\t\tLoadingResponsePlaceholder = DefaultLoadingResponsePlaceholder,\n\t\t...restProps\n\t} = props;\n\n\tconst { content, status, error } = useServerSideRender( restProps );\n\n\t// Store the previous successful HTML response to show while loading.\n\tuseEffect( () => {\n\t\tif ( content ) {\n\t\t\tprevContentRef.current = content;\n\t\t}\n\t}, [ content ] );\n\n\tif ( status === 'loading' ) {\n\t\treturn (\n\t\t\t<LoadingResponsePlaceholder { ...props }>\n\t\t\t\t{ /* eslint-disable-next-line react-hooks/refs */ }\n\t\t\t\t{ !! prevContentRef.current && (\n\t\t\t\t\t<RawHTML className={ className }>\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// eslint-disable-next-line react-hooks/refs\n\t\t\t\t\t\t\tprevContentRef.current\n\t\t\t\t\t\t}\n\t\t\t\t\t</RawHTML>\n\t\t\t\t) }\n\t\t\t</LoadingResponsePlaceholder>\n\t\t);\n\t}\n\n\tif ( status === 'success' && ! content ) {\n\t\treturn <EmptyResponsePlaceholder { ...props } />;\n\t}\n\n\tif ( status === 'error' ) {\n\t\treturn <ErrorResponsePlaceholder message={ error } { ...props } />;\n\t}\n\n\treturn <RawHTML className={ className }>{ content || '' }</RawHTML>;\n}\n\n/**\n * A component that renders server-side content for blocks.\n *\n * Note: URL query will include the current post ID when applicable.\n * This is useful for blocks that depend on the context of the current post for rendering.\n *\n * @example\n * ```jsx\n * import { ServerSideRender } from '@wordpress/server-side-render';\n * // Legacy import for WordPress 6.8 and earlier\n * // import { default as ServerSideRender } from '@wordpress/server-side-render';\n *\n * function Example() {\n * return (\n * <ServerSideRender\n * block=\"core/archives\"\n * attributes={ { showPostCounts: true } }\n * urlQueryArgs={ { customArg: 'value' } }\n * className=\"custom-class\"\n * />\n * );\n * }\n * ```\n *\n * @param props Component props.\n * @param props.urlQueryArgs Additional query arguments to append to the request URL.\n * @return The rendered server-side content.\n */\nexport function ServerSideRenderWithPostId( {\n\turlQueryArgs = EMPTY_OBJECT,\n\t...props\n}: ServerSideRenderWithPostIdProps ) {\n\tconst currentPostId = useSelect( ( select ) => {\n\t\t// FIXME: @wordpress/server-side-render should not depend on @wordpress/editor.\n\t\t// It is used by blocks that can be loaded into a *non-post* block editor.\n\t\t// eslint-disable-next-line @wordpress/data-no-store-string-literals\n\t\tconst editorStore = select( 'core/editor' );\n\t\t// @ts-expect-error - editorStore is not typed in @wordpress/data\n\t\tconst postId = editorStore?.getCurrentPostId?.();\n\n\t\t// For templates and template parts we use a custom ID format.\n\t\t// Since they aren't real posts, we don't want to use their ID\n\t\t// for server-side rendering. Since they use a string based ID,\n\t\t// we can assume real post IDs are numbers.\n\t\treturn postId && typeof postId === 'number' ? postId : null;\n\t}, [] );\n\n\tconst newUrlQueryArgs = useMemo( () => {\n\t\tif ( ! currentPostId ) {\n\t\t\treturn urlQueryArgs;\n\t\t}\n\t\treturn {\n\t\t\tpost_id: currentPostId,\n\t\t\t...urlQueryArgs,\n\t\t};\n\t}, [ currentPostId, urlQueryArgs ] );\n\n\treturn <ServerSideRender urlQueryArgs={ newUrlQueryArgs } { ...props } />;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAMO;AACP,kBAA4B;AAC5B,wBAAqC;AACrC,kBAA0B;AAK1B,kBAAoC;AAalC;AAJF,IAAM,eAAe,CAAC;AAEtB,SAAS,gCAAiC,EAAE,UAAU,GAAsB;AAC3E,SACC,4CAAC,iCAAY,WACV,8BAAI,0BAA2B,GAClC;AAEF;AAEA,SAAS,gCAAiC;AAAA,EACzC;AAAA,EACA;AACD,GAA2B;AAC1B,QAAM,mBAAe;AAAA;AAAA,QAEpB,gBAAI,yBAA0B;AAAA,IAC9B,eAAW,gBAAI,eAAgB;AAAA,EAChC;AACA,SAAO,4CAAC,iCAAY,WAA0B,wBAAc;AAC7D;AAEA,SAAS,kCAAmC;AAAA,EAC3C;AACD,GAA6B;AAC5B,QAAM,CAAE,YAAY,aAAc,QAAI,yBAAU,KAAM;AAEtD,gCAAW,MAAM;AAEhB,UAAM,UAAU,WAAY,MAAM;AACjC,oBAAe,IAAK;AAAA,IACrB,GAAG,GAAK;AACR,WAAO,MAAM,aAAc,OAAQ;AAAA,EACpC,GAAG,CAAC,CAAE;AAEN,SACC,6CAAC,SAAI,OAAQ,EAAE,UAAU,WAAW,GACjC;AAAA,kBACD;AAAA,MAAC;AAAA;AAAA,QACA,OAAQ;AAAA,UACP,UAAU;AAAA,UACV,KAAK;AAAA,UACL,MAAM;AAAA,UACN,WAAW;AAAA,UACX,YAAY;AAAA,QACb;AAAA,QAEA,sDAAC,6BAAQ;AAAA;AAAA,IACV;AAAA,IAED,4CAAC,SAAI,OAAQ,EAAE,SAAS,aAAa,QAAQ,EAAE,GAC5C,UACH;AAAA,KACD;AAEF;AAEO,SAAS,iBAAkB,OAA+B;AAChE,QAAM,qBAAiB,uBAAQ,EAAG;AAClC,QAAM;AAAA,IACL;AAAA,IACA,2BAA2B;AAAA,IAC3B,2BAA2B;AAAA,IAC3B,6BAA6B;AAAA,IAC7B,GAAG;AAAA,EACJ,IAAI;AAEJ,QAAM,EAAE,SAAS,QAAQ,MAAM,QAAI,iCAAqB,SAAU;AAGlE,gCAAW,MAAM;AAChB,QAAK,SAAU;AACd,qBAAe,UAAU;AAAA,IAC1B;AAAA,EACD,GAAG,CAAE,OAAQ,CAAE;AAEf,MAAK,WAAW,WAAY;AAC3B,WACC,4CAAC,8BAA6B,GAAG,OAE9B,WAAC,CAAE,eAAe,WACnB,4CAAC;AAAA,MAAQ;AAAA;AAAA,MAGP,yBAAe;AAAA,KAEjB,GAEF;AAAA,EAEF;AAEA,MAAK,WAAW,aAAa,CAAE,SAAU;AACxC,WAAO,4CAAC,4BAA2B,GAAG,OAAQ;AAAA,EAC/C;AAEA,MAAK,WAAW,SAAU;AACzB,WAAO,4CAAC,4BAAyB,SAAU,OAAU,GAAG,OAAQ;AAAA,EACjE;AAEA,SAAO,4CAAC,0BAAQ,WAA0B,qBAAW,IAAI;AAC1D;AA8BO,SAAS,2BAA4B;AAAA,EAC3C,eAAe;AAAA,EACf,GAAG;AACJ,GAAqC;AACpC,QAAM,oBAAgB,uBAAW,CAAE,WAAY;AAI9C,UAAM,cAAc,OAAQ,aAAc;AAE1C,UAAM,SAAS,aAAa,mBAAmB;AAM/C,WAAO,UAAU,OAAO,WAAW,WAAW,SAAS;AAAA,EACxD,GAAG,CAAC,CAAE;AAEN,QAAM,sBAAkB,wBAAS,MAAM;AACtC,QAAK,CAAE,eAAgB;AACtB,aAAO;AAAA,IACR;AACA,WAAO;AAAA,MACN,SAAS;AAAA,MACT,GAAG;AAAA,IACJ;AAAA,EACD,GAAG,CAAE,eAAe,YAAa,CAAE;AAEnC,SAAO,4CAAC,oBAAiB,cAAe,iBAAoB,GAAG,OAAQ;AACxE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/types.cjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
|
|
16
|
+
// packages/server-side-render/src/types.ts
|
|
17
|
+
var types_exports = {};
|
|
18
|
+
module.exports = __toCommonJS(types_exports);
|
|
19
|
+
//# sourceMappingURL=types.cjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/types.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport type React from 'react';\n\n/**\n * Internal dependencies\n */\nimport type { UseServerSideRenderArgs } from './hook';\n\nexport interface PlaceholderProps {\n\t/** Additional classes to apply to the wrapper element. */\n\tclassName?: string;\n}\n\nexport interface ErrorPlaceholderProps extends PlaceholderProps {\n\t/** Error message describing the problem. */\n\tmessage?: string;\n}\n\nexport interface LoadingPlaceholderProps {\n\tchildren?: React.ReactNode;\n}\n\nexport interface ServerSideRenderProps extends UseServerSideRenderArgs {\n\t/** Additional classes to apply to the wrapper element. */\n\tclassName?: string;\n\t/** Component rendered when the API response is empty. */\n\tEmptyResponsePlaceholder?: React.ComponentType< PlaceholderProps >;\n\t/** Component rendered when the API response is an error. */\n\tErrorResponsePlaceholder?: React.ComponentType< ErrorPlaceholderProps >;\n\t/** Component rendered while the API request is loading. */\n\tLoadingResponsePlaceholder?: React.ComponentType< LoadingPlaceholderProps >;\n}\n\nexport interface ServerSideRenderWithPostIdProps\n\textends Omit< ServerSideRenderProps, 'urlQueryArgs' > {\n\t/** Additional query arguments to append to the request URL. */\n\turlQueryArgs?: Record< string, unknown >;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/build-module/hook.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// packages/server-side-render/src/hook.
|
|
1
|
+
// packages/server-side-render/src/hook.ts
|
|
2
2
|
import { debounce } from "@wordpress/compose";
|
|
3
3
|
import { useEffect, useState, useRef } from "@wordpress/element";
|
|
4
4
|
import apiFetch from "@wordpress/api-fetch";
|
|
@@ -37,7 +37,9 @@ function removeBlockSupportAttributes(attributes) {
|
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
function useServerSideRender(args) {
|
|
40
|
-
const [response, setResponse] = useState({
|
|
40
|
+
const [response, setResponse] = useState({
|
|
41
|
+
status: "idle"
|
|
42
|
+
});
|
|
41
43
|
const shouldDebounceRef = useRef(false);
|
|
42
44
|
const {
|
|
43
45
|
attributes,
|
|
@@ -47,7 +49,7 @@ function useServerSideRender(args) {
|
|
|
47
49
|
urlQueryArgs
|
|
48
50
|
} = args;
|
|
49
51
|
let sanitizedAttributes = attributes && __experimentalSanitizeBlockAttributes(block, attributes);
|
|
50
|
-
if (skipBlockSupportAttributes) {
|
|
52
|
+
if (skipBlockSupportAttributes && sanitizedAttributes) {
|
|
51
53
|
sanitizedAttributes = removeBlockSupportAttributes(sanitizedAttributes);
|
|
52
54
|
}
|
|
53
55
|
const isPostRequest = "POST" === httpMethod;
|
|
@@ -74,12 +76,12 @@ function useServerSideRender(args) {
|
|
|
74
76
|
content: res ? res.rendered : ""
|
|
75
77
|
});
|
|
76
78
|
}).catch((error) => {
|
|
77
|
-
if (error.name === "AbortError") {
|
|
79
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
78
80
|
return;
|
|
79
81
|
}
|
|
80
82
|
setResponse({
|
|
81
83
|
status: "error",
|
|
82
|
-
error: error.message
|
|
84
|
+
error: error instanceof Error ? error.message : String(error)
|
|
83
85
|
});
|
|
84
86
|
}).finally(() => {
|
|
85
87
|
shouldDebounceRef.current = true;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/hook.
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { debounce } from '@wordpress/compose';\nimport { useEffect, useState, useRef } from '@wordpress/element';\nimport apiFetch from '@wordpress/api-fetch';\nimport { addQueryArgs } from '@wordpress/url';\nimport { __experimentalSanitizeBlockAttributes } from '@wordpress/blocks';\n\nexport function rendererPath(
|
|
5
|
-
"mappings": ";AAGA,SAAS,gBAAgB;AACzB,SAAS,WAAW,UAAU,cAAc;AAC5C,OAAO,cAAc;AACrB,SAAS,oBAAoB;
|
|
3
|
+
"sources": ["../src/hook.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { debounce } from '@wordpress/compose';\nimport { useEffect, useState, useRef } from '@wordpress/element';\nimport apiFetch from '@wordpress/api-fetch';\nimport { addQueryArgs } from '@wordpress/url';\n\nimport { __experimentalSanitizeBlockAttributes } from '@wordpress/blocks';\n\nexport function rendererPath(\n\tblock: string,\n\tattributes: Record< string, unknown > | null = null,\n\turlQueryArgs: Record< string, unknown > = {}\n): string {\n\treturn addQueryArgs( `/wp/v2/block-renderer/${ block }`, {\n\t\tcontext: 'edit',\n\t\t...( null !== attributes ? { attributes } : {} ),\n\t\t...urlQueryArgs,\n\t} );\n}\n\nexport function removeBlockSupportAttributes(\n\tattributes: Record< string, unknown > & {\n\t\tstyle?: Record< string, unknown >;\n\t}\n): Record< string, unknown > {\n\tconst {\n\t\tbackgroundColor,\n\t\tborderColor,\n\t\tfontFamily,\n\t\tfontSize,\n\t\tgradient,\n\t\ttextColor,\n\t\tclassName,\n\t\t...restAttributes\n\t} = attributes;\n\n\tconst {\n\t\tborder,\n\t\tcolor,\n\t\telements,\n\t\tshadow,\n\t\tspacing,\n\t\ttypography,\n\t\t...restStyles\n\t} = attributes?.style || {};\n\n\treturn {\n\t\t...restAttributes,\n\t\tstyle: restStyles,\n\t};\n}\n\n/**\n * Server-side render response object.\n */\nexport interface ServerSideRenderResponse {\n\t/** The current request status: 'idle', 'loading', 'success', or 'error'. */\n\tstatus: 'idle' | 'loading' | 'success' | 'error';\n\t/** The rendered block content (available when status is 'success'). */\n\tcontent?: string;\n\t/** The error message (available when status is 'error'). */\n\terror?: string;\n}\n\n/**\n * Configuration object for the useServerSideRender hook.\n */\nexport interface UseServerSideRenderArgs {\n\t/** The block attributes to be sent to the server for rendering. */\n\tattributes: Record< string, unknown >;\n\t/** The identifier of the block to be serverside rendered. Example: 'core/archives'. */\n\tblock: string;\n\t/** Whether to remove block support attributes before sending. */\n\tskipBlockSupportAttributes?: boolean;\n\t/** The HTTP method to use ('GET' or 'POST'). Default is 'GET'. */\n\thttpMethod?: 'GET' | 'POST';\n\t/** Additional query arguments to append to the request URL. */\n\turlQueryArgs?: Record< string, unknown >;\n}\n\n/**\n * A hook for server-side rendering a preview of dynamic blocks to display in the editor.\n *\n * Handles fetching server-rendered previews for blocks, managing loading states,\n * and automatically debouncing requests to prevent excessive API calls. It supports both\n * GET and POST requests, with POST requests used for larger attribute payloads.\n *\n * @example\n * Basic usage:\n *\n * ```jsx\n * import { RawHTML } from '@wordpress/element';\n * import { useServerSideRender } from '@wordpress/server-side-render';\n *\n * function MyServerSideRender( { attributes, block } ) {\n * const { content, status, error } = useServerSideRender( {\n * attributes,\n * block,\n * } );\n *\n * if ( status === 'loading' ) {\n * return <div>Loading...</div>;\n * }\n *\n * if ( status === 'error' ) {\n * return <div>Error: { error }</div>;\n * }\n *\n * return <RawHTML>{ content }</RawHTML>;\n * }\n * ```\n *\n * @param args The hook configuration object.\n *\n * @return The server-side render response object.\n */\nexport function useServerSideRender(\n\targs: UseServerSideRenderArgs\n): ServerSideRenderResponse {\n\tconst [ response, setResponse ] = useState< ServerSideRenderResponse >( {\n\t\tstatus: 'idle',\n\t} );\n\tconst shouldDebounceRef = useRef< boolean >( false );\n\n\tconst {\n\t\tattributes,\n\t\tblock,\n\t\tskipBlockSupportAttributes = false,\n\t\thttpMethod = 'GET',\n\t\turlQueryArgs,\n\t} = args;\n\n\tlet sanitizedAttributes: Record< string, unknown > | null =\n\t\tattributes &&\n\t\t__experimentalSanitizeBlockAttributes( block, attributes );\n\n\tif ( skipBlockSupportAttributes && sanitizedAttributes ) {\n\t\tsanitizedAttributes =\n\t\t\tremoveBlockSupportAttributes( sanitizedAttributes );\n\t}\n\n\t// If httpMethod is 'POST', send the attributes in the request body instead of the URL.\n\t// This allows sending a larger attributes object than in a GET request, where the attributes are in the URL.\n\tconst isPostRequest = 'POST' === httpMethod;\n\tconst urlAttributes = isPostRequest ? null : sanitizedAttributes;\n\tconst path = rendererPath( block, urlAttributes, urlQueryArgs );\n\tconst body = isPostRequest\n\t\t? JSON.stringify( { attributes: sanitizedAttributes ?? null } )\n\t\t: undefined;\n\n\tuseEffect( () => {\n\t\tconst controller = new AbortController();\n\t\tconst debouncedFetch = debounce(\n\t\t\tfunction () {\n\t\t\t\t{\n\t\t\t\t\tsetResponse( { status: 'loading' } );\n\n\t\t\t\t\tapiFetch< { rendered: string } >( {\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tmethod: isPostRequest ? 'POST' : 'GET',\n\t\t\t\t\t\tbody,\n\t\t\t\t\t\theaders: isPostRequest\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t: {},\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t} )\n\t\t\t\t\t\t.then( ( res ) => {\n\t\t\t\t\t\t\tsetResponse( {\n\t\t\t\t\t\t\t\tstatus: 'success',\n\t\t\t\t\t\t\t\tcontent: res ? res.rendered : '',\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.catch( ( error: unknown ) => {\n\t\t\t\t\t\t\t// The request was aborted, do not update the response.\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t\t\t\terror.name === 'AbortError'\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsetResponse( {\n\t\t\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\t\t\terror:\n\t\t\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t\t\t: String( error ),\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.finally( () => {\n\t\t\t\t\t\t\t// Debounce requests after first fetch.\n\t\t\t\t\t\t\tshouldDebounceRef.current = true;\n\t\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t},\n\t\t\tshouldDebounceRef.current ? 500 : 0\n\t\t);\n\n\t\tdebouncedFetch();\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t\tdebouncedFetch.cancel();\n\t\t};\n\t}, [ path, isPostRequest, body ] );\n\n\treturn response;\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,SAAS,gBAAgB;AACzB,SAAS,WAAW,UAAU,cAAc;AAC5C,OAAO,cAAc;AACrB,SAAS,oBAAoB;AAE7B,SAAS,6CAA6C;AAE/C,SAAS,aACf,OACA,aAA+C,MAC/C,eAA0C,CAAC,GAClC;AACT,SAAO,aAAc,yBAA0B,KAAM,IAAI;AAAA,IACxD,SAAS;AAAA,IACT,GAAK,SAAS,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IAC7C,GAAG;AAAA,EACJ,CAAE;AACH;AAEO,SAAS,6BACf,YAG4B;AAC5B,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACJ,IAAI;AAEJ,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACJ,IAAI,YAAY,SAAS,CAAC;AAE1B,SAAO;AAAA,IACN,GAAG;AAAA,IACH,OAAO;AAAA,EACR;AACD;AAkEO,SAAS,oBACf,MAC2B;AAC3B,QAAM,CAAE,UAAU,WAAY,IAAI,SAAsC;AAAA,IACvE,QAAQ;AAAA,EACT,CAAE;AACF,QAAM,oBAAoB,OAAmB,KAAM;AAEnD,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA,6BAA6B;AAAA,IAC7B,aAAa;AAAA,IACb;AAAA,EACD,IAAI;AAEJ,MAAI,sBACH,cACA,sCAAuC,OAAO,UAAW;AAE1D,MAAK,8BAA8B,qBAAsB;AACxD,0BACC,6BAA8B,mBAAoB;AAAA,EACpD;AAIA,QAAM,gBAAgB,WAAW;AACjC,QAAM,gBAAgB,gBAAgB,OAAO;AAC7C,QAAM,OAAO,aAAc,OAAO,eAAe,YAAa;AAC9D,QAAM,OAAO,gBACV,KAAK,UAAW,EAAE,YAAY,uBAAuB,KAAK,CAAE,IAC5D;AAEH,YAAW,MAAM;AAChB,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,iBAAiB;AAAA,MACtB,WAAY;AACX;AACC,sBAAa,EAAE,QAAQ,UAAU,CAAE;AAEnC,mBAAkC;AAAA,YACjC;AAAA,YACA,QAAQ,gBAAgB,SAAS;AAAA,YACjC;AAAA,YACA,SAAS,gBACN;AAAA,cACA,gBAAgB;AAAA,YAChB,IACA,CAAC;AAAA,YACJ,QAAQ,WAAW;AAAA,UACpB,CAAE,EACA,KAAM,CAAE,QAAS;AACjB,wBAAa;AAAA,cACZ,QAAQ;AAAA,cACR,SAAS,MAAM,IAAI,WAAW;AAAA,YAC/B,CAAE;AAAA,UACH,CAAE,EACD,MAAO,CAAE,UAAoB;AAE7B,gBACC,iBAAiB,SACjB,MAAM,SAAS,cACd;AACD;AAAA,YACD;AAEA,wBAAa;AAAA,cACZ,QAAQ;AAAA,cACR,OACC,iBAAiB,QACd,MAAM,UACN,OAAQ,KAAM;AAAA,YACnB,CAAE;AAAA,UACH,CAAE,EACD,QAAS,MAAM;AAEf,8BAAkB,UAAU;AAAA,UAC7B,CAAE;AAAA,QACJ;AAAA,MACD;AAAA,MACA,kBAAkB,UAAU,MAAM;AAAA,IACnC;AAEA,mBAAe;AAEf,WAAO,MAAM;AACZ,iBAAW,MAAM;AACjB,qBAAe,OAAO;AAAA,IACvB;AAAA,EACD,GAAG,CAAE,MAAM,eAAe,IAAK,CAAE;AAEjC,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build-module/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// packages/server-side-render/src/index.
|
|
1
|
+
// packages/server-side-render/src/index.ts
|
|
2
2
|
import { ServerSideRenderWithPostId } from "./server-side-render.mjs";
|
|
3
3
|
import { useServerSideRender } from "./hook.mjs";
|
|
4
4
|
var ServerSideRenderCompat = ServerSideRenderWithPostId;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.
|
|
4
|
-
"sourcesContent": ["/**\n * Internal dependencies\n */\nimport { ServerSideRenderWithPostId } from './server-side-render';\nimport { useServerSideRender } from './hook';\n\n/**\n * A compatibility layer for the `ServerSideRender` component when used with `wp` global namespace.\n *\n * @deprecated Use `ServerSideRender` non-default export instead.\n *\n * @example\n * ```js\n * import ServerSideRender from '@wordpress/server-side-render';\n * ```\n */\nconst ServerSideRenderCompat
|
|
5
|
-
"mappings": ";AAGA,SAAS,kCAAkC;AAC3C,SAAS,2BAA2B;AAYpC,IAAM,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Internal dependencies\n */\nimport { ServerSideRenderWithPostId } from './server-side-render';\nimport { useServerSideRender } from './hook';\n\n/**\n * A compatibility layer for the `ServerSideRender` component when used with `wp` global namespace.\n *\n * @deprecated Use `ServerSideRender` non-default export instead.\n *\n * @example\n * ```js\n * import ServerSideRender from '@wordpress/server-side-render';\n * ```\n */\nconst ServerSideRenderCompat =\n\tServerSideRenderWithPostId as typeof ServerSideRenderWithPostId & {\n\t\tServerSideRender: typeof ServerSideRenderWithPostId;\n\t\tuseServerSideRender: typeof useServerSideRender;\n\t};\n\nServerSideRenderCompat.ServerSideRender = ServerSideRenderWithPostId;\nServerSideRenderCompat.useServerSideRender = useServerSideRender;\n\nexport { ServerSideRenderWithPostId as ServerSideRender };\nexport { useServerSideRender };\nexport default ServerSideRenderCompat;\n"],
|
|
5
|
+
"mappings": ";AAGA,SAAS,kCAAkC;AAC3C,SAAS,2BAA2B;AAYpC,IAAM,yBACL;AAKD,uBAAuB,mBAAmB;AAC1C,uBAAuB,sBAAsB;AAI7C,IAAO,gBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
// packages/server-side-render/src/server-side-render.
|
|
1
|
+
// packages/server-side-render/src/server-side-render.tsx
|
|
2
2
|
import {
|
|
3
3
|
RawHTML,
|
|
4
4
|
useEffect,
|
|
5
5
|
useState,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef
|
|
8
8
|
} from "@wordpress/element";
|
|
9
9
|
import { __, sprintf } from "@wordpress/i18n";
|
|
10
10
|
import { Placeholder, Spinner } from "@wordpress/components";
|
|
@@ -15,15 +15,20 @@ var EMPTY_OBJECT = {};
|
|
|
15
15
|
function DefaultEmptyResponsePlaceholder({ className }) {
|
|
16
16
|
return /* @__PURE__ */ jsx(Placeholder, { className, children: __("Block rendered as empty.") });
|
|
17
17
|
}
|
|
18
|
-
function DefaultErrorResponsePlaceholder({
|
|
18
|
+
function DefaultErrorResponsePlaceholder({
|
|
19
|
+
message,
|
|
20
|
+
className
|
|
21
|
+
}) {
|
|
19
22
|
const errorMessage = sprintf(
|
|
20
23
|
// translators: %s: error message describing the problem
|
|
21
24
|
__("Error loading block: %s"),
|
|
22
|
-
message
|
|
25
|
+
message || __("Unknown error")
|
|
23
26
|
);
|
|
24
27
|
return /* @__PURE__ */ jsx(Placeholder, { className, children: errorMessage });
|
|
25
28
|
}
|
|
26
|
-
function DefaultLoadingResponsePlaceholder({
|
|
29
|
+
function DefaultLoadingResponsePlaceholder({
|
|
30
|
+
children
|
|
31
|
+
}) {
|
|
27
32
|
const [showLoader, setShowLoader] = useState(false);
|
|
28
33
|
useEffect(() => {
|
|
29
34
|
const timeout = setTimeout(() => {
|
|
@@ -64,7 +69,11 @@ function ServerSideRender(props) {
|
|
|
64
69
|
}
|
|
65
70
|
}, [content]);
|
|
66
71
|
if (status === "loading") {
|
|
67
|
-
return /* @__PURE__ */ jsx(LoadingResponsePlaceholder, { ...props, children: !!prevContentRef.current && /* @__PURE__ */ jsx(RawHTML, {
|
|
72
|
+
return /* @__PURE__ */ jsx(LoadingResponsePlaceholder, { ...props, children: !!prevContentRef.current && /* @__PURE__ */ jsx(RawHTML, {
|
|
73
|
+
className,
|
|
74
|
+
// eslint-disable-next-line react-hooks/refs
|
|
75
|
+
children: prevContentRef.current
|
|
76
|
+
}) });
|
|
68
77
|
}
|
|
69
78
|
if (status === "success" && !content) {
|
|
70
79
|
return /* @__PURE__ */ jsx(EmptyResponsePlaceholder, { ...props });
|
|
@@ -72,14 +81,15 @@ function ServerSideRender(props) {
|
|
|
72
81
|
if (status === "error") {
|
|
73
82
|
return /* @__PURE__ */ jsx(ErrorResponsePlaceholder, { message: error, ...props });
|
|
74
83
|
}
|
|
75
|
-
return /* @__PURE__ */ jsx(RawHTML, { className, children: content });
|
|
84
|
+
return /* @__PURE__ */ jsx(RawHTML, { className, children: content || "" });
|
|
76
85
|
}
|
|
77
86
|
function ServerSideRenderWithPostId({
|
|
78
87
|
urlQueryArgs = EMPTY_OBJECT,
|
|
79
88
|
...props
|
|
80
89
|
}) {
|
|
81
90
|
const currentPostId = useSelect((select) => {
|
|
82
|
-
const
|
|
91
|
+
const editorStore = select("core/editor");
|
|
92
|
+
const postId = editorStore?.getCurrentPostId?.();
|
|
83
93
|
return postId && typeof postId === "number" ? postId : null;
|
|
84
94
|
}, []);
|
|
85
95
|
const newUrlQueryArgs = useMemo(() => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/server-side-render.
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tRawHTML,\n\tuseEffect,\n\tuseState,\n\
|
|
5
|
-
"mappings": ";AAGA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,IAAI,eAAe;AAC5B,SAAS,aAAa,eAAe;AACrC,SAAS,iBAAiB;AAK1B,SAAS,2BAA2B;
|
|
3
|
+
"sources": ["../src/server-side-render.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tRawHTML,\n\tuseEffect,\n\tuseState,\n\tuseMemo,\n\tuseRef,\n} from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { Placeholder, Spinner } from '@wordpress/components';\nimport { useSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport { useServerSideRender } from './hook';\nimport type {\n\tPlaceholderProps,\n\tErrorPlaceholderProps,\n\tLoadingPlaceholderProps,\n\tServerSideRenderProps,\n\tServerSideRenderWithPostIdProps,\n} from './types';\n\nconst EMPTY_OBJECT = {};\n\nfunction DefaultEmptyResponsePlaceholder( { className }: PlaceholderProps ) {\n\treturn (\n\t\t<Placeholder className={ className }>\n\t\t\t{ __( 'Block rendered as empty.' ) }\n\t\t</Placeholder>\n\t);\n}\n\nfunction DefaultErrorResponsePlaceholder( {\n\tmessage,\n\tclassName,\n}: ErrorPlaceholderProps ) {\n\tconst errorMessage = sprintf(\n\t\t// translators: %s: error message describing the problem\n\t\t__( 'Error loading block: %s' ),\n\t\tmessage || __( 'Unknown error' )\n\t);\n\treturn <Placeholder className={ className }>{ errorMessage }</Placeholder>;\n}\n\nfunction DefaultLoadingResponsePlaceholder( {\n\tchildren,\n}: LoadingPlaceholderProps ) {\n\tconst [ showLoader, setShowLoader ] = useState( false );\n\n\tuseEffect( () => {\n\t\t// Schedule showing the Spinner after 1 second.\n\t\tconst timeout = setTimeout( () => {\n\t\t\tsetShowLoader( true );\n\t\t}, 1000 );\n\t\treturn () => clearTimeout( timeout );\n\t}, [] );\n\n\treturn (\n\t\t<div style={ { position: 'relative' } }>\n\t\t\t{ showLoader && (\n\t\t\t\t<div\n\t\t\t\t\tstyle={ {\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: '50%',\n\t\t\t\t\t\tleft: '50%',\n\t\t\t\t\t\tmarginTop: '-9px',\n\t\t\t\t\t\tmarginLeft: '-9px',\n\t\t\t\t\t} }\n\t\t\t\t>\n\t\t\t\t\t<Spinner />\n\t\t\t\t</div>\n\t\t\t) }\n\t\t\t<div style={ { opacity: showLoader ? '0.3' : 1 } }>\n\t\t\t\t{ children }\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function ServerSideRender( props: ServerSideRenderProps ) {\n\tconst prevContentRef = useRef( '' );\n\tconst {\n\t\tclassName,\n\t\tEmptyResponsePlaceholder = DefaultEmptyResponsePlaceholder,\n\t\tErrorResponsePlaceholder = DefaultErrorResponsePlaceholder,\n\t\tLoadingResponsePlaceholder = DefaultLoadingResponsePlaceholder,\n\t\t...restProps\n\t} = props;\n\n\tconst { content, status, error } = useServerSideRender( restProps );\n\n\t// Store the previous successful HTML response to show while loading.\n\tuseEffect( () => {\n\t\tif ( content ) {\n\t\t\tprevContentRef.current = content;\n\t\t}\n\t}, [ content ] );\n\n\tif ( status === 'loading' ) {\n\t\treturn (\n\t\t\t<LoadingResponsePlaceholder { ...props }>\n\t\t\t\t{ /* eslint-disable-next-line react-hooks/refs */ }\n\t\t\t\t{ !! prevContentRef.current && (\n\t\t\t\t\t<RawHTML className={ className }>\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// eslint-disable-next-line react-hooks/refs\n\t\t\t\t\t\t\tprevContentRef.current\n\t\t\t\t\t\t}\n\t\t\t\t\t</RawHTML>\n\t\t\t\t) }\n\t\t\t</LoadingResponsePlaceholder>\n\t\t);\n\t}\n\n\tif ( status === 'success' && ! content ) {\n\t\treturn <EmptyResponsePlaceholder { ...props } />;\n\t}\n\n\tif ( status === 'error' ) {\n\t\treturn <ErrorResponsePlaceholder message={ error } { ...props } />;\n\t}\n\n\treturn <RawHTML className={ className }>{ content || '' }</RawHTML>;\n}\n\n/**\n * A component that renders server-side content for blocks.\n *\n * Note: URL query will include the current post ID when applicable.\n * This is useful for blocks that depend on the context of the current post for rendering.\n *\n * @example\n * ```jsx\n * import { ServerSideRender } from '@wordpress/server-side-render';\n * // Legacy import for WordPress 6.8 and earlier\n * // import { default as ServerSideRender } from '@wordpress/server-side-render';\n *\n * function Example() {\n * return (\n * <ServerSideRender\n * block=\"core/archives\"\n * attributes={ { showPostCounts: true } }\n * urlQueryArgs={ { customArg: 'value' } }\n * className=\"custom-class\"\n * />\n * );\n * }\n * ```\n *\n * @param props Component props.\n * @param props.urlQueryArgs Additional query arguments to append to the request URL.\n * @return The rendered server-side content.\n */\nexport function ServerSideRenderWithPostId( {\n\turlQueryArgs = EMPTY_OBJECT,\n\t...props\n}: ServerSideRenderWithPostIdProps ) {\n\tconst currentPostId = useSelect( ( select ) => {\n\t\t// FIXME: @wordpress/server-side-render should not depend on @wordpress/editor.\n\t\t// It is used by blocks that can be loaded into a *non-post* block editor.\n\t\t// eslint-disable-next-line @wordpress/data-no-store-string-literals\n\t\tconst editorStore = select( 'core/editor' );\n\t\t// @ts-expect-error - editorStore is not typed in @wordpress/data\n\t\tconst postId = editorStore?.getCurrentPostId?.();\n\n\t\t// For templates and template parts we use a custom ID format.\n\t\t// Since they aren't real posts, we don't want to use their ID\n\t\t// for server-side rendering. Since they use a string based ID,\n\t\t// we can assume real post IDs are numbers.\n\t\treturn postId && typeof postId === 'number' ? postId : null;\n\t}, [] );\n\n\tconst newUrlQueryArgs = useMemo( () => {\n\t\tif ( ! currentPostId ) {\n\t\t\treturn urlQueryArgs;\n\t\t}\n\t\treturn {\n\t\t\tpost_id: currentPostId,\n\t\t\t...urlQueryArgs,\n\t\t};\n\t}, [ currentPostId, urlQueryArgs ] );\n\n\treturn <ServerSideRender urlQueryArgs={ newUrlQueryArgs } { ...props } />;\n}\n"],
|
|
5
|
+
"mappings": ";AAGA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,IAAI,eAAe;AAC5B,SAAS,aAAa,eAAe;AACrC,SAAS,iBAAiB;AAK1B,SAAS,2BAA2B;AAalC,cAgCA,YAhCA;AAJF,IAAM,eAAe,CAAC;AAEtB,SAAS,gCAAiC,EAAE,UAAU,GAAsB;AAC3E,SACC,oBAAC,eAAY,WACV,aAAI,0BAA2B,GAClC;AAEF;AAEA,SAAS,gCAAiC;AAAA,EACzC;AAAA,EACA;AACD,GAA2B;AAC1B,QAAM,eAAe;AAAA;AAAA,IAEpB,GAAI,yBAA0B;AAAA,IAC9B,WAAW,GAAI,eAAgB;AAAA,EAChC;AACA,SAAO,oBAAC,eAAY,WAA0B,wBAAc;AAC7D;AAEA,SAAS,kCAAmC;AAAA,EAC3C;AACD,GAA6B;AAC5B,QAAM,CAAE,YAAY,aAAc,IAAI,SAAU,KAAM;AAEtD,YAAW,MAAM;AAEhB,UAAM,UAAU,WAAY,MAAM;AACjC,oBAAe,IAAK;AAAA,IACrB,GAAG,GAAK;AACR,WAAO,MAAM,aAAc,OAAQ;AAAA,EACpC,GAAG,CAAC,CAAE;AAEN,SACC,qBAAC,SAAI,OAAQ,EAAE,UAAU,WAAW,GACjC;AAAA,kBACD;AAAA,MAAC;AAAA;AAAA,QACA,OAAQ;AAAA,UACP,UAAU;AAAA,UACV,KAAK;AAAA,UACL,MAAM;AAAA,UACN,WAAW;AAAA,UACX,YAAY;AAAA,QACb;AAAA,QAEA,8BAAC,WAAQ;AAAA;AAAA,IACV;AAAA,IAED,oBAAC,SAAI,OAAQ,EAAE,SAAS,aAAa,QAAQ,EAAE,GAC5C,UACH;AAAA,KACD;AAEF;AAEO,SAAS,iBAAkB,OAA+B;AAChE,QAAM,iBAAiB,OAAQ,EAAG;AAClC,QAAM;AAAA,IACL;AAAA,IACA,2BAA2B;AAAA,IAC3B,2BAA2B;AAAA,IAC3B,6BAA6B;AAAA,IAC7B,GAAG;AAAA,EACJ,IAAI;AAEJ,QAAM,EAAE,SAAS,QAAQ,MAAM,IAAI,oBAAqB,SAAU;AAGlE,YAAW,MAAM;AAChB,QAAK,SAAU;AACd,qBAAe,UAAU;AAAA,IAC1B;AAAA,EACD,GAAG,CAAE,OAAQ,CAAE;AAEf,MAAK,WAAW,WAAY;AAC3B,WACC,oBAAC,8BAA6B,GAAG,OAE9B,WAAC,CAAE,eAAe,WACnB,oBAAC;AAAA,MAAQ;AAAA;AAAA,MAGP,yBAAe;AAAA,KAEjB,GAEF;AAAA,EAEF;AAEA,MAAK,WAAW,aAAa,CAAE,SAAU;AACxC,WAAO,oBAAC,4BAA2B,GAAG,OAAQ;AAAA,EAC/C;AAEA,MAAK,WAAW,SAAU;AACzB,WAAO,oBAAC,4BAAyB,SAAU,OAAU,GAAG,OAAQ;AAAA,EACjE;AAEA,SAAO,oBAAC,WAAQ,WAA0B,qBAAW,IAAI;AAC1D;AA8BO,SAAS,2BAA4B;AAAA,EAC3C,eAAe;AAAA,EACf,GAAG;AACJ,GAAqC;AACpC,QAAM,gBAAgB,UAAW,CAAE,WAAY;AAI9C,UAAM,cAAc,OAAQ,aAAc;AAE1C,UAAM,SAAS,aAAa,mBAAmB;AAM/C,WAAO,UAAU,OAAO,WAAW,WAAW,SAAS;AAAA,EACxD,GAAG,CAAC,CAAE;AAEN,QAAM,kBAAkB,QAAS,MAAM;AACtC,QAAK,CAAE,eAAgB;AACtB,aAAO;AAAA,IACR;AACA,WAAO;AAAA,MACN,SAAS;AAAA,MACT,GAAG;AAAA,IACJ;AAAA,EACD,GAAG,CAAE,eAAe,YAAa,CAAE;AAEnC,SAAO,oBAAC,oBAAiB,cAAe,iBAAoB,GAAG,OAAQ;AACxE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.mjs.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export declare function rendererPath(block: string, attributes?: Record<string, unknown> | null, urlQueryArgs?: Record<string, unknown>): string;
|
|
2
|
+
export declare function removeBlockSupportAttributes(attributes: Record<string, unknown> & {
|
|
3
|
+
style?: Record<string, unknown>;
|
|
4
|
+
}): Record<string, unknown>;
|
|
5
|
+
/**
|
|
6
|
+
* Server-side render response object.
|
|
7
|
+
*/
|
|
8
|
+
export interface ServerSideRenderResponse {
|
|
9
|
+
/** The current request status: 'idle', 'loading', 'success', or 'error'. */
|
|
10
|
+
status: 'idle' | 'loading' | 'success' | 'error';
|
|
11
|
+
/** The rendered block content (available when status is 'success'). */
|
|
12
|
+
content?: string;
|
|
13
|
+
/** The error message (available when status is 'error'). */
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Configuration object for the useServerSideRender hook.
|
|
18
|
+
*/
|
|
19
|
+
export interface UseServerSideRenderArgs {
|
|
20
|
+
/** The block attributes to be sent to the server for rendering. */
|
|
21
|
+
attributes: Record<string, unknown>;
|
|
22
|
+
/** The identifier of the block to be serverside rendered. Example: 'core/archives'. */
|
|
23
|
+
block: string;
|
|
24
|
+
/** Whether to remove block support attributes before sending. */
|
|
25
|
+
skipBlockSupportAttributes?: boolean;
|
|
26
|
+
/** The HTTP method to use ('GET' or 'POST'). Default is 'GET'. */
|
|
27
|
+
httpMethod?: 'GET' | 'POST';
|
|
28
|
+
/** Additional query arguments to append to the request URL. */
|
|
29
|
+
urlQueryArgs?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A hook for server-side rendering a preview of dynamic blocks to display in the editor.
|
|
33
|
+
*
|
|
34
|
+
* Handles fetching server-rendered previews for blocks, managing loading states,
|
|
35
|
+
* and automatically debouncing requests to prevent excessive API calls. It supports both
|
|
36
|
+
* GET and POST requests, with POST requests used for larger attribute payloads.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* Basic usage:
|
|
40
|
+
*
|
|
41
|
+
* ```jsx
|
|
42
|
+
* import { RawHTML } from '@wordpress/element';
|
|
43
|
+
* import { useServerSideRender } from '@wordpress/server-side-render';
|
|
44
|
+
*
|
|
45
|
+
* function MyServerSideRender( { attributes, block } ) {
|
|
46
|
+
* const { content, status, error } = useServerSideRender( {
|
|
47
|
+
* attributes,
|
|
48
|
+
* block,
|
|
49
|
+
* } );
|
|
50
|
+
*
|
|
51
|
+
* if ( status === 'loading' ) {
|
|
52
|
+
* return <div>Loading...</div>;
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* if ( status === 'error' ) {
|
|
56
|
+
* return <div>Error: { error }</div>;
|
|
57
|
+
* }
|
|
58
|
+
*
|
|
59
|
+
* return <RawHTML>{ content }</RawHTML>;
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @param args The hook configuration object.
|
|
64
|
+
*
|
|
65
|
+
* @return The server-side render response object.
|
|
66
|
+
*/
|
|
67
|
+
export declare function useServerSideRender(args: UseServerSideRenderArgs): ServerSideRenderResponse;
|
|
68
|
+
//# sourceMappingURL=hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"AAUA,wBAAgB,YAAY,CAC3B,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,GAAG,IAAW,EACnD,YAAY,GAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAO,GAC1C,MAAM,CAMR;AAED,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,GAAG;IACvC,KAAK,CAAC,EAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,CAAC;CAClC,GACC,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,CA0B3B;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACxC,4EAA4E;IAC5E,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACjD,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,CAAC;IACtC,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,kEAAkE;IAClE,UAAU,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,uBAAuB,GAC3B,wBAAwB,CA2F1B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { ServerSideRenderWithPostId } from './server-side-render';
|
|
5
|
+
import { useServerSideRender } from './hook';
|
|
6
|
+
/**
|
|
7
|
+
* A compatibility layer for the `ServerSideRender` component when used with `wp` global namespace.
|
|
8
|
+
*
|
|
9
|
+
* @deprecated Use `ServerSideRender` non-default export instead.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```js
|
|
13
|
+
* import ServerSideRender from '@wordpress/server-side-render';
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare const ServerSideRenderCompat: typeof ServerSideRenderWithPostId & {
|
|
17
|
+
ServerSideRender: typeof ServerSideRenderWithPostId;
|
|
18
|
+
useServerSideRender: typeof useServerSideRender;
|
|
19
|
+
};
|
|
20
|
+
export { ServerSideRenderWithPostId as ServerSideRender };
|
|
21
|
+
export { useServerSideRender };
|
|
22
|
+
export default ServerSideRenderCompat;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAE7C;;;;;;;;;GASG;AACH,QAAA,MAAM,sBAAsB,EACG,OAAO,0BAA0B,GAAG;IACjE,gBAAgB,EAAE,OAAO,0BAA0B,CAAC;IACpD,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;CAChD,CAAC;AAKH,OAAO,EAAE,0BAA0B,IAAI,gBAAgB,EAAE,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,CAAC;eAChB,sBAAsB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ServerSideRenderProps, ServerSideRenderWithPostIdProps } from './types';
|
|
2
|
+
export declare function ServerSideRender(props: ServerSideRenderProps): import("react").JSX.Element;
|
|
3
|
+
/**
|
|
4
|
+
* A component that renders server-side content for blocks.
|
|
5
|
+
*
|
|
6
|
+
* Note: URL query will include the current post ID when applicable.
|
|
7
|
+
* This is useful for blocks that depend on the context of the current post for rendering.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```jsx
|
|
11
|
+
* import { ServerSideRender } from '@wordpress/server-side-render';
|
|
12
|
+
* // Legacy import for WordPress 6.8 and earlier
|
|
13
|
+
* // import { default as ServerSideRender } from '@wordpress/server-side-render';
|
|
14
|
+
*
|
|
15
|
+
* function Example() {
|
|
16
|
+
* return (
|
|
17
|
+
* <ServerSideRender
|
|
18
|
+
* block="core/archives"
|
|
19
|
+
* attributes={ { showPostCounts: true } }
|
|
20
|
+
* urlQueryArgs={ { customArg: 'value' } }
|
|
21
|
+
* className="custom-class"
|
|
22
|
+
* />
|
|
23
|
+
* );
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @param props Component props.
|
|
28
|
+
* @param props.urlQueryArgs Additional query arguments to append to the request URL.
|
|
29
|
+
* @return The rendered server-side content.
|
|
30
|
+
*/
|
|
31
|
+
export declare function ServerSideRenderWithPostId({ urlQueryArgs, ...props }: ServerSideRenderWithPostIdProps): import("react").JSX.Element;
|
|
32
|
+
//# sourceMappingURL=server-side-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-side-render.d.ts","sourceRoot":"","sources":["../src/server-side-render.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAIX,qBAAqB,EACrB,+BAA+B,EAC/B,MAAM,SAAS,CAAC;AA2DjB,wBAAgB,gBAAgB,CAAE,KAAK,EAAE,qBAAqB,+BA4C7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,0BAA0B,CAAE,EAC3C,YAA2B,EAC3B,GAAG,KAAK,EACR,EAAE,+BAA+B,+BA2BjC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import type React from 'react';
|
|
5
|
+
/**
|
|
6
|
+
* Internal dependencies
|
|
7
|
+
*/
|
|
8
|
+
import type { UseServerSideRenderArgs } from './hook';
|
|
9
|
+
export interface PlaceholderProps {
|
|
10
|
+
/** Additional classes to apply to the wrapper element. */
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ErrorPlaceholderProps extends PlaceholderProps {
|
|
14
|
+
/** Error message describing the problem. */
|
|
15
|
+
message?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface LoadingPlaceholderProps {
|
|
18
|
+
children?: React.ReactNode;
|
|
19
|
+
}
|
|
20
|
+
export interface ServerSideRenderProps extends UseServerSideRenderArgs {
|
|
21
|
+
/** Additional classes to apply to the wrapper element. */
|
|
22
|
+
className?: string;
|
|
23
|
+
/** Component rendered when the API response is empty. */
|
|
24
|
+
EmptyResponsePlaceholder?: React.ComponentType<PlaceholderProps>;
|
|
25
|
+
/** Component rendered when the API response is an error. */
|
|
26
|
+
ErrorResponsePlaceholder?: React.ComponentType<ErrorPlaceholderProps>;
|
|
27
|
+
/** Component rendered while the API request is loading. */
|
|
28
|
+
LoadingResponsePlaceholder?: React.ComponentType<LoadingPlaceholderProps>;
|
|
29
|
+
}
|
|
30
|
+
export interface ServerSideRenderWithPostIdProps extends Omit<ServerSideRenderProps, 'urlQueryArgs'> {
|
|
31
|
+
/** Additional query arguments to append to the request URL. */
|
|
32
|
+
urlQueryArgs?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;GAEG;AACH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AAEtD,MAAM,WAAW,gBAAgB;IAChC,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC9D,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACrE,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,wBAAwB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAE,gBAAgB,CAAE,CAAC;IACnE,4DAA4D;IAC5D,wBAAwB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAE,qBAAqB,CAAE,CAAC;IACxE,2DAA2D;IAC3D,0BAA0B,CAAC,EAAE,KAAK,CAAC,aAAa,CAAE,uBAAuB,CAAE,CAAC;CAC5E;AAED,MAAM,WAAW,+BAChB,SAAQ,IAAI,CAAE,qBAAqB,EAAE,cAAc,CAAE;IACrD,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,CAAC;CACzC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/server-side-render",
|
|
3
|
-
"version": "6.24.0",
|
|
3
|
+
"version": "6.24.2-next.v.202606191442.0+17fe7db8a",
|
|
4
4
|
"description": "The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -34,31 +34,38 @@
|
|
|
34
34
|
"module": "build-module/index.mjs",
|
|
35
35
|
"exports": {
|
|
36
36
|
".": {
|
|
37
|
+
"types": "./build-types/index.d.ts",
|
|
37
38
|
"import": "./build-module/index.mjs",
|
|
38
39
|
"require": "./build/index.cjs"
|
|
39
40
|
},
|
|
40
41
|
"./package.json": "./package.json"
|
|
41
42
|
},
|
|
42
|
-
"react-native": "src/index",
|
|
43
43
|
"wpScript": true,
|
|
44
44
|
"wpScriptDefaultExport": true,
|
|
45
|
+
"types": "build-types/index.d.ts",
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"@wordpress/api-fetch": "^7.48.0",
|
|
47
|
-
"@wordpress/blocks": "^15.21.0",
|
|
48
|
-
"@wordpress/components": "^35.
|
|
49
|
-
"@wordpress/compose": "^8.1.0",
|
|
50
|
-
"@wordpress/data": "^10.48.0",
|
|
51
|
-
"@wordpress/deprecated": "^4.48.0",
|
|
52
|
-
"@wordpress/element": "^8.0.0",
|
|
53
|
-
"@wordpress/i18n": "^6.21.0",
|
|
54
|
-
"@wordpress/url": "^4.48.0"
|
|
47
|
+
"@wordpress/api-fetch": "^7.48.2-next.v.202606191442.0+17fe7db8a",
|
|
48
|
+
"@wordpress/blocks": "^15.21.3-next.v.202606191442.0+17fe7db8a",
|
|
49
|
+
"@wordpress/components": "^35.1.1-next.v.202606191442.0+17fe7db8a",
|
|
50
|
+
"@wordpress/compose": "^8.1.2-next.v.202606191442.0+17fe7db8a",
|
|
51
|
+
"@wordpress/data": "^10.48.2-next.v.202606191442.0+17fe7db8a",
|
|
52
|
+
"@wordpress/deprecated": "^4.48.2-next.v.202606191442.0+17fe7db8a",
|
|
53
|
+
"@wordpress/element": "^8.0.2-next.v.202606191442.0+17fe7db8a",
|
|
54
|
+
"@wordpress/i18n": "^6.21.2-next.v.202606191442.0+17fe7db8a",
|
|
55
|
+
"@wordpress/url": "^4.48.2-next.v.202606191442.0+17fe7db8a"
|
|
55
56
|
},
|
|
56
57
|
"peerDependencies": {
|
|
58
|
+
"@types/react": "^18.3.27",
|
|
57
59
|
"react": "^18.0.0",
|
|
58
60
|
"react-dom": "^18.0.0"
|
|
59
61
|
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"@types/react": {
|
|
64
|
+
"optional": true
|
|
65
|
+
}
|
|
66
|
+
},
|
|
60
67
|
"publishConfig": {
|
|
61
68
|
"access": "public"
|
|
62
69
|
},
|
|
63
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "1b6a19222df5a88f161880b5789efb3171d8f425"
|
|
64
71
|
}
|
package/src/{hook.js → hook.ts}
RENAMED
|
@@ -5,9 +5,14 @@ import { debounce } from '@wordpress/compose';
|
|
|
5
5
|
import { useEffect, useState, useRef } from '@wordpress/element';
|
|
6
6
|
import apiFetch from '@wordpress/api-fetch';
|
|
7
7
|
import { addQueryArgs } from '@wordpress/url';
|
|
8
|
+
|
|
8
9
|
import { __experimentalSanitizeBlockAttributes } from '@wordpress/blocks';
|
|
9
10
|
|
|
10
|
-
export function rendererPath(
|
|
11
|
+
export function rendererPath(
|
|
12
|
+
block: string,
|
|
13
|
+
attributes: Record< string, unknown > | null = null,
|
|
14
|
+
urlQueryArgs: Record< string, unknown > = {}
|
|
15
|
+
): string {
|
|
11
16
|
return addQueryArgs( `/wp/v2/block-renderer/${ block }`, {
|
|
12
17
|
context: 'edit',
|
|
13
18
|
...( null !== attributes ? { attributes } : {} ),
|
|
@@ -15,7 +20,11 @@ export function rendererPath( block, attributes = null, urlQueryArgs = {} ) {
|
|
|
15
20
|
} );
|
|
16
21
|
}
|
|
17
22
|
|
|
18
|
-
export function removeBlockSupportAttributes(
|
|
23
|
+
export function removeBlockSupportAttributes(
|
|
24
|
+
attributes: Record< string, unknown > & {
|
|
25
|
+
style?: Record< string, unknown >;
|
|
26
|
+
}
|
|
27
|
+
): Record< string, unknown > {
|
|
19
28
|
const {
|
|
20
29
|
backgroundColor,
|
|
21
30
|
borderColor,
|
|
@@ -44,11 +53,32 @@ export function removeBlockSupportAttributes( attributes ) {
|
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
/**
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
* Server-side render response object.
|
|
57
|
+
*/
|
|
58
|
+
export interface ServerSideRenderResponse {
|
|
59
|
+
/** The current request status: 'idle', 'loading', 'success', or 'error'. */
|
|
60
|
+
status: 'idle' | 'loading' | 'success' | 'error';
|
|
61
|
+
/** The rendered block content (available when status is 'success'). */
|
|
62
|
+
content?: string;
|
|
63
|
+
/** The error message (available when status is 'error'). */
|
|
64
|
+
error?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Configuration object for the useServerSideRender hook.
|
|
51
69
|
*/
|
|
70
|
+
export interface UseServerSideRenderArgs {
|
|
71
|
+
/** The block attributes to be sent to the server for rendering. */
|
|
72
|
+
attributes: Record< string, unknown >;
|
|
73
|
+
/** The identifier of the block to be serverside rendered. Example: 'core/archives'. */
|
|
74
|
+
block: string;
|
|
75
|
+
/** Whether to remove block support attributes before sending. */
|
|
76
|
+
skipBlockSupportAttributes?: boolean;
|
|
77
|
+
/** The HTTP method to use ('GET' or 'POST'). Default is 'GET'. */
|
|
78
|
+
httpMethod?: 'GET' | 'POST';
|
|
79
|
+
/** Additional query arguments to append to the request URL. */
|
|
80
|
+
urlQueryArgs?: Record< string, unknown >;
|
|
81
|
+
}
|
|
52
82
|
|
|
53
83
|
/**
|
|
54
84
|
* A hook for server-side rendering a preview of dynamic blocks to display in the editor.
|
|
@@ -82,18 +112,17 @@ export function removeBlockSupportAttributes( attributes ) {
|
|
|
82
112
|
* }
|
|
83
113
|
* ```
|
|
84
114
|
*
|
|
85
|
-
* @param
|
|
86
|
-
* @param {Object} args.attributes The block attributes to be sent to the server for rendering.
|
|
87
|
-
* @param {string} args.block The identifier of the block to be serverside rendered. Example: 'core/archives'.
|
|
88
|
-
* @param {boolean} [args.skipBlockSupportAttributes=false] Whether to remove block support attributes before sending.
|
|
89
|
-
* @param {string} [args.httpMethod='GET'] The HTTP method to use ('GET' or 'POST'). Default is 'GET'.
|
|
90
|
-
* @param {Object} [args.urlQueryArgs] Additional query arguments to append to the request URL.
|
|
115
|
+
* @param args The hook configuration object.
|
|
91
116
|
*
|
|
92
|
-
* @return
|
|
117
|
+
* @return The server-side render response object.
|
|
93
118
|
*/
|
|
94
|
-
export function useServerSideRender(
|
|
95
|
-
|
|
96
|
-
|
|
119
|
+
export function useServerSideRender(
|
|
120
|
+
args: UseServerSideRenderArgs
|
|
121
|
+
): ServerSideRenderResponse {
|
|
122
|
+
const [ response, setResponse ] = useState< ServerSideRenderResponse >( {
|
|
123
|
+
status: 'idle',
|
|
124
|
+
} );
|
|
125
|
+
const shouldDebounceRef = useRef< boolean >( false );
|
|
97
126
|
|
|
98
127
|
const {
|
|
99
128
|
attributes,
|
|
@@ -103,11 +132,11 @@ export function useServerSideRender( args ) {
|
|
|
103
132
|
urlQueryArgs,
|
|
104
133
|
} = args;
|
|
105
134
|
|
|
106
|
-
let sanitizedAttributes =
|
|
135
|
+
let sanitizedAttributes: Record< string, unknown > | null =
|
|
107
136
|
attributes &&
|
|
108
137
|
__experimentalSanitizeBlockAttributes( block, attributes );
|
|
109
138
|
|
|
110
|
-
if ( skipBlockSupportAttributes ) {
|
|
139
|
+
if ( skipBlockSupportAttributes && sanitizedAttributes ) {
|
|
111
140
|
sanitizedAttributes =
|
|
112
141
|
removeBlockSupportAttributes( sanitizedAttributes );
|
|
113
142
|
}
|
|
@@ -128,7 +157,7 @@ export function useServerSideRender( args ) {
|
|
|
128
157
|
{
|
|
129
158
|
setResponse( { status: 'loading' } );
|
|
130
159
|
|
|
131
|
-
apiFetch( {
|
|
160
|
+
apiFetch< { rendered: string } >( {
|
|
132
161
|
path,
|
|
133
162
|
method: isPostRequest ? 'POST' : 'GET',
|
|
134
163
|
body,
|
|
@@ -145,15 +174,21 @@ export function useServerSideRender( args ) {
|
|
|
145
174
|
content: res ? res.rendered : '',
|
|
146
175
|
} );
|
|
147
176
|
} )
|
|
148
|
-
.catch( ( error ) => {
|
|
177
|
+
.catch( ( error: unknown ) => {
|
|
149
178
|
// The request was aborted, do not update the response.
|
|
150
|
-
if (
|
|
179
|
+
if (
|
|
180
|
+
error instanceof Error &&
|
|
181
|
+
error.name === 'AbortError'
|
|
182
|
+
) {
|
|
151
183
|
return;
|
|
152
184
|
}
|
|
153
185
|
|
|
154
186
|
setResponse( {
|
|
155
187
|
status: 'error',
|
|
156
|
-
error:
|
|
188
|
+
error:
|
|
189
|
+
error instanceof Error
|
|
190
|
+
? error.message
|
|
191
|
+
: String( error ),
|
|
157
192
|
} );
|
|
158
193
|
} )
|
|
159
194
|
.finally( () => {
|
|
@@ -14,7 +14,12 @@ import { useServerSideRender } from './hook';
|
|
|
14
14
|
* import ServerSideRender from '@wordpress/server-side-render';
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
const ServerSideRenderCompat =
|
|
17
|
+
const ServerSideRenderCompat =
|
|
18
|
+
ServerSideRenderWithPostId as typeof ServerSideRenderWithPostId & {
|
|
19
|
+
ServerSideRender: typeof ServerSideRenderWithPostId;
|
|
20
|
+
useServerSideRender: typeof useServerSideRender;
|
|
21
|
+
};
|
|
22
|
+
|
|
18
23
|
ServerSideRenderCompat.ServerSideRender = ServerSideRenderWithPostId;
|
|
19
24
|
ServerSideRenderCompat.useServerSideRender = useServerSideRender;
|
|
20
25
|
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
RawHTML,
|
|
6
6
|
useEffect,
|
|
7
7
|
useState,
|
|
8
|
-
useRef,
|
|
9
8
|
useMemo,
|
|
9
|
+
useRef,
|
|
10
10
|
} from '@wordpress/element';
|
|
11
11
|
import { __, sprintf } from '@wordpress/i18n';
|
|
12
12
|
import { Placeholder, Spinner } from '@wordpress/components';
|
|
@@ -16,10 +16,17 @@ import { useSelect } from '@wordpress/data';
|
|
|
16
16
|
* Internal dependencies
|
|
17
17
|
*/
|
|
18
18
|
import { useServerSideRender } from './hook';
|
|
19
|
+
import type {
|
|
20
|
+
PlaceholderProps,
|
|
21
|
+
ErrorPlaceholderProps,
|
|
22
|
+
LoadingPlaceholderProps,
|
|
23
|
+
ServerSideRenderProps,
|
|
24
|
+
ServerSideRenderWithPostIdProps,
|
|
25
|
+
} from './types';
|
|
19
26
|
|
|
20
27
|
const EMPTY_OBJECT = {};
|
|
21
28
|
|
|
22
|
-
function DefaultEmptyResponsePlaceholder( { className } ) {
|
|
29
|
+
function DefaultEmptyResponsePlaceholder( { className }: PlaceholderProps ) {
|
|
23
30
|
return (
|
|
24
31
|
<Placeholder className={ className }>
|
|
25
32
|
{ __( 'Block rendered as empty.' ) }
|
|
@@ -27,16 +34,21 @@ function DefaultEmptyResponsePlaceholder( { className } ) {
|
|
|
27
34
|
);
|
|
28
35
|
}
|
|
29
36
|
|
|
30
|
-
function DefaultErrorResponsePlaceholder( {
|
|
37
|
+
function DefaultErrorResponsePlaceholder( {
|
|
38
|
+
message,
|
|
39
|
+
className,
|
|
40
|
+
}: ErrorPlaceholderProps ) {
|
|
31
41
|
const errorMessage = sprintf(
|
|
32
42
|
// translators: %s: error message describing the problem
|
|
33
43
|
__( 'Error loading block: %s' ),
|
|
34
|
-
message
|
|
44
|
+
message || __( 'Unknown error' )
|
|
35
45
|
);
|
|
36
46
|
return <Placeholder className={ className }>{ errorMessage }</Placeholder>;
|
|
37
47
|
}
|
|
38
48
|
|
|
39
|
-
function DefaultLoadingResponsePlaceholder( {
|
|
49
|
+
function DefaultLoadingResponsePlaceholder( {
|
|
50
|
+
children,
|
|
51
|
+
}: LoadingPlaceholderProps ) {
|
|
40
52
|
const [ showLoader, setShowLoader ] = useState( false );
|
|
41
53
|
|
|
42
54
|
useEffect( () => {
|
|
@@ -69,7 +81,7 @@ function DefaultLoadingResponsePlaceholder( { children } ) {
|
|
|
69
81
|
);
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
export function ServerSideRender( props ) {
|
|
84
|
+
export function ServerSideRender( props: ServerSideRenderProps ) {
|
|
73
85
|
const prevContentRef = useRef( '' );
|
|
74
86
|
const {
|
|
75
87
|
className,
|
|
@@ -91,9 +103,13 @@ export function ServerSideRender( props ) {
|
|
|
91
103
|
if ( status === 'loading' ) {
|
|
92
104
|
return (
|
|
93
105
|
<LoadingResponsePlaceholder { ...props }>
|
|
106
|
+
{ /* eslint-disable-next-line react-hooks/refs */ }
|
|
94
107
|
{ !! prevContentRef.current && (
|
|
95
108
|
<RawHTML className={ className }>
|
|
96
|
-
{
|
|
109
|
+
{
|
|
110
|
+
// eslint-disable-next-line react-hooks/refs
|
|
111
|
+
prevContentRef.current
|
|
112
|
+
}
|
|
97
113
|
</RawHTML>
|
|
98
114
|
) }
|
|
99
115
|
</LoadingResponsePlaceholder>
|
|
@@ -108,7 +124,7 @@ export function ServerSideRender( props ) {
|
|
|
108
124
|
return <ErrorResponsePlaceholder message={ error } { ...props } />;
|
|
109
125
|
}
|
|
110
126
|
|
|
111
|
-
return <RawHTML className={ className }>{ content }</RawHTML>;
|
|
127
|
+
return <RawHTML className={ className }>{ content || '' }</RawHTML>;
|
|
112
128
|
}
|
|
113
129
|
|
|
114
130
|
/**
|
|
@@ -135,28 +151,21 @@ export function ServerSideRender( props ) {
|
|
|
135
151
|
* }
|
|
136
152
|
* ```
|
|
137
153
|
*
|
|
138
|
-
* @param
|
|
139
|
-
* @param
|
|
140
|
-
* @
|
|
141
|
-
* @param {string} [props.className] Additional classes to apply to the wrapper element.
|
|
142
|
-
* @param {string} [props.httpMethod='GET'] The HTTP method to use ('GET' or 'POST'). Default is 'GET'
|
|
143
|
-
* @param {Object} [props.urlQueryArgs] Additional query arguments to append to the request URL.
|
|
144
|
-
* @param {boolean} [props.skipBlockSupportAttributes=false] Whether to remove block support attributes before sending.
|
|
145
|
-
* @param {Function} [props.EmptyResponsePlaceholder] Component rendered when the API response is empty.
|
|
146
|
-
* @param {Function} [props.ErrorResponsePlaceholder] Component rendered when the API response is an error.
|
|
147
|
-
* @param {Function} [props.LoadingResponsePlaceholder] Component rendered while the API request is loading.
|
|
148
|
-
*
|
|
149
|
-
* @return {React.JSX.Element} The rendered server-side content.
|
|
154
|
+
* @param props Component props.
|
|
155
|
+
* @param props.urlQueryArgs Additional query arguments to append to the request URL.
|
|
156
|
+
* @return The rendered server-side content.
|
|
150
157
|
*/
|
|
151
158
|
export function ServerSideRenderWithPostId( {
|
|
152
159
|
urlQueryArgs = EMPTY_OBJECT,
|
|
153
160
|
...props
|
|
154
|
-
} ) {
|
|
161
|
+
}: ServerSideRenderWithPostIdProps ) {
|
|
155
162
|
const currentPostId = useSelect( ( select ) => {
|
|
156
163
|
// FIXME: @wordpress/server-side-render should not depend on @wordpress/editor.
|
|
157
164
|
// It is used by blocks that can be loaded into a *non-post* block editor.
|
|
158
165
|
// eslint-disable-next-line @wordpress/data-no-store-string-literals
|
|
159
|
-
const
|
|
166
|
+
const editorStore = select( 'core/editor' );
|
|
167
|
+
// @ts-expect-error - editorStore is not typed in @wordpress/data
|
|
168
|
+
const postId = editorStore?.getCurrentPostId?.();
|
|
160
169
|
|
|
161
170
|
// For templates and template parts we use a custom ID format.
|
|
162
171
|
// Since they aren't real posts, we don't want to use their ID
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import type React from 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import type { UseServerSideRenderArgs } from './hook';
|
|
10
|
+
|
|
11
|
+
export interface PlaceholderProps {
|
|
12
|
+
/** Additional classes to apply to the wrapper element. */
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ErrorPlaceholderProps extends PlaceholderProps {
|
|
17
|
+
/** Error message describing the problem. */
|
|
18
|
+
message?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface LoadingPlaceholderProps {
|
|
22
|
+
children?: React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ServerSideRenderProps extends UseServerSideRenderArgs {
|
|
26
|
+
/** Additional classes to apply to the wrapper element. */
|
|
27
|
+
className?: string;
|
|
28
|
+
/** Component rendered when the API response is empty. */
|
|
29
|
+
EmptyResponsePlaceholder?: React.ComponentType< PlaceholderProps >;
|
|
30
|
+
/** Component rendered when the API response is an error. */
|
|
31
|
+
ErrorResponsePlaceholder?: React.ComponentType< ErrorPlaceholderProps >;
|
|
32
|
+
/** Component rendered while the API request is loading. */
|
|
33
|
+
LoadingResponsePlaceholder?: React.ComponentType< LoadingPlaceholderProps >;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ServerSideRenderWithPostIdProps
|
|
37
|
+
extends Omit< ServerSideRenderProps, 'urlQueryArgs' > {
|
|
38
|
+
/** Additional query arguments to append to the request URL. */
|
|
39
|
+
urlQueryArgs?: Record< string, unknown >;
|
|
40
|
+
}
|
|
File without changes
|