Skip to content
This repository was archived by the owner on Oct 4, 2022. It is now read-only.

Commit df888f1

Browse files
authored
Merge pull request #816 from Yoast/highlight-wordforms-snippet-preview
Add KeywordForms to Snippet components
2 parents 9dd067e + 19e454a commit df888f1

File tree

5 files changed

+499
-32
lines changed

5 files changed

+499
-32
lines changed

composites/Plugin/SnippetEditor/components/SnippetEditor.js

+4
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ class SnippetEditor extends React.Component {
516516
date,
517517
locale,
518518
keyword,
519+
wordsToHighlight,
519520
showCloseButton,
520521
} = this.props;
521522

@@ -538,6 +539,7 @@ class SnippetEditor extends React.Component {
538539
<div>
539540
<SnippetPreview
540541
keyword={ keyword }
542+
wordsToHighlight={ wordsToHighlight }
541543
mode={ mode }
542544
date={ date }
543545
activeField={ this.mapFieldToPreview( activeField ) }
@@ -586,6 +588,7 @@ SnippetEditor.propTypes = {
586588
descriptionLengthProgress: lengthProgressShape,
587589
mapEditorDataToPreview: PropTypes.func,
588590
keyword: PropTypes.string,
591+
wordsToHighlight: PropTypes.array,
589592
locale: PropTypes.string,
590593
hasPaperStyle: PropTypes.bool,
591594
showCloseButton: PropTypes.bool,
@@ -594,6 +597,7 @@ SnippetEditor.propTypes = {
594597
SnippetEditor.defaultProps = {
595598
mode: DEFAULT_MODE,
596599
date: "",
600+
wordsToHighlight: [],
597601
replacementVariables: [],
598602
recommendedReplacementVariables: [],
599603
titleLengthProgress: {

composites/Plugin/SnippetEditor/tests/__snapshots__/SnippetEditorTest.js.snap

+26
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ exports[`SnippetEditor activates a field on onMouseUp() and opens the editor 1`]
487487
onMouseUp={[Function]}
488488
title="Test title"
489489
url="example.org/test-slug"
490+
wordsToHighlight={Array []}
490491
/>
491492
<ModeSwitcher
492493
active="mobile"
@@ -1116,6 +1117,7 @@ exports[`SnippetEditor calls callbacks when the editors are focused or changed 1
11161117
"score": 0,
11171118
}
11181119
}
1120+
wordsToHighlight={Array []}
11191121
>
11201122
<ErrorBoundary>
11211123
<div>
@@ -1135,6 +1137,7 @@ exports[`SnippetEditor calls callbacks when the editors are focused or changed 1
11351137
onMouseUp={[Function]}
11361138
title="Test title"
11371139
url="example.org/test-slug"
1140+
wordsToHighlight={Array []}
11381141
>
11391142
<section>
11401143
<SnippetPreview__MobileContainer
@@ -3034,6 +3037,7 @@ exports[`SnippetEditor calls callbacks when the editors are focused or changed 2
30343037
"score": 0,
30353038
}
30363039
}
3040+
wordsToHighlight={Array []}
30373041
>
30383042
<ErrorBoundary>
30393043
<div>
@@ -3053,6 +3057,7 @@ exports[`SnippetEditor calls callbacks when the editors are focused or changed 2
30533057
onMouseUp={[Function]}
30543058
title="Test title"
30553059
url="example.org/test-slug"
3060+
wordsToHighlight={Array []}
30563061
>
30573062
<section>
30583063
<SnippetPreview__MobileContainer
@@ -4952,6 +4957,7 @@ exports[`SnippetEditor calls callbacks when the editors are focused or changed 3
49524957
"score": 0,
49534958
}
49544959
}
4960+
wordsToHighlight={Array []}
49554961
>
49564962
<ErrorBoundary>
49574963
<div>
@@ -4971,6 +4977,7 @@ exports[`SnippetEditor calls callbacks when the editors are focused or changed 3
49714977
onMouseUp={[Function]}
49724978
title="Test title"
49734979
url="example.org/test-slug"
4980+
wordsToHighlight={Array []}
49744981
>
49754982
<section>
49764983
<SnippetPreview__MobileContainer
@@ -6870,6 +6877,7 @@ exports[`SnippetEditor closes when calling close() 1`] = `
68706877
"score": 0,
68716878
}
68726879
}
6880+
wordsToHighlight={Array []}
68736881
>
68746882
<ErrorBoundary>
68756883
<div>
@@ -6889,6 +6897,7 @@ exports[`SnippetEditor closes when calling close() 1`] = `
68896897
onMouseUp={[Function]}
68906898
title="Test title"
68916899
url="example.org/test-slug"
6900+
wordsToHighlight={Array []}
68926901
>
68936902
<section>
68946903
<SnippetPreview__MobileContainer
@@ -8545,6 +8554,7 @@ exports[`SnippetEditor closes when calling close() 2`] = `
85458554
"score": 0,
85468555
}
85478556
}
8557+
wordsToHighlight={Array []}
85488558
>
85498559
<ErrorBoundary>
85508560
<div>
@@ -8564,6 +8574,7 @@ exports[`SnippetEditor closes when calling close() 2`] = `
85648574
onMouseUp={[Function]}
85658575
title="Test title"
85668576
url="example.org/test-slug"
8577+
wordsToHighlight={Array []}
85678578
>
85688579
<section>
85698580
<SnippetPreview__MobileContainer
@@ -9812,6 +9823,7 @@ exports[`SnippetEditor colored progress bars can handle a score of 6 1`] = `
98129823
"score": 6,
98139824
}
98149825
}
9826+
wordsToHighlight={Array []}
98159827
>
98169828
<ErrorBoundary>
98179829
<div>
@@ -9831,6 +9843,7 @@ exports[`SnippetEditor colored progress bars can handle a score of 6 1`] = `
98319843
onMouseUp={[Function]}
98329844
title="Test title"
98339845
url="example.org/test-slug"
9846+
wordsToHighlight={Array []}
98349847
>
98359848
<section>
98369849
<SnippetPreview__MobileContainer
@@ -11730,6 +11743,7 @@ exports[`SnippetEditor colored progress bars can handle scores of 3 and 9 1`] =
1173011743
"score": 3,
1173111744
}
1173211745
}
11746+
wordsToHighlight={Array []}
1173311747
>
1173411748
<ErrorBoundary>
1173511749
<div>
@@ -11749,6 +11763,7 @@ exports[`SnippetEditor colored progress bars can handle scores of 3 and 9 1`] =
1174911763
onMouseUp={[Function]}
1175011764
title="Test title"
1175111765
url="example.org/test-slug"
11766+
wordsToHighlight={Array []}
1175211767
>
1175311768
<section>
1175411769
<SnippetPreview__MobileContainer
@@ -14596,6 +14611,7 @@ exports[`SnippetEditor highlights the active ReplacementVariableEditor when call
1459614611
"score": 0,
1459714612
}
1459814613
}
14614+
wordsToHighlight={Array []}
1459914615
>
1460014616
<ErrorBoundary>
1460114617
<div>
@@ -14615,6 +14631,7 @@ exports[`SnippetEditor highlights the active ReplacementVariableEditor when call
1461514631
onMouseUp={[Function]}
1461614632
title="Test title"
1461714633
url="example.org/test-slug"
14634+
wordsToHighlight={Array []}
1461814635
>
1461914636
<section>
1462014637
<SnippetPreview__MobileContainer
@@ -16534,6 +16551,7 @@ exports[`SnippetEditor highlights the hovered field when onMouseEnter() is calle
1653416551
"score": 0,
1653516552
}
1653616553
}
16554+
wordsToHighlight={Array []}
1653716555
>
1653816556
<ErrorBoundary>
1653916557
<div>
@@ -16553,6 +16571,7 @@ exports[`SnippetEditor highlights the hovered field when onMouseEnter() is calle
1655316571
onMouseUp={[Function]}
1655416572
title="Test title"
1655516573
url="example.org/test-slug"
16574+
wordsToHighlight={Array []}
1655616575
>
1655716576
<section>
1655816577
<SnippetPreview__MobileContainer
@@ -18460,6 +18479,7 @@ exports[`SnippetEditor opens when calling open() 1`] = `
1846018479
"score": 0,
1846118480
}
1846218481
}
18482+
wordsToHighlight={Array []}
1846318483
>
1846418484
<ErrorBoundary>
1846518485
<div>
@@ -18479,6 +18499,7 @@ exports[`SnippetEditor opens when calling open() 1`] = `
1847918499
onMouseUp={[Function]}
1848018500
title="Test title"
1848118501
url="example.org/test-slug"
18502+
wordsToHighlight={Array []}
1848218503
>
1848318504
<section>
1848418505
<SnippetPreview__MobileContainer
@@ -20389,6 +20410,7 @@ exports[`SnippetEditor passes replacement variables to the title and description
2038920410
"score": 0,
2039020411
}
2039120412
}
20413+
wordsToHighlight={Array []}
2039220414
>
2039320415
<ErrorBoundary>
2039420416
<div>
@@ -20408,6 +20430,7 @@ exports[`SnippetEditor passes replacement variables to the title and description
2040820430
onMouseUp={[Function]}
2040920431
title="Test title"
2041020432
url="example.org/test-slug"
20433+
wordsToHighlight={Array []}
2041120434
>
2041220435
<section>
2041320436
<SnippetPreview__MobileContainer
@@ -22312,6 +22335,7 @@ exports[`SnippetEditor removes the highlight from the hovered field on calling o
2231222335
onMouseUp={[Function]}
2231322336
title="Test title"
2231422337
url="example.org/test-slug"
22338+
wordsToHighlight={Array []}
2231522339
/>
2231622340
<ModeSwitcher
2231722341
active="mobile"
@@ -22941,6 +22965,7 @@ exports[`SnippetEditor removes the highlight when calling unsetFieldFocus 1`] =
2294122965
"score": 0,
2294222966
}
2294322967
}
22968+
wordsToHighlight={Array []}
2294422969
>
2294522970
<ErrorBoundary>
2294622971
<div>
@@ -22960,6 +22985,7 @@ exports[`SnippetEditor removes the highlight when calling unsetFieldFocus 1`] =
2296022985
onMouseUp={[Function]}
2296122986
title="Test title"
2296222987
url="example.org/test-slug"
22988+
wordsToHighlight={Array []}
2296322989
>
2296422990
<section>
2296522991
<SnippetPreview__MobileContainer

composites/Plugin/SnippetPreview/components/SnippetPreview.js

+37-30
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React, { PureComponent } from "react";
33
import styled from "styled-components";
44
import interpolateComponents from "interpolate-components";
55
import transliterate from "yoastseo/src/stringProcessing/transliterate";
6-
import createWordRegex from "yoastseo/src/stringProcessing/createWordRegex";
6+
import createRegexFromArray from "yoastseo/src/stringProcessing/createRegexFromArray";
77
import replaceSpecialCharactersAndDiacritics from "yoastseo/src/stringProcessing/replaceDiacritics";
88
import PropTypes from "prop-types";
99
import truncate from "lodash/truncate";
@@ -197,44 +197,49 @@ const Amp = styled.div`
197197
* Highlights a keyword with strong React elements.
198198
*
199199
* @param {string} locale ISO 639 (2/3 characters) locale.
200-
* @param {string} keyword The keyword.
201-
* @param {string} text The text in which to highlight a keyword.
202-
* @param {string} cleanText Optional. The text in which to highlight a keyword
200+
* @param {string[]} wordsToHighlight The array of words to be highlighted.
201+
* @param {string} text The text in which to highlight words.
202+
* @param {string} cleanText Optional. The text in which to highlight words
203203
* without special characters and diacritics.
204204
*
205205
* @returns {ReactElement} React elements to be rendered.
206206
*/
207-
function highlightKeyword( locale, keyword, text, cleanText ) {
208-
if ( ! keyword ) {
207+
function highlightWords( locale, wordsToHighlight, text, cleanText ) {
208+
if ( wordsToHighlight.length === 0 ) {
209209
return text;
210210
}
211211

212-
/*
213-
* When a text has been cleaned up from special characters and diacritics
214-
* we need to match against a cleaned up keyword as well.
215-
*/
216-
const textToUse = cleanText ? cleanText : text;
217-
const keywordToUse = cleanText ? replaceSpecialCharactersAndDiacritics( keyword ) : keyword;
212+
// Clean the text from special characters and diacritics.
213+
let textToUse = cleanText ? cleanText : text;
218214

219-
// Match keyword case-insensitively.
220-
const keywordMatcher = createWordRegex( keywordToUse, "", false );
215+
// Initiate an array of cleaned and transliterated forms.
216+
const wordsToHighlightCleaned = [];
221217

222-
text = textToUse.replace( keywordMatcher, function( matchedKeyword ) {
223-
return `{{strong}}${ matchedKeyword }{{/strong}}`;
218+
wordsToHighlight.forEach( function( form ) {
219+
/*
220+
* When a text has been cleaned up from special characters and diacritics
221+
* we need to match against a cleaned up keyword as well.
222+
*/
223+
form = cleanText ? replaceSpecialCharactersAndDiacritics( form ) : form;
224+
225+
wordsToHighlightCleaned.push( form );
226+
227+
// Transliterate the keyword for highlighting
228+
const formTransliterated = transliterate( form, locale );
229+
230+
if ( formTransliterated !== form ) {
231+
wordsToHighlightCleaned.push( formTransliterated );
232+
}
224233
} );
225234

226-
// Transliterate the keyword for highlighting
227-
const transliteratedKeyword = transliterate( keyword, locale );
228-
if ( transliteratedKeyword !== keyword ) {
229-
const transliteratedKeywordMatcher = createWordRegex( transliteratedKeyword, "", false );
230-
// Let the transliteration run on the text with no previous replacements.
231-
text = text.replace( transliteratedKeywordMatcher, function( matchedKeyword ) {
232-
return `{{strong}}${ matchedKeyword }{{/strong}}`;
233-
} );
234-
}
235+
const keywordFormsMatcher = createRegexFromArray( wordsToHighlightCleaned, false, "", false );
236+
237+
textToUse = textToUse.replace( keywordFormsMatcher, function( matchedKeyword ) {
238+
return `{{strong}}${ matchedKeyword }{{/strong}}`;
239+
} );
235240

236241
return interpolateComponents( {
237-
mixedString: text,
242+
mixedString: textToUse,
238243
components: { strong: <strong /> },
239244
} );
240245
}
@@ -470,7 +475,7 @@ export default class SnippetPreview extends PureComponent {
470475

471476
/*
472477
* We need to replace special characters and diacritics only on the url
473-
* string because when highlightKeyword kicks in, interpolateComponents
478+
* string because when highlightWords kicks in, interpolateComponents
474479
* returns an array of strings plus a strong React element, and replace()
475480
* can't run on an array.
476481
*/
@@ -562,7 +567,7 @@ export default class SnippetPreview extends PureComponent {
562567
*/
563568
renderDescription() {
564569
const {
565-
keyword,
570+
wordsToHighlight,
566571
locale,
567572
onMouseUp,
568573
onMouseLeave,
@@ -587,7 +592,7 @@ export default class SnippetPreview extends PureComponent {
587592
innerRef={ this.setDescriptionRef }
588593
>
589594
{ renderedDate }
590-
{ highlightKeyword( locale, keyword, this.getDescription() ) }
595+
{ highlightWords( locale, wordsToHighlight, this.getDescription() ) }
591596
</DesktopDescriptionWithCaret>
592597
);
593598
} else if ( mode === MODE_MOBILE ) {
@@ -601,7 +606,7 @@ export default class SnippetPreview extends PureComponent {
601606
innerRef={ this.setDescriptionRef }
602607
>
603608
{ renderedDate }
604-
{ highlightKeyword( locale, keyword, this.getDescription() ) }
609+
{ highlightWords( locale, wordsToHighlight, this.getDescription() ) }
605610
</MobileDescription>
606611
</MobileDescriptionWithCaret>
607612
);
@@ -718,6 +723,7 @@ SnippetPreview.propTypes = {
718723
hoveredField: PropTypes.string,
719724
activeField: PropTypes.string,
720725
keyword: PropTypes.string,
726+
wordsToHighlight: PropTypes.array,
721727
locale: PropTypes.string,
722728
mode: PropTypes.oneOf( MODES ),
723729
isAmp: PropTypes.bool,
@@ -731,6 +737,7 @@ SnippetPreview.propTypes = {
731737
SnippetPreview.defaultProps = {
732738
date: "",
733739
keyword: "",
740+
wordsToHighlight: [],
734741
breadcrumbs: null,
735742
locale: "en",
736743
hoveredField: "",

0 commit comments

Comments
 (0)