Skip to content
Merged
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ Summarize your post with a list of headings. Add HTML anchors to Heading blocks
- **Experimental:** true
- **Category:** design
- **Supports:** color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Attributes:** headings, onlyIncludeCurrentPage
- **Attributes:** headings, maxLevel, onlyIncludeCurrentPage

## Tag Cloud

Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/table-of-contents/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"onlyIncludeCurrentPage": {
"type": "boolean",
"default": false
},
"maxLevel": {
"type": "number"
}
},
"supports": {
Expand Down
49 changes: 45 additions & 4 deletions packages/block-library/src/table-of-contents/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { createBlock } from '@wordpress/blocks';
import {
Placeholder,
ToggleControl,
SelectControl,
ToolbarButton,
ToolbarGroup,
__experimentalToolsPanel as ToolsPanel,
Expand Down Expand Up @@ -39,15 +40,16 @@ import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
*
* @param {Object} props The props.
* @param {Object} props.attributes The block attributes.
* @param {HeadingData[]} props.attributes.headings A list of data for each heading in the post.
* @param {HeadingData[]} props.attributes.headings The list of data for each heading in the post.
* @param {boolean} props.attributes.onlyIncludeCurrentPage Whether to only include headings from the current page (if the post is paginated).
* @param {string} props.clientId
* @param {(attributes: Object) => void} props.setAttributes
* @param {number|undefined} props.attributes.maxLevel The maximum heading level to include, or null to include all levels.
* @param {string} props.clientId The client id.
* @param {(attributes: Object) => void} props.setAttributes The set attributes function.
*
* @return {Component} The component.
*/
export default function TableOfContentsEdit( {
attributes: { headings = [], onlyIncludeCurrentPage },
attributes: { headings = [], onlyIncludeCurrentPage, maxLevel },
clientId,
setAttributes,
} ) {
Expand Down Expand Up @@ -115,6 +117,7 @@ export default function TableOfContentsEdit( {
resetAll={ () => {
setAttributes( {
onlyIncludeCurrentPage: false,
maxLevel: undefined,
} );
} }
dropdownMenuProps={ dropdownMenuProps }
Expand Down Expand Up @@ -145,6 +148,44 @@ export default function TableOfContentsEdit( {
}
/>
</ToolsPanelItem>
<ToolsPanelItem
hasValue={ () => !! maxLevel }
label={ __( 'Limit heading levels' ) }
onDeselect={ () =>
setAttributes( { maxLevel: undefined } )
}
isShownByDefault
>
<SelectControl
__nextHasNoMarginBottom
__next40pxDefaultSize
label={ __( 'Include headings down to level' ) }
value={ maxLevel || '' }
options={ [
{ value: '', label: __( 'All levels' ) },
{ value: '1', label: __( 'Heading 1' ) },
{ value: '2', label: __( 'Heading 2' ) },
{ value: '3', label: __( 'Heading 3' ) },
{ value: '4', label: __( 'Heading 4' ) },
{ value: '5', label: __( 'Heading 5' ) },
{ value: '6', label: __( 'Heading 6' ) },
] }
onChange={ ( value ) =>
setAttributes( {
maxLevel: value ? parseInt( value ) : undefined,
} )
}
help={
maxLevel
? __(
'Including all heading levels in the table of contents.'
)
: __(
'Only include headings up to and including this level.'
)
}
/>
</ToolsPanelItem>
</ToolsPanel>
</InspectorControls>
);
Expand Down
8 changes: 7 additions & 1 deletion packages/block-library/src/table-of-contents/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ function getLatestHeadings( select, clientId ) {
const permalink = select( 'core/editor' ).getPermalink() ?? null;

const isPaginated = getBlocksByName( 'core/nextpage' ).length !== 0;
const { onlyIncludeCurrentPage } = getBlockAttributes( clientId ) ?? {};
const { onlyIncludeCurrentPage, maxLevel } =
getBlockAttributes( clientId ) ?? {};

// Get post-content block client ID.
const [ postContentClientId = '' ] = getBlocksByName( 'core/post-content' );
Expand Down Expand Up @@ -100,6 +101,11 @@ function getLatestHeadings( select, clientId ) {
if ( blockName === 'core/heading' ) {
const headingAttributes = getBlockAttributes( blockClientId );

// Skip headings that are deeper than maxLevel
if ( maxLevel && headingAttributes.level > maxLevel ) {
continue;
}

const canBeLinked =
typeof headingPageLink === 'string' &&
typeof headingAttributes.anchor === 'string' &&
Expand Down
Loading