diff --git a/lib/compat/wordpress-6.6/class-gutenberg-rest-templates-controller-6-6.php b/lib/compat/wordpress-6.6/class-gutenberg-rest-templates-controller-6-6.php
new file mode 100644
index 00000000000000..42f8d0400393ca
--- /dev/null
+++ b/lib/compat/wordpress-6.6/class-gutenberg-rest-templates-controller-6-6.php
@@ -0,0 +1,66 @@
+ rest_authorization_required_code(),
+ )
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if a given request has access to read templates.
+ *
+ * @since 6.6
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
+ */
+ public function get_item_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
+ /*
+ * Allow access to anyone who can edit posts.
+ */
+ if ( ! current_user_can( 'edit_posts' ) ) {
+ return new WP_Error(
+ 'rest_cannot_manage_templates',
+ __( 'Sorry, you are not allowed to access the templates on this site.', 'default' ),
+ array(
+ 'status' => rest_authorization_required_code(),
+ )
+ );
+ }
+
+ return true;
+ }
+}
diff --git a/lib/compat/wordpress-6.6/rest-api.php b/lib/compat/wordpress-6.6/rest-api.php
new file mode 100644
index 00000000000000..bf462cd11ca4b4
--- /dev/null
+++ b/lib/compat/wordpress-6.6/rest-api.php
@@ -0,0 +1,31 @@
+ {
+ const { getSettings } = select( blockEditorStore );
+ return getSettings()?.supportsLayout;
+ }, [] );
+ const [ defaultLayout ] = useSettings( 'layout' );
+ const usedLayout = layout?.inherit ? defaultLayout || {} : layout;
+
+ const [ blocks ] = useEntityBlockEditor( 'postType', 'wp_template_part', {
+ id,
+ context: 'view',
+ } );
+
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
+ value: blocks,
+ onChange: () => {},
+ onInput: () => {},
+ renderAppender: undefined,
+ layout: themeSupportsLayout ? usedLayout : undefined,
+ } );
+
+ return ;
+}
+
export default function TemplatePartEdit( {
attributes,
setAttributes,
clientId,
} ) {
const { createSuccessNotice } = useDispatch( noticesStore );
+ const { canEditTemplatePart, canViewTemplatePart } = useSelect(
+ ( select ) => ( {
+ canEditTemplatePart:
+ select( coreStore ).canUser( 'create', 'template-parts' ) ??
+ false,
+ canViewTemplatePart:
+ select( coreStore ).canUser( 'read', 'template-parts' ) ??
+ false,
+ } ),
+ []
+ );
+
const currentTheme = useSelect(
( select ) => select( coreStore ).getCurrentTheme()?.stylesheet,
[]
@@ -161,6 +204,23 @@ export default function TemplatePartEdit( {
setAttributes
);
+ if ( ! canEditTemplatePart && canViewTemplatePart ) {
+ return (
+
+
+
+ );
+ }
+
// We don't want to render a missing state if we have any inner blocks.
// A new template part is automatically created if we have any inner blocks but no entity.
if (
diff --git a/packages/core-data/src/entity-provider.js b/packages/core-data/src/entity-provider.js
index 51830f622a026d..3c7012d2dccb44 100644
--- a/packages/core-data/src/entity-provider.js
+++ b/packages/core-data/src/entity-provider.js
@@ -145,14 +145,19 @@ const parsedBlocksCache = new WeakMap();
* `BlockEditorProvider` and are intended to be used with it,
* or similar components or hooks.
*
- * @param {string} kind The entity kind.
- * @param {string} name The entity name.
+ * @param {string} kind The entity kind.
+ * @param {string} name The entity name.
* @param {Object} options
- * @param {string} [options.id] An entity ID to use instead of the context-provided one.
+ * @param {string} [options.id] An entity ID to use instead of the context-provided one.
+ * @param {string} [options.context] The context param to be passed to the REST API.
*
* @return {[WPBlock[], Function, Function]} The block array and setters.
*/
-export function useEntityBlockEditor( kind, name, { id: _id } = {} ) {
+export function useEntityBlockEditor(
+ kind,
+ name,
+ { id: _id, context = 'edit' } = {}
+) {
const providerId = useEntityId( kind, name );
const id = _id ?? providerId;
const { getEntityRecord, getEntityRecordEdits } = useSelect( STORE_NAME );
@@ -162,7 +167,9 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) {
return {};
}
const { getEditedEntityRecord } = select( STORE_NAME );
- const editedRecord = getEditedEntityRecord( kind, name, id );
+ const editedRecord = getEditedEntityRecord( kind, name, id, {
+ context,
+ } );
return {
editedBlocks: editedRecord.blocks,
content: editedRecord.content,
diff --git a/packages/edit-post/src/editor.js b/packages/edit-post/src/editor.js
index fd44d3dae4ca4a..41043954454f26 100644
--- a/packages/edit-post/src/editor.js
+++ b/packages/edit-post/src/editor.js
@@ -55,12 +55,12 @@ function Editor( {
getEditorSettings().supportsTemplateMode;
const isViewable =
getPostType( currentPost.postType )?.viewable ?? false;
- const canEditTemplate = canUser( 'create', 'templates' );
+ const canViewTemplate = canUser( 'read', 'templates' );
return {
template:
supportsTemplateMode &&
isViewable &&
- canEditTemplate &&
+ canViewTemplate &&
currentPost.postType !== 'wp_template'
? getEditedPostTemplate()
: null,
diff --git a/packages/editor/src/components/editor-canvas/edit-template-blocks-notification.js b/packages/editor/src/components/editor-canvas/edit-template-blocks-notification.js
index 2000ae5727190c..3581a49608c734 100644
--- a/packages/editor/src/components/editor-canvas/edit-template-blocks-notification.js
+++ b/packages/editor/src/components/editor-canvas/edit-template-blocks-notification.js
@@ -2,6 +2,7 @@
* WordPress dependencies
*/
import { useSelect, useDispatch } from '@wordpress/data';
+import { store as coreStore } from '@wordpress/core-data';
import { useEffect, useState, useRef } from '@wordpress/element';
import { store as noticesStore } from '@wordpress/notices';
import { __ } from '@wordpress/i18n';
@@ -42,12 +43,20 @@ export default function EditTemplateBlocksNotification( { contentRef } ) {
const { createInfoNotice, removeNotice } = useDispatch( noticesStore );
+ const canEditTemplate = useSelect(
+ ( select ) =>
+ select( coreStore ).canUser( 'create', 'templates' ) ?? false
+ );
+
const [ isDialogOpen, setIsDialogOpen ] = useState( false );
const lastNoticeId = useRef( 0 );
useEffect( () => {
const handleClick = async ( event ) => {
+ if ( ! canEditTemplate ) {
+ return;
+ }
if ( ! event.target.classList.contains( 'is-root-container' ) ) {
return;
}
@@ -104,8 +113,13 @@ export default function EditTemplateBlocksNotification( { contentRef } ) {
onNavigateToEntityRecord,
templateId,
removeNotice,
+ canEditTemplate,
] );
+ if ( ! canEditTemplate ) {
+ return null;
+ }
+
return (
+ select( coreStore ).canUser( 'create', 'templates' ) ?? false
+ );
+
const { createSuccessNotice } = useDispatch( noticesStore );
const { setRenderingMode } = useDispatch( editorStore );
@@ -81,30 +87,33 @@ export default function BlockThemeControl( { id } ) {
{ ( { onClose } ) => (
<>
-
-
+ { canCreateTemplate && (
+
+ ) }
-
+ { canCreateTemplate && (
+
+ ) }