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.' + ); + } ); } );