Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
50 changes: 50 additions & 0 deletions docs/how-to-guides/customize-content-tags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
myst:
html_meta:
"description": "How to hide or replace the tags (subjects) shown below content in Plone Aurora"
"property=og:description": "How to hide or replace the tags (subjects) shown below content in Plone Aurora"
"property=og:title": "Customize the content tags"
"keywords": "Plone Aurora, tags, subjects, slot, belowContent"
---

# Customize the content tags

Plone Aurora renders a content item's tags (its `subjects`) below the content as links to the search.
The tags come from a slot component registered for the `belowContent` slot.
This guide shows you how to hide or replace them.

## Hide the tags

Set `showTags` to `false` in your add-on configuration to hide the tags on every page.

```ts
import type { ConfigType } from '@plone/registry';

export default function install(config: ConfigType) {
config.settings.showTags = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is ok. However, since the Tags are registered slot components, the same can be achieved by just unregistering the Tags slot component. That would also render this documentation unnecessary, "debloating" the docs. What do you think @pnicolli ?

@pnicolli pnicolli Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense if we point this to the slots docs in some way so people can find those easily while reading this.
@sneridagh ?

return config;
}
```

The slot renders the tags whenever an item has `subjects`, unless `showTags` is `false`.

## Replace the tags component

Register your own component for the `belowContent` slot under the same name to override the default.

```ts
import type { ConfigType } from '@plone/registry';
import MyTags from './MyTags';

export default function install(config: ConfigType) {
config.registerSlotComponent({
name: 'Tags',
slot: 'belowContent',
component: MyTags,
});
return config;
}
```

Your component receives the slot props, including `content`, from which you can read `content.subjects`.
To learn how slots work in general, refer to {doc}`register-slots`.
1 change: 1 addition & 0 deletions docs/how-to-guides/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ icons
configure-plate-code-block-languages
bind-metadata-fields-to-plate-text-blocks
custom-content-types
customize-content-tags
```
8 changes: 8 additions & 0 deletions packages/layout/config/slots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import HeaderTools from '../slots/Tools';
import ContentArea from '../slots/ContentArea';
import MainFooter from '../slots/MainFooter/MainFooter';
import Breadcrumbs from '../slots/Breadcrumbs';
import Tags from '../slots/Tags/Tags';
import { NotContentTypeCondition } from '../helpers';

export default function install(config: ConfigType) {
Expand Down Expand Up @@ -70,6 +71,13 @@ export default function install(config: ConfigType) {
component: ContentArea,
});

// Tags (Subjects)
config.registerSlotComponent({
name: 'Tags',
slot: 'belowContent',
component: Tags,
});

// Footer Slot
config.registerSlotComponent({
name: 'Footer',
Expand Down
3 changes: 3 additions & 0 deletions packages/layout/locales/de/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"toolbar": {
"label": "Werkzeugleiste"
},
"tags": {
"label": "Schlagwörter"
},
"views": {
"link": {
"linkLabel": "Die Linkadresse lautet:",
Expand Down
3 changes: 3 additions & 0 deletions packages/layout/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"toolbar": {
"label": "Toolbar"
},
"tags": {
"label": "Tags"
},
"views": {
"link": {
"linkLabel": "The link address is:",
Expand Down
3 changes: 3 additions & 0 deletions packages/layout/locales/it/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"toolbar": {
"label": "Barra degli strumenti"
},
"tags": {
"label": "Etichette"
},
"views": {
"link": {
"linkLabel": "L'indirizzo del link è:",
Expand Down
1 change: 1 addition & 0 deletions packages/layout/news/63.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a Tags (Subjects) slot that renders a content item's tags below the content as links to the search. @nils-pzr
21 changes: 21 additions & 0 deletions packages/layout/slots/Tags/Tags.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@layer custom {
.tags {
display: flex;
flex-wrap: wrap;
margin-top: 16px;
gap: 8px;
}

.tag {
padding: 4px 12px;
border-radius: 9999px;
background: var(--quanta-azure);
color: var(--quanta-puya);
Comment on lines +12 to +13

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not meet minimum contrast requirements. Not sure if that's a concern for the layout package, but if swapped with a TabGroup (see my other comment) it can be resolved easily, while also solving the issue with these styles not being centralized, since Tags are more than likely going to be used in other parts of the app as well. Consequently, most, if not all of these styles can be removed, as they already exist in the TabGroup base styles. (You would need to import the TabGroup basic styles inside packages/layout/styles/publicui.css)

font-size: 0.875rem;
text-decoration: none;
}

.tag:hover {
opacity: 0.8;
}
}
32 changes: 32 additions & 0 deletions packages/layout/slots/Tags/Tags.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router';
import Tags from './Tags';

const renderTags = (subjects: string[]) =>
render(
<MemoryRouter>
<Tags
content={{ subjects } as never}
location={{ pathname: '/' } as never}
/>
</MemoryRouter>,
);

describe('Tags slot', () => {
it('renders nothing when there are no tags', () => {
const { container } = renderTags([]);
expect(container).toBeEmptyDOMElement();
});

it('renders a search link for each tag', () => {
renderTags(['News', 'Plone & Co']);
expect(screen.getByRole('link', { name: 'News' })).toHaveAttribute(
'href',
'/search?Subject=News',
);
expect(screen.getByRole('link', { name: 'Plone & Co' })).toHaveAttribute(
'href',
'/search?Subject=Plone%20%26%20Co',
);
});
});
33 changes: 33 additions & 0 deletions packages/layout/slots/Tags/Tags.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Link } from 'react-router';
import { useTranslation } from 'react-i18next';
import config from '@plone/registry';
import type { SlotComponentProps } from '../SlotRenderer';
import SectionWrapper from '../../components/SectionWrapper/SectionWrapper';
import styles from './Tags.module.css';

const Tags = (props: SlotComponentProps) => {
const { t } = useTranslation();
const tags = (props.content?.subjects ?? []) as string[];

if (config.settings.showTags === false || tags.length === 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified. Not a big deal, but this is enough for my IDE to spit out a warning.

Suggested change
if (config.settings.showTags === false || tags.length === 0) {
if (!config.settings.showTags|| tags.length === 0) {

return null;
}

return (
<SectionWrapper as="nav" width="layout" aria-label={t('layout.tags.label')}>
<div className={styles.tags}>
{tags.map((tag) => (
<Link
key={tag}
to={`/search?Subject=${encodeURIComponent(tag)}`}
className={styles.tag}
>
{tag}
</Link>
))}
</div>
Comment on lines +18 to +28

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a candidate for a TagGroup. That would also remove the need for separate styling here, since the TagGroup already has base styles. See https://plone-components.readthedocs.io/latest/?path=/docs/basic-taggroup--docs

</SectionWrapper>
);
};

export default Tags;
Loading