From b0bc5db4b36884dd0acab6c91db60c9b74e7526b Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 10:56:06 +0100 Subject: [PATCH 01/12] Add ability for inline link format to parse and handle rel no follow --- packages/format-library/src/link/index.js | 1 + packages/format-library/src/link/inline.js | 3 ++- packages/format-library/src/link/utils.js | 20 +++++++++++++++++--- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/format-library/src/link/index.js b/packages/format-library/src/link/index.js index 03e25a37b9b8e9..50019be4cc958e 100644 --- a/packages/format-library/src/link/index.js +++ b/packages/format-library/src/link/index.js @@ -131,6 +131,7 @@ export const link = { type: 'data-type', id: 'data-id', target: 'target', + rel: 'rel', }, __unstablePasteRule( value, { html, plainText } ) { if ( isCollapsed( value ) ) { diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js index 29636a8d8b94be..1953d568e00a37 100644 --- a/packages/format-library/src/link/inline.js +++ b/packages/format-library/src/link/inline.js @@ -60,6 +60,7 @@ function InlineLinkUI( { type: activeAttributes.type, id: activeAttributes.id, opensInNewTab: activeAttributes.target === '_blank', + noFollow: activeAttributes.rel?.includes( 'nofollow' ), title: richTextText, }; @@ -77,7 +78,6 @@ function InlineLinkUI( { const didToggleSetting = linkValue.opensInNewTab !== nextValue.opensInNewTab && nextValue.url === undefined; - // Merge the next value with the current link value. nextValue = { ...linkValue, @@ -93,6 +93,7 @@ function InlineLinkUI( { ? String( nextValue.id ) : undefined, opensInNewWindow: nextValue.opensInNewTab, + noFollow: nextValue.noFollow, } ); const newText = nextValue.title || newUrl; diff --git a/packages/format-library/src/link/utils.js b/packages/format-library/src/link/utils.js index 4c7a582a2e8f21..5189aa89760306 100644 --- a/packages/format-library/src/link/utils.js +++ b/packages/format-library/src/link/utils.js @@ -85,10 +85,16 @@ export function isValidHref( href ) { * @param {string} options.type The type of the link. * @param {string} options.id The ID of the link. * @param {boolean} options.opensInNewWindow Whether this link will open in a new window. - * + * @param {boolean} options.noFollow Whether this link is marked as no follow relationship. * @return {Object} The final format object. */ -export function createLinkFormat( { url, type, id, opensInNewWindow } ) { +export function createLinkFormat( { + url, + type, + id, + opensInNewWindow, + noFollow, +} ) { const format = { type: 'core/link', attributes: { @@ -101,7 +107,15 @@ export function createLinkFormat( { url, type, id, opensInNewWindow } ) { if ( opensInNewWindow ) { format.attributes.target = '_blank'; - format.attributes.rel = 'noreferrer noopener'; + format.attributes.rel = format.attributes.rel + ? format.attributes.rel + ' noreferrer noopener' + : 'noreferrer noopener'; + } + + if ( noFollow ) { + format.attributes.rel = format.attributes.rel + ? format.attributes.rel + ' nofollow' + : 'nofollow'; } return format; From 994531680476faf36c85cf49f1b1f7b34f7d7538 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 10:56:26 +0100 Subject: [PATCH 02/12] Add no follow to Link Control --- .../block-editor/src/components/link-control/constants.js | 4 ++++ .../block-editor/src/components/link-control/style.scss | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/link-control/constants.js b/packages/block-editor/src/components/link-control/constants.js index e70ff7b04c7477..72f07a16bd6746 100644 --- a/packages/block-editor/src/components/link-control/constants.js +++ b/packages/block-editor/src/components/link-control/constants.js @@ -24,4 +24,8 @@ export const DEFAULT_LINK_SETTINGS = [ id: 'opensInNewTab', title: __( 'Open in new tab' ), }, + { + id: 'noFollow', + title: __( 'No follow' ), + }, ]; diff --git a/packages/block-editor/src/components/link-control/style.scss b/packages/block-editor/src/components/link-control/style.scss index 0ca13fa9167773..eef5297676af47 100644 --- a/packages/block-editor/src/components/link-control/style.scss +++ b/packages/block-editor/src/components/link-control/style.scss @@ -401,7 +401,7 @@ $preview-image-height: 140px; } .block-editor-link-control__setting { - margin-bottom: $grid-unit-20; + margin-bottom: 0; flex: 1; padding: $grid-unit-10 0 $grid-unit-10 $grid-unit-30; @@ -410,10 +410,6 @@ $preview-image-height: 140px; margin-left: 0; } - &.block-editor-link-control__setting:last-child { - margin-bottom: 0; - } - .is-preview & { padding: 20px $grid-unit-10 $grid-unit-10 0; } From 87c8ce8e4886afb097a4b250fa6f677ddf9189b4 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 11:01:31 +0100 Subject: [PATCH 03/12] Add support for optional help text on setting controls --- packages/block-editor/src/components/link-control/settings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-editor/src/components/link-control/settings.js b/packages/block-editor/src/components/link-control/settings.js index 1d70cc97dff417..e63ef926358fe9 100644 --- a/packages/block-editor/src/components/link-control/settings.js +++ b/packages/block-editor/src/components/link-control/settings.js @@ -26,6 +26,7 @@ const LinkControlSettings = ( { value, onChange = noop, settings } ) => { label={ setting.title } onChange={ handleSettingChange( setting ) } checked={ value ? !! value[ setting.id ] : false } + help={ setting?.help } /> ) ); From a7a5bdac05f23a0957bcb7737e4460bf35d17e61 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 11:01:50 +0100 Subject: [PATCH 04/12] Only apply new setting to inline links for now --- .../src/components/link-control/constants.js | 4 ---- packages/format-library/src/link/inline.js | 13 +++++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/link-control/constants.js b/packages/block-editor/src/components/link-control/constants.js index 72f07a16bd6746..e70ff7b04c7477 100644 --- a/packages/block-editor/src/components/link-control/constants.js +++ b/packages/block-editor/src/components/link-control/constants.js @@ -24,8 +24,4 @@ export const DEFAULT_LINK_SETTINGS = [ id: 'opensInNewTab', title: __( 'Open in new tab' ), }, - { - id: 'noFollow', - title: __( 'No follow' ), - }, ]; diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js index 1953d568e00a37..57b6d2ebbefc2b 100644 --- a/packages/format-library/src/link/inline.js +++ b/packages/format-library/src/link/inline.js @@ -31,6 +31,18 @@ import { createLinkFormat, isValidHref, getFormatBoundary } from './utils'; import { link as settings } from './index'; import useLinkInstanceKey from './use-link-instance-key'; +const LINK_SETTINGS = [ + { + id: 'opensInNewTab', + title: __( 'Open in new tab' ), + }, + { + id: 'noFollow', + title: __( 'No follow' ), + help: __( 'Search engines should ignore this link' ), + }, +]; + function InlineLinkUI( { isActive, activeAttributes, @@ -248,6 +260,7 @@ function InlineLinkUI( { withCreateSuggestion={ userCanCreatePages } createSuggestionButtonText={ createButtonText } hasTextControl + settings={ LINK_SETTINGS } /> ); From c9b2a6b8708166c5315b255b009d54bfbde88c43 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 11:08:28 +0100 Subject: [PATCH 05/12] Expose default link settings for use by component consumers --- packages/block-editor/src/components/link-control/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-editor/src/components/link-control/index.js b/packages/block-editor/src/components/link-control/index.js index ac1ec660934a3a..4e0a1f2291b02c 100644 --- a/packages/block-editor/src/components/link-control/index.js +++ b/packages/block-editor/src/components/link-control/index.js @@ -475,5 +475,6 @@ function LinkControl( { } LinkControl.ViewerFill = ViewerFill; +LinkControl.DEFAULT_LINK_SETTINGS = DEFAULT_LINK_SETTINGS; export default LinkControl; From d3c1449f7e0ed1485c7bcf2325524317beaf2004 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 11:08:48 +0100 Subject: [PATCH 06/12] Extend default settings in inline link implementation --- packages/format-library/src/link/inline.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js index 57b6d2ebbefc2b..f9ec884f57ed25 100644 --- a/packages/format-library/src/link/inline.js +++ b/packages/format-library/src/link/inline.js @@ -32,10 +32,7 @@ import { link as settings } from './index'; import useLinkInstanceKey from './use-link-instance-key'; const LINK_SETTINGS = [ - { - id: 'opensInNewTab', - title: __( 'Open in new tab' ), - }, + ...LinkControl.DEFAULT_LINK_SETTINGS, { id: 'noFollow', title: __( 'No follow' ), From db72d42f846995fb1f3c6bd8becc08a633f28681 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 12:11:02 +0100 Subject: [PATCH 07/12] Use nofollow lowercase --- packages/format-library/src/link/inline.js | 13 +++++++++---- packages/format-library/src/link/utils.js | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js index f9ec884f57ed25..cc6969e58dc581 100644 --- a/packages/format-library/src/link/inline.js +++ b/packages/format-library/src/link/inline.js @@ -34,9 +34,14 @@ import useLinkInstanceKey from './use-link-instance-key'; const LINK_SETTINGS = [ ...LinkControl.DEFAULT_LINK_SETTINGS, { - id: 'noFollow', + id: 'nofollow', title: __( 'No follow' ), - help: __( 'Search engines should ignore this link' ), + help: createInterpolateElement( + __( + 'Search engines should ignore this link (mark as nofollow)' + ), + { code: } + ), }, ]; @@ -69,7 +74,7 @@ function InlineLinkUI( { type: activeAttributes.type, id: activeAttributes.id, opensInNewTab: activeAttributes.target === '_blank', - noFollow: activeAttributes.rel?.includes( 'nofollow' ), + nofollow: activeAttributes.rel?.includes( 'nofollow' ), title: richTextText, }; @@ -102,7 +107,7 @@ function InlineLinkUI( { ? String( nextValue.id ) : undefined, opensInNewWindow: nextValue.opensInNewTab, - noFollow: nextValue.noFollow, + nofollow: nextValue.nofollow, } ); const newText = nextValue.title || newUrl; diff --git a/packages/format-library/src/link/utils.js b/packages/format-library/src/link/utils.js index 5189aa89760306..12fc56f2420313 100644 --- a/packages/format-library/src/link/utils.js +++ b/packages/format-library/src/link/utils.js @@ -85,7 +85,7 @@ export function isValidHref( href ) { * @param {string} options.type The type of the link. * @param {string} options.id The ID of the link. * @param {boolean} options.opensInNewWindow Whether this link will open in a new window. - * @param {boolean} options.noFollow Whether this link is marked as no follow relationship. + * @param {boolean} options.nofollow Whether this link is marked as no follow relationship. * @return {Object} The final format object. */ export function createLinkFormat( { @@ -93,7 +93,7 @@ export function createLinkFormat( { type, id, opensInNewWindow, - noFollow, + nofollow, } ) { const format = { type: 'core/link', @@ -112,7 +112,7 @@ export function createLinkFormat( { : 'noreferrer noopener'; } - if ( noFollow ) { + if ( nofollow ) { format.attributes.rel = format.attributes.rel ? format.attributes.rel + ' nofollow' : 'nofollow'; From cf2015f7de018c9e64c3638256253dbc84644e95 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 12:14:08 +0100 Subject: [PATCH 08/12] Make help text the title --- packages/block-editor/src/components/link-control/style.scss | 4 ++++ packages/format-library/src/link/inline.js | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/link-control/style.scss b/packages/block-editor/src/components/link-control/style.scss index eef5297676af47..2b37d7fccdfe4b 100644 --- a/packages/block-editor/src/components/link-control/style.scss +++ b/packages/block-editor/src/components/link-control/style.scss @@ -405,6 +405,10 @@ $preview-image-height: 140px; flex: 1; padding: $grid-unit-10 0 $grid-unit-10 $grid-unit-30; + .components-base-control__field { + display: flex; // don't allow label to wrap under checkbox. + } + // Cancel left margin inherited from WP Admin Forms CSS. input { margin-left: 0; diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js index cc6969e58dc581..ae0e10961e33f3 100644 --- a/packages/format-library/src/link/inline.js +++ b/packages/format-library/src/link/inline.js @@ -35,8 +35,7 @@ const LINK_SETTINGS = [ ...LinkControl.DEFAULT_LINK_SETTINGS, { id: 'nofollow', - title: __( 'No follow' ), - help: createInterpolateElement( + title: createInterpolateElement( __( 'Search engines should ignore this link (mark as nofollow)' ), From ab7d7f93dfcd71bc742a8e7afcd35491bb7b0b7e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 12:41:58 +0100 Subject: [PATCH 09/12] Adds test coverage --- test/e2e/specs/editor/blocks/links.spec.js | 82 ++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/test/e2e/specs/editor/blocks/links.spec.js b/test/e2e/specs/editor/blocks/links.spec.js index b84f954566fd55..83efef0bce2f02 100644 --- a/test/e2e/specs/editor/blocks/links.spec.js +++ b/test/e2e/specs/editor/blocks/links.spec.js @@ -233,4 +233,86 @@ test.describe( 'Links', () => { // This verifies that the editor preference was persisted. await expect( page.getByLabel( 'Open in new tab' ) ).not.toBeVisible(); } ); + + test( 'can toggle link settings and save', async ( { + page, + editor, + pageUtils, + } ) => { + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { + content: + 'Gutenberg', + }, + } ); + + // Move caret into the link. + await pageUtils.pressKeys( 'ArrowRight' ); + + // Switch Link UI to "edit" mode. + await page.getByRole( 'button', { name: 'Edit' } ).click(); + + // Open Advanced Settings + await page + .getByRole( 'region', { + name: 'Editor content', + } ) + .getByRole( 'button', { + name: 'Advanced', + } ) + .click(); + + // expect settings for `Open in new tab` and `No follow` + await expect( page.getByLabel( 'Open in new tab' ) ).not.toBeChecked(); + await expect( page.getByLabel( 'nofollow' ) ).not.toBeChecked(); + + // Toggle both of the settings + await page.getByLabel( 'Open in new tab' ).click(); + await page.getByLabel( 'nofollow' ).click(); + + // Save the link + await page + .locator( '.block-editor-link-control' ) + .getByRole( 'button', { name: 'Save' } ) + .click(); + + // Expect correct attributes to be set on the underlying link. + await expect.poll( editor.getBlocks ).toMatchObject( [ + { + name: 'core/paragraph', + attributes: { + content: `Gutenberg`, + }, + }, + ] ); + + // Move caret back into the link. + await page.keyboard.press( 'ArrowRight' ); + await page.keyboard.press( 'ArrowRight' ); + + // Edit the link + await page.getByRole( 'button', { name: 'Edit' } ).click(); + + // Toggle both the settings to be off. + // Note: no need to toggle settings again because the open setting should be persisted. + await page.getByLabel( 'Open in new tab' ).click(); + await page.getByLabel( 'nofollow' ).click(); + + // Save the link + await page + .locator( '.block-editor-link-control' ) + .getByRole( 'button', { name: 'Save' } ) + .click(); + + // Expect correct attributes to be set on the underlying link. + await expect.poll( editor.getBlocks ).toMatchObject( [ + { + name: 'core/paragraph', + attributes: { + content: `Gutenberg`, + }, + }, + ] ); + } ); } ); From 6955878908c29e352360a18ab4f1a53d63114170 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 13:12:02 +0100 Subject: [PATCH 10/12] Use help text to reduce size of label --- packages/format-library/src/link/inline.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js index ae0e10961e33f3..216fcfd7fed0dc 100644 --- a/packages/format-library/src/link/inline.js +++ b/packages/format-library/src/link/inline.js @@ -36,11 +36,10 @@ const LINK_SETTINGS = [ { id: 'nofollow', title: createInterpolateElement( - __( - 'Search engines should ignore this link (mark as nofollow)' - ), + __( 'Mark as nofollow' ), { code: } ), + help: __( 'Search engines should ignore this link.' ), }, ]; From ed90bf776236d413bcb1a4a9eb900d5e45035443 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 25 Aug 2023 13:12:36 +0100 Subject: [PATCH 11/12] Correct text to qualify statement Search engines are not compelled to obey this rule --- packages/format-library/src/link/inline.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js index 216fcfd7fed0dc..243c53f7956ccd 100644 --- a/packages/format-library/src/link/inline.js +++ b/packages/format-library/src/link/inline.js @@ -39,7 +39,7 @@ const LINK_SETTINGS = [ __( 'Mark as nofollow' ), { code: } ), - help: __( 'Search engines should ignore this link.' ), + help: __( 'Ask search engines to ignore this link.' ), }, ]; From ab5a41c7979b81f0827289f1adde7f505bcc2702 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 31 Aug 2023 11:01:51 +0100 Subject: [PATCH 12/12] Remove help text --- packages/format-library/src/link/inline.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/format-library/src/link/inline.js b/packages/format-library/src/link/inline.js index 243c53f7956ccd..62dc4ee3229421 100644 --- a/packages/format-library/src/link/inline.js +++ b/packages/format-library/src/link/inline.js @@ -39,7 +39,6 @@ const LINK_SETTINGS = [ __( 'Mark as nofollow' ), { code: } ), - help: __( 'Ask search engines to ignore this link.' ), }, ];