diff --git a/backport-changelog/6.8/8063.md b/backport-changelog/6.9/8063.md
similarity index 75%
rename from backport-changelog/6.8/8063.md
rename to backport-changelog/6.9/8063.md
index 342240eca9874f..8e82d2da0ee7aa 100644
--- a/backport-changelog/6.8/8063.md
+++ b/backport-changelog/6.9/8063.md
@@ -2,3 +2,4 @@ https://github.com/WordPress/wordpress-develop/pull/8063
* https://github.com/WordPress/gutenberg/pull/67125
* https://github.com/WordPress/gutenberg/pull/71811
+* https://github.com/WordPress/gutenberg/pull/72029
diff --git a/lib/compat/wordpress-6.9/template-activate.php b/lib/compat/wordpress-6.9/template-activate.php
index 5dd3d80608d9b1..c92f57594aa951 100644
--- a/lib/compat/wordpress-6.9/template-activate.php
+++ b/lib/compat/wordpress-6.9/template-activate.php
@@ -27,6 +27,22 @@ function gutenberg_maintain_templates_routes() {
$controller = new WP_REST_Templates_Controller( 'wp_template' );
$wp_post_types['wp_template']->rest_base = 'wp_template';
$controller->register_routes();
+
+ // Add the same field as wp_registered_template.
+ register_rest_field(
+ 'wp_template',
+ 'theme',
+ array(
+ 'get_callback' => function ( $post_arr ) {
+ $terms = get_the_terms( $post_arr['id'], 'wp_theme' );
+ if ( is_wp_error( $terms ) || empty( $terms ) ) {
+ return null;
+ }
+
+ return $terms[0]->slug;
+ },
+ )
+ );
}
// 3. We need a route to get that raw static templates from themes and plugins.
@@ -211,7 +227,16 @@ function ( $slug ) use ( $specific_template, $active_templates ) {
continue;
}
- $templates[] = _build_block_template_result_from_post( $post );
+ $template = _build_block_template_result_from_post( $post );
+
+ // Ensure the active templates are associated with the active theme.
+ // See _build_block_template_object_from_post_object.
+ if ( get_stylesheet() !== $template->theme ) {
+ $remaining_slugs[] = $slug;
+ continue;
+ }
+
+ $templates[] = $template;
}
// For any remaining slugs, use the static template.
diff --git a/packages/edit-site/src/components/dataviews-actions/index.js b/packages/edit-site/src/components/dataviews-actions/index.js
index 64083f36bc4218..7f4fa3f2b21180 100644
--- a/packages/edit-site/src/components/dataviews-actions/index.js
+++ b/packages/edit-site/src/components/dataviews-actions/index.js
@@ -17,6 +17,9 @@ import { unlock } from '../../lock-unlock';
const { useHistory } = unlock( routerPrivateApis );
export const useSetActiveTemplateAction = () => {
+ const activeTheme = useSelect( ( select ) =>
+ select( coreStore ).getCurrentTheme()
+ );
const { getEntityRecord } = useSelect( coreStore );
const { editEntityRecord, saveEditedEntityRecord } =
useDispatch( coreStore );
@@ -31,7 +34,10 @@ export const useSetActiveTemplateAction = () => {
isPrimary: true,
icon: edit,
isEligible( item ) {
- return ! ( item.slug === 'index' && item.source === 'theme' );
+ return (
+ ! ( item.slug === 'index' && item.source === 'theme' ) &&
+ item.theme === activeTheme.stylesheet
+ );
},
async callback( items ) {
const deactivate = items.some( ( item ) => item._isActive );
@@ -61,7 +67,12 @@ export const useSetActiveTemplateAction = () => {
await saveEditedEntityRecord( 'root', 'site' );
},
} ),
- [ editEntityRecord, saveEditedEntityRecord, getEntityRecord ]
+ [
+ editEntityRecord,
+ saveEditedEntityRecord,
+ getEntityRecord,
+ activeTheme,
+ ]
);
};
diff --git a/packages/edit-site/src/components/page-templates/fields.js b/packages/edit-site/src/components/page-templates/fields.js
index 04aba955e07b27..4a5f0ae0377e2d 100644
--- a/packages/edit-site/src/components/page-templates/fields.js
+++ b/packages/edit-site/src/components/page-templates/fields.js
@@ -20,7 +20,11 @@ import {
privateApis as blockEditorPrivateApis,
} from '@wordpress/block-editor';
import { EditorProvider } from '@wordpress/editor';
-import { privateApis as corePrivateApis } from '@wordpress/core-data';
+import {
+ privateApis as corePrivateApis,
+ store as coreStore,
+} from '@wordpress/core-data';
+import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
@@ -160,6 +164,23 @@ export const activeField = {
},
};
+export const useThemeField = () => {
+ const activeTheme = useSelect( ( select ) =>
+ select( coreStore ).getCurrentTheme()
+ );
+ return {
+ label: __( 'Compatible Theme' ),
+ id: 'theme',
+ getValue: ( { item } ) => item.theme,
+ render: function Render( { item } ) {
+ if ( item.theme === activeTheme.stylesheet ) {
+ return { item.theme };
+ }
+ return { item.theme };
+ },
+ };
+};
+
export const slugField = {
label: __( 'Template Type' ),
id: 'slug',
diff --git a/packages/edit-site/src/components/page-templates/index.js b/packages/edit-site/src/components/page-templates/index.js
index 22b7bded399d17..6b77ee2bf3339a 100644
--- a/packages/edit-site/src/components/page-templates/index.js
+++ b/packages/edit-site/src/components/page-templates/index.js
@@ -37,6 +37,7 @@ import {
previewField,
activeField,
slugField,
+ useThemeField,
} from './fields';
const { usePostActions, templateTitleField } = unlock( editorPrivateApis );
@@ -67,7 +68,7 @@ const DEFAULT_VIEW = {
titleField: 'title',
descriptionField: 'description',
mediaField: 'preview',
- fields: [ 'author', 'active', 'slug' ],
+ fields: [ 'author', 'active', 'slug', 'theme' ],
filters: [],
...defaultLayouts[ LAYOUT_GRID ],
};
@@ -119,11 +120,14 @@ export default function PageTemplates() {
} ) );
}, [ setView, activeView ] );
- const activeTemplatesOption = useSelect(
- ( select ) =>
- select( coreStore ).getEntityRecord( 'root', 'site' )
- ?.active_templates
- );
+ const { activeTemplatesOption, activeTheme } = useSelect( ( select ) => {
+ const { getEntityRecord, getCurrentTheme } = select( coreStore );
+ return {
+ activeTemplatesOption: getEntityRecord( 'root', 'site' )
+ ?.active_templates,
+ activeTheme: getCurrentTheme(),
+ };
+ } );
// Todo: this will have to be better so that we're not fetching all the
// records all the time. Active templates query will need to move server
// side.
@@ -154,7 +158,9 @@ export default function PageTemplates() {
} else {
// Replace the template in the array.
const template = userRecords.find(
- ( { id } ) => id === activeId
+ ( userRecord ) =>
+ userRecord.id === activeId &&
+ userRecord.theme === activeTheme.stylesheet
);
if ( template ) {
const index = _active.findIndex(
@@ -170,7 +176,7 @@ export default function PageTemplates() {
}
}
return _active;
- }, [ userRecords, staticRecords, activeTemplatesOption ] );
+ }, [ userRecords, staticRecords, activeTemplatesOption, activeTheme ] );
let _records;
let isLoadingData;
@@ -188,15 +194,11 @@ export default function PageTemplates() {
const records = useMemo( () => {
return _records.map( ( record ) => ( {
...record,
- _isActive:
- typeof record.id === 'string'
- ? activeTemplatesOption[ record.slug ] === record.id ||
- activeTemplatesOption[ record.slug ] === undefined
- : Object.values( activeTemplatesOption ).includes(
- record.id
- ),
+ _isActive: activeTemplates.find(
+ ( template ) => template.id === record.id
+ ),
} ) );
- }, [ _records, activeTemplatesOption ] );
+ }, [ _records, activeTemplates ] );
const users = useSelect(
( select ) => {
@@ -232,6 +234,7 @@ export default function PageTemplates() {
[ history, path, view?.type ]
);
+ const themeField = useThemeField();
const fields = useMemo( () => {
const _fields = [
previewField,
@@ -240,6 +243,9 @@ export default function PageTemplates() {
activeField,
slugField,
];
+ if ( activeView === 'user' ) {
+ _fields.push( themeField );
+ }
const elements = [];
for ( const author in users ) {
elements.push( {
@@ -252,7 +258,7 @@ export default function PageTemplates() {
elements,
} );
return _fields;
- }, [ users ] );
+ }, [ users, activeView ] );
const { data, paginationInfo } = useMemo( () => {
return filterSortAndPaginate( records, view, fields );
diff --git a/test/e2e/specs/site-editor/template-activate.spec.js b/test/e2e/specs/site-editor/template-activate.spec.js
index 0f33d8a7fce248..3891453b01b49d 100644
--- a/test/e2e/specs/site-editor/template-activate.spec.js
+++ b/test/e2e/specs/site-editor/template-activate.spec.js
@@ -126,4 +126,34 @@ test.describe( 'Template Activate', () => {
'Copied from Index.'
);
} );
+
+ test( 'should deactivate after theme change', async ( {
+ admin,
+ page,
+ requestUtils,
+ editor,
+ } ) => {
+ await admin.visitSiteEditor( { postType: 'wp_template' } );
+ await page.getByRole( 'button', { name: 'Add Template' } ).click();
+ await page.getByRole( 'button', { name: 'Blog Home' } ).click();
+ await page.waitForSelector( 'iframe[name="editor-canvas"]' );
+ await editor.insertBlock( {
+ name: 'core/paragraph',
+ attributes: { content: 'My home template test.' },
+ } );
+ await page.getByRole( 'button', { name: 'Save', exact: true } ).click();
+ await page.getByRole( 'button', { name: 'Activate' } ).click();
+ await expect( page.locator( '.components-notice' ) ).toContainText(
+ 'Template activated.'
+ );
+ await page.goto( '/' );
+ await expect( page.locator( 'body' ) ).toContainText(
+ 'My home template test.'
+ );
+ await requestUtils.activateTheme( 'twentytwentyfive' );
+ await page.reload();
+ await expect( page.locator( 'body' ) ).not.toContainText(
+ 'My home template test.'
+ );
+ } );
} );