Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/core-fields/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
"remove-accents": "^0.5.0"
},
"devDependencies": {
"@testing-library/react": "^16.3.3",
"vitest": "^5.0.3"
},
"peerDependencies": {
Expand Down
29 changes: 23 additions & 6 deletions packages/core-fields/src/post_type_supports/template/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ type TemplateEditComponentProps = Pick<

const EMPTY_ARRAY: [] = [];

// The value of the default template option. The post stores the default
// template as an empty string, but the select treats an empty value as no
// selection and shows its placeholder.
const DEFAULT_TEMPLATE_VALUE = '__default';
Comment thread
ntsekouras marked this conversation as resolved.
Resolved

function toItemValue( template: string | undefined ) {
return template || DEFAULT_TEMPLATE_VALUE;
}

function fromItemValue( itemValue: string | null | undefined ) {
return ! itemValue || itemValue === DEFAULT_TEMPLATE_VALUE ? '' : itemValue;
}

/**
* Whether the post is the front page or the posts page, which are assigned
* a template by the reading settings rather than by this field.
Expand Down Expand Up @@ -60,7 +73,7 @@ function ClassicTemplateEdit( {
Object.entries( data?.available_templates ?? {} ).map(
( [ templateSlug, title ] ) => ( {
label: title,
value: templateSlug,
value: toItemValue( templateSlug ),
} )
),
[ data ]
Expand All @@ -71,12 +84,14 @@ function ClassicTemplateEdit( {
label={ __( 'Template' ) }
hideLabelFromVision
value={
items.find( ( item ) => item.value === value ) ??
items.find( ( item ) => item.value === toItemValue( value ) ) ??
items[ 0 ] ??
null
}
items={ items }
onValueChange={ ( item ) => onChange( item?.value ?? '' ) }
onValueChange={ ( item ) =>
onChange( fromItemValue( item?.value ) )
}
disabled={ ! canSwitchTemplate }
/>
);
Expand Down Expand Up @@ -111,7 +126,7 @@ function BlockThemeTemplateEdit( {
const value = field.getValue( { item: data } );
const items = useMemo(
() => [
{ label: defaultTemplateLabel, value: '' },
{ label: defaultTemplateLabel, value: DEFAULT_TEMPLATE_VALUE },
...templates.map( ( template ) => ( {
label: getItemTitle( template ),
value: template.slug,
Expand All @@ -124,12 +139,14 @@ function BlockThemeTemplateEdit( {
label={ __( 'Template' ) }
hideLabelFromVision
value={
items.find( ( item ) => item.value === value ) ??
items.find( ( item ) => item.value === toItemValue( value ) ) ??
items[ 0 ] ??
null
}
items={ items }
onValueChange={ ( item ) => onChange( item?.value ?? '' ) }
onValueChange={ ( item ) =>
onChange( fromItemValue( item?.value ) )
}
disabled={ ! canSwitchTemplate }
/>
);
Expand Down
94 changes: 94 additions & 0 deletions packages/core-fields/src/test/template-edit.jsdom.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { render, screen } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import {
createReduxStore,
createRegistry,
RegistryProvider,
} from '@wordpress/data';
import { unlock } from '../lock-unlock';
import TemplateEdit from '../post_type_supports/template/edit';

const field = {
id: 'template',
getValue: ( { item }: { item: { template?: string } } ) => item.template,
} as any;

const CUSTOM_TEMPLATES = [ { slug: 'custom', title: { rendered: 'Custom' } } ];
const DEFAULT_TEMPLATE = {
slug: 'single',
title: { rendered: 'Single Posts' },
};

// The field reads the post type, the theme, and the templates from the
// `core` store; a stand-in avoids the resolvers' requests.
function createTestRegistry( { isBlockTheme }: { isBlockTheme: boolean } ) {
const store = createReduxStore( 'core', {
reducer: ( state = {} ) => state,
selectors: {
getPostType: () => ( { viewable: true } ),
getCurrentTheme: () => ( { is_block_theme: isBlockTheme } ),
getEntityRecords: () => CUSTOM_TEMPLATES,
getDefaultTemplateId: () => 'theme//single',
getEntityRecord: () => DEFAULT_TEMPLATE,
},
} );
unlock( store ).registerPrivateSelectors( {
getTemplateId: () => 'theme//single',
getHomePage: () => null,
getPostsPageId: () => null,
} );
const registry = createRegistry();
registry.register( store );
return registry;
}

describe( 'TemplateEdit', () => {
it( 'shows the default template of a block theme as the selected one', () => {
render(
<RegistryProvider
value={ createTestRegistry( { isBlockTheme: true } ) }
>
<TemplateEdit
data={ {
id: 1,
type: 'post',
slug: 'hello',
template: '',
} }
field={ field }
onChange={ () => {} }
/>
</RegistryProvider>
);

const select = screen.getByRole( 'combobox', { name: 'Template' } );
expect( select ).toHaveTextContent( 'Single Posts' );
expect( select ).not.toHaveAttribute( 'data-placeholder' );
} );

it( 'shows the default template of a classic theme as the selected one', () => {
render(
<RegistryProvider
value={ createTestRegistry( { isBlockTheme: false } ) }
>
<TemplateEdit
data={ {
id: 1,
type: 'post',
template: '',
available_templates: {
'': 'Default template',
'full-width.php': 'Full Width',
},
} }
field={ field }
onChange={ () => {} }
/>
</RegistryProvider>
);

const select = screen.getByRole( 'combobox', { name: 'Template' } );
expect( select ).toHaveTextContent( 'Default template' );
expect( select ).not.toHaveAttribute( 'data-placeholder' );
} );
} );
Loading