Skip to content

Commit

Permalink
Link Control: Add more controls
Browse files Browse the repository at this point in the history
After almost three years and a lot of fruitful discussion, it's finally here. The ability to add a nofollow rel to a link.

Everything works in the backend as shown on the screengrab. The only thing I couldn't figure out in the time I had was how to save this to the markup so it also renders correctly on the frontend. Hope someone can help with this or point me in the right direction.

Fixes WordPress#23011
  • Loading branch information
tomdevisser committed Mar 3, 2023
1 parent 45e038e commit 7d1351c
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,10 @@ export const DEFAULT_LINK_SETTINGS = [
id: 'opensInNewTab',
title: __( 'Open in new tab' ),
},
{
id: 'markAsNoFollow',
title: __(
'Search engines should ignore this link (mark as nofollow)'
),
},
];
13 changes: 8 additions & 5 deletions packages/block-editor/src/components/link-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ import { DEFAULT_LINK_SETTINGS } from './constants';
*
* @typedef WPLinkControlDefaultValue
*
* @property {string} url Link URL.
* @property {string=} title Link title.
* @property {boolean=} opensInNewTab Whether link should open in a new browser
* tab. This value is only assigned if not
* providing a custom `settings` prop.
* @property {string} url Link URL.
* @property {string=} title Link title.
* @property {boolean=} opensInNewTab Whether link should open in a new browser
* tab. This value is only assigned if not
* providing a custom `settings` prop.
* @property {boolean=} markAsNoFollow Whether link should be marked as
* `nofollow`. This value is only assigned
* if not providing a custom `settings` prop.
*/

/* eslint-disable jsdoc/valid-types */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function useInternalInputValue( value ) {
if ( value && value !== internalInputValue ) {
setInternalInputValue( value );
}
}, [ value ] );
}, [ internalInputValue, value ] );

return [ internalInputValue, setInternalInputValue ];
}
2 changes: 2 additions & 0 deletions packages/format-library/src/link/inline.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ function InlineLinkUI( {
type: activeAttributes.type,
id: activeAttributes.id,
opensInNewTab: activeAttributes.target === '_blank',
markAsNoFollow: activeAttributes.rel?.includes( 'nofollow' ),
title: richTextText,
...nextLinkValue,
};
Expand Down Expand Up @@ -118,6 +119,7 @@ function InlineLinkUI( {
? String( nextValue.id )
: undefined,
opensInNewWindow: nextValue.opensInNewTab,
markAsNoFollow: nextValue.markAsNoFollow,
} );

const newText = nextValue.title || newUrl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ const LinkSettingsScreen = ( {
const [ opensInNewWindow, setOpensInNewWindows ] = useState(
activeAttributes.target === '_blank'
);
const [ markedAsNoFollow, setMarkedAsNoFollow ] = useState(
( activeAttributes.rel = 'nofollow' )
);
const [ linkValues, setLinkValues ] = useState( {
isActiveLink: isActive,
isRemovingLink: false,
Expand All @@ -64,7 +67,7 @@ const LinkSettingsScreen = ( {
onHandleClosingBottomSheet( () => {
submit( inputValue, { skipStateUpdates: true } );
} );
}, [ inputValue, opensInNewWindow, text ] );
}, [ inputValue, opensInNewWindow, markedAsNoFollow, text ] );

useEffect( () => {
const { isActiveLink, isRemovingLink } = linkValues;
Expand Down Expand Up @@ -99,6 +102,7 @@ const LinkSettingsScreen = ( {
const format = createLinkFormat( {
url,
opensInNewWindow,
markedAsNoFollow,
text: linkText,
} );
let newAttributes;
Expand Down Expand Up @@ -213,6 +217,15 @@ const LinkSettingsScreen = ( {
onValueChange={ setOpensInNewWindows }
separatorType={ 'fullWidth' }
/>
<BottomSheet.SwitchCell
icon={ external }
label={ __(
'Search engines should ignore this link (mark as nofollow)'
) }
value={ markedAsNoFollow }
onValueChange={ setMarkedAsNoFollow }
separatorType={ 'fullWidth' }
/>
<BottomSheet.Cell
label={ __( 'Remove link' ) }
labelStyle={ styles.clearLinkButton }
Expand Down
19 changes: 17 additions & 2 deletions packages/format-library/src/link/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,17 @@ 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.markAsNoFollow Whether this link will be marked as nofollow.
*
* @return {Object} The final format object.
*/
export function createLinkFormat( { url, type, id, opensInNewWindow } ) {
export function createLinkFormat( {
url,
type,
id,
opensInNewWindow,
markAsNoFollow,
} ) {
const format = {
type: 'core/link',
attributes: {
Expand All @@ -101,7 +108,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 ( markAsNoFollow ) {
format.attributes.rel = format.attributes.rel
? format.attributes.rel + ' nofollow'
: 'nofollow';
}

return format;
Expand Down

0 comments on commit 7d1351c

Please sign in to comment.