Skip to content

Commit

Permalink
Add home template details to inspector controls
Browse files Browse the repository at this point in the history
  • Loading branch information
ntsekouras committed May 17, 2024
1 parent d538f42 commit 39a1785
Show file tree
Hide file tree
Showing 7 changed files with 420 additions and 1 deletion.
8 changes: 7 additions & 1 deletion packages/editor/src/components/sidebar/post-summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
TEMPLATE_POST_TYPE,
} from '../../store/constants';
import TemplateAreas from '../template-areas';
import SiteSettingsPanel from '../site-settings-panel';

/**
* Module Constants
Expand Down Expand Up @@ -87,7 +88,12 @@ export default function PostSummary( { onActionPerformed } ) {
<PostStickyPanel />
<PostFormatPanel />
<PostAuthorPanel />
{ isTemplate && <TemplateAreas /> }
{ isTemplate && (
<>
<SiteSettingsPanel />
<TemplateAreas />
</>
) }
{ fills }
{ ! isPattern &&
! isTemplate &&
Expand Down
121 changes: 121 additions & 0 deletions packages/editor/src/components/site-settings-panel/blog-title-panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { debounce } from '@wordpress/compose';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { decodeEntities } from '@wordpress/html-entities';
import {
Button,
Dropdown,
__experimentalInputControl as InputControl,
} from '@wordpress/components';
import { useState, useEffect, useMemo } from '@wordpress/element';
import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import PostPanelRow from '../post-panel-row';

const EMPTY_OBJECT = {};

export default function BlogTitlePanel() {
const { editEntityRecord } = useDispatch( coreStore );
const { postsPageTitle, postsPageId } = useSelect( ( select ) => {
const { getEntityRecord } = select( coreStore );
const siteSettings = getEntityRecord( 'root', 'site' );
const _postsPageRecord = siteSettings?.page_for_posts
? getEntityRecord(
'postType',
'page',
siteSettings?.page_for_posts
)
: EMPTY_OBJECT;
return {
postsPageId: _postsPageRecord?.id,
postsPageTitle: _postsPageRecord?.title?.rendered,
};
}, [] );
const [ postsPageTitleValue, setPostsPageTitleValue ] = useState( '' );

/*
* This hook serves to set the server-retrieved postsPageTitle
* value to local state.
*/
useEffect( () => {
setPostsPageTitleValue( postsPageTitle );
}, [ postsPageTitle ] );

// Use internal state instead of a ref to make sure that the component
// re-renders when the popover's anchor updates.
const [ popoverAnchor, setPopoverAnchor ] = useState( null );
// Memoize popoverProps to avoid returning a new object every time.
const popoverProps = useMemo(
() => ( {
// Anchor the popover to the middle of the entire row so that it doesn't
// move around when the label changes.
anchor: popoverAnchor,
placement: 'left-start',
offset: 36,
shift: true,
} ),
[ popoverAnchor ]
);

if ( ! postsPageId ) {
return null;
}

const setPostsPageTitle = ( newValue ) => {
setPostsPageTitleValue( newValue );
editEntityRecord( 'postType', 'page', postsPageId, {
title: newValue,
} );
};
const decodedTitle = decodeEntities( postsPageTitle );
return (
<PostPanelRow label={ __( 'Blog title' ) } ref={ setPopoverAnchor }>
<Dropdown
popoverProps={ popoverProps }
contentClassName="editor-site-settings-dropdown__content"
focusOnMount
renderToggle={ ( { isOpen, onToggle } ) => (
<Button
size="compact"
variant="tertiary"
aria-expanded={ isOpen }
aria-label={ sprintf(
// translators: %s: Current post link.
__( 'Change blog title: %s' ),
decodedTitle
) }
onClick={ onToggle }
>
{ decodedTitle }
</Button>
) }
renderContent={ ( { onClose } ) => (
<>
<InspectorPopoverHeader
title={ __( 'Blog title' ) }
onClose={ onClose }
/>
<InputControl
placeholder={ __( 'No Title' ) }
size={ '__unstable-large' }
value={ postsPageTitleValue }
onChange={ debounce( setPostsPageTitle, 300 ) }
label={ __( 'Blog title' ) }
help={ __(
'Set the Posts Page title. Appears in search results, and when the page is shared on social media.'
) }
hideLabelFromVision
/>
</>
) }
/>
</PostPanelRow>
);
}
133 changes: 133 additions & 0 deletions packages/editor/src/components/site-settings-panel/discussion-panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import {
Button,
Dropdown,
RadioControl,
__experimentalVStack as VStack,
__experimentalText as Text,
} from '@wordpress/components';
import { useState, useEffect, useMemo } from '@wordpress/element';
import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import PostPanelRow from '../post-panel-row';

