From 9cbeb6f34c52e6aca671d0125db2857c7937578c Mon Sep 17 00:00:00 2001 From: George Haberis Date: Fri, 23 Jan 2026 16:37:59 +0000 Subject: [PATCH 1/2] make affiliate disclaimer server side only --- .../src/components/AffiliateDisclaimer.tsx | 122 ++++++++++++++++++ .../AffiliateDisclaimerInline.importable.tsx | 50 ------- .../AffiliateDisclaimerLeftCol.importable.tsx | 35 ----- .../GalleryAffiliateDisclaimer.importable.tsx | 40 ------ dotcom-rendering/src/layouts/AudioLayout.tsx | 9 +- .../src/layouts/GalleryLayout.tsx | 6 +- .../src/layouts/ImmersiveLayout.tsx | 16 +-- .../src/layouts/ShowcaseLayout.tsx | 16 +-- .../src/layouts/StandardLayout.tsx | 16 +-- .../src/lib/affiliateDisclaimerHelpers.tsx | 46 ------- dotcom-rendering/src/lib/renderElement.tsx | 8 +- 11 files changed, 137 insertions(+), 227 deletions(-) create mode 100644 dotcom-rendering/src/components/AffiliateDisclaimer.tsx delete mode 100644 dotcom-rendering/src/components/AffiliateDisclaimerInline.importable.tsx delete mode 100644 dotcom-rendering/src/components/AffiliateDisclaimerLeftCol.importable.tsx delete mode 100644 dotcom-rendering/src/components/GalleryAffiliateDisclaimer.importable.tsx delete mode 100644 dotcom-rendering/src/lib/affiliateDisclaimerHelpers.tsx diff --git a/dotcom-rendering/src/components/AffiliateDisclaimer.tsx b/dotcom-rendering/src/components/AffiliateDisclaimer.tsx new file mode 100644 index 00000000000..e0f30117cc9 --- /dev/null +++ b/dotcom-rendering/src/components/AffiliateDisclaimer.tsx @@ -0,0 +1,122 @@ +import { css } from '@emotion/react'; +import { + palette, + space, + textSans12, + textSans14, + textSans15, +} from '@guardian/source/foundations'; +import { Hide } from '@guardian/source/react-components'; +import { palette as themePalette } from '../palette'; + +const disclaimerLeftColStyles = css` + ${textSans15}; + /** + * Typography preset styles should not be overridden. + * This has been done because the styles do not directly map to the new presets. + * Please speak to your team's designer and update this to use a more appropriate preset. + */ + line-height: 1.15; + padding-top: ${space[1]}px; + padding-bottom: ${space[1]}px; +`; + +const galleryDisclaimerStyles = css` + ${textSans12}; + line-height: 1.5; + color: ${themePalette('--affiliate-disclaimer-text')}; + a { + color: ${themePalette('--affiliate-disclaimer-text')}; + transition: border-color 0.15s ease-out; + border-bottom: 1px solid ${palette.neutral[46]}; + text-decoration: none; + } + a:hover { + border-bottom: 1px solid + ${themePalette('--affiliate-disclaimer-text-hover')}; + text-decoration: none; + } +`; + +const disclaimerInlineStyles = css` + ${textSans14}; + /** + * Typography preset styles should not be overridden. + * This has been done because the styles do not directly map to the new presets. + * Please speak to your team's designer and update this to use a more appropriate preset. + */ + line-height: 1.15; + float: left; + clear: left; + width: 8.75rem; + background-color: ${themePalette('--affiliate-disclaimer-background')}; + :hover { + background-color: ${themePalette( + '--affiliate-disclaimer-background-hover', + )}; + } + margin-top: ${space[1]}px; + margin-right: ${space[5]}px; + margin-bottom: ${space[1]}px; + padding-top: ${space[0]}px; + padding-right: 5px; + padding-left: 5px; + padding-bottom: ${space[3]}px; +`; + +const DisclaimerText = () => ( +

+ The Guardian’s journalism is independent. We will earn a commission if + you buy something through an affiliate link.  + + Learn more + + . +

+); + +const affiliateDisclaimerId = 'affiliate-disclaimer'; + +const AffiliateDisclaimer = () => ( + + + +); + +const affiliateDisclaimerInlineId = 'affiliate-disclaimer-inline'; + +const AffiliateDisclaimerInline = () => ( + + + +); + +const affiliateDisclaimerGalleryId = 'affiliate-disclaimer-gallery'; + +const AffiliateDisclaimerGallery = () => ( + +); + +export { + AffiliateDisclaimer, + AffiliateDisclaimerInline, + AffiliateDisclaimerGallery, +}; diff --git a/dotcom-rendering/src/components/AffiliateDisclaimerInline.importable.tsx b/dotcom-rendering/src/components/AffiliateDisclaimerInline.importable.tsx deleted file mode 100644 index cadd1e0036d..00000000000 --- a/dotcom-rendering/src/components/AffiliateDisclaimerInline.importable.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { css } from '@emotion/react'; -import { space, textSans14 } from '@guardian/source/foundations'; -import { Hide } from '@guardian/source/react-components'; -import { - DisclaimerText, - useAffiliateDisclaimerEvent, -} from '../lib/affiliateDisclaimerHelpers'; -import { palette as themePalette } from '../palette'; - -const disclaimerInlineStyles = css` - ${textSans14}; - /** - * Typography preset styles should not be overridden. - * This has been done because the styles do not directly map to the new presets. - * Please speak to your team's designer and update this to use a more appropriate preset. - */ - line-height: 1.15; - float: left; - clear: left; - width: 8.75rem; - background-color: ${themePalette('--affiliate-disclaimer-background')}; - :hover { - background-color: ${themePalette( - '--affiliate-disclaimer-background-hover', - )}; - } - margin-top: ${space[1]}px; - margin-right: ${space[5]}px; - margin-bottom: ${space[1]}px; - padding-top: ${space[0]}px; - padding-right: 5px; - padding-left: 5px; - padding-bottom: ${space[3]}px; -`; - -const AffiliateDisclaimerInline = () => { - useAffiliateDisclaimerEvent(); - return ( - - - - ); -}; - -export { AffiliateDisclaimerInline }; diff --git a/dotcom-rendering/src/components/AffiliateDisclaimerLeftCol.importable.tsx b/dotcom-rendering/src/components/AffiliateDisclaimerLeftCol.importable.tsx deleted file mode 100644 index e29ebc24480..00000000000 --- a/dotcom-rendering/src/components/AffiliateDisclaimerLeftCol.importable.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { css } from '@emotion/react'; -import { space, textSans15 } from '@guardian/source/foundations'; -import { Hide } from '@guardian/source/react-components'; -import { - DisclaimerText, - useAffiliateDisclaimerEvent, -} from '../lib/affiliateDisclaimerHelpers'; - -const disclaimerLeftColStyles = css` - ${textSans15}; - /** - * Typography preset styles should not be overridden. - * This has been done because the styles do not directly map to the new presets. - * Please speak to your team's designer and update this to use a more appropriate preset. - */ - line-height: 1.15; - padding-top: ${space[1]}px; - padding-bottom: ${space[1]}px; -`; - -const AffiliateDisclaimerLeftCol = () => { - useAffiliateDisclaimerEvent(); - return ( - - - - ); -}; - -export { AffiliateDisclaimerLeftCol }; diff --git a/dotcom-rendering/src/components/GalleryAffiliateDisclaimer.importable.tsx b/dotcom-rendering/src/components/GalleryAffiliateDisclaimer.importable.tsx deleted file mode 100644 index 17e6ec49d5d..00000000000 --- a/dotcom-rendering/src/components/GalleryAffiliateDisclaimer.importable.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { css } from '@emotion/react'; -import { palette, space, textSans12 } from '@guardian/source/foundations'; -import { - DisclaimerText, - useAffiliateDisclaimerEvent, -} from '../lib/affiliateDisclaimerHelpers'; -import { palette as themePalette } from '../palette'; - -const galleryDisclaimerStyles = css` - ${textSans12}; - line-height: 1.5; - color: ${themePalette('--affiliate-disclaimer-text')}; - padding-top: ${space[1]}px; - padding-bottom: ${space[1]}px; - a { - color: ${themePalette('--affiliate-disclaimer-text')}; - transition: border-color 0.15s ease-out; - border-bottom: 1px solid ${palette.neutral[46]}; - text-decoration: none; - } - a:hover { - border-bottom: 1px solid - ${themePalette('--affiliate-disclaimer-text-hover')}; - text-decoration: none; - } -`; - -const GalleryAffiliateDisclaimer = () => { - useAffiliateDisclaimerEvent(); - return ( - - ); -}; - -export { GalleryAffiliateDisclaimer }; diff --git a/dotcom-rendering/src/layouts/AudioLayout.tsx b/dotcom-rendering/src/layouts/AudioLayout.tsx index 40a499f3297..d4327da1612 100644 --- a/dotcom-rendering/src/layouts/AudioLayout.tsx +++ b/dotcom-rendering/src/layouts/AudioLayout.tsx @@ -7,7 +7,7 @@ import { } from '@guardian/source/foundations'; import { StraightLines } from '@guardian/source-development-kitchen/react-components'; import { AdSlot, MobileStickyContainer } from '../components/AdSlot.web'; -import { AffiliateDisclaimerLeftCol } from '../components/AffiliateDisclaimerLeftCol.importable'; +import { AffiliateDisclaimer } from '../components/AffiliateDisclaimer'; import { ArticleBody } from '../components/ArticleBody'; import { ArticleContainer } from '../components/ArticleContainer'; import { ArticleHeadline } from '../components/ArticleHeadline'; @@ -272,12 +272,7 @@ export const AudioLayout = (props: WebProps) => { } /> {!!article.affiliateLinksDisclaimer && ( - - - + )} diff --git a/dotcom-rendering/src/layouts/GalleryLayout.tsx b/dotcom-rendering/src/layouts/GalleryLayout.tsx index 84595e53d7a..48ecd17e03b 100644 --- a/dotcom-rendering/src/layouts/GalleryLayout.tsx +++ b/dotcom-rendering/src/layouts/GalleryLayout.tsx @@ -19,7 +19,7 @@ import { DiscussionLayout } from '../components/DiscussionLayout'; import { FetchMoreGalleriesData } from '../components/FetchMoreGalleriesData.importable'; import { Footer } from '../components/Footer'; import { DesktopAdSlot, MobileAdSlot } from '../components/GalleryAdSlots'; -import { GalleryAffiliateDisclaimer } from '../components/GalleryAffiliateDisclaimer.importable'; +import { AffiliateDisclaimerGallery } from '../components/AffiliateDisclaimer'; import { GalleryImage } from '../components/GalleryImage'; import { HeaderAdSlot } from '../components/HeaderAdSlot'; import { Island } from '../components/Island'; @@ -496,9 +496,7 @@ const Meta = ({ /> ) : null} {!!frontendData.affiliateLinksDisclaimer && ( - - - + )} ); diff --git a/dotcom-rendering/src/layouts/ImmersiveLayout.tsx b/dotcom-rendering/src/layouts/ImmersiveLayout.tsx index 93f69b74996..773d723e870 100644 --- a/dotcom-rendering/src/layouts/ImmersiveLayout.tsx +++ b/dotcom-rendering/src/layouts/ImmersiveLayout.tsx @@ -9,7 +9,7 @@ import { import { StraightLines } from '@guardian/source-development-kitchen/react-components'; import { AdPortals } from '../components/AdPortals.importable'; import { AdSlot, MobileStickyContainer } from '../components/AdSlot.web'; -import { AffiliateDisclaimerLeftCol } from '../components/AffiliateDisclaimerLeftCol.importable'; +import { AffiliateDisclaimer } from '../components/AffiliateDisclaimer'; import { AppsFooter } from '../components/AppsFooter.importable'; import { ArticleBody } from '../components/ArticleBody'; import { ArticleContainer } from '../components/ArticleContainer'; @@ -633,12 +633,7 @@ export const ImmersiveLayout = (props: WebProps | AppProps) => { } /> {!!article.affiliateLinksDisclaimer && ( - - - + )} @@ -668,12 +663,7 @@ export const ImmersiveLayout = (props: WebProps | AppProps) => { } /> {!!article.affiliateLinksDisclaimer && ( - - - + )} )} diff --git a/dotcom-rendering/src/layouts/ShowcaseLayout.tsx b/dotcom-rendering/src/layouts/ShowcaseLayout.tsx index 345d7036186..3dd5fbbdc41 100644 --- a/dotcom-rendering/src/layouts/ShowcaseLayout.tsx +++ b/dotcom-rendering/src/layouts/ShowcaseLayout.tsx @@ -10,7 +10,7 @@ import { Hide } from '@guardian/source/react-components'; import { StraightLines } from '@guardian/source-development-kitchen/react-components'; import { AdPortals } from '../components/AdPortals.importable'; import { AdSlot, MobileStickyContainer } from '../components/AdSlot.web'; -import { AffiliateDisclaimerLeftCol } from '../components/AffiliateDisclaimerLeftCol.importable'; +import { AffiliateDisclaimer } from '../components/AffiliateDisclaimer'; import { AppsFooter } from '../components/AppsFooter.importable'; import { ArticleBody } from '../components/ArticleBody'; import { ArticleContainer } from '../components/ArticleContainer'; @@ -511,12 +511,7 @@ export const ShowcaseLayout = (props: WebProps | AppsProps) => { } /> {!!article.affiliateLinksDisclaimer && ( - - - + )} @@ -546,12 +541,7 @@ export const ShowcaseLayout = (props: WebProps | AppsProps) => { } /> {!!article.affiliateLinksDisclaimer && ( - - - + )} )} diff --git a/dotcom-rendering/src/layouts/StandardLayout.tsx b/dotcom-rendering/src/layouts/StandardLayout.tsx index baeaa756d5c..e3275ff7177 100644 --- a/dotcom-rendering/src/layouts/StandardLayout.tsx +++ b/dotcom-rendering/src/layouts/StandardLayout.tsx @@ -10,7 +10,7 @@ import { Hide } from '@guardian/source/react-components'; import { StraightLines } from '@guardian/source-development-kitchen/react-components'; import { AdPortals } from '../components/AdPortals.importable'; import { AdSlot, MobileStickyContainer } from '../components/AdSlot.web'; -import { AffiliateDisclaimerLeftCol } from '../components/AffiliateDisclaimerLeftCol.importable'; +import { AffiliateDisclaimer } from '../components/AffiliateDisclaimer'; import { AppsEpic } from '../components/AppsEpic.importable'; import { AppsFooter } from '../components/AppsFooter.importable'; import { ArticleBody } from '../components/ArticleBody'; @@ -656,12 +656,7 @@ export const StandardLayout = (props: WebProps | AppProps) => { /> {!!article.affiliateLinksDisclaimer && ( - - - + )} @@ -691,12 +686,7 @@ export const StandardLayout = (props: WebProps | AppProps) => { } /> {!!article.affiliateLinksDisclaimer && ( - - - + )} )} diff --git a/dotcom-rendering/src/lib/affiliateDisclaimerHelpers.tsx b/dotcom-rendering/src/lib/affiliateDisclaimerHelpers.tsx deleted file mode 100644 index 97f4fab7edd..00000000000 --- a/dotcom-rendering/src/lib/affiliateDisclaimerHelpers.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { useEffect } from 'react'; -import { submitComponentEvent } from '../client/ophan/ophan'; -import { useConfig } from '../components/ConfigContext'; - -/** - * On Articles we render multiple Affiliate Disclaimer components, - * For example one in the left column (for non-mobile breakpoints) - * and one inline (for mobile breakpoints), however we don't want to - * trigger multiple detect events, eg. one event per component, - * one event per Article is desired, we're therefore keeping a record - * of the event being tracked here to achieve this. - */ -let affiliateDisclaimerDetectTracked = false; - -const useAffiliateDisclaimerEvent = (): void => { - const { renderingTarget } = useConfig(); - - useEffect(() => { - if (!affiliateDisclaimerDetectTracked) { - void submitComponentEvent( - { - action: 'DETECT', - component: { - componentType: 'AFFILIATE_DISCLAIMER', - }, - }, - renderingTarget, - ); - - affiliateDisclaimerDetectTracked = true; - } - }, [renderingTarget]); -}; - -const DisclaimerText = () => ( -

- The Guardian’s journalism is independent. We will earn a commission if - you buy something through an affiliate link.  - - Learn more - - . -

-); - -export { DisclaimerText, useAffiliateDisclaimerEvent }; diff --git a/dotcom-rendering/src/lib/renderElement.tsx b/dotcom-rendering/src/lib/renderElement.tsx index 55d8c605e95..94ed19c651b 100644 --- a/dotcom-rendering/src/lib/renderElement.tsx +++ b/dotcom-rendering/src/lib/renderElement.tsx @@ -1,5 +1,5 @@ import { AdPlaceholder } from '../components/AdPlaceholder.apps'; -import { AffiliateDisclaimerInline } from '../components/AffiliateDisclaimerInline.importable'; +import { AffiliateDisclaimerInline } from '../components/AffiliateDisclaimer'; import { AudioAtomWrapper } from '../components/AudioAtomWrapper.importable'; import { BlockquoteBlockComponent } from '../components/BlockquoteBlockComponent'; import { CalloutBlockComponent } from '../components/CalloutBlockComponent.importable'; @@ -958,11 +958,7 @@ export const renderElement = ({ ); case 'model.dotcomrendering.pageElements.DisclaimerBlockElement': { - return ( - - - - ); + return ; } case 'model.dotcomrendering.pageElements.CrosswordElement': return ( From 04424272acb452bbf37ecd7b3180d4c83112e8b0 Mon Sep 17 00:00:00 2001 From: George Haberis Date: Fri, 23 Jan 2026 16:41:16 +0000 Subject: [PATCH 2/2] fix validation --- dotcom-rendering/src/layouts/GalleryLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotcom-rendering/src/layouts/GalleryLayout.tsx b/dotcom-rendering/src/layouts/GalleryLayout.tsx index 48ecd17e03b..a756a61b1ad 100644 --- a/dotcom-rendering/src/layouts/GalleryLayout.tsx +++ b/dotcom-rendering/src/layouts/GalleryLayout.tsx @@ -9,6 +9,7 @@ import { Hide } from '@guardian/source/react-components'; import { AdPlaceholder } from '../components/AdPlaceholder.apps'; import { AdPortals } from '../components/AdPortals.importable'; import { AdSlot } from '../components/AdSlot.web'; +import { AffiliateDisclaimerGallery } from '../components/AffiliateDisclaimer'; import { AppsFooter } from '../components/AppsFooter.importable'; import { ArticleHeadline } from '../components/ArticleHeadline'; import { ArticleMetaApps } from '../components/ArticleMeta.apps'; @@ -19,7 +20,6 @@ import { DiscussionLayout } from '../components/DiscussionLayout'; import { FetchMoreGalleriesData } from '../components/FetchMoreGalleriesData.importable'; import { Footer } from '../components/Footer'; import { DesktopAdSlot, MobileAdSlot } from '../components/GalleryAdSlots'; -import { AffiliateDisclaimerGallery } from '../components/AffiliateDisclaimer'; import { GalleryImage } from '../components/GalleryImage'; import { HeaderAdSlot } from '../components/HeaderAdSlot'; import { Island } from '../components/Island';