const COMMENT_OPTIONS = [
{
label: (
<>
{ __( 'Open' ) }
<Text variant="muted" size={ 12 }>
{ __( 'Visitors can add new comments and replies.' ) }
</Text>
</>
),
value: 'open',
},
{
label: (
<>
{ __( 'Closed' ) }
<Text variant="muted" size={ 12 }>
{ __( 'Visitors cannot add new comments or replies.' ) }
</Text>
<Text variant="muted" size={ 12 }>
{ __( 'Existing comments remain visible.' ) }
</Text>
</>
),
value: '',
},
];

export default function DiscussionPanel() {
const { editEntityRecord } = useDispatch( coreStore );
const allowCommentsOnNewPosts = useSelect( ( select ) => {
const { getEntityRecord } = select( coreStore );
const siteSettings = getEntityRecord( 'root', 'site' );
return siteSettings?.default_comment_status || '';
}, [] );
const [ commentsOnNewPostsValue, setCommentsOnNewPostsValue ] =
useState( '' );
/*
* This hook serves to set the server-retrieved allowCommentsOnNewPosts
* value to local state.
*/
useEffect( () => {
setCommentsOnNewPostsValue( allowCommentsOnNewPosts );
}, [ allowCommentsOnNewPosts ] );

// Use internal state instead of a ref to make sure that the component
// re-renders when the popover's anchor updates.
const [ popoverAnchor, setPopoverAnchor ] = useState( null );
// Memoize popoverProps to avoid returning a new object every time.
const popoverProps = useMemo(
() => ( {
// Anchor the popover to the middle of the entire row so that it doesn't
// move around when the label changes.
anchor: popoverAnchor,
placement: 'left-start',
offset: 36,
shift: true,
} ),
[ popoverAnchor ]
);
const setAllowCommentsOnNewPosts = ( newValue ) => {
setCommentsOnNewPostsValue( newValue );
editEntityRecord( 'root', 'site', undefined, {
default_comment_status: newValue ? 'open' : null,
} );
};
return (
<PostPanelRow label={ __( 'Discussion' ) } ref={ setPopoverAnchor }>
<Dropdown
popoverProps={ popoverProps }
contentClassName="editor-site-settings-dropdown__content"
focusOnMount
renderToggle={ ( { isOpen, onToggle } ) => (
<Button
size="compact"
variant="tertiary"
aria-expanded={ isOpen }
aria-label={ __( 'Change discussion settings' ) }
onClick={ onToggle }
>
{ commentsOnNewPostsValue
? __( 'Comments open' )
: __( 'Comments closed' ) }
</Button>
) }
renderContent={ ( { onClose } ) => (
<>
<InspectorPopoverHeader
title={ __( 'Discussion' ) }
onClose={ onClose }
/>
<VStack spacing={ 3 }>
<Text>
{ __(
'Changes will apply to new posts only. Individual posts may override these settings.'
) }
</Text>
<RadioControl
className="editor-comment-status__options"
hideLabelFromVision
label={ __( 'Comment status' ) }
options={ COMMENT_OPTIONS }
onChange={ setAllowCommentsOnNewPosts }
selected={ commentsOnNewPostsValue }
/>
</VStack>
</>
) }
/>
</PostPanelRow>
);
}
30 changes: 30 additions & 0 deletions packages/editor/src/components/site-settings-panel/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { __experimentalVStack as VStack } from '@wordpress/components';

/**
* Internal dependencies
*/
import BlogTitlePanel from './blog-title-panel';
import PostsPerPagePanel from './posts-per-page-panel';
import DiscussionPanel from './discussion-panel';
import { store as editorStore } from '../../store';

export default function SiteSettingsPanel() {
const postSlug = useSelect(
( select ) => select( editorStore ).getEditedPostAttribute( 'slug' ),
[]
);
if ( ! [ 'home', 'index' ].includes( postSlug ) ) {
return null;
}
return (
<VStack spacing={ 1 } className="editor-site-settings-panel">
<BlogTitlePanel />
<PostsPerPagePanel />
<DiscussionPanel />
</VStack>
);
}
Loading

0 comments on commit 39a1785

Please sign in to comment